From 62db6621eedbdb9003b909689782d147ffe77327 Mon Sep 17 00:00:00 2001 From: Luke Sneeringer Date: Fri, 2 Jun 2017 14:36:29 -0700 Subject: [PATCH] Vision semi-GAPIC (#3373) --- .gitignore | 1 + bigquery/google/cloud/bigquery/client.py | 14 +- bigquery/google/cloud/bigquery/dataset.py | 8 +- bigquery/google/cloud/bigquery/job.py | 60 +- bigquery/google/cloud/bigquery/query.py | 38 +- bigquery/google/cloud/bigquery/table.py | 12 +- bigquery/tests/system.py | 6 +- bigtable/tests/unit/test_row_data.py | 2 +- core/google/cloud/exceptions.py | 4 +- core/google/cloud/iam.py | 2 +- core/google/cloud/operation.py | 2 +- datastore/google/cloud/datastore/query.py | 12 +- dns/google/cloud/dns/changes.py | 4 +- dns/google/cloud/dns/client.py | 4 +- dns/google/cloud/dns/resource_record_set.py | 2 +- dns/google/cloud/dns/zone.py | 12 +- docs/bigquery/snippets.py | 2 +- docs/conf.py | 15 +- docs/index.rst | 2 +- docs/vision/annotations.rst | 7 - docs/vision/batch.rst | 10 - docs/vision/client.rst | 10 - docs/vision/color.rst | 10 - docs/vision/crop-hint.rst | 10 - docs/vision/entity.rst | 10 - docs/vision/face.rst | 10 - docs/vision/feature.rst | 10 - docs/vision/gapic/api.rst | 6 + docs/vision/gapic/types.rst | 5 + docs/vision/image.rst | 26 - docs/vision/index.rst | 131 ++ docs/vision/safe-search.rst | 10 - docs/vision/text.rst | 10 - docs/vision/usage.rst | 414 ---- docs/vision/web.rst | 10 - .../google/cloud/error_reporting/client.py | 2 +- logging/google/cloud/logging/_gax.py | 6 +- logging/google/cloud/logging/_http.py | 34 +- logging/google/cloud/logging/client.py | 14 +- logging/google/cloud/logging/entries.py | 6 +- .../cloud/logging/handlers/app_engine.py | 2 +- .../google/cloud/logging/handlers/handlers.py | 4 +- logging/google/cloud/logging/logger.py | 14 +- logging/google/cloud/logging/metric.py | 4 +- logging/google/cloud/logging/sink.py | 4 +- .../google/cloud/monitoring/timeseries.py | 2 +- nox.py | 2 +- pubsub/google/cloud/pubsub/_gax.py | 36 +- pubsub/google/cloud/pubsub/_http.py | 42 +- pubsub/google/cloud/pubsub/client.py | 6 +- pubsub/google/cloud/pubsub/iam.py | 2 +- pubsub/google/cloud/pubsub/message.py | 2 +- pubsub/google/cloud/pubsub/snapshot.py | 4 +- pubsub/google/cloud/pubsub/subscription.py | 26 +- pubsub/google/cloud/pubsub/topic.py | 16 +- .../google/cloud/resource_manager/client.py | 2 +- .../google/cloud/resource_manager/project.py | 4 +- .../google/cloud/runtimeconfig/_helpers.py | 4 +- .../google/cloud/runtimeconfig/config.py | 8 +- .../google/cloud/runtimeconfig/variable.py | 18 +- setup.py | 5 +- spanner/google/cloud/spanner/client.py | 6 +- spanner/google/cloud/spanner/database.py | 18 +- spanner/google/cloud/spanner/instance.py | 12 +- spanner/google/cloud/spanner/session.py | 10 +- spanner/google/cloud/spanner/snapshot.py | 4 +- spanner/tests/unit/test_streamed.py | 2 +- speech/google/cloud/speech/_gax.py | 4 +- speech/google/cloud/speech/encoding.py | 2 +- speech/google/cloud/speech/sample.py | 2 +- storage/google/cloud/storage/acl.py | 2 +- storage/google/cloud/storage/batch.py | 2 +- storage/google/cloud/storage/blob.py | 54 +- storage/google/cloud/storage/bucket.py | 46 +- translate/google/cloud/translate/client.py | 6 +- vision/MANIFEST.in | 2 +- vision/google/cloud/gapic/__init__.py | 1 + vision/google/cloud/gapic/vision/__init__.py | 1 + .../google/cloud/gapic/vision/v1/__init__.py | 0 vision/google/cloud/gapic/vision/v1/enums.py | 195 ++ .../gapic/vision/v1/image_annotator_client.py | 179 ++ .../v1/image_annotator_client_config.json | 33 + vision/google/cloud/proto/__init__.py | 1 + vision/google/cloud/proto/vision/__init__.py | 1 + .../google/cloud/proto/vision/v1/__init__.py | 1 + .../cloud/proto/vision/v1/geometry_pb2.py | 211 ++ .../proto/vision/v1/geometry_pb2_grpc.py | 3 + .../proto/vision/v1/image_annotator_pb2.py | 1996 +++++++++++++++++ .../vision/v1/image_annotator_pb2_grpc.py | 50 + .../proto/vision/v1/text_annotation_pb2.py | 742 ++++++ .../vision/v1/text_annotation_pb2_grpc.py | 3 + .../proto/vision/v1/web_detection_pb2.py | 290 +++ .../proto/vision/v1/web_detection_pb2_grpc.py | 3 + vision/google/cloud/vision/__init__.py | 33 +- vision/google/cloud/vision/client.py | 9 + vision/google/cloud/vision/decorators.py | 116 + vision/google/cloud/vision/face.py | 2 +- vision/google/cloud/vision/feature.py | 4 +- vision/google/cloud/vision/geometry.py | 4 +- vision/google/cloud/vision/helpers.py | 85 + vision/google/cloud/vision/image.py | 2 +- vision/google/cloud/vision/likelihood.py | 2 +- vision/google/cloud/vision_v1/__init__.py | 35 + vision/google/cloud/vision_v1/types.py | 35 + vision/nox.py | 53 +- vision/setup.py | 62 +- .../v1/test_image_annotator_client_v1.py | 75 + vision/tests/system.py | 797 +------ vision/tests/system_old.py | 744 ++++++ vision/tests/unit/__init__.py | 13 - vision/tests/unit/test_decorators.py | 69 + vision/tests/unit/test_helpers.py | 136 ++ 112 files changed, 5649 insertions(+), 1669 deletions(-) delete mode 100644 docs/vision/annotations.rst delete mode 100644 docs/vision/batch.rst delete mode 100644 docs/vision/client.rst delete mode 100644 docs/vision/color.rst delete mode 100644 docs/vision/crop-hint.rst delete mode 100644 docs/vision/entity.rst delete mode 100644 docs/vision/face.rst delete mode 100644 docs/vision/feature.rst create mode 100644 docs/vision/gapic/api.rst create mode 100644 docs/vision/gapic/types.rst delete mode 100644 docs/vision/image.rst create mode 100644 docs/vision/index.rst delete mode 100644 docs/vision/safe-search.rst delete mode 100644 docs/vision/text.rst delete mode 100644 docs/vision/usage.rst delete mode 100644 docs/vision/web.rst create mode 100644 vision/google/cloud/gapic/__init__.py create mode 100644 vision/google/cloud/gapic/vision/__init__.py create mode 100644 vision/google/cloud/gapic/vision/v1/__init__.py create mode 100644 vision/google/cloud/gapic/vision/v1/enums.py create mode 100644 vision/google/cloud/gapic/vision/v1/image_annotator_client.py create mode 100644 vision/google/cloud/gapic/vision/v1/image_annotator_client_config.json create mode 100644 vision/google/cloud/proto/__init__.py create mode 100644 vision/google/cloud/proto/vision/__init__.py create mode 100644 vision/google/cloud/proto/vision/v1/__init__.py create mode 100644 vision/google/cloud/proto/vision/v1/geometry_pb2.py create mode 100644 vision/google/cloud/proto/vision/v1/geometry_pb2_grpc.py create mode 100644 vision/google/cloud/proto/vision/v1/image_annotator_pb2.py create mode 100644 vision/google/cloud/proto/vision/v1/image_annotator_pb2_grpc.py create mode 100644 vision/google/cloud/proto/vision/v1/text_annotation_pb2.py create mode 100644 vision/google/cloud/proto/vision/v1/text_annotation_pb2_grpc.py create mode 100644 vision/google/cloud/proto/vision/v1/web_detection_pb2.py create mode 100644 vision/google/cloud/proto/vision/v1/web_detection_pb2_grpc.py create mode 100644 vision/google/cloud/vision/decorators.py create mode 100644 vision/google/cloud/vision/helpers.py create mode 100644 vision/google/cloud/vision_v1/__init__.py create mode 100644 vision/google/cloud/vision_v1/types.py create mode 100644 vision/tests/gapic/v1/test_image_annotator_client_v1.py create mode 100644 vision/tests/system_old.py create mode 100644 vision/tests/unit/test_decorators.py create mode 100644 vision/tests/unit/test_helpers.py diff --git a/.gitignore b/.gitignore index cf78b1e3e91a9..df4fe06fa5aee 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,7 @@ pip-log.txt .nox .tox .cache +htmlcov # Translations *.mo diff --git a/bigquery/google/cloud/bigquery/client.py b/bigquery/google/cloud/bigquery/client.py index bf0b0a31dcc03..5f0101f35de53 100644 --- a/bigquery/google/cloud/bigquery/client.py +++ b/bigquery/google/cloud/bigquery/client.py @@ -86,7 +86,7 @@ def __init__(self, project=None, credentials=None, _http=None): def list_projects(self, max_results=None, page_token=None): """List projects for the project associated with this client. - See: + See https://cloud.google.com/bigquery/docs/reference/rest/v2/projects/list :type max_results: int @@ -111,7 +111,7 @@ def list_datasets(self, include_all=False, max_results=None, page_token=None): """List datasets for the project associated with this client. - See: + See https://cloud.google.com/bigquery/docs/reference/rest/v2/datasets/list :type include_all: bool @@ -183,7 +183,7 @@ def list_jobs(self, max_results=None, page_token=None, all_users=None, state_filter=None): """List jobs for the project associated with this client. - See: + See https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs/list :type max_results: int @@ -227,7 +227,7 @@ def list_jobs(self, max_results=None, page_token=None, all_users=None, def load_table_from_storage(self, job_name, destination, *source_uris): """Construct a job for loading data into a table from CloudStorage. - See: + See https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs#configuration.load :type job_name: str @@ -249,7 +249,7 @@ def load_table_from_storage(self, job_name, destination, *source_uris): def copy_table(self, job_name, destination, *sources): """Construct a job for copying one or more tables into another table. - See: + See https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs#configuration.copy :type job_name: str @@ -269,7 +269,7 @@ def copy_table(self, job_name, destination, *sources): def extract_table_to_storage(self, job_name, source, *destination_uris): """Construct a job for extracting a table into Cloud Storage files. - See: + See https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs#configuration.extract :type job_name: str @@ -293,7 +293,7 @@ def run_async_query(self, job_name, query, udf_resources=(), query_parameters=()): """Construct a job for running a SQL query asynchronously. - See: + See https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs#configuration.query :type job_name: str diff --git a/bigquery/google/cloud/bigquery/dataset.py b/bigquery/google/cloud/bigquery/dataset.py index f98bb95b10988..bce74ca9f3664 100644 --- a/bigquery/google/cloud/bigquery/dataset.py +++ b/bigquery/google/cloud/bigquery/dataset.py @@ -89,7 +89,7 @@ def __repr__(self): class Dataset(object): """Datasets are containers for tables. - See: + See https://cloud.google.com/bigquery/docs/reference/rest/v2/datasets :type name: str @@ -417,7 +417,7 @@ def _build_resource(self): def create(self, client=None): """API call: create the dataset via a PUT request. - See: + See https://cloud.google.com/bigquery/docs/reference/rest/v2/tables/insert :type client: :class:`~google.cloud.bigquery.client.Client` or @@ -530,7 +530,7 @@ def update(self, client=None): def delete(self, client=None): """API call: delete the dataset via a DELETE request. - See: + See https://cloud.google.com/bigquery/docs/reference/rest/v2/tables/delete :type client: :class:`~google.cloud.bigquery.client.Client` or @@ -544,7 +544,7 @@ def delete(self, client=None): def list_tables(self, max_results=None, page_token=None): """List tables for the project associated with this client. - See: + See https://cloud.google.com/bigquery/docs/reference/rest/v2/tables/list :type max_results: int diff --git a/bigquery/google/cloud/bigquery/job.py b/bigquery/google/cloud/bigquery/job.py index c6ee642dfc7cd..4f791bdbea0c9 100644 --- a/bigquery/google/cloud/bigquery/job.py +++ b/bigquery/google/cloud/bigquery/job.py @@ -301,7 +301,7 @@ def _get_resource_config(cls, resource): def begin(self, client=None): """API call: begin the job via a POST request - See: + See https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs/insert :type client: :class:`~google.cloud.bigquery.client.Client` or @@ -497,57 +497,57 @@ def output_rows(self): return int(statistics['load']['outputRows']) allow_jagged_rows = _TypedProperty('allow_jagged_rows', bool) - """See: + """See https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs#configuration.load.allowJaggedRows """ allow_quoted_newlines = _TypedProperty('allow_quoted_newlines', bool) - """See: + """See https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs#configuration.load.allowQuotedNewlines """ create_disposition = CreateDisposition('create_disposition') - """See: + """See https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs#configuration.load.createDisposition """ encoding = Encoding('encoding') - """See: + """See https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs#configuration.load.encoding """ field_delimiter = _TypedProperty('field_delimiter', six.string_types) - """See: + """See https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs#configuration.load.fieldDelimiter """ ignore_unknown_values = _TypedProperty('ignore_unknown_values', bool) - """See: + """See https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs#configuration.load.ignoreUnknownValues """ max_bad_records = _TypedProperty('max_bad_records', six.integer_types) - """See: + """See https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs#configuration.load.maxBadRecords """ quote_character = _TypedProperty('quote_character', six.string_types) - """See: + """See https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs#configuration.load.quote """ skip_leading_rows = _TypedProperty('skip_leading_rows', six.integer_types) - """See: + """See https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs#configuration.load.skipLeadingRows """ source_format = SourceFormat('source_format') - """See: + """See https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs#configuration.load.sourceFormat """ write_disposition = WriteDisposition('write_disposition') - """See: + """See https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs#configuration.load.writeDisposition """ @@ -672,12 +672,12 @@ def __init__(self, name, destination, sources, client): self._configuration = _CopyConfiguration() create_disposition = CreateDisposition('create_disposition') - """See: + """See https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs#configuration.copy.createDisposition """ write_disposition = WriteDisposition('write_disposition') - """See: + """See https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs#configuration.copy.writeDisposition """ @@ -795,22 +795,22 @@ def __init__(self, name, source, destination_uris, client): self._configuration = _ExtractConfiguration() compression = Compression('compression') - """See: + """See https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs#configuration.extract.compression """ destination_format = DestinationFormat('destination_format') - """See: + """See https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs#configuration.extract.destinationFormat """ field_delimiter = _TypedProperty('field_delimiter', six.string_types) - """See: + """See https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs#configuration.extract.fieldDelimiter """ print_header = _TypedProperty('print_header', bool) - """See: + """See https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs#configuration.extract.printHeader """ @@ -936,32 +936,32 @@ def __init__(self, name, query, client, self._configuration = _AsyncQueryConfiguration() allow_large_results = _TypedProperty('allow_large_results', bool) - """See: + """See https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs#configuration.query.allowLargeResults """ create_disposition = CreateDisposition('create_disposition') - """See: + """See https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs#configuration.query.createDisposition """ default_dataset = _TypedProperty('default_dataset', Dataset) - """See: + """See https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs#configuration.query.defaultDataset """ destination = _TypedProperty('destination', Table) - """See: + """See https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs#configuration.query.destinationTable """ flatten_results = _TypedProperty('flatten_results', bool) - """See: + """See https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs#configuration.query.flattenResults """ priority = QueryPriority('priority') - """See: + """See https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs#configuration.query.priority """ @@ -970,34 +970,34 @@ def __init__(self, name, query, client, udf_resources = UDFResourcesProperty() use_query_cache = _TypedProperty('use_query_cache', bool) - """See: + """See https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs#configuration.query.useQueryCache """ use_legacy_sql = _TypedProperty('use_legacy_sql', bool) - """See: + """See https://cloud.google.com/bigquery/docs/\ reference/v2/jobs#configuration.query.useLegacySql """ dry_run = _TypedProperty('dry_run', bool) - """See: + """See https://cloud.google.com/bigquery/docs/\ reference/rest/v2/jobs#configuration.dryRun """ write_disposition = WriteDisposition('write_disposition') - """See: + """See https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs#configuration.query.writeDisposition """ maximum_billing_tier = _TypedProperty('maximum_billing_tier', int) - """See: + """See https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs#configuration.query.maximumBillingTier """ maximum_bytes_billed = _TypedProperty('maximum_bytes_billed', int) - """See: + """See https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs#configuration.query.maximumBytesBilled """ diff --git a/bigquery/google/cloud/bigquery/query.py b/bigquery/google/cloud/bigquery/query.py index ee24d8397b736..ea704bf4a8e5f 100644 --- a/bigquery/google/cloud/bigquery/query.py +++ b/bigquery/google/cloud/bigquery/query.py @@ -123,7 +123,7 @@ def _require_client(self, client): def cache_hit(self): """Query results served from cache. - See: + See https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs/query#cacheHit :rtype: bool or ``NoneType`` @@ -136,7 +136,7 @@ def cache_hit(self): def complete(self): """Server completed query. - See: + See https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs/query#jobComplete :rtype: bool or ``NoneType`` @@ -149,7 +149,7 @@ def complete(self): def errors(self): """Errors generated by the query. - See: + See https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs/query#errors :rtype: list of mapping, or ``NoneType`` @@ -162,7 +162,7 @@ def errors(self): def name(self): """Job name, generated by the back-end. - See: + See https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs/query#jobReference :rtype: list of mapping, or ``NoneType`` @@ -190,7 +190,7 @@ def job(self): def page_token(self): """Token for fetching next bach of results. - See: + See https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs/query#pageToken :rtype: str, or ``NoneType`` @@ -202,7 +202,7 @@ def page_token(self): def total_rows(self): """Total number of rows returned by the query. - See: + See https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs/query#totalRows :rtype: int, or ``NoneType`` @@ -216,7 +216,7 @@ def total_rows(self): def total_bytes_processed(self): """Total number of bytes processed by the query. - See: + See https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs/query#totalBytesProcessed :rtype: int, or ``NoneType`` @@ -230,7 +230,7 @@ def total_bytes_processed(self): def num_dml_affected_rows(self): """Total number of rows affected by a DML query. - See: + See https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs/query#numDmlAffectedRows :rtype: int, or ``NoneType`` @@ -244,7 +244,7 @@ def num_dml_affected_rows(self): def rows(self): """Query results. - See: + See https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs/query#rows :rtype: list of tuples of row values, or ``NoneType`` @@ -256,7 +256,7 @@ def rows(self): def schema(self): """Schema for query results. - See: + See https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs/query#schema :rtype: list of :class:`SchemaField`, or ``NoneType`` @@ -265,41 +265,41 @@ def schema(self): return _parse_schema_resource(self._properties.get('schema', {})) default_dataset = _TypedProperty('default_dataset', Dataset) - """See: + """See https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs/query#defaultDataset """ dry_run = _TypedProperty('dry_run', bool) - """See: + """See https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs/query#dryRun """ max_results = _TypedProperty('max_results', six.integer_types) - """See: + """See https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs/query#maxResults """ preserve_nulls = _TypedProperty('preserve_nulls', bool) - """See: + """See https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs/query#preserveNulls """ query_parameters = QueryParametersProperty() timeout_ms = _TypedProperty('timeout_ms', six.integer_types) - """See: + """See https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs/query#timeoutMs """ udf_resources = UDFResourcesProperty() use_query_cache = _TypedProperty('use_query_cache', bool) - """See: + """See https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs/query#useQueryCache """ use_legacy_sql = _TypedProperty('use_legacy_sql', bool) - """See: + """See https://cloud.google.com/bigquery/docs/\ reference/v2/jobs/query#useLegacySql """ @@ -361,7 +361,7 @@ def _build_resource(self): def run(self, client=None): """API call: run the query via a POST request - See: + See https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs/query :type client: :class:`~google.cloud.bigquery.client.Client` or @@ -382,7 +382,7 @@ def fetch_data(self, max_results=None, page_token=None, start_index=None, timeout_ms=None, client=None): """API call: fetch a page of query result data via a GET request - See: + See https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs/getQueryResults :type max_results: int diff --git a/bigquery/google/cloud/bigquery/table.py b/bigquery/google/cloud/bigquery/table.py index d7b80dc257739..92ebfebb2d6ec 100644 --- a/bigquery/google/cloud/bigquery/table.py +++ b/bigquery/google/cloud/bigquery/table.py @@ -43,7 +43,7 @@ class Table(object): """Tables represent a set of rows whose values correspond to a schema. - See: + See https://cloud.google.com/bigquery/docs/reference/rest/v2/tables :type name: str @@ -480,7 +480,7 @@ def _build_resource(self): def create(self, client=None): """API call: create the dataset via a PUT request - See: + See https://cloud.google.com/bigquery/docs/reference/rest/v2/tables/insert :type client: :class:`~google.cloud.bigquery.client.Client` or @@ -630,7 +630,7 @@ def update(self, client=None): def delete(self, client=None): """API call: delete the table via a DELETE request - See: + See https://cloud.google.com/bigquery/docs/reference/rest/v2/tables/delete :type client: :class:`~google.cloud.bigquery.client.Client` or @@ -644,7 +644,7 @@ def delete(self, client=None): def fetch_data(self, max_results=None, page_token=None, client=None): """API call: fetch the table data via a GET request - See: + See https://cloud.google.com/bigquery/docs/reference/rest/v2/tabledata/list .. note:: @@ -696,7 +696,7 @@ def insert_data(self, client=None): """API call: insert table data via a POST request - See: + See https://cloud.google.com/bigquery/docs/reference/rest/v2/tabledata/insertAll :type rows: list of tuples @@ -718,7 +718,7 @@ def insert_data(self, :param template_suffix: (Optional) treat ``name`` as a template table and provide a suffix. BigQuery will create the table `` + `` based - on the schema of the template table. See: + on the schema of the template table. See https://cloud.google.com/bigquery/streaming-data-into-bigquery#template-tables :type client: :class:`~google.cloud.bigquery.client.Client` or diff --git a/bigquery/tests/system.py b/bigquery/tests/system.py index baad4a2405075..86e376a2ccb1f 100644 --- a/bigquery/tests/system.py +++ b/bigquery/tests/system.py @@ -59,7 +59,7 @@ def _rate_limit_exceeded(forbidden): # We need to wait to stay within the rate limits. # The alternative outcome is a 403 Forbidden response from upstream, which # they return instead of the more appropriate 429. -# See: https://cloud.google.com/bigquery/quota-policy +# See https://cloud.google.com/bigquery/quota-policy retry_403 = RetryErrors(Forbidden, error_predicate=_rate_limit_exceeded) @@ -326,7 +326,7 @@ def test_insert_data_then_dump_table(self): rows = () - # Allow for "warm up" before rows visible. See: + # Allow for "warm up" before rows visible. See # https://cloud.google.com/bigquery/streaming-data-into-bigquery#dataavailability # 8 tries -> 1 + 2 + 4 + 8 + 16 + 32 + 64 = 127 seconds retry = RetryResult(_has_rows, max_tries=8) @@ -495,7 +495,7 @@ def test_load_table_from_storage_then_dump_table(self): def _job_done(instance): return instance.state in ('DONE', 'done') - # Allow for 90 seconds of "warm up" before rows visible. See: + # Allow for 90 seconds of "warm up" before rows visible. See # https://cloud.google.com/bigquery/streaming-data-into-bigquery#dataavailability # 8 tries -> 1 + 2 + 4 + 8 + 16 + 32 + 64 = 127 seconds retry = RetryInstanceState(_job_done, max_tries=8) diff --git a/bigtable/tests/unit/test_row_data.py b/bigtable/tests/unit/test_row_data.py index eed5e77c56309..51534138b66c6 100644 --- a/bigtable/tests/unit/test_row_data.py +++ b/bigtable/tests/unit/test_row_data.py @@ -709,7 +709,7 @@ def _generate_cell_chunks(chunk_text_pbs): def _parse_readrows_acceptance_tests(filename): """Parse acceptance tests from JSON - See: + See https://github.com/GoogleCloudPlatform/cloud-bigtable-client/blob/\ 4d3185662ca61bc9fa1bdf1ec0166f6e5ecf86c6/bigtable-client-core/src/\ test/resources/com/google/cloud/bigtable/grpc/scanner/v2/ diff --git a/core/google/cloud/exceptions.py b/core/google/cloud/exceptions.py index ab0ede688ef3f..32080de7ff501 100644 --- a/core/google/cloud/exceptions.py +++ b/core/google/cloud/exceptions.py @@ -14,7 +14,7 @@ """Custom exceptions for :mod:`google.cloud` package. -See: https://cloud.google.com/storage/docs/json_api/v1/status-codes +See https://cloud.google.com/storage/docs/json_api/v1/status-codes """ # Avoid the grpc and google.cloud.grpc collision. @@ -48,7 +48,7 @@ class GoogleCloudError(Exception): code = None """HTTP status code. Concrete subclasses *must* define. - See: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html + See http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html """ def __init__(self, message, errors=()): diff --git a/core/google/cloud/iam.py b/core/google/cloud/iam.py index eefc084a5f5c5..49bb11266ceef 100644 --- a/core/google/cloud/iam.py +++ b/core/google/cloud/iam.py @@ -38,7 +38,7 @@ class Policy(collections.MutableMapping): """IAM Policy - See: + See https://cloud.google.com/iam/reference/rest/v1/Policy :type etag: str diff --git a/core/google/cloud/operation.py b/core/google/cloud/operation.py index 8bc848e7facb1..4e700a553e4fd 100644 --- a/core/google/cloud/operation.py +++ b/core/google/cloud/operation.py @@ -43,7 +43,7 @@ def _compute_type_url(klass, prefix=_GOOGLE_APIS_PREFIX): def register_type(klass, type_url=None): """Register a klass as the factory for a given type URL. - :type klass: type + :type klass: :class:`type` :param klass: class to be used as a factory for the given type :type type_url: str diff --git a/datastore/google/cloud/datastore/query.py b/datastore/google/cloud/datastore/query.py index 726e3acc49206..2ab65064f85e1 100644 --- a/datastore/google/cloud/datastore/query.py +++ b/datastore/google/cloud/datastore/query.py @@ -63,14 +63,15 @@ class Query(object): (Optional) key of the ancestor to which this query's results are restricted. - :type filters: sequence of (property_name, operator, value) tuples - :param filters: property filters applied by this query. + :type filters: tuple[str, str, str] + :param filters: Property filters applied by this query. The sequence + is ``(property_name, operator, value)``. :type projection: sequence of string :param projection: fields returned as part of query results. :type order: sequence of string - :param order: field names used to order query results. Prepend '-' + :param order: field names used to order query results. Prepend ``-`` to a field name to sort it in descending order. :type distinct_on: sequence of string @@ -198,8 +199,9 @@ def ancestor(self): def filters(self): """Filters set on the query. - :rtype: sequence of (property_name, operator, value) tuples. - :returns: The filters set on the query. + :rtype: tuple[str, str, str] + :returns: The filters set on the query. The sequence is + ``(property_name, operator, value)``. """ return self._filters[:] diff --git a/dns/google/cloud/dns/changes.py b/dns/google/cloud/dns/changes.py index e900cbcebd226..c393d0b23431c 100644 --- a/dns/google/cloud/dns/changes.py +++ b/dns/google/cloud/dns/changes.py @@ -26,7 +26,7 @@ class Changes(object): Changes are owned by a :class:`google.cloud.dns.zone.ManagedZone` instance. - See: + See https://cloud.google.com/dns/api/v1/changes :type zone: :class:`google.cloud.dns.zone.ManagedZone` @@ -205,7 +205,7 @@ def _build_resource(self): def create(self, client=None): """API call: create the change set via a POST request. - See: + See https://cloud.google.com/dns/api/v1/changes/create :type client: :class:`google.cloud.dns.client.Client` diff --git a/dns/google/cloud/dns/client.py b/dns/google/cloud/dns/client.py index fcc0bb48b72d2..1984c3d1a247b 100644 --- a/dns/google/cloud/dns/client.py +++ b/dns/google/cloud/dns/client.py @@ -57,7 +57,7 @@ def __init__(self, project=None, credentials=None, _http=None): def quotas(self): """Return DNS quotas for the project associated with this client. - See: + See https://cloud.google.com/dns/api/v1/projects/get :rtype: mapping @@ -74,7 +74,7 @@ def quotas(self): def list_zones(self, max_results=None, page_token=None): """List zones for the project associated with this client. - See: + See https://cloud.google.com/dns/api/v1/managedZones/list :type max_results: int diff --git a/dns/google/cloud/dns/resource_record_set.py b/dns/google/cloud/dns/resource_record_set.py index 994dcf01ca4d9..458625f1b4bd6 100644 --- a/dns/google/cloud/dns/resource_record_set.py +++ b/dns/google/cloud/dns/resource_record_set.py @@ -20,7 +20,7 @@ class ResourceRecordSet(object): RRS are owned by a :class:`google.cloud.dns.zone.ManagedZone` instance. - See: + See https://cloud.google.com/dns/api/v1/resourceRecordSets :type name: str diff --git a/dns/google/cloud/dns/zone.py b/dns/google/cloud/dns/zone.py index 3eecf079bccf4..3c589d493311e 100644 --- a/dns/google/cloud/dns/zone.py +++ b/dns/google/cloud/dns/zone.py @@ -26,7 +26,7 @@ class ManagedZone(object): """ManagedZones are containers for DNS resource records. - See: + See https://cloud.google.com/dns/api/v1/managedZones :type name: str @@ -152,7 +152,7 @@ def name_server_set(self): Most users will leave this blank. - See: + See https://cloud.google.com/dns/api/v1/managedZones#nameServerSet :rtype: str, or ``NoneType`` @@ -250,7 +250,7 @@ def _build_resource(self): def create(self, client=None): """API call: create the zone via a PUT request - See: + See https://cloud.google.com/dns/api/v1/managedZones/create :type client: :class:`google.cloud.dns.client.Client` @@ -308,7 +308,7 @@ def reload(self, client=None): def delete(self, client=None): """API call: delete the zone via a DELETE request - See: + See https://cloud.google.com/dns/api/v1/managedZones/delete :type client: :class:`google.cloud.dns.client.Client` @@ -323,7 +323,7 @@ def list_resource_record_sets(self, max_results=None, page_token=None, client=None): """List resource record sets for this zone. - See: + See https://cloud.google.com/dns/api/v1/resourceRecordSets/list :type max_results: int @@ -357,7 +357,7 @@ def list_resource_record_sets(self, max_results=None, page_token=None, def list_changes(self, max_results=None, page_token=None, client=None): """List change sets for this zone. - See: + See https://cloud.google.com/dns/api/v1/resourceRecordSets/list :type max_results: int diff --git a/docs/bigquery/snippets.py b/docs/bigquery/snippets.py index 204d7dc3a5aa6..6e395add09fc3 100644 --- a/docs/bigquery/snippets.py +++ b/docs/bigquery/snippets.py @@ -336,7 +336,7 @@ def table_update(client, to_delete): def _warm_up_inserted_table_data(table): - # Allow for 90 seconds of "warm up" before rows visible. See: + # Allow for 90 seconds of "warm up" before rows visible. See # https://cloud.google.com/bigquery/streaming-data-into-bigquery#dataavailability rows = () counter = 18 diff --git a/docs/conf.py b/docs/conf.py index dd50c4807e365..89c2cb7a3d3bc 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -51,6 +51,7 @@ 'sphinx.ext.autosummary', 'sphinx.ext.doctest', 'sphinx.ext.intersphinx', + 'sphinx.ext.napoleon', 'sphinx.ext.todo', 'sphinx.ext.viewcode', ] @@ -244,6 +245,12 @@ #latex_domain_indices = True +# -- Options for warnings ------------------------------------------------------ + + +suppress_warnings = [] + + # -- Options for manual page output -------------------------------------------- # One entry per manual page. List of tuples @@ -285,9 +292,11 @@ # Refer to the Python standard library and the oauth2client and # httplib2 libraries. intersphinx_mapping = { + 'google-auth': ('https://google-auth.readthedocs.io/en/stable', None), + 'google-gax': ('https://gax-python.readthedocs.io/en/latest/', None), + 'grpc': ('http://www.grpc.io/grpc/python/', None), 'httplib2': ('http://httplib2.readthedocs.io/en/latest/', None), - 'oauth2client': ('http://oauth2client.readthedocs.io/en/latest', None), 'pandas': ('http://pandas.pydata.org/pandas-docs/stable/', None), - 'python': ('https://docs.python.org/2', None), - 'google-auth': ('https://google-auth.readthedocs.io/en/stable', None), + 'python': ('https://docs.python.org/3', None), + 'oauth2client': ('http://oauth2client.readthedocs.io/en/latest', None), } diff --git a/docs/index.rst b/docs/index.rst index 88a39b4c9a945..3402e3e629fef 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -18,7 +18,7 @@ logging/usage storage/client translate/usage - vision/usage + vision/index Google Cloud Client Library for Python ====================================== diff --git a/docs/vision/annotations.rst b/docs/vision/annotations.rst deleted file mode 100644 index 57ac2acbe8069..0000000000000 --- a/docs/vision/annotations.rst +++ /dev/null @@ -1,7 +0,0 @@ -Vision Annotations -================== - -.. automodule:: google.cloud.vision.annotations - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/vision/batch.rst b/docs/vision/batch.rst deleted file mode 100644 index 38d4ec340c471..0000000000000 --- a/docs/vision/batch.rst +++ /dev/null @@ -1,10 +0,0 @@ -Vision Batch -============ - -Batch -~~~~~ - -.. automodule:: google.cloud.vision.batch - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/vision/client.rst b/docs/vision/client.rst deleted file mode 100644 index 36977d9729312..0000000000000 --- a/docs/vision/client.rst +++ /dev/null @@ -1,10 +0,0 @@ -Vision Client -============= - -Client -~~~~~~ - -.. automodule:: google.cloud.vision.client - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/vision/color.rst b/docs/vision/color.rst deleted file mode 100644 index f2a9a53f1d8a3..0000000000000 --- a/docs/vision/color.rst +++ /dev/null @@ -1,10 +0,0 @@ -Vision Image Properties -======================= - -Image Properties Annotation -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. automodule:: google.cloud.vision.color - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/vision/crop-hint.rst b/docs/vision/crop-hint.rst deleted file mode 100644 index 14be33de2761c..0000000000000 --- a/docs/vision/crop-hint.rst +++ /dev/null @@ -1,10 +0,0 @@ -Vision Crop Hint -================ - -Crop Hint -~~~~~~~~~ - -.. automodule:: google.cloud.vision.crop_hint - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/vision/entity.rst b/docs/vision/entity.rst deleted file mode 100644 index 7c5145f54d7d1..0000000000000 --- a/docs/vision/entity.rst +++ /dev/null @@ -1,10 +0,0 @@ -Vision Entity -============= - -Entity -~~~~~~ - -.. automodule:: google.cloud.vision.entity - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/vision/face.rst b/docs/vision/face.rst deleted file mode 100644 index 56f5413991322..0000000000000 --- a/docs/vision/face.rst +++ /dev/null @@ -1,10 +0,0 @@ -Vision Face -=========== - -Face -~~~~ - -.. automodule:: google.cloud.vision.face - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/vision/feature.rst b/docs/vision/feature.rst deleted file mode 100644 index 325b0caad717b..0000000000000 --- a/docs/vision/feature.rst +++ /dev/null @@ -1,10 +0,0 @@ -Vision Feature -============== - -Feature -~~~~~~~ - -.. automodule:: google.cloud.vision.feature - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/vision/gapic/api.rst b/docs/vision/gapic/api.rst new file mode 100644 index 0000000000000..6a5aca57a3b2a --- /dev/null +++ b/docs/vision/gapic/api.rst @@ -0,0 +1,6 @@ +Vision Client API +================= + +.. automodule:: google.cloud.vision_v1 + :members: + :inherited-members: diff --git a/docs/vision/gapic/types.rst b/docs/vision/gapic/types.rst new file mode 100644 index 0000000000000..136dfde585767 --- /dev/null +++ b/docs/vision/gapic/types.rst @@ -0,0 +1,5 @@ +Vision Client Types +=================== + +.. automodule:: google.cloud.vision_v1.types + :members: diff --git a/docs/vision/image.rst b/docs/vision/image.rst deleted file mode 100644 index 491097c3ff31b..0000000000000 --- a/docs/vision/image.rst +++ /dev/null @@ -1,26 +0,0 @@ -Vision Image -============ - -Image -~~~~~ - -.. automodule:: google.cloud.vision.image - :members: - :undoc-members: - :show-inheritance: - -Geometry -~~~~~~~~ - -.. automodule:: google.cloud.vision.geometry - :members: - :undoc-members: - :show-inheritance: - -Likelihood -~~~~~~~~~~ - -.. automodule:: google.cloud.vision.likelihood - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/vision/index.rst b/docs/vision/index.rst new file mode 100644 index 0000000000000..49f90d502d46c --- /dev/null +++ b/docs/vision/index.rst @@ -0,0 +1,131 @@ +###### +Vision +###### + +The Google Cloud `Vision`_ (`Vision API docs`_) API enables developers to +understand the content of an image by encapsulating powerful machine +learning models in an easy to use REST API. It quickly classifies images +into thousands of categories (e.g., "sailboat", "lion", "Eiffel Tower"), +detects individual objects and faces within images, and finds and reads +printed words contained within images. You can build metadata on your +image catalog, moderate offensive content, or enable new marketing +scenarios through image sentiment analysis. Analyze images uploaded +in the request or integrate with your image storage on Google Cloud +Storage. + +.. _Vision: https://cloud.google.com/vision/ +.. _Vision API docs: https://cloud.google.com/vision/reference/rest/ + + +******************************** +Authentication and Configuration +******************************** + +- For an overview of authentication in ``google-cloud-python``, + see :doc:`/core/auth`. + +- In addition to any authentication configuration, you should also set the + :envvar:`GOOGLE_CLOUD_PROJECT` environment variable for the project you'd + like to interact with. If the :envvar:`GOOGLE_CLOUD_PROJECT` environment + variable is not present, the project ID from JSON file credentials is used. + + If you are using Google App Engine or Google Compute Engine + this will be detected automatically. + +- After configuring your environment, create a + :class:`~google.cloud.vision.client.Client`. + +.. code-block:: python + + >>> from google.cloud import vision + >>> client = vision.ImageAnnotatorClient() + +or pass in ``credentials`` and ``project`` explicitly. + +.. code-block:: python + + >>> from google.cloud import vision + >>> client = vision.Client(project='my-project', credentials=creds) + + +***************** +Annotate an Image +***************** + +You can call the :meth:`annotate_image` method directly: + +.. code-block:: python + + >>> from google.cloud import vision + >>> client = vision.ImageAnnotatorClient() + >>> response = client.annotate_image({ + ... 'image': {'source': {'image_uri': 'gs://my-test-bucket/image.jpg'}}, + ... 'features': [{'type': vision.enums.Feature.Type.FACE_DETECTOIN}], + ... }) + >>> len(response.annotations) + 2 + >>> for face in response.annotations[0].faces: + ... print(face.joy) + Likelihood.VERY_LIKELY + Likelihood.VERY_LIKELY + Likelihood.VERY_LIKELY + >>> for logo in response.annotations[0].logos: + ... print(logo.description) + 'google' + 'github' + + +************************ +Single-feature Shortcuts +************************ + +If you are only requesting a single feature, you may find it easier to ask +for it using our direct methods: + +.. code-block:: python + + >>> from google.cloud import vision + >>> client = vision.ImageAnnotatorClient() + >>> response = client.face_detection({ + ... 'source': {'image_uri': 'gs://my-test-bucket/image.jpg'}, + ... }) + >>> len(response.annotations) + 1 + >>> for face in resposne.annotations[0].faces: + ... print(face.joy) + Likelihood.VERY_LIKELY + Likelihood.VERY_LIKELY + Likelihood.VERY_LIKELY + + +**************** +No results found +**************** + +If no results for the detection performed can be extracted from the image, then +an empty list is returned. This behavior is similiar with all detection types. + + +Example with :meth:`~google.cloud.vision.ImageAnnotatorClient.logo_detection`: + +.. code-block:: python + + >>> from google.cloud import vision + >>> client = vision.ImageAnnotatorClient() + >>> with open('./image.jpg', 'rb') as image_file: + ... content = image_file.read() + >>> response = client.logo_detection({ + ... 'content': content, + ... }) + >>> len(response.annotations) + 0 + +************* +API Reference +************* + +.. toctree:: + :maxdepth: 2 + + gapic/api + gapic/types diff --git a/docs/vision/safe-search.rst b/docs/vision/safe-search.rst deleted file mode 100644 index 8f84bc5a9d192..0000000000000 --- a/docs/vision/safe-search.rst +++ /dev/null @@ -1,10 +0,0 @@ -Vision Safe Search -================== - -Safe Search Annotation -~~~~~~~~~~~~~~~~~~~~~~ - -.. automodule:: google.cloud.vision.safe_search - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/vision/text.rst b/docs/vision/text.rst deleted file mode 100644 index 85f162494a42c..0000000000000 --- a/docs/vision/text.rst +++ /dev/null @@ -1,10 +0,0 @@ -Vision Full Text -================ - -Full Text Annotation -~~~~~~~~~~~~~~~~~~~~ - -.. automodule:: google.cloud.vision.text - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/vision/usage.rst b/docs/vision/usage.rst deleted file mode 100644 index 07775aaef9a90..0000000000000 --- a/docs/vision/usage.rst +++ /dev/null @@ -1,414 +0,0 @@ -###### -Vision -###### - -.. toctree:: - :maxdepth: 2 - :hidden: - - annotations - batch - client - color - crop-hint - entity - feature - face - image - safe-search - text - web - -******************************** -Authentication and Configuration -******************************** - -- For an overview of authentication in ``google-cloud-python``, - see :doc:`/core/auth`. - -- In addition to any authentication configuration, you should also set the - :envvar:`GOOGLE_CLOUD_PROJECT` environment variable for the project you'd - like to interact with. If the GOOGLE_CLOUD_PROJECT environment variable is - not present, the project ID from JSON file credentials is used. - - If you are using Google App Engine or Google Compute Engine - this will be detected automatically. - -- After configuring your environment, create a - :class:`~google.cloud.vision.client.Client`. - -.. code-block:: python - - >>> from google.cloud import vision - >>> client = vision.Client() - -or pass in ``credentials`` and ``project`` explicitly. - -.. code-block:: python - - >>> from google.cloud import vision - >>> client = vision.Client(project='my-project', credentials=creds) - - -***************************************************** -Creating an :class:`~google.cloud.vision.image.Image` -***************************************************** - -The :class:`~google.cloud.vision.image.Image` class is used to load image -data from sources such as a Google Cloud Storage URI, raw bytes, or a file. - - -From a Google Cloud Storage URI -=============================== - -.. code-block:: python - - >>> from google.cloud import vision - >>> client = vision.Client() - >>> image = client.image(source_uri='gs://my-test-bucket/image.jpg') - - -From a filename -=============== - -.. code-block:: python - - >>> image = client.image(filename='image.jpg') - -From raw bytes -============== - -.. code-block:: python - - >>> with open('./image.jpg', 'rb') as image_file: - ... bytes_image = client.image(content=image_file.read()) - - -**************** -Manual Detection -**************** - -You can call the detection method manually. - -.. code-block:: python - - >>> from google.cloud import vision - >>> from google.cloud.vision.feature import Feature - >>> from google.cloud.vision.feature import FeatureTypes - >>> client = vision.Client() - >>> image = client.image(source_uri='gs://my-test-bucket/image.jpg') - >>> features = [Feature(FeatureTypes.FACE_DETECTION, 5), - ... Feature(FeatureTypes.LOGO_DETECTION, 3)] - >>> annotations = image.detect(features) - >>> len(annotations) - 2 - >>> for face in annotations[0].faces: - ... print(face.joy) - Likelihood.VERY_LIKELY - Likelihood.VERY_LIKELY - Likelihood.VERY_LIKELY - >>> for logo in annotations[0].logos: - ... print(logo.description) - 'google' - 'github' - - -********** -Crop Hints -********** - -:meth:`~google.cloud.vision.image.Image.detect_crop_hints` will attempt to find -boundaries that contain interesting data which can be used to crop an image. - -.. code-block:: python - - >>> from google.cloud import vision - >>> client = vision.Client() - >>> image = client.image(source_uri='gs://my-test-bucket/image.jpg') - >>> crop_hints = image.detect_crop_hints(aspect_ratios=[1.3333], limit=2) - >>> first_hint = crop_hints[0] - >>> first_hint.bounds.vertices[0].x_coordinate - 77 - >>> first_hint.bounds.vertices[0].y_coordinate - 102 - >>> first_hint.confidence - 0.5 - >>> first_hint.importance_fraction - 1.22000002861 - - -************** -Face Detection -************** - -:meth:`~google.cloud.vision.image.Image.detect_faces` will search for faces in -an image and return the coordinates in the image of each `landmark type`_ that -was detected. - -.. _landmark type: https://cloud.google.com/vision/docs/reference/rest/v1/images/annotate#type_1 - -.. code-block:: python - - >>> from google.cloud import vision - >>> client = vision.Client() - >>> image = client.image(source_uri='gs://my-test-bucket/image.jpg') - >>> faces = image.detect_faces(limit=10) - >>> first_face = faces[0] - >>> first_face.landmarks.left_eye.landmark_type - LandmarkTypes.LEFT_EYE - >>> first_face.landmarks.left_eye.position.x_coordinate - 1301.2404 - >>> first_face.detection_confidence - 0.9863683 - >>> first_face.joy - Likelihood.VERY_UNLIKELY - >>> first_face.anger - Likelihood.VERY_UNLIKELY - - -*************** -Label Detection -*************** - -:meth:`~google.cloud.vision.image.Image.detect_labels` will attempt to label -objects in an image. If there is a car, person and a dog in the image, label -detection will attempt to identify those objects and score the level of -certainty from ``0.0 to 1.0``. - -.. code-block:: python - - >>> from google.cloud import vision - >>> client = vision.Client() - >>> image = client.image(source_uri='gs://my-storage-bucket/image.jpg') - >>> labels = image.detect_labels(limit=3) - >>> labels[0].description - 'automobile' - >>> labels[0].score - 0.9863683 - - -****************** -Landmark Detection -****************** - -:meth:`~google.cloud.vision.image.Image.detect_landmarks` will attempt to -detect landmarks such as "Mount Rushmore" and the "Sydney Opera House". The API -will also provide their known geographical locations if available. - -.. code-block:: python - - >>> from google.cloud import vision - >>> client = vision.Client() - >>> with open('./image.jpg', 'rb') as image_file: - ... image = client.image(content=image_file.read()) - >>> landmarks = image.detect_landmarks() - >>> landmarks[0].description - 'Sydney Opera House' - >>> landmarks[0].locations[0].latitude - -33.857123 - >>> landmarks[0].locations[0].longitude - 151.213921 - >>> landmarks[0].bounds.vertices[0].x_coordinate - 78 - >>> landmarks[0].bounds.vertices[0].y_coordinate - 162 - - -************** -Logo Detection -************** - -With :meth:`~google.cloud.vision.image.Image.detect_logos`, you can identify -brand logos in an image. Their shape and location in the image can be found by -iterating through the detected logo's ``vertices``. - -.. code-block:: python - - >>> from google.cloud import vision - >>> client = vision.Client() - >>> with open('./image.jpg', 'rb') as image_file: - ... image = client.image(content=image_file.read()) - >>> logos = image.detect_logos(limit=3) - >>> print(len(logos)) - 3 - >>> first_logo = logos[0] - >>> first_logo.description - 'Google' - >>> first_logo.score - 0.9795432 - >>> print(len(first_logo.bounds.vertices)) - 4 - >>> first_logo.bounds.vertices[0].x_coordinate - 78 - >>> first_logo.bounds.vertices[0].y_coordinate - 62 - - -********************* -Safe Search Detection -********************* - -:meth:`~google.cloud.vision.image.Image.detect_safe_search` will try to -categorize the entire contents of the image under four categories. - -- adult: Represents the likelihood that the image contains adult content. -- spoof: The likelihood that an obvious modification was made to the image's - canonical version to make it appear funny or offensive. -- medical: Likelihood this is a medical image. -- violence: Violence likelihood. - -.. code-block:: python - - >>> from google.cloud import vision - >>> client = vision.Client() - >>> with open('./image.jpg', 'rb') as image_file: - ... image = client.image(content=image_file.read()) - >>> safe_search = image.detect_safe_search() - >>> safe_search.adult - Likelihood.VERY_UNLIKELY - >>> safe_search.spoof - Likelihood.POSSIBLE - >>> safe_search.medical - Likelihood.VERY_LIKELY - >>> safe_search.violence - Likelihood.LIKELY - - -************** -Text Detection -************** - -:meth:`~google.cloud.vision.image.Image.detect_text` performs OCR to find text -in an image. - -.. code-block:: python - - >>> from google.cloud import vision - >>> client = vision.Client() - >>> with open('./image.jpg', 'rb') as image_file: - ... image = client.image(content=image_file.read()) - >>> texts = image.detect_text() - >>> texts[0].locale - 'en' - >>> texts[0].description - 'some text in the image' - >>> texts[1].description - 'some other text in the image' - - -**************** -Image Properties -**************** - -:meth:`~google.cloud.vision.image.Image.detect_properties` will process the -image and determine the dominant colors in the image. - -.. code-block:: python - - >>> from google.cloud import vision - >>> client = vision.Client() - >>> with open('./image.jpg', 'rb') as image_file: - ... image = client.image(content=image_file.read()) - >>> properties = image.detect_properties() - >>> colors = properties.colors - >>> first_color = colors[0] - >>> first_color.color.red - 244.0 - >>> first_color.color.blue - 134.0 - >>> first_color.score - 0.65519291 - >>> first_color.pixel_fraction - 0.758658 - - -********************* -Batch image detection -********************* - -Multiple images can be processed with a single request by passing -:class:`~google.cloud.vision.image.Image` to -:meth:`~google.cloud.vision.client.Client.batch()`. - -.. code-block:: python - - >>> from google.cloud import vision - >>> from google.cloud.vision.feature import Feature - >>> from google.cloud.vision.feature import FeatureTypes - >>> - >>> client = vision.Client() - >>> batch = client.batch() - >>> - >>> image_one = client.image(source_uri='gs://my-test-bucket/image1.jpg') - >>> image_two = client.image(source_uri='gs://my-test-bucket/image2.jpg') - >>> face_feature = Feature(FeatureTypes.FACE_DETECTION, 2) - >>> logo_feature = Feature(FeatureTypes.LOGO_DETECTION, 2) - >>> batch.add_image(image_one, [face_feature, logo_feature]) - >>> batch.add_image(image_two, [logo_feature]) - >>> results = batch.detect() - >>> for image in results: - ... for face in image.faces: - ... print('=' * 40) - ... print(face.joy) - ======================================== - - ======================================== - - - -************* -Web Detection -************* - -:meth:`~google.cloud.vision.image.Image.detect_web` search for images on the -web that are similar to the image you have. - -.. code-block:: python - - >>> from google.cloud import vision - >>> client = vision.Client() - >>> with open('./image.jpg', 'rb') as image_file: - ... image = client.image(content=image_file.read()) - >>> web_images = image.detect_web(limit=2) - >>> for full_matching_image in web_images.full_matching_images: - ... print('=' * 20) - ... print(full_matching_image.url) - ==================== - 'https://example.com/image.jpg' - >>> for partial_matching_image in web_images.partial_matching_images: - ... print('=' * 20) - ... print(partial_matching_image.url) - ==================== - >>> for page_with_matching_images in web_images.pages_with_matching_images: - ... print('=' * 20) - ... print(page_with_matching_images.url) - ==================== - 'https://example.com/portfolio/' - >>> for entity in web_images.web_entities: - ... print('=' * 20) - ... print(entity.description) - ==================== - 'Mount Rushmore National Memorial' - ==================== - 'Landmark' - - -**************** -No results found -**************** - -If no results for the detection performed can be extracted from the image, then -an empty list is returned. This behavior is similiar with all detection types. - - -Example with :meth:`~google.cloud.vision.image.Image.detect_logos`: - -.. code-block:: python - - >>> from google.cloud import vision - >>> client = vision.Client() - >>> with open('./image.jpg', 'rb') as image_file: - ... image = client.image(content=image_file.read()) - >>> logos = image.detect_logos(limit=3) - >>> logos - [] diff --git a/docs/vision/web.rst b/docs/vision/web.rst deleted file mode 100644 index e4df464c12c7f..0000000000000 --- a/docs/vision/web.rst +++ /dev/null @@ -1,10 +0,0 @@ -Vision Web Annotations -====================== - -Web Annotations -~~~~~~~~~~~~~~~ - -.. automodule:: google.cloud.vision.web - :members: - :undoc-members: - :show-inheritance: diff --git a/error_reporting/google/cloud/error_reporting/client.py b/error_reporting/google/cloud/error_reporting/client.py index 18138826fc373..77c2da631f20e 100644 --- a/error_reporting/google/cloud/error_reporting/client.py +++ b/error_reporting/google/cloud/error_reporting/client.py @@ -149,7 +149,7 @@ def __init__(self, project=None, def report_errors_api(self): """Helper for logging-related API calls. - See: + See https://cloud.google.com/logging/docs/reference/v2/rest/v2/entries https://cloud.google.com/logging/docs/reference/v2/rest/v2/projects.logs diff --git a/logging/google/cloud/logging/_gax.py b/logging/google/cloud/logging/_gax.py index d1e6196bbebb5..3fb648d98f7fc 100644 --- a/logging/google/cloud/logging/_gax.py +++ b/logging/google/cloud/logging/_gax.py @@ -68,7 +68,7 @@ def list_entries(self, projects, filter_='', order_by='', :type filter_: str :param filter_: - a filter expression. See: + a filter expression. See https://cloud.google.com/logging/docs/view/advanced_filters :type order_by: str @@ -193,7 +193,7 @@ def list_sinks(self, project, page_size=0, page_token=None): def sink_create(self, project, sink_name, filter_, destination): """API call: create a sink resource. - See: + See https://cloud.google.com/logging/docs/reference/v2/rest/v2/projects.sinks/create :type project: str @@ -346,7 +346,7 @@ def list_metrics(self, project, page_size=0, page_token=None): def metric_create(self, project, metric_name, filter_, description): """API call: create a metric resource. - See: + See https://cloud.google.com/logging/docs/reference/v2/rest/v2/projects.metrics/create :type project: str diff --git a/logging/google/cloud/logging/_http.py b/logging/google/cloud/logging/_http.py index 0838e7fe42acc..7ca5c457c25df 100644 --- a/logging/google/cloud/logging/_http.py +++ b/logging/google/cloud/logging/_http.py @@ -52,7 +52,7 @@ class Connection(_http.JSONConnection): class _LoggingAPI(object): """Helper mapping logging-related APIs. - See: + See https://cloud.google.com/logging/docs/reference/v2/rest/v2/entries https://cloud.google.com/logging/docs/reference/v2/rest/v2/projects.logs @@ -68,7 +68,7 @@ def list_entries(self, projects, filter_=None, order_by=None, page_size=None, page_token=None): """Return a page of log entry resources. - See: + See https://cloud.google.com/logging/docs/reference/v2/rest/v2/entries/list :type projects: list of strings @@ -77,7 +77,7 @@ def list_entries(self, projects, filter_=None, order_by=None, :type filter_: str :param filter_: - a filter expression. See: + a filter expression. See https://cloud.google.com/logging/docs/view/advanced_filters :type order_by: str @@ -127,7 +127,7 @@ def write_entries(self, entries, logger_name=None, resource=None, labels=None): """API call: log an entry resource via a POST request - See: + See https://cloud.google.com/logging/docs/reference/v2/rest/v2/entries/write :type entries: sequence of mapping @@ -161,7 +161,7 @@ def write_entries(self, entries, logger_name=None, resource=None, def logger_delete(self, project, logger_name): """API call: delete all entries in a logger via a DELETE request - See: + See https://cloud.google.com/logging/docs/reference/v2/rest/v2/projects.logs/delete :type project: str @@ -177,7 +177,7 @@ def logger_delete(self, project, logger_name): class _SinksAPI(object): """Helper mapping sink-related APIs. - See: + See https://cloud.google.com/logging/docs/reference/v2/rest/v2/projects.sinks :type client: :class:`~google.cloud.logging.client.Client` @@ -190,7 +190,7 @@ def __init__(self, client): def list_sinks(self, project, page_size=None, page_token=None): """List sinks for the project associated with this client. - See: + See https://cloud.google.com/logging/docs/reference/v2/rest/v2/projects.sinks/list :type project: str @@ -224,7 +224,7 @@ def list_sinks(self, project, page_size=None, page_token=None): def sink_create(self, project, sink_name, filter_, destination): """API call: create a sink resource. - See: + See https://cloud.google.com/logging/docs/reference/v2/rest/v2/projects.sinks/create :type project: str @@ -252,7 +252,7 @@ def sink_create(self, project, sink_name, filter_, destination): def sink_get(self, project, sink_name): """API call: retrieve a sink resource. - See: + See https://cloud.google.com/logging/docs/reference/v2/rest/v2/projects.sinks/get :type project: str @@ -270,7 +270,7 @@ def sink_get(self, project, sink_name): def sink_update(self, project, sink_name, filter_, destination): """API call: update a sink resource. - See: + See https://cloud.google.com/logging/docs/reference/v2/rest/v2/projects.sinks/update :type project: str @@ -301,7 +301,7 @@ def sink_update(self, project, sink_name, filter_, destination): def sink_delete(self, project, sink_name): """API call: delete a sink resource. - See: + See https://cloud.google.com/logging/docs/reference/v2/rest/v2/projects.sinks/delete :type project: str @@ -317,7 +317,7 @@ def sink_delete(self, project, sink_name): class _MetricsAPI(object): """Helper mapping sink-related APIs. - See: + See https://cloud.google.com/logging/docs/reference/v2/rest/v2/projects.metrics :type client: :class:`~google.cloud.logging.client.Client` @@ -330,7 +330,7 @@ def __init__(self, client): def list_metrics(self, project, page_size=None, page_token=None): """List metrics for the project associated with this client. - See: + See https://cloud.google.com/logging/docs/reference/v2/rest/v2/projects.metrics/list :type project: str @@ -364,7 +364,7 @@ def list_metrics(self, project, page_size=None, page_token=None): def metric_create(self, project, metric_name, filter_, description=None): """API call: create a metric resource. - See: + See https://cloud.google.com/logging/docs/reference/v2/rest/v2/projects.metrics/create :type project: str @@ -391,7 +391,7 @@ def metric_create(self, project, metric_name, filter_, description=None): def metric_get(self, project, metric_name): """API call: retrieve a metric resource. - See: + See https://cloud.google.com/logging/docs/reference/v2/rest/v2/projects.metrics/get :type project: str @@ -409,7 +409,7 @@ def metric_get(self, project, metric_name): def metric_update(self, project, metric_name, filter_, description): """API call: update a metric resource. - See: + See https://cloud.google.com/logging/docs/reference/v2/rest/v2/projects.metrics/update :type project: str @@ -439,7 +439,7 @@ def metric_update(self, project, metric_name, filter_, description): def metric_delete(self, project, metric_name): """API call: delete a metric resource. - See: + See https://cloud.google.com/logging/docs/reference/v2/rest/v2/projects.metrics/delete :type project: str diff --git a/logging/google/cloud/logging/client.py b/logging/google/cloud/logging/client.py index cb6d9d70fb4f5..ca698dde99def 100644 --- a/logging/google/cloud/logging/client.py +++ b/logging/google/cloud/logging/client.py @@ -115,7 +115,7 @@ def __init__(self, project=None, credentials=None, def logging_api(self): """Helper for logging-related API calls. - See: + See https://cloud.google.com/logging/docs/reference/v2/rest/v2/entries https://cloud.google.com/logging/docs/reference/v2/rest/v2/projects.logs """ @@ -130,7 +130,7 @@ def logging_api(self): def sinks_api(self): """Helper for log sink-related API calls. - See: + See https://cloud.google.com/logging/docs/reference/v2/rest/v2/projects.sinks """ if self._sinks_api is None: @@ -144,7 +144,7 @@ def sinks_api(self): def metrics_api(self): """Helper for log metric-related API calls. - See: + See https://cloud.google.com/logging/docs/reference/v2/rest/v2/projects.metrics """ if self._metrics_api is None: @@ -169,7 +169,7 @@ def list_entries(self, projects=None, filter_=None, order_by=None, page_size=None, page_token=None): """Return a page of log entries. - See: + See https://cloud.google.com/logging/docs/reference/v2/rest/v2/entries/list :type projects: list of strings @@ -178,7 +178,7 @@ def list_entries(self, projects=None, filter_=None, order_by=None, :type filter_: str :param filter_: - a filter expression. See: + a filter expression. See https://cloud.google.com/logging/docs/view/advanced_filters :type order_by: str @@ -231,7 +231,7 @@ def sink(self, name, filter_=None, destination=None): def list_sinks(self, page_size=None, page_token=None): """List sinks for the project associated with this client. - See: + See https://cloud.google.com/logging/docs/reference/v2/rest/v2/projects.sinks/list :type page_size: int @@ -276,7 +276,7 @@ def metric(self, name, filter_=None, description=''): def list_metrics(self, page_size=None, page_token=None): """List metrics for the project associated with this client. - See: + See https://cloud.google.com/logging/docs/reference/v2/rest/v2/projects.metrics/list :type page_size: int diff --git a/logging/google/cloud/logging/entries.py b/logging/google/cloud/logging/entries.py index 24c8392eba147..d39092c3e324a 100644 --- a/logging/google/cloud/logging/entries.py +++ b/logging/google/cloud/logging/entries.py @@ -137,7 +137,7 @@ def from_api_repr(cls, resource, client, loggers=None): class TextEntry(_BaseEntry): """Entry created with ``textPayload``. - See: + See https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry """ _PAYLOAD_KEY = 'textPayload' @@ -146,7 +146,7 @@ class TextEntry(_BaseEntry): class StructEntry(_BaseEntry): """Entry created with ``jsonPayload``. - See: + See https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry """ _PAYLOAD_KEY = 'jsonPayload' @@ -155,7 +155,7 @@ class StructEntry(_BaseEntry): class ProtobufEntry(_BaseEntry): """Entry created with ``protoPayload``. - See: + See https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry :type payload: str, dict or any_pb2.Any diff --git a/logging/google/cloud/logging/handlers/app_engine.py b/logging/google/cloud/logging/handlers/app_engine.py index c7394f32262d1..7011819f8a2fe 100644 --- a/logging/google/cloud/logging/handlers/app_engine.py +++ b/logging/google/cloud/logging/handlers/app_engine.py @@ -38,7 +38,7 @@ class AppEngineHandler(CloudLoggingHandler): :param client: The authenticated Google Cloud Logging client for this handler to use. - :type transport: type + :type transport: :class:`type` :param transport: The transport class. It should be a subclass of :class:`.Transport`. If unspecified, :class:`.BackgroundThreadTransport` will be used. diff --git a/logging/google/cloud/logging/handlers/handlers.py b/logging/google/cloud/logging/handlers/handlers.py index 2269c2858f33a..97afde9f87fbe 100644 --- a/logging/google/cloud/logging/handlers/handlers.py +++ b/logging/google/cloud/logging/handlers/handlers.py @@ -46,7 +46,7 @@ class CloudLoggingHandler(logging.StreamHandler): to 'python'. The name of the Python logger will be represented in the ``python_logger`` field. - :type transport: type + :type transport: :class:`type` :param transport: Class for creating new transport objects. It should extend from the base :class:`.Transport` type and implement :meth`.Transport.send`. Defaults to @@ -91,7 +91,7 @@ def emit(self, record): Overrides the default emit behavior of ``StreamHandler``. - See: https://docs.python.org/2/library/logging.html#handler-objects + See https://docs.python.org/2/library/logging.html#handler-objects :type record: :class:`logging.LogRecord` :param record: The record to be logged. diff --git a/logging/google/cloud/logging/logger.py b/logging/google/cloud/logging/logger.py index 874d05014479b..a13b06cd260b5 100644 --- a/logging/google/cloud/logging/logger.py +++ b/logging/google/cloud/logging/logger.py @@ -25,7 +25,7 @@ class Logger(object): """Loggers represent named targets for log entries. - See: + See https://cloud.google.com/logging/docs/reference/v2/rest/v2/projects.logs :type name: str @@ -179,7 +179,7 @@ def log_text(self, text, client=None, labels=None, insert_id=None, resource=_GLOBAL_RESOURCE): """API call: log a text message via a POST request - See: + See https://cloud.google.com/logging/docs/reference/v2/rest/v2/entries/write :type text: str @@ -221,7 +221,7 @@ def log_struct(self, info, client=None, labels=None, insert_id=None, resource=_GLOBAL_RESOURCE): """API call: log a structured message via a POST request - See: + See https://cloud.google.com/logging/docs/reference/v2/rest/v2/entries/write :type info: dict @@ -263,7 +263,7 @@ def log_proto(self, message, client=None, labels=None, insert_id=None, resource=_GLOBAL_RESOURCE): """API call: log a protobuf message via a POST request - See: + See https://cloud.google.com/logging/docs/reference/v2/rest/v2/entries/list :type message: :class:`~google.protobuf.message.Message` @@ -304,7 +304,7 @@ def log_proto(self, message, client=None, labels=None, insert_id=None, def delete(self, client=None): """API call: delete all entries in a logger via a DELETE request - See: + See https://cloud.google.com/logging/docs/reference/v2/rest/v2/projects.logs/delete :type client: :class:`~google.cloud.logging.client.Client` or @@ -319,7 +319,7 @@ def list_entries(self, projects=None, filter_=None, order_by=None, page_size=None, page_token=None): """Return a page of log entries. - See: + See https://cloud.google.com/logging/docs/reference/v2/rest/v2/entries/list :type projects: list of strings @@ -328,7 +328,7 @@ def list_entries(self, projects=None, filter_=None, order_by=None, :type filter_: str :param filter_: - a filter expression. See: + a filter expression. See https://cloud.google.com/logging/docs/view/advanced_filters :type order_by: str diff --git a/logging/google/cloud/logging/metric.py b/logging/google/cloud/logging/metric.py index 8067fb281b23b..ff0a4748540aa 100644 --- a/logging/google/cloud/logging/metric.py +++ b/logging/google/cloud/logging/metric.py @@ -20,7 +20,7 @@ class Metric(object): """Metrics represent named filters for log entries. - See: + See https://cloud.google.com/logging/docs/reference/v2/rest/v2/projects.metrics :type name: str @@ -102,7 +102,7 @@ def _require_client(self, client): def create(self, client=None): """API call: create the metric via a PUT request - See: + See https://cloud.google.com/logging/docs/reference/v2/rest/v2/projects.metrics/create :type client: :class:`~google.cloud.logging.client.Client` or diff --git a/logging/google/cloud/logging/sink.py b/logging/google/cloud/logging/sink.py index 184cf36b00e68..3f468e6cf2f08 100644 --- a/logging/google/cloud/logging/sink.py +++ b/logging/google/cloud/logging/sink.py @@ -20,7 +20,7 @@ class Sink(object): """Sinks represent filtered exports for log entries. - See: + See https://cloud.google.com/logging/docs/reference/v2/rest/v2/projects.sinks :type name: str @@ -106,7 +106,7 @@ def _require_client(self, client): def create(self, client=None): """API call: create the sink via a PUT request - See: + See https://cloud.google.com/logging/docs/reference/v2/rest/v2/projects.sinks/create :type client: :class:`~google.cloud.logging.client.Client` or diff --git a/monitoring/google/cloud/monitoring/timeseries.py b/monitoring/google/cloud/monitoring/timeseries.py index a8b9551f1b6ce..f13b00c3403be 100644 --- a/monitoring/google/cloud/monitoring/timeseries.py +++ b/monitoring/google/cloud/monitoring/timeseries.py @@ -152,7 +152,7 @@ def _make_typed_value(value): type to send to the API. For example, a Python float will be sent to the API with "doubleValue" as its key. - See: https://cloud.google.com/monitoring/api/ref_v3/rest/v3/TypedValue + See https://cloud.google.com/monitoring/api/ref_v3/rest/v3/TypedValue :type value: bool, int, float, str, or dict :param value: value to infer the typed value of. diff --git a/nox.py b/nox.py index 0496492572f9b..ba3de939901ad 100644 --- a/nox.py +++ b/nox.py @@ -33,7 +33,7 @@ def docs(session): 'resource_manager/', 'runtimeconfig/', 'spanner/', 'speech/', 'storage/', 'translate/', 'vision/', ) - session.install('.') + session.install('-e', '.') # Build the docs! session.run('bash', './test_utils/scripts/update_docs.sh') diff --git a/pubsub/google/cloud/pubsub/_gax.py b/pubsub/google/cloud/pubsub/_gax.py index 7301927552215..d32f8eb069a78 100644 --- a/pubsub/google/cloud/pubsub/_gax.py +++ b/pubsub/google/cloud/pubsub/_gax.py @@ -60,7 +60,7 @@ def __init__(self, gax_api, client): def list_topics(self, project, page_size=0, page_token=None): """List topics for the project associated with this API. - See: + See https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.topics/list :type project: str @@ -90,7 +90,7 @@ def list_topics(self, project, page_size=0, page_token=None): def topic_create(self, topic_path): """API call: create a topic - See: + See https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.topics/create :type topic_path: str @@ -113,7 +113,7 @@ def topic_create(self, topic_path): def topic_get(self, topic_path): """API call: retrieve a topic - See: + See https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.topics/get :type topic_path: str @@ -136,7 +136,7 @@ def topic_get(self, topic_path): def topic_delete(self, topic_path): """API call: delete a topic - See: + See https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.topics/delete :type topic_path: str @@ -153,7 +153,7 @@ def topic_delete(self, topic_path): def topic_publish(self, topic_path, messages, timeout=30): """API call: publish one or more messages to a topic - See: + See https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.topics/publish :type topic_path: str @@ -186,7 +186,7 @@ def topic_publish(self, topic_path, messages, timeout=30): def topic_list_subscriptions(self, topic, page_size=0, page_token=None): """API call: list subscriptions bound to a topic - See: + See https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.topics.subscriptions/list :type topic: :class:`~google.cloud.pubsub.topic.Topic` @@ -242,7 +242,7 @@ def __init__(self, gax_api, client): def list_subscriptions(self, project, page_size=0, page_token=None): """List subscriptions for the project associated with this API. - See: + See https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.subscriptions/list :type project: str @@ -283,7 +283,7 @@ def subscription_create(self, subscription_path, topic_path, message_retention_duration=None): """API call: create a subscription - See: + See https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.subscriptions/create :type subscription_path: str @@ -345,7 +345,7 @@ def subscription_create(self, subscription_path, topic_path, def subscription_get(self, subscription_path): """API call: retrieve a subscription - See: + See https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.subscriptions/get :type subscription_path: str @@ -367,7 +367,7 @@ def subscription_get(self, subscription_path): def subscription_delete(self, subscription_path): """API call: delete a subscription - See: + See https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.subscriptions/delete :type subscription_path: str @@ -386,7 +386,7 @@ def subscription_modify_push_config(self, subscription_path, push_endpoint): """API call: update push config of a subscription - See: + See https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.subscriptions/modifyPushConfig :type subscription_path: str @@ -411,7 +411,7 @@ def subscription_pull(self, subscription_path, return_immediately=False, max_messages=1): """API call: retrieve messages for a subscription - See: + See https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.subscriptions/modifyPushConfig :type subscription_path: str @@ -452,7 +452,7 @@ def subscription_pull(self, subscription_path, return_immediately=False, def subscription_acknowledge(self, subscription_path, ack_ids): """API call: acknowledge retrieved messages - See: + See https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.subscriptions/modifyPushConfig :type subscription_path: str @@ -474,7 +474,7 @@ def subscription_modify_ack_deadline(self, subscription_path, ack_ids, ack_deadline): """API call: update ack deadline for retrieved messages - See: + See https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.subscriptions/modifyAckDeadline :type subscription_path: str @@ -500,7 +500,7 @@ def subscription_modify_ack_deadline(self, subscription_path, ack_ids, def subscription_seek(self, subscription_path, time=None, snapshot=None): """API call: seek a subscription - See: + See https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.subscriptions/seek :type subscription_path: str @@ -524,7 +524,7 @@ def subscription_seek(self, subscription_path, time=None, snapshot=None): def list_snapshots(self, project, page_size=0, page_token=None): """List snapshots for the project associated with this API. - See: + See https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.snapshots/list :type project: str @@ -561,7 +561,7 @@ def list_snapshots(self, project, page_size=0, page_token=None): def snapshot_create(self, snapshot_path, subscription_path): """API call: create a snapshot - See: + See https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.snapshots/create :type snapshot_path: str @@ -594,7 +594,7 @@ def snapshot_create(self, snapshot_path, subscription_path): def snapshot_delete(self, snapshot_path): """API call: delete a topic - See: + See https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.snapshots/delete :type snapshot_path: str diff --git a/pubsub/google/cloud/pubsub/_http.py b/pubsub/google/cloud/pubsub/_http.py index 0c059df7453af..f1d07237d7df8 100644 --- a/pubsub/google/cloud/pubsub/_http.py +++ b/pubsub/google/cloud/pubsub/_http.py @@ -116,7 +116,7 @@ def __init__(self, client): def list_topics(self, project, page_size=None, page_token=None): """API call: list topics for a given project - See: + See https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.topics/list :type project: str @@ -148,7 +148,7 @@ def list_topics(self, project, page_size=None, page_token=None): def topic_create(self, topic_path): """API call: create a topic - See: + See https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.topics/create :type topic_path: str @@ -163,7 +163,7 @@ def topic_create(self, topic_path): def topic_get(self, topic_path): """API call: retrieve a topic - See: + See https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.topics/get :type topic_path: str @@ -178,7 +178,7 @@ def topic_get(self, topic_path): def topic_delete(self, topic_path): """API call: delete a topic - See: + See https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.topics/delete :type topic_path: str @@ -190,7 +190,7 @@ def topic_delete(self, topic_path): def topic_publish(self, topic_path, messages): """API call: publish one or more messages to a topic - See: + See https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.topics/publish :type topic_path: str @@ -213,7 +213,7 @@ def topic_publish(self, topic_path, messages): def topic_list_subscriptions(self, topic, page_size=None, page_token=None): """API call: list subscriptions bound to a topic - See: + See https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.topics.subscriptions/list :type topic: :class:`~google.cloud.pubsub.topic.Topic` @@ -260,7 +260,7 @@ def __init__(self, client): def list_subscriptions(self, project, page_size=None, page_token=None): """API call: list subscriptions for a given project - See: + See https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.subscriptions/list :type project: str @@ -302,7 +302,7 @@ def subscription_create(self, subscription_path, topic_path, message_retention_duration=None): """API call: create a subscription - See: + See https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.subscriptions/create :type subscription_path: str @@ -364,7 +364,7 @@ def subscription_create(self, subscription_path, topic_path, def subscription_get(self, subscription_path): """API call: retrieve a subscription - See: + See https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.subscriptions/get :type subscription_path: str @@ -381,7 +381,7 @@ def subscription_get(self, subscription_path): def subscription_delete(self, subscription_path): """API call: delete a subscription - See: + See https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.subscriptions/delete :type subscription_path: str @@ -396,7 +396,7 @@ def subscription_modify_push_config(self, subscription_path, push_endpoint): """API call: update push config of a subscription - See: + See https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.subscriptions/modifyPushConfig :type subscription_path: str @@ -417,7 +417,7 @@ def subscription_pull(self, subscription_path, return_immediately=False, max_messages=1): """API call: retrieve messages for a subscription - See: + See https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.subscriptions/modifyPushConfig :type subscription_path: str @@ -450,7 +450,7 @@ def subscription_pull(self, subscription_path, return_immediately=False, def subscription_acknowledge(self, subscription_path, ack_ids): """API call: acknowledge retrieved messages - See: + See https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.subscriptions/modifyPushConfig :type subscription_path: str @@ -471,7 +471,7 @@ def subscription_modify_ack_deadline(self, subscription_path, ack_ids, ack_deadline): """API call: update ack deadline for retrieved messages - See: + See https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.subscriptions/modifyAckDeadline :type subscription_path: str @@ -496,7 +496,7 @@ def subscription_modify_ack_deadline(self, subscription_path, ack_ids, def subscription_seek(self, subscription_path, time=None, snapshot=None): """API call: seek a subscription - See: + See https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.subscriptions/seek :type subscription_path: str @@ -521,7 +521,7 @@ def subscription_seek(self, subscription_path, time=None, snapshot=None): def list_snapshots(self, project, page_size=None, page_token=None): """List snapshots for the project associated with this API. - See: + See https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.snapshots/list :type project: str @@ -559,7 +559,7 @@ def list_snapshots(self, project, page_size=None, page_token=None): def snapshot_create(self, snapshot_path, subscription_path): """API call: create a snapshot - See: + See https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.snapshots/create :type snapshot_path: str @@ -581,7 +581,7 @@ def snapshot_create(self, snapshot_path, subscription_path): def snapshot_delete(self, snapshot_path): """API call: delete a topic - See: + See https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.snapshots/delete :type snapshot_path: str @@ -605,7 +605,7 @@ def __init__(self, client): def get_iam_policy(self, target_path): """API call: fetch the IAM policy for the target - See: + See https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.topics/getIamPolicy https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.subscriptions/getIamPolicy @@ -621,7 +621,7 @@ def get_iam_policy(self, target_path): def set_iam_policy(self, target_path, policy): """API call: update the IAM policy for the target - See: + See https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.topics/setIamPolicy https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.subscriptions/setIamPolicy @@ -641,7 +641,7 @@ def set_iam_policy(self, target_path, policy): def test_iam_permissions(self, target_path, permissions): """API call: test permissions - See: + See https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.topics/testIamPermissions https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.subscriptions/testIamPermissions diff --git a/pubsub/google/cloud/pubsub/client.py b/pubsub/google/cloud/pubsub/client.py index 17bb67cb66e20..902188beaab6e 100644 --- a/pubsub/google/cloud/pubsub/client.py +++ b/pubsub/google/cloud/pubsub/client.py @@ -136,7 +136,7 @@ def iam_policy_api(self): def list_topics(self, page_size=None, page_token=None): """List topics for the project associated with this client. - See: + See https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.topics/list Example: @@ -165,7 +165,7 @@ def list_topics(self, page_size=None, page_token=None): def list_subscriptions(self, page_size=None, page_token=None): """List subscriptions for the project associated with this client. - See: + See https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.topics/list Example: @@ -195,7 +195,7 @@ def list_subscriptions(self, page_size=None, page_token=None): def list_snapshots(self, page_size=None, page_token=None): """List snapshots for the project associated with this API. - See: + See https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.snapshots/list :type project: str diff --git a/pubsub/google/cloud/pubsub/iam.py b/pubsub/google/cloud/pubsub/iam.py index 9c7e46af222aa..7dce1c2c4cfa8 100644 --- a/pubsub/google/cloud/pubsub/iam.py +++ b/pubsub/google/cloud/pubsub/iam.py @@ -96,7 +96,7 @@ class Policy(_BasePolicy): """IAM Policy / Bindings. - See: + See https://cloud.google.com/pubsub/docs/reference/rest/Shared.Types/Policy https://cloud.google.com/pubsub/docs/reference/rest/Shared.Types/Binding """ diff --git a/pubsub/google/cloud/pubsub/message.py b/pubsub/google/cloud/pubsub/message.py index 6b93e3b890ede..e2153d5cb14f6 100644 --- a/pubsub/google/cloud/pubsub/message.py +++ b/pubsub/google/cloud/pubsub/message.py @@ -20,7 +20,7 @@ class Message(object): """Messages can be published to a topic and received by subscribers. - See: + See https://cloud.google.com/pubsub/docs/reference/rest/v1/PubsubMessage :type data: bytes diff --git a/pubsub/google/cloud/pubsub/snapshot.py b/pubsub/google/cloud/pubsub/snapshot.py index 557ea93818d6e..599cd05d8765e 100644 --- a/pubsub/google/cloud/pubsub/snapshot.py +++ b/pubsub/google/cloud/pubsub/snapshot.py @@ -108,7 +108,7 @@ def _require_client(self, client): def create(self, client=None): """API call: create the snapshot - See: + See https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.snapshots/create :type client: :class:`~google.cloud.pubsub.client.Client` or @@ -127,7 +127,7 @@ def create(self, client=None): def delete(self, client=None): """API call: delete the snapshot - See: + See https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.snapshots/delete :type client: :class:`~google.cloud.pubsub.client.Client` or diff --git a/pubsub/google/cloud/pubsub/subscription.py b/pubsub/google/cloud/pubsub/subscription.py index 22f93246924c2..86ca1f97c230a 100644 --- a/pubsub/google/cloud/pubsub/subscription.py +++ b/pubsub/google/cloud/pubsub/subscription.py @@ -27,7 +27,7 @@ class Subscription(object): """Subscriptions receive messages published to their topics. - See: + See https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.subscriptions :type name: str @@ -69,7 +69,7 @@ class Subscription(object): _DELETED_TOPIC_PATH = '_deleted-topic_' """Value of ``projects.subscriptions.topic`` when topic has been deleted. - See: + See https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.subscriptions#Subscription.FIELDS.topic """ @@ -195,7 +195,7 @@ def _require_client(self, client): def create(self, client=None): """API call: create the subscription via a PUT request - See: + See https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.subscriptions/create Example: @@ -280,7 +280,7 @@ def reload(self, client=None): def delete(self, client=None): """API call: delete the subscription via a DELETE request. - See: + See https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.subscriptions/delete Example: @@ -301,7 +301,7 @@ def delete(self, client=None): def modify_push_configuration(self, push_endpoint, client=None): """API call: update the push endpoint for the subscription. - See: + See https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.subscriptions/modifyPushConfig Example: @@ -332,7 +332,7 @@ def modify_push_configuration(self, push_endpoint, client=None): def pull(self, return_immediately=False, max_messages=1, client=None): """API call: retrieve messages for the subscription. - See: + See https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.subscriptions/pull Example: @@ -371,7 +371,7 @@ def pull(self, return_immediately=False, max_messages=1, client=None): def acknowledge(self, ack_ids, client=None): """API call: acknowledge retrieved messages for the subscription. - See: + See https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.subscriptions/acknowledge Example: @@ -395,7 +395,7 @@ def acknowledge(self, ack_ids, client=None): def modify_ack_deadline(self, ack_ids, ack_deadline, client=None): """API call: update acknowledgement deadline for a retrieved message. - See: + See https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.subscriptions/modifyAckDeadline :type ack_ids: list of string @@ -428,7 +428,7 @@ def snapshot(self, name, client=None): def seek_snapshot(self, snapshot, client=None): """API call: seek a subscription to a given snapshot - See: + See https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.subscriptions/seek :type snapshot: :class:`Snapshot` @@ -441,7 +441,7 @@ def seek_snapshot(self, snapshot, client=None): def seek_timestamp(self, timestamp, client=None): """API call: seek a subscription to a given point in time - See: + See https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.subscriptions/seek :type time: :class:`datetime.datetime` @@ -455,7 +455,7 @@ def seek_timestamp(self, timestamp, client=None): def get_iam_policy(self, client=None): """Fetch the IAM policy for the subscription. - See: + See https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.subscriptions/getIamPolicy Example: @@ -481,7 +481,7 @@ def get_iam_policy(self, client=None): def set_iam_policy(self, policy, client=None): """Update the IAM policy for the subscription. - See: + See https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.subscriptions/setIamPolicy Example: @@ -512,7 +512,7 @@ def set_iam_policy(self, policy, client=None): def check_iam_permissions(self, permissions, client=None): """Verify permissions allowed for the current user. - See: + See https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.subscriptions/testIamPermissions Example: diff --git a/pubsub/google/cloud/pubsub/topic.py b/pubsub/google/cloud/pubsub/topic.py index f9a8c28a3a09c..92c323ed63d72 100644 --- a/pubsub/google/cloud/pubsub/topic.py +++ b/pubsub/google/cloud/pubsub/topic.py @@ -32,7 +32,7 @@ class Topic(object): Subscribers then receive those messages. - See: + See https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.topics :type name: str @@ -155,7 +155,7 @@ def _require_client(self, client): def create(self, client=None): """API call: create the topic via a PUT request - See: + See https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.topics/create Example: @@ -206,7 +206,7 @@ def exists(self, client=None): def delete(self, client=None): """API call: delete the topic via a DELETE request - See: + See https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.topics/delete Example: @@ -237,7 +237,7 @@ def _timestamp_message(self, attrs): def publish(self, message, client=None, **attrs): """API call: publish a message to a topic via a POST request - See: + See https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.topics/publish Example without message attributes: @@ -307,7 +307,7 @@ def batch(self, client=None, **kwargs): def list_subscriptions(self, page_size=None, page_token=None, client=None): """List subscriptions for the project associated with this client. - See: + See https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.topics.subscriptions/list Example: @@ -342,7 +342,7 @@ def list_subscriptions(self, page_size=None, page_token=None, client=None): def get_iam_policy(self, client=None): """Fetch the IAM policy for the topic. - See: + See https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.topics/getIamPolicy Example: @@ -368,7 +368,7 @@ def get_iam_policy(self, client=None): def set_iam_policy(self, policy, client=None): """Update the IAM policy for the topic. - See: + See https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.topics/setIamPolicy Example: @@ -399,7 +399,7 @@ def set_iam_policy(self, policy, client=None): def check_iam_permissions(self, permissions, client=None): """Verify permissions allowed for the current user. - See: + See https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.topics/testIamPermissions Example: diff --git a/resource_manager/google/cloud/resource_manager/client.py b/resource_manager/google/cloud/resource_manager/client.py index c16e095e4cc64..d2cea6cad2cdc 100644 --- a/resource_manager/google/cloud/resource_manager/client.py +++ b/resource_manager/google/cloud/resource_manager/client.py @@ -125,7 +125,7 @@ def list_projects(self, filter_params=None, page_size=None): >>> for project in client.list_projects(env_filter): ... print(project.project_id) - See: + See https://cloud.google.com/resource-manager/reference/rest/v1beta1/projects/list Complete filtering example:: diff --git a/resource_manager/google/cloud/resource_manager/project.py b/resource_manager/google/cloud/resource_manager/project.py index 40767357a7daf..689bae91dd927 100644 --- a/resource_manager/google/cloud/resource_manager/project.py +++ b/resource_manager/google/cloud/resource_manager/project.py @@ -36,7 +36,7 @@ class Project(object): >>> project.labels['environment'] = 'production' >>> project.update() - See: + See https://cloud.google.com/resource-manager/reference/rest/v1beta1/projects :type project_id: str @@ -218,7 +218,7 @@ def update(self, client=None): def delete(self, client=None, reload_data=False): """API call: delete the project via a ``DELETE`` request. - See: + See https://cloud.google.com/resource-manager/reference/rest/v1beta1/projects/delete This actually changes the status (``lifecycleState``) from ``ACTIVE`` diff --git a/runtimeconfig/google/cloud/runtimeconfig/_helpers.py b/runtimeconfig/google/cloud/runtimeconfig/_helpers.py index e03bb794f605c..5424e3e5243ae 100644 --- a/runtimeconfig/google/cloud/runtimeconfig/_helpers.py +++ b/runtimeconfig/google/cloud/runtimeconfig/_helpers.py @@ -25,7 +25,7 @@ def config_name_from_full_name(full_name): :param full_name: The full resource name of a config. The full resource name looks like ``projects/project-name/configs/config-name`` and is returned as the - ``name`` field of a config resource. See: + ``name`` field of a config resource. See https://cloud.google.com/deployment-manager/runtime-configurator/reference/rest/v1beta1/projects.configs :rtype: str @@ -54,7 +54,7 @@ def variable_name_from_full_name(full_name): :param full_name: The full resource name of a variable. The full resource name looks like ``projects/prj-name/configs/cfg-name/variables/var-name`` and is - returned as the ``name`` field of a variable resource. See: + returned as the ``name`` field of a variable resource. See https://cloud.google.com/deployment-manager/runtime-configurator/reference/rest/v1beta1/projects.configs.variables :rtype: str diff --git a/runtimeconfig/google/cloud/runtimeconfig/config.py b/runtimeconfig/google/cloud/runtimeconfig/config.py index 0af33d034d5ae..4b85ff5843bff 100644 --- a/runtimeconfig/google/cloud/runtimeconfig/config.py +++ b/runtimeconfig/google/cloud/runtimeconfig/config.py @@ -25,7 +25,7 @@ class Config(object): This consists of metadata and a hierarchy of variables. - See: + See https://cloud.google.com/deployment-manager/runtime-configurator/reference/rest/v1beta1/projects.configs :type client: :class:`google.cloud.runtimeconfig.client.Client` @@ -53,7 +53,7 @@ def client(self): def description(self): """Description of the config object. - See: + See https://cloud.google.com/deployment-manager/runtime-configurator/reference/rest/v1beta1/projects.configs#resource-runtimeconfig :rtype: str, or ``NoneType`` @@ -164,7 +164,7 @@ def reload(self, client=None): This method will reload the newest data for the config. - See: + See https://cloud.google.com/deployment-manager/runtime-configurator/reference/rest/v1beta1/projects.configs/get :type client: :class:`google.cloud.runtimeconfig.client.Client` @@ -216,7 +216,7 @@ def list_variables(self, page_size=None, page_token=None, client=None): This only lists variable names, not the values. - See: + See https://cloud.google.com/deployment-manager/runtime-configurator/reference/rest/v1beta1/projects.configs.variables/list :type page_size: int diff --git a/runtimeconfig/google/cloud/runtimeconfig/variable.py b/runtimeconfig/google/cloud/runtimeconfig/variable.py index 602653f5b357b..14241f6f8d3e5 100644 --- a/runtimeconfig/google/cloud/runtimeconfig/variable.py +++ b/runtimeconfig/google/cloud/runtimeconfig/variable.py @@ -16,19 +16,19 @@ .. data:: STATE_UNSPECIFIED - The default variable state. See: + The default variable state. See https://cloud.google.com/deployment-manager/runtime-configurator/reference/rest/v1beta1/projects.configs.variables#VariableState .. data:: STATE_UPDATED Indicates the variable was updated, while `variables.watch` was executing. - See: + See https://cloud.google.com/deployment-manager/runtime-configurator/reference/rest/v1beta1/projects.configs.variables#VariableState .. data:: STATE_DELETED Indicates the variable was deleted, while `variables.watch`_ was executing. - See: + See https://cloud.google.com/deployment-manager/runtime-configurator/reference/rest/v1beta1/projects.configs.variables#VariableState .. _variables.watch: @@ -50,7 +50,7 @@ class Variable(object): """A variable in the Cloud RuntimeConfig service. - See: + See https://cloud.google.com/deployment-manager/runtime-configurator/reference/rest/v1beta1/projects.configs.variables :type name: str @@ -118,7 +118,7 @@ def client(self): def value(self): """Value of the variable, as bytes. - See: + See https://cloud.google.com/deployment-manager/runtime-configurator/reference/rest/v1beta1/projects.configs.variables :rtype: bytes or ``NoneType`` @@ -134,7 +134,7 @@ def value(self): def state(self): """Retrieve the state of the variable. - See: + See https://cloud.google.com/deployment-manager/runtime-configurator/reference/rest/v1beta1/projects.configs.variables#VariableState :rtype: str @@ -148,7 +148,7 @@ def state(self): def update_time(self): """Retrieve the timestamp at which the variable was updated. - See: + See https://cloud.google.com/deployment-manager/runtime-configurator/reference/rest/v1beta1/projects.configs.variables :rtype: :class:`datetime.datetime` or ``NoneType`` @@ -190,7 +190,7 @@ def _set_properties(self, resource): def exists(self, client=None): """API call: test for the existence of the variable via a GET request - See: + See https://cloud.google.com/deployment-manager/runtime-configurator/reference/rest/v1beta1/projects.configs.variables/get :type client: :class:`~google.cloud.runtimeconfig.client.Client` @@ -217,7 +217,7 @@ def reload(self, client=None): This method will reload the newest data for the variable. - See: + See https://cloud.google.com/deployment-manager/runtime-configurator/reference/rest/v1beta1/projects.configs/get :type client: :class:`google.cloud.runtimeconfig.client.Client` diff --git a/setup.py b/setup.py index fd21cc0147bee..9570fbb5ef4ee 100644 --- a/setup.py +++ b/setup.py @@ -62,10 +62,11 @@ 'google-cloud-pubsub >= 0.25.0, < 0.26dev', 'google-cloud-resource-manager >= 0.24.0, < 0.25dev', 'google-cloud-spanner >= 0.24.1, < 0.25dev', - 'google-cloud-speech >= 0.24.0, < 0.25dev', + 'google-cloud-speech >= 0.25.0, < 0.26dev', 'google-cloud-storage >= 1.1.0, < 2.0dev', 'google-cloud-translate >= 0.24.0, < 0.25dev', - 'google-cloud-vision >= 0.24.0, < 0.25dev', + 'google-cloud-videointelligence >= 0.25.0, < 0.26dev', + 'google-cloud-vision >= 0.25.0, < 0.26dev', 'google-cloud-runtimeconfig >= 0.24.0, < 0.25dev', ] diff --git a/spanner/google/cloud/spanner/client.py b/spanner/google/cloud/spanner/client.py index b260e7959aa21..c95e16e2c23c9 100644 --- a/spanner/google/cloud/spanner/client.py +++ b/spanner/google/cloud/spanner/client.py @@ -191,7 +191,7 @@ def copy(self): def list_instance_configs(self, page_size=None, page_token=None): """List available instance configurations for the client's project. - See: + See https://cloud.google.com/spanner/reference/rpc/google.spanner.admin.database.v1#google.spanner.admin.database.v1.InstanceAdmin.ListInstanceConfigs :type page_size: int @@ -250,11 +250,11 @@ def instance(self, instance_id, def list_instances(self, filter_='', page_size=None, page_token=None): """List instances for the client's project. - See: + See https://cloud.google.com/spanner/reference/rpc/google.spanner.admin.database.v1#google.spanner.admin.database.v1.InstanceAdmin.ListInstances :type filter_: string - :param filter_: (Optional) Filter to select instances listed. See: + :param filter_: (Optional) Filter to select instances listed. See the ``ListInstancesRequest`` docs above for examples. :type page_size: int diff --git a/spanner/google/cloud/spanner/database.py b/spanner/google/cloud/spanner/database.py index 221842c12dca7..12af9ca20edb6 100644 --- a/spanner/google/cloud/spanner/database.py +++ b/spanner/google/cloud/spanner/database.py @@ -150,7 +150,7 @@ def name(self): def ddl_statements(self): """DDL Statements used to define database schema. - See: + See cloud.google.com/spanner/docs/data-definition-language :rtype: sequence of string @@ -180,7 +180,7 @@ def create(self): Inclues any configured schema assigned to :attr:`ddl_statements`. - See: + See https://cloud.google.com/spanner/reference/rpc/google.spanner.admin.database.v1#google.spanner.admin.database.v1.DatabaseAdmin.CreateDatabase """ api = self._instance._client.database_admin_api @@ -211,7 +211,7 @@ def create(self): def exists(self): """Test whether this database exists. - See: + See https://cloud.google.com/spanner/reference/rpc/google.spanner.admin.database.v1#google.spanner.admin.database.v1.DatabaseAdmin.GetDatabaseDDL """ api = self._instance._client.database_admin_api @@ -230,7 +230,7 @@ def reload(self): Refresh any configured schema into :attr:`ddl_statements`. - See: + See https://cloud.google.com/spanner/reference/rpc/google.spanner.admin.database.v1#google.spanner.admin.database.v1.DatabaseAdmin.GetDatabaseDDL """ api = self._instance._client.database_admin_api @@ -249,7 +249,7 @@ def update_ddl(self, ddl_statements): Apply any configured schema from :attr:`ddl_statements`. - See: + See https://cloud.google.com/spanner/reference/rpc/google.spanner.admin.database.v1#google.spanner.admin.database.v1.DatabaseAdmin.UpdateDatabase :rtype: :class:`google.cloud.operation.Operation` @@ -273,7 +273,7 @@ def update_ddl(self, ddl_statements): def drop(self): """Drop this database. - See: + See https://cloud.google.com/spanner/reference/rpc/google.spanner.admin.database.v1#google.spanner.admin.database.v1.DatabaseAdmin.DropDatabase """ api = self._instance._client.database_admin_api @@ -343,7 +343,7 @@ def execute_sql(self, sql, params=None, param_types=None, query_mode=None, :type query_mode: :class:`google.spanner.v1.spanner_pb2.ExecuteSqlRequest.QueryMode` - :param query_mode: Mode governing return of results / query plan. See: + :param query_mode: Mode governing return of results / query plan. See https://cloud.google.com/spanner/reference/rpc/google.spanner.v1#google.spanner.v1.ExecuteSqlRequest.QueryMode1 :type resume_token: bytes @@ -396,7 +396,7 @@ def snapshot(self, read_timestamp=None, min_read_timestamp=None, The wrapper *must* be used as a context manager, with the snapshot as the value returned by the wrapper. - See: + See https://cloud.google.com/spanner/reference/rpc/google.spanner.v1#google.spanner.v1.TransactionOptions.ReadOnly If no options are passed, reads will use the ``strong`` model, reading @@ -519,7 +519,7 @@ def __exit__(self, exc_type, exc_val, exc_tb): def _check_ddl_statements(value): """Validate DDL Statements used to define database schema. - See: + See https://cloud.google.com/spanner/docs/data-definition-language :type value: list of string diff --git a/spanner/google/cloud/spanner/instance.py b/spanner/google/cloud/spanner/instance.py index 2935fc2ad57f8..711b8c4898532 100644 --- a/spanner/google/cloud/spanner/instance.py +++ b/spanner/google/cloud/spanner/instance.py @@ -188,7 +188,7 @@ def copy(self): def create(self): """Create this instance. - See: + See https://cloud.google.com/spanner/reference/rpc/google.spanner.admin.instance.v1#google.spanner.admin.instance.v1.InstanceAdmin.CreateInstance .. note:: @@ -234,7 +234,7 @@ def create(self): def exists(self): """Test whether this instance exists. - See: + See https://cloud.google.com/spanner/reference/rpc/google.spanner.admin.instance.v1#google.spanner.admin.instance.v1.InstanceAdmin.GetInstanceConfig """ api = self._client.instance_admin_api @@ -252,7 +252,7 @@ def exists(self): def reload(self): """Reload the metadata for this instance. - See: + See https://cloud.google.com/spanner/reference/rpc/google.spanner.admin.instance.v1#google.spanner.admin.instance.v1.InstanceAdmin.GetInstanceConfig """ api = self._client.instance_admin_api @@ -270,7 +270,7 @@ def reload(self): def update(self): """Update this instance. - See: + See https://cloud.google.com/spanner/reference/rpc/google.spanner.admin.instance.v1#google.spanner.admin.instance.v1.InstanceAdmin.UpdateInstance .. note:: @@ -315,7 +315,7 @@ def update(self): def delete(self): """Mark an instance and all of its databases for permanent deletion. - See: + See https://cloud.google.com/spanner/reference/rpc/google.spanner.admin.instance.v1#google.spanner.admin.instance.v1.InstanceAdmin.DeleteInstance Immediately upon completion of the request: @@ -360,7 +360,7 @@ def database(self, database_id, ddl_statements=(), pool=None): def list_databases(self, page_size=None, page_token=None): """List databases for the instance. - See: + See https://cloud.google.com/spanner/reference/rpc/google.spanner.admin.database.v1#google.spanner.admin.database.v1.DatabaseAdmin.ListDatabases :type page_size: int diff --git a/spanner/google/cloud/spanner/session.py b/spanner/google/cloud/spanner/session.py index 9617ceb111492..45baffa92d43e 100644 --- a/spanner/google/cloud/spanner/session.py +++ b/spanner/google/cloud/spanner/session.py @@ -86,7 +86,7 @@ def name(self): def create(self): """Create this session, bound to its database. - See: + See https://cloud.google.com/spanner/reference/rpc/google.spanner.v1#google.spanner.v1.Spanner.CreateSession :raises: :exc:`ValueError` if :attr:`session_id` is already set. @@ -101,7 +101,7 @@ def create(self): def exists(self): """Test for the existence of this session. - See: + See https://cloud.google.com/spanner/reference/rpc/google.spanner.v1#google.spanner.v1.Spanner.GetSession :rtype: bool @@ -123,7 +123,7 @@ def exists(self): def delete(self): """Delete this session. - See: + See https://cloud.google.com/spanner/reference/rpc/google.spanner.v1#google.spanner.v1.Spanner.GetSession :raises: :exc:`ValueError` if :attr:`session_id` is not already set. @@ -143,7 +143,7 @@ def snapshot(self, read_timestamp=None, min_read_timestamp=None, max_staleness=None, exact_staleness=None): """Create a snapshot to perform a set of reads with shared staleness. - See: + See https://cloud.google.com/spanner/reference/rpc/google.spanner.v1#google.spanner.v1.TransactionOptions.ReadOnly If no options are passed, reads will use the ``strong`` model, reading @@ -225,7 +225,7 @@ def execute_sql(self, sql, params=None, param_types=None, query_mode=None, :type query_mode: :class:`google.spanner.v1.spanner_pb2.ExecuteSqlRequest.QueryMode` - :param query_mode: Mode governing return of results / query plan. See: + :param query_mode: Mode governing return of results / query plan. See https://cloud.google.com/spanner/reference/rpc/google.spanner.v1#google.spanner.v1.ExecuteSqlRequest.QueryMode1 :type resume_token: bytes diff --git a/spanner/google/cloud/spanner/snapshot.py b/spanner/google/cloud/spanner/snapshot.py index 22b39dbc813de..05fcba63f322e 100644 --- a/spanner/google/cloud/spanner/snapshot.py +++ b/spanner/google/cloud/spanner/snapshot.py @@ -101,7 +101,7 @@ def execute_sql(self, sql, params=None, param_types=None, query_mode=None, :type query_mode: :class:`google.cloud.proto.spanner.v1.ExecuteSqlRequest.QueryMode` - :param query_mode: Mode governing return of results / query plan. See: + :param query_mode: Mode governing return of results / query plan. See https://cloud.google.com/spanner/reference/rpc/google.spanner.v1#google.spanner.v1.ExecuteSqlRequest.QueryMode1 :type resume_token: bytes @@ -134,7 +134,7 @@ def execute_sql(self, sql, params=None, param_types=None, query_mode=None, class Snapshot(_SnapshotBase): """Allow a set of reads / SQL statements with shared staleness. - See: + See https://cloud.google.com/spanner/reference/rpc/google.spanner.v1#google.spanner.v1.TransactionOptions.ReadOnly If no options are passed, reads will use the ``strong`` model, reading diff --git a/spanner/tests/unit/test_streamed.py b/spanner/tests/unit/test_streamed.py index 740a3e0f0ea00..3300e4048cc7d 100644 --- a/spanner/tests/unit/test_streamed.py +++ b/spanner/tests/unit/test_streamed.py @@ -982,7 +982,7 @@ def _normalize_results(rows_data, fields): def _parse_streaming_read_acceptance_tests(filename): """Parse acceptance tests from JSON - See: streaming-read-acceptance-test.json + See streaming-read-acceptance-test.json """ import json diff --git a/speech/google/cloud/speech/_gax.py b/speech/google/cloud/speech/_gax.py index b643f35aa9c95..c03c085402147 100644 --- a/speech/google/cloud/speech/_gax.py +++ b/speech/google/cloud/speech/_gax.py @@ -41,7 +41,7 @@ class GAPICSpeechAPI(object): """Manage calls through GAPIC wrappers to the Speech API. :type client: `~google.cloud.core.client.Client` - :param client: Instance of ``Client`. + :param client: Instance of ``Client``. """ def __init__(self, client=None): self._client = client @@ -131,7 +131,7 @@ def streaming_recognize(self, sample, language_code, .. note:: Streaming recognition requests are limited to 1 minute of audio. - See: https://cloud.google.com/speech/limits#content + See https://cloud.google.com/speech/limits#content Yields :class:`~streaming_response.StreamingSpeechResponse` containing results and metadata from the streaming request. diff --git a/speech/google/cloud/speech/encoding.py b/speech/google/cloud/speech/encoding.py index 529f8e45e889f..d4fa697181cb5 100644 --- a/speech/google/cloud/speech/encoding.py +++ b/speech/google/cloud/speech/encoding.py @@ -18,7 +18,7 @@ class Encoding(object): """Audio encoding types. - See: + See https://cloud.google.com/speech/reference/rest/v1/RecognitionConfig#AudioEncoding """ diff --git a/speech/google/cloud/speech/sample.py b/speech/google/cloud/speech/sample.py index 0380fac125861..9814fcdf92d23 100644 --- a/speech/google/cloud/speech/sample.py +++ b/speech/google/cloud/speech/sample.py @@ -179,7 +179,7 @@ def streaming_recognize(self, language_code, .. note:: Streaming recognition requests are limited to 1 minute of audio. - See: https://cloud.google.com/speech/limits#content + See https://cloud.google.com/speech/limits#content Yields: Instance of :class:`~google.cloud.speech.result.StreamingSpeechResult` diff --git a/storage/google/cloud/storage/acl.py b/storage/google/cloud/storage/acl.py index 389a312fb219b..c4525ea887357 100644 --- a/storage/google/cloud/storage/acl.py +++ b/storage/google/cloud/storage/acl.py @@ -188,7 +188,7 @@ class ACL(object): 'bucketOwnerRead', 'bucketOwnerFullControl', ]) - """See: + """See https://cloud.google.com/storage/docs/access-control/lists#predefined-acl """ diff --git a/storage/google/cloud/storage/batch.py b/storage/google/cloud/storage/batch.py index 146c52a227bcd..0ab95a98743c7 100644 --- a/storage/google/cloud/storage/batch.py +++ b/storage/google/cloud/storage/batch.py @@ -13,7 +13,7 @@ # limitations under the License. """Batch updates / deletes of storage buckets / blobs. -See: https://cloud.google.com/storage/docs/json_api/v1/how-tos/batch +See https://cloud.google.com/storage/docs/json_api/v1/how-tos/batch """ from email.encoders import encode_noop from email.generator import Generator diff --git a/storage/google/cloud/storage/blob.py b/storage/google/cloud/storage/blob.py index 671cda3052a18..8805cd7342294 100644 --- a/storage/google/cloud/storage/blob.py +++ b/storage/google/cloud/storage/blob.py @@ -130,7 +130,7 @@ class Blob(_PropertyMixin): ) """Allowed values for :attr:`storage_class`. - See: + See https://cloud.google.com/storage/docs/json_api/v1/objects#storageClass https://cloud.google.com/storage/docs/per-object-storage-class @@ -1054,7 +1054,7 @@ def create_resumable_upload_session( def get_iam_policy(self, client=None): """Retrieve the IAM policy for the object. - See: + See https://cloud.google.com/storage/docs/json_api/v1/objects/getIamPolicy :type client: :class:`~google.cloud.storage.client.Client` or @@ -1076,7 +1076,7 @@ def get_iam_policy(self, client=None): def set_iam_policy(self, policy, client=None): """Update the IAM policy for the bucket. - See: + See https://cloud.google.com/storage/docs/json_api/v1/objects/setIamPolicy :type policy: :class:`google.cloud.iam.Policy` @@ -1104,7 +1104,7 @@ def set_iam_policy(self, policy, client=None): def test_iam_permissions(self, permissions, client=None): """API call: test permissions - See: + See https://cloud.google.com/storage/docs/json_api/v1/objects/testIamPermissions :type permissions: list of string @@ -1217,7 +1217,7 @@ def rewrite(self, source, token=None, client=None): def update_storage_class(self, new_class, client=None): """Update blob's storage class via a rewrite-in-place. - See: + See https://cloud.google.com/storage/docs/per-object-storage-class :type new_class: str @@ -1244,7 +1244,7 @@ def update_storage_class(self, new_class, client=None): cache_control = _scalar_property('cacheControl') """HTTP 'Cache-Control' header for this object. - See: `RFC 7234`_ and `API reference docs`_. + See `RFC 7234`_ and `API reference docs`_. If the property is not set locally, returns :data:`None`. @@ -1256,7 +1256,7 @@ def update_storage_class(self, new_class, client=None): content_disposition = _scalar_property('contentDisposition') """HTTP 'Content-Disposition' header for this object. - See: `RFC 6266`_ and `API reference docs`_. + See `RFC 6266`_ and `API reference docs`_. If the property is not set locally, returns :data:`None`. @@ -1268,7 +1268,7 @@ def update_storage_class(self, new_class, client=None): content_encoding = _scalar_property('contentEncoding') """HTTP 'Content-Encoding' header for this object. - See: `RFC 7231`_ and `API reference docs`_. + See `RFC 7231`_ and `API reference docs`_. If the property is not set locally, returns ``None``. @@ -1280,7 +1280,7 @@ def update_storage_class(self, new_class, client=None): content_language = _scalar_property('contentLanguage') """HTTP 'Content-Language' header for this object. - See: `BCP47`_ and `API reference docs`_. + See `BCP47`_ and `API reference docs`_. If the property is not set locally, returns :data:`None`. @@ -1292,7 +1292,7 @@ def update_storage_class(self, new_class, client=None): content_type = _scalar_property(_CONTENT_TYPE_FIELD) """HTTP 'Content-Type' header for this object. - See: `RFC 2616`_ and `API reference docs`_. + See `RFC 2616`_ and `API reference docs`_. If the property is not set locally, returns :data:`None`. @@ -1304,7 +1304,7 @@ def update_storage_class(self, new_class, client=None): crc32c = _scalar_property('crc32c') """CRC32C checksum for this object. - See: `RFC 4960`_ and `API reference docs`_. + See `RFC 4960`_ and `API reference docs`_. If the property is not set locally, returns :data:`None`. @@ -1317,7 +1317,7 @@ def update_storage_class(self, new_class, client=None): def component_count(self): """Number of underlying components that make up this object. - See: https://cloud.google.com/storage/docs/json_api/v1/objects + See https://cloud.google.com/storage/docs/json_api/v1/objects :rtype: int or ``NoneType`` :returns: The component count (in case of a composed object) or @@ -1332,7 +1332,7 @@ def component_count(self): def etag(self): """Retrieve the ETag for the object. - See: `RFC 2616 (etags)`_ and `API reference docs`_. + See `RFC 2616 (etags)`_ and `API reference docs`_. :rtype: str or ``NoneType`` :returns: The blob etag or ``None`` if the property is not set locally. @@ -1345,7 +1345,7 @@ def etag(self): def generation(self): """Retrieve the generation for the object. - See: https://cloud.google.com/storage/docs/json_api/v1/objects + See https://cloud.google.com/storage/docs/json_api/v1/objects :rtype: int or ``NoneType`` :returns: The generation of the blob or ``None`` if the property @@ -1359,7 +1359,7 @@ def generation(self): def id(self): """Retrieve the ID for the object. - See: https://cloud.google.com/storage/docs/json_api/v1/objects + See https://cloud.google.com/storage/docs/json_api/v1/objects :rtype: str or ``NoneType`` :returns: The ID of the blob or ``None`` if the property is not @@ -1370,7 +1370,7 @@ def id(self): md5_hash = _scalar_property('md5Hash') """MD5 hash for this object. - See: `RFC 1321`_ and `API reference docs`_. + See `RFC 1321`_ and `API reference docs`_. If the property is not set locally, returns ``None``. @@ -1383,7 +1383,7 @@ def id(self): def media_link(self): """Retrieve the media download URI for the object. - See: https://cloud.google.com/storage/docs/json_api/v1/objects + See https://cloud.google.com/storage/docs/json_api/v1/objects :rtype: str or ``NoneType`` :returns: The media link for the blob or ``None`` if the property is @@ -1395,7 +1395,7 @@ def media_link(self): def metadata(self): """Retrieve arbitrary/application specific metadata for the object. - See: https://cloud.google.com/storage/docs/json_api/v1/objects + See https://cloud.google.com/storage/docs/json_api/v1/objects :rtype: dict or ``NoneType`` :returns: The metadata associated with the blob or ``None`` if the @@ -1407,7 +1407,7 @@ def metadata(self): def metadata(self, value): """Update arbitrary/application specific metadata for the object. - See: https://cloud.google.com/storage/docs/json_api/v1/objects + See https://cloud.google.com/storage/docs/json_api/v1/objects :type value: dict :param value: (Optional) The blob metadata to set. @@ -1418,7 +1418,7 @@ def metadata(self, value): def metageneration(self): """Retrieve the metageneration for the object. - See: https://cloud.google.com/storage/docs/json_api/v1/objects + See https://cloud.google.com/storage/docs/json_api/v1/objects :rtype: int or ``NoneType`` :returns: The metageneration of the blob or ``None`` if the property @@ -1432,7 +1432,7 @@ def metageneration(self): def owner(self): """Retrieve info about the owner of the object. - See: https://cloud.google.com/storage/docs/json_api/v1/objects + See https://cloud.google.com/storage/docs/json_api/v1/objects :rtype: dict or ``NoneType`` :returns: Mapping of owner's role/ID. If the property is not set @@ -1444,7 +1444,7 @@ def owner(self): def self_link(self): """Retrieve the URI for the object. - See: https://cloud.google.com/storage/docs/json_api/v1/objects + See https://cloud.google.com/storage/docs/json_api/v1/objects :rtype: str or ``NoneType`` :returns: The self link for the blob or ``None`` if the property is @@ -1456,7 +1456,7 @@ def self_link(self): def size(self): """Size of the object, in bytes. - See: https://cloud.google.com/storage/docs/json_api/v1/objects + See https://cloud.google.com/storage/docs/json_api/v1/objects :rtype: int or ``NoneType`` :returns: The size of the blob or ``None`` if the property @@ -1474,7 +1474,7 @@ def size(self): exists in a bucket, call :meth:`update_storage_class` (which uses the "storage.objects.rewrite" method). - See: https://cloud.google.com/storage/docs/storage-classes + See https://cloud.google.com/storage/docs/storage-classes :rtype: str or ``NoneType`` :returns: If set, one of "MULTI_REGIONAL", "REGIONAL", @@ -1486,7 +1486,7 @@ def size(self): def time_deleted(self): """Retrieve the timestamp at which the object was deleted. - See: https://cloud.google.com/storage/docs/json_api/v1/objects + See https://cloud.google.com/storage/docs/json_api/v1/objects :rtype: :class:`datetime.datetime` or ``NoneType`` :returns: Datetime object parsed from RFC3339 valid timestamp, or @@ -1501,7 +1501,7 @@ def time_deleted(self): def time_created(self): """Retrieve the timestamp at which the object was created. - See: https://cloud.google.com/storage/docs/json_api/v1/objects + See https://cloud.google.com/storage/docs/json_api/v1/objects :rtype: :class:`datetime.datetime` or ``NoneType`` :returns: Datetime object parsed from RFC3339 valid timestamp, or @@ -1515,7 +1515,7 @@ def time_created(self): def updated(self): """Retrieve the timestamp at which the object was updated. - See: https://cloud.google.com/storage/docs/json_api/v1/objects + See https://cloud.google.com/storage/docs/json_api/v1/objects :rtype: :class:`datetime.datetime` or ``NoneType`` :returns: Datetime object parsed from RFC3339 valid timestamp, or diff --git a/storage/google/cloud/storage/bucket.py b/storage/google/cloud/storage/bucket.py index f0f040e0627e0..506d1ce6e26d4 100644 --- a/storage/google/cloud/storage/bucket.py +++ b/storage/google/cloud/storage/bucket.py @@ -103,7 +103,7 @@ class Bucket(_PropertyMixin): ) """Allowed values for :attr:`storage_class`. - See: + See https://cloud.google.com/storage/docs/json_api/v1/buckets#storageClass https://cloud.google.com/storage/docs/storage-classes """ @@ -527,7 +527,7 @@ def rename_blob(self, blob, new_name, client=None): def cors(self): """Retrieve or set CORS policies configured for this bucket. - See: http://www.w3.org/TR/cors/ and + See http://www.w3.org/TR/cors/ and https://cloud.google.com/storage/docs/json_api/v1/buckets :setter: Set CORS policies for this bucket. @@ -543,7 +543,7 @@ def cors(self): def cors(self, entries): """Set CORS policies configured for this bucket. - See: http://www.w3.org/TR/cors/ and + See http://www.w3.org/TR/cors/ and https://cloud.google.com/storage/docs/json_api/v1/buckets :type entries: list of dictionaries @@ -555,7 +555,7 @@ def cors(self, entries): def etag(self): """Retrieve the ETag for the bucket. - See: https://tools.ietf.org/html/rfc2616#section-3.11 and + See https://tools.ietf.org/html/rfc2616#section-3.11 and https://cloud.google.com/storage/docs/json_api/v1/buckets :rtype: str or ``NoneType`` @@ -568,7 +568,7 @@ def etag(self): def id(self): """Retrieve the ID for the bucket. - See: https://cloud.google.com/storage/docs/json_api/v1/buckets + See https://cloud.google.com/storage/docs/json_api/v1/buckets :rtype: str or ``NoneType`` :returns: The ID of the bucket or ``None`` if the property is not @@ -580,7 +580,7 @@ def id(self): def lifecycle_rules(self): """Lifecycle rules configured for this bucket. - See: https://cloud.google.com/storage/docs/lifecycle and + See https://cloud.google.com/storage/docs/lifecycle and https://cloud.google.com/storage/docs/json_api/v1/buckets :rtype: list(dict) @@ -596,7 +596,7 @@ def lifecycle_rules(self, rules): location = _scalar_property('location') """Retrieve location configured for this bucket. - See: https://cloud.google.com/storage/docs/json_api/v1/buckets and + See https://cloud.google.com/storage/docs/json_api/v1/buckets and https://cloud.google.com/storage/docs/bucket-locations If the property is not set locally, returns ``None``. @@ -607,7 +607,7 @@ def lifecycle_rules(self, rules): def get_logging(self): """Return info about access logging for this bucket. - See: https://cloud.google.com/storage/docs/access-logs#status + See https://cloud.google.com/storage/docs/access-logs#status :rtype: dict or None :returns: a dict w/ keys, ``logBucket`` and ``logObjectPrefix`` @@ -619,7 +619,7 @@ def get_logging(self): def enable_logging(self, bucket_name, object_prefix=''): """Enable access logging for this bucket. - See: https://cloud.google.com/storage/docs/access-logs + See https://cloud.google.com/storage/docs/access-logs :type bucket_name: str :param bucket_name: name of bucket in which to store access logs @@ -633,7 +633,7 @@ def enable_logging(self, bucket_name, object_prefix=''): def disable_logging(self): """Disable access logging for this bucket. - See: https://cloud.google.com/storage/docs/access-logs#disabling + See https://cloud.google.com/storage/docs/access-logs#disabling """ self._patch_property('logging', None) @@ -641,7 +641,7 @@ def disable_logging(self): def metageneration(self): """Retrieve the metageneration for the bucket. - See: https://cloud.google.com/storage/docs/json_api/v1/buckets + See https://cloud.google.com/storage/docs/json_api/v1/buckets :rtype: int or ``NoneType`` :returns: The metageneration of the bucket or ``None`` if the property @@ -655,7 +655,7 @@ def metageneration(self): def owner(self): """Retrieve info about the owner of the bucket. - See: https://cloud.google.com/storage/docs/json_api/v1/buckets + See https://cloud.google.com/storage/docs/json_api/v1/buckets :rtype: dict or ``NoneType`` :returns: Mapping of owner's role/ID. If the property is not set @@ -667,7 +667,7 @@ def owner(self): def project_number(self): """Retrieve the number of the project to which the bucket is assigned. - See: https://cloud.google.com/storage/docs/json_api/v1/buckets + See https://cloud.google.com/storage/docs/json_api/v1/buckets :rtype: int or ``NoneType`` :returns: The project number that owns the bucket or ``None`` if the @@ -681,7 +681,7 @@ def project_number(self): def self_link(self): """Retrieve the URI for the bucket. - See: https://cloud.google.com/storage/docs/json_api/v1/buckets + See https://cloud.google.com/storage/docs/json_api/v1/buckets :rtype: str or ``NoneType`` :returns: The self link for the bucket or ``None`` if the property is @@ -693,7 +693,7 @@ def self_link(self): def storage_class(self): """Retrieve the storage class for the bucket. - See: https://cloud.google.com/storage/docs/storage-classes + See https://cloud.google.com/storage/docs/storage-classes :rtype: str or ``NoneType`` :returns: If set, one of "MULTI_REGIONAL", "REGIONAL", @@ -706,7 +706,7 @@ def storage_class(self): def storage_class(self, value): """Set the storage class for the bucket. - See: https://cloud.google.com/storage/docs/storage-classes + See https://cloud.google.com/storage/docs/storage-classes :type value: str :param value: one of "MULTI_REGIONAL", "REGIONAL", "NEARLINE", @@ -720,7 +720,7 @@ def storage_class(self, value): def time_created(self): """Retrieve the timestamp at which the bucket was created. - See: https://cloud.google.com/storage/docs/json_api/v1/buckets + See https://cloud.google.com/storage/docs/json_api/v1/buckets :rtype: :class:`datetime.datetime` or ``NoneType`` :returns: Datetime object parsed from RFC3339 valid timestamp, or @@ -734,7 +734,7 @@ def time_created(self): def versioning_enabled(self): """Is versioning enabled for this bucket? - See: https://cloud.google.com/storage/docs/object-versioning for + See https://cloud.google.com/storage/docs/object-versioning for details. :rtype: bool @@ -747,7 +747,7 @@ def versioning_enabled(self): def versioning_enabled(self, value): """Enable versioning for this bucket. - See: https://cloud.google.com/storage/docs/object-versioning for + See https://cloud.google.com/storage/docs/object-versioning for details. :type value: convertible to boolean @@ -758,7 +758,7 @@ def versioning_enabled(self, value): def configure_website(self, main_page_suffix=None, not_found_page=None): """Configure website-related properties. - See: https://cloud.google.com/storage/docs/hosting-static-website + See https://cloud.google.com/storage/docs/hosting-static-website .. note:: This (apparently) only works @@ -807,7 +807,7 @@ def disable_website(self): def get_iam_policy(self, client=None): """Retrieve the IAM policy for the bucket. - See: + See https://cloud.google.com/storage/docs/json_api/v1/buckets/getIamPolicy :type client: :class:`~google.cloud.storage.client.Client` or @@ -829,7 +829,7 @@ def get_iam_policy(self, client=None): def set_iam_policy(self, policy, client=None): """Update the IAM policy for the bucket. - See: + See https://cloud.google.com/storage/docs/json_api/v1/buckets/setIamPolicy :type policy: :class:`google.cloud.iam.Policy` @@ -857,7 +857,7 @@ def set_iam_policy(self, policy, client=None): def test_iam_permissions(self, permissions, client=None): """API call: test permissions - See: + See https://cloud.google.com/storage/docs/json_api/v1/buckets/testIamPermissions :type permissions: list of string diff --git a/translate/google/cloud/translate/client.py b/translate/google/cloud/translate/client.py index 5945265d8124b..9acd7d65cc470 100644 --- a/translate/google/cloud/translate/client.py +++ b/translate/google/cloud/translate/client.py @@ -71,7 +71,7 @@ def get_languages(self, target_language=None): Response - See: + See https://cloud.google.com/translate/docs/discovering-supported-languages :type target_language: str @@ -98,7 +98,7 @@ def get_languages(self, target_language=None): def detect_language(self, values): """Detect the language of a string or list of strings. - See: https://cloud.google.com/translate/docs/detecting-language + See https://cloud.google.com/translate/docs/detecting-language :type values: str or list :param values: String or list of strings that will have @@ -165,7 +165,7 @@ def translate(self, values, target_language=None, format_=None, model=None): """Translate a string or list of strings. - See: https://cloud.google.com/translate/docs/translating-text + See https://cloud.google.com/translate/docs/translating-text :type values: str or list :param values: String or list of strings to translate. diff --git a/vision/MANIFEST.in b/vision/MANIFEST.in index 9f7100c9528a7..fc77f8c82ff0a 100644 --- a/vision/MANIFEST.in +++ b/vision/MANIFEST.in @@ -1,4 +1,4 @@ include README.rst LICENSE recursive-include google *.json *.proto -recursive-include unit_tests * +recursive-include tests * global-exclude *.pyc __pycache__ diff --git a/vision/google/cloud/gapic/__init__.py b/vision/google/cloud/gapic/__init__.py new file mode 100644 index 0000000000000..de40ea7ca058e --- /dev/null +++ b/vision/google/cloud/gapic/__init__.py @@ -0,0 +1 @@ +__import__('pkg_resources').declare_namespace(__name__) diff --git a/vision/google/cloud/gapic/vision/__init__.py b/vision/google/cloud/gapic/vision/__init__.py new file mode 100644 index 0000000000000..de40ea7ca058e --- /dev/null +++ b/vision/google/cloud/gapic/vision/__init__.py @@ -0,0 +1 @@ +__import__('pkg_resources').declare_namespace(__name__) diff --git a/vision/google/cloud/gapic/vision/v1/__init__.py b/vision/google/cloud/gapic/vision/v1/__init__.py new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/vision/google/cloud/gapic/vision/v1/enums.py b/vision/google/cloud/gapic/vision/v1/enums.py new file mode 100644 index 0000000000000..80eea7a1729ed --- /dev/null +++ b/vision/google/cloud/gapic/vision/v1/enums.py @@ -0,0 +1,195 @@ +# Copyright 2016 Google Inc. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Wrappers for protocol buffer enum types.""" + + +class TextAnnotation(object): + class DetectedBreak(object): + class BreakType(object): + """ + Enum to denote the type of break found. New line, space etc. + + Attributes: + UNKNOWN (int): Unknown break label type. + SPACE (int): Regular space. + SURE_SPACE (int): Sure space (very wide). + EOL_SURE_SPACE (int): Line-wrapping break. + HYPHEN (int): End-line hyphen that is not present in text; does + LINE_BREAK (int): not co-occur with SPACE, LEADER_SPACE, or + LINE_BREAK. + Line break that ends a paragraph. + """ + UNKNOWN = 0 + SPACE = 1 + SURE_SPACE = 2 + EOL_SURE_SPACE = 3 + HYPHEN = 4 + LINE_BREAK = 5 + + +class Block(object): + class BlockType(object): + """ + Type of a block (text, image etc) as identified by OCR. + + Attributes: + UNKNOWN (int): Unknown block type. + TEXT (int): Regular text block. + TABLE (int): Table block. + PICTURE (int): Image block. + RULER (int): Horizontal/vertical line box. + BARCODE (int): Barcode block. + """ + UNKNOWN = 0 + TEXT = 1 + TABLE = 2 + PICTURE = 3 + RULER = 4 + BARCODE = 5 + + +class Likelihood(object): + """ + A bucketized representation of likelihood, which is intended to give clients + highly stable results across model upgrades. + + Attributes: + UNKNOWN (int): Unknown likelihood. + VERY_UNLIKELY (int): It is very unlikely that the image belongs to the specified vertical. + UNLIKELY (int): It is unlikely that the image belongs to the specified vertical. + POSSIBLE (int): It is possible that the image belongs to the specified vertical. + LIKELY (int): It is likely that the image belongs to the specified vertical. + VERY_LIKELY (int): It is very likely that the image belongs to the specified vertical. + """ + UNKNOWN = 0 + VERY_UNLIKELY = 1 + UNLIKELY = 2 + POSSIBLE = 3 + LIKELY = 4 + VERY_LIKELY = 5 + + +class Feature(object): + class Type(object): + """ + Type of image feature. + + Attributes: + TYPE_UNSPECIFIED (int): Unspecified feature type. + FACE_DETECTION (int): Run face detection. + LANDMARK_DETECTION (int): Run landmark detection. + LOGO_DETECTION (int): Run logo detection. + LABEL_DETECTION (int): Run label detection. + TEXT_DETECTION (int): Run OCR. + DOCUMENT_TEXT_DETECTION (int): Run dense text document OCR. Takes precedence when both + DOCUMENT_TEXT_DETECTION and TEXT_DETECTION are present. + SAFE_SEARCH_DETECTION (int): Run computer vision models to compute image safe-search properties. + IMAGE_PROPERTIES (int): Compute a set of image properties, such as the image's dominant colors. + CROP_HINTS (int): Run crop hints. + WEB_DETECTION (int): Run web detection. + """ + TYPE_UNSPECIFIED = 0 + FACE_DETECTION = 1 + LANDMARK_DETECTION = 2 + LOGO_DETECTION = 3 + LABEL_DETECTION = 4 + TEXT_DETECTION = 5 + DOCUMENT_TEXT_DETECTION = 11 + SAFE_SEARCH_DETECTION = 6 + IMAGE_PROPERTIES = 7 + CROP_HINTS = 9 + WEB_DETECTION = 10 + + +class FaceAnnotation(object): + class Landmark(object): + class Type(object): + """ + Face landmark (feature) type. + Left and right are defined from the vantage of the viewer of the image + without considering mirror projections typical of photos. So, ``LEFT_EYE``, + typically, is the person's right eye. + + Attributes: + UNKNOWN_LANDMARK (int): Unknown face landmark detected. Should not be filled. + LEFT_EYE (int): Left eye. + RIGHT_EYE (int): Right eye. + LEFT_OF_LEFT_EYEBROW (int): Left of left eyebrow. + RIGHT_OF_LEFT_EYEBROW (int): Right of left eyebrow. + LEFT_OF_RIGHT_EYEBROW (int): Left of right eyebrow. + RIGHT_OF_RIGHT_EYEBROW (int): Right of right eyebrow. + MIDPOINT_BETWEEN_EYES (int): Midpoint between eyes. + NOSE_TIP (int): Nose tip. + UPPER_LIP (int): Upper lip. + LOWER_LIP (int): Lower lip. + MOUTH_LEFT (int): Mouth left. + MOUTH_RIGHT (int): Mouth right. + MOUTH_CENTER (int): Mouth center. + NOSE_BOTTOM_RIGHT (int): Nose, bottom right. + NOSE_BOTTOM_LEFT (int): Nose, bottom left. + NOSE_BOTTOM_CENTER (int): Nose, bottom center. + LEFT_EYE_TOP_BOUNDARY (int): Left eye, top boundary. + LEFT_EYE_RIGHT_CORNER (int): Left eye, right corner. + LEFT_EYE_BOTTOM_BOUNDARY (int): Left eye, bottom boundary. + LEFT_EYE_LEFT_CORNER (int): Left eye, left corner. + RIGHT_EYE_TOP_BOUNDARY (int): Right eye, top boundary. + RIGHT_EYE_RIGHT_CORNER (int): Right eye, right corner. + RIGHT_EYE_BOTTOM_BOUNDARY (int): Right eye, bottom boundary. + RIGHT_EYE_LEFT_CORNER (int): Right eye, left corner. + LEFT_EYEBROW_UPPER_MIDPOINT (int): Left eyebrow, upper midpoint. + RIGHT_EYEBROW_UPPER_MIDPOINT (int): Right eyebrow, upper midpoint. + LEFT_EAR_TRAGION (int): Left ear tragion. + RIGHT_EAR_TRAGION (int): Right ear tragion. + LEFT_EYE_PUPIL (int): Left eye pupil. + RIGHT_EYE_PUPIL (int): Right eye pupil. + FOREHEAD_GLABELLA (int): Forehead glabella. + CHIN_GNATHION (int): Chin gnathion. + CHIN_LEFT_GONION (int): Chin left gonion. + CHIN_RIGHT_GONION (int): Chin right gonion. + """ + UNKNOWN_LANDMARK = 0 + LEFT_EYE = 1 + RIGHT_EYE = 2 + LEFT_OF_LEFT_EYEBROW = 3 + RIGHT_OF_LEFT_EYEBROW = 4 + LEFT_OF_RIGHT_EYEBROW = 5 + RIGHT_OF_RIGHT_EYEBROW = 6 + MIDPOINT_BETWEEN_EYES = 7 + NOSE_TIP = 8 + UPPER_LIP = 9 + LOWER_LIP = 10 + MOUTH_LEFT = 11 + MOUTH_RIGHT = 12 + MOUTH_CENTER = 13 + NOSE_BOTTOM_RIGHT = 14 + NOSE_BOTTOM_LEFT = 15 + NOSE_BOTTOM_CENTER = 16 + LEFT_EYE_TOP_BOUNDARY = 17 + LEFT_EYE_RIGHT_CORNER = 18 + LEFT_EYE_BOTTOM_BOUNDARY = 19 + LEFT_EYE_LEFT_CORNER = 20 + RIGHT_EYE_TOP_BOUNDARY = 21 + RIGHT_EYE_RIGHT_CORNER = 22 + RIGHT_EYE_BOTTOM_BOUNDARY = 23 + RIGHT_EYE_LEFT_CORNER = 24 + LEFT_EYEBROW_UPPER_MIDPOINT = 25 + RIGHT_EYEBROW_UPPER_MIDPOINT = 26 + LEFT_EAR_TRAGION = 27 + RIGHT_EAR_TRAGION = 28 + LEFT_EYE_PUPIL = 29 + RIGHT_EYE_PUPIL = 30 + FOREHEAD_GLABELLA = 31 + CHIN_GNATHION = 32 + CHIN_LEFT_GONION = 33 + CHIN_RIGHT_GONION = 34 diff --git a/vision/google/cloud/gapic/vision/v1/image_annotator_client.py b/vision/google/cloud/gapic/vision/v1/image_annotator_client.py new file mode 100644 index 0000000000000..fb84bbc1aa886 --- /dev/null +++ b/vision/google/cloud/gapic/vision/v1/image_annotator_client.py @@ -0,0 +1,179 @@ +# Copyright 2017, Google Inc. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# EDITING INSTRUCTIONS +# This file was generated from the file +# https://github.com/google/googleapis/blob/master/google/cloud/vision/v1/image_annotator.proto, +# and updates to that file get reflected here through a refresh process. +# For the short term, the refresh process will only be runnable by Google engineers. +# +# The only allowed edits are to method and file documentation. A 3-way +# merge preserves those additions if the generated source changes. +"""Accesses the google.cloud.vision.v1 ImageAnnotator API.""" + +import collections +import json +import os +import pkg_resources +import platform + +from google.gax import api_callable +from google.gax import config +from google.gax import path_template +import google.gax + +from google.cloud.gapic.vision.v1 import enums +from google.cloud.proto.vision.v1 import image_annotator_pb2 + + +class ImageAnnotatorClient(object): + """Service that performs Google Cloud Vision API detection tasks over + client images, such as face, landmark, logo, label, and text detection. The + ImageAnnotator service returns detected entities from the images. + """ + + SERVICE_ADDRESS = 'vision.googleapis.com' + """The default address of the service.""" + + DEFAULT_SERVICE_PORT = 443 + """The default port of the service.""" + + # The scopes needed to make gRPC calls to all of the methods defined in + # this service + _ALL_SCOPES = ('https://www.googleapis.com/auth/cloud-platform', ) + + def __init__(self, + service_path=SERVICE_ADDRESS, + port=DEFAULT_SERVICE_PORT, + channel=None, + credentials=None, + ssl_credentials=None, + scopes=None, + client_config=None, + app_name=None, + app_version='', + lib_name=None, + lib_version='', + metrics_headers=()): + """Constructor. + + Args: + service_path (string): The domain name of the API remote host. + port (int): The port on which to connect to the remote host. + channel (:class:`grpc.Channel`): A ``Channel`` instance through + which to make calls. + credentials (object): The authorization credentials to attach to + requests. These credentials identify this application to the + service. + ssl_credentials (:class:`grpc.ChannelCredentials`): A + ``ChannelCredentials`` instance for use with an SSL-enabled + channel. + scopes (list[string]): A list of OAuth2 scopes to attach to requests. + client_config (dict): + A dictionary for call options for each method. See + :func:`google.gax.construct_settings` for the structure of + this data. Falls back to the default config if not specified + or the specified config is missing data points. + app_name (string): The name of the application calling + the service. Recommended for analytics purposes. + app_version (string): The version of the application calling + the service. Recommended for analytics purposes. + lib_name (string): The API library software used for calling + the service. (Unless you are writing an API client itself, + leave this as default.) + lib_version (string): The API library software version used + for calling the service. (Unless you are writing an API client + itself, leave this as default.) + metrics_headers (dict): A dictionary of values for tracking + client library metrics. Ultimately serializes to a string + (e.g. 'foo/1.2.3 bar/3.14.1'). This argument should be + considered private. + + Returns: + A ImageAnnotatorClient object. + """ + # Unless the calling application specifically requested + # OAuth scopes, request everything. + if scopes is None: + scopes = self._ALL_SCOPES + + # Initialize an empty client config, if none is set. + if client_config is None: + client_config = {} + + # Initialize metrics_headers as an ordered dictionary + # (cuts down on cardinality of the resulting string slightly). + metrics_headers = collections.OrderedDict(metrics_headers) + metrics_headers['gl-python'] = platform.python_version() + + # The library may or may not be set, depending on what is + # calling this client. Newer client libraries set the library name + # and version. + if lib_name: + metrics_headers[lib_name] = lib_version + + # Finally, track the GAPIC package version. + metrics_headers['gapic'] = pkg_resources.get_distribution( + 'google-cloud-vision', ).version + + # Load the configuration defaults. + default_client_config = json.loads( + pkg_resources.resource_string( + __name__, 'image_annotator_client_config.json').decode()) + defaults = api_callable.construct_settings( + 'google.cloud.vision.v1.ImageAnnotator', + default_client_config, + client_config, + config.STATUS_CODE_NAMES, + metrics_headers=metrics_headers, ) + self.image_annotator_stub = config.create_stub( + image_annotator_pb2.ImageAnnotatorStub, + channel=channel, + service_path=service_path, + service_port=port, + credentials=credentials, + scopes=scopes, + ssl_credentials=ssl_credentials) + + self._batch_annotate_images = api_callable.create_api_call( + self.image_annotator_stub.BatchAnnotateImages, + settings=defaults['batch_annotate_images']) + + # Service calls + def batch_annotate_images(self, requests, options=None): + """ + Run image detection and annotation for a batch of images. + + Example: + >>> from google.cloud.gapic.vision.v1 import image_annotator_client + >>> client = image_annotator_client.ImageAnnotatorClient() + >>> requests = [] + >>> response = client.batch_annotate_images(requests) + + Args: + requests (list[:class:`google.cloud.proto.vision.v1.image_annotator_pb2.AnnotateImageRequest`]): Individual image annotation requests for this batch. + options (:class:`google.gax.CallOptions`): Overrides the default + settings for this call, e.g, timeout, retries etc. + + Returns: + A :class:`google.cloud.proto.vision.v1.image_annotator_pb2.BatchAnnotateImagesResponse` instance. + + Raises: + :exc:`google.gax.errors.GaxError` if the RPC is aborted. + :exc:`ValueError` if the parameters are invalid. + """ + # Create the request object. + request = image_annotator_pb2.BatchAnnotateImagesRequest( + requests=requests) + return self._batch_annotate_images(request, options) diff --git a/vision/google/cloud/gapic/vision/v1/image_annotator_client_config.json b/vision/google/cloud/gapic/vision/v1/image_annotator_client_config.json new file mode 100644 index 0000000000000..b7b8b93a7521a --- /dev/null +++ b/vision/google/cloud/gapic/vision/v1/image_annotator_client_config.json @@ -0,0 +1,33 @@ +{ + "interfaces": { + "google.cloud.vision.v1.ImageAnnotator": { + "retry_codes": { + "idempotent": [ + "DEADLINE_EXCEEDED", + "UNAVAILABLE" + ], + "non_idempotent": [ + "UNAVAILABLE" + ] + }, + "retry_params": { + "default": { + "initial_retry_delay_millis": 100, + "retry_delay_multiplier": 1.3, + "max_retry_delay_millis": 60000, + "initial_rpc_timeout_millis": 60000, + "rpc_timeout_multiplier": 1.0, + "max_rpc_timeout_millis": 60000, + "total_timeout_millis": 600000 + } + }, + "methods": { + "BatchAnnotateImages": { + "timeout_millis": 60000, + "retry_codes_name": "idempotent", + "retry_params_name": "default" + } + } + } + } +} diff --git a/vision/google/cloud/proto/__init__.py b/vision/google/cloud/proto/__init__.py new file mode 100644 index 0000000000000..de40ea7ca058e --- /dev/null +++ b/vision/google/cloud/proto/__init__.py @@ -0,0 +1 @@ +__import__('pkg_resources').declare_namespace(__name__) diff --git a/vision/google/cloud/proto/vision/__init__.py b/vision/google/cloud/proto/vision/__init__.py new file mode 100644 index 0000000000000..de40ea7ca058e --- /dev/null +++ b/vision/google/cloud/proto/vision/__init__.py @@ -0,0 +1 @@ +__import__('pkg_resources').declare_namespace(__name__) diff --git a/vision/google/cloud/proto/vision/v1/__init__.py b/vision/google/cloud/proto/vision/v1/__init__.py new file mode 100644 index 0000000000000..8b137891791fe --- /dev/null +++ b/vision/google/cloud/proto/vision/v1/__init__.py @@ -0,0 +1 @@ + diff --git a/vision/google/cloud/proto/vision/v1/geometry_pb2.py b/vision/google/cloud/proto/vision/v1/geometry_pb2.py new file mode 100644 index 0000000000000..f0824ead74be6 --- /dev/null +++ b/vision/google/cloud/proto/vision/v1/geometry_pb2.py @@ -0,0 +1,211 @@ +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: google/cloud/proto/vision/v1/geometry.proto + +import sys +_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) +from google.protobuf import descriptor as _descriptor +from google.protobuf import message as _message +from google.protobuf import reflection as _reflection +from google.protobuf import symbol_database as _symbol_database +from google.protobuf import descriptor_pb2 +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor.FileDescriptor( + name='google/cloud/proto/vision/v1/geometry.proto', + package='google.cloud.vision.v1', + syntax='proto3', + serialized_pb=_b('\n+google/cloud/proto/vision/v1/geometry.proto\x12\x16google.cloud.vision.v1\"\x1e\n\x06Vertex\x12\t\n\x01x\x18\x01 \x01(\x05\x12\t\n\x01y\x18\x02 \x01(\x05\"@\n\x0c\x42oundingPoly\x12\x30\n\x08vertices\x18\x01 \x03(\x0b\x32\x1e.google.cloud.vision.v1.Vertex\"+\n\x08Position\x12\t\n\x01x\x18\x01 \x01(\x02\x12\t\n\x01y\x18\x02 \x01(\x02\x12\t\n\x01z\x18\x03 \x01(\x02\x42n\n\x1a\x63om.google.cloud.vision.v1B\rGeometryProtoP\x01Z\n\x10\x66\x64_bounding_poly\x18\x02 \x01(\x0b\x32$.google.cloud.vision.v1.BoundingPoly\x12\x42\n\tlandmarks\x18\x03 \x03(\x0b\x32/.google.cloud.vision.v1.FaceAnnotation.Landmark\x12\x12\n\nroll_angle\x18\x04 \x01(\x02\x12\x11\n\tpan_angle\x18\x05 \x01(\x02\x12\x12\n\ntilt_angle\x18\x06 \x01(\x02\x12\x1c\n\x14\x64\x65tection_confidence\x18\x07 \x01(\x02\x12\x1e\n\x16landmarking_confidence\x18\x08 \x01(\x02\x12:\n\x0ejoy_likelihood\x18\t \x01(\x0e\x32\".google.cloud.vision.v1.Likelihood\x12=\n\x11sorrow_likelihood\x18\n \x01(\x0e\x32\".google.cloud.vision.v1.Likelihood\x12<\n\x10\x61nger_likelihood\x18\x0b \x01(\x0e\x32\".google.cloud.vision.v1.Likelihood\x12?\n\x13surprise_likelihood\x18\x0c \x01(\x0e\x32\".google.cloud.vision.v1.Likelihood\x12\x44\n\x18under_exposed_likelihood\x18\r \x01(\x0e\x32\".google.cloud.vision.v1.Likelihood\x12>\n\x12\x62lurred_likelihood\x18\x0e \x01(\x0e\x32\".google.cloud.vision.v1.Likelihood\x12?\n\x13headwear_likelihood\x18\x0f \x01(\x0e\x32\".google.cloud.vision.v1.Likelihood\x1a\xb9\x07\n\x08Landmark\x12\x42\n\x04type\x18\x03 \x01(\x0e\x32\x34.google.cloud.vision.v1.FaceAnnotation.Landmark.Type\x12\x32\n\x08position\x18\x04 \x01(\x0b\x32 .google.cloud.vision.v1.Position\"\xb4\x06\n\x04Type\x12\x14\n\x10UNKNOWN_LANDMARK\x10\x00\x12\x0c\n\x08LEFT_EYE\x10\x01\x12\r\n\tRIGHT_EYE\x10\x02\x12\x18\n\x14LEFT_OF_LEFT_EYEBROW\x10\x03\x12\x19\n\x15RIGHT_OF_LEFT_EYEBROW\x10\x04\x12\x19\n\x15LEFT_OF_RIGHT_EYEBROW\x10\x05\x12\x1a\n\x16RIGHT_OF_RIGHT_EYEBROW\x10\x06\x12\x19\n\x15MIDPOINT_BETWEEN_EYES\x10\x07\x12\x0c\n\x08NOSE_TIP\x10\x08\x12\r\n\tUPPER_LIP\x10\t\x12\r\n\tLOWER_LIP\x10\n\x12\x0e\n\nMOUTH_LEFT\x10\x0b\x12\x0f\n\x0bMOUTH_RIGHT\x10\x0c\x12\x10\n\x0cMOUTH_CENTER\x10\r\x12\x15\n\x11NOSE_BOTTOM_RIGHT\x10\x0e\x12\x14\n\x10NOSE_BOTTOM_LEFT\x10\x0f\x12\x16\n\x12NOSE_BOTTOM_CENTER\x10\x10\x12\x19\n\x15LEFT_EYE_TOP_BOUNDARY\x10\x11\x12\x19\n\x15LEFT_EYE_RIGHT_CORNER\x10\x12\x12\x1c\n\x18LEFT_EYE_BOTTOM_BOUNDARY\x10\x13\x12\x18\n\x14LEFT_EYE_LEFT_CORNER\x10\x14\x12\x1a\n\x16RIGHT_EYE_TOP_BOUNDARY\x10\x15\x12\x1a\n\x16RIGHT_EYE_RIGHT_CORNER\x10\x16\x12\x1d\n\x19RIGHT_EYE_BOTTOM_BOUNDARY\x10\x17\x12\x19\n\x15RIGHT_EYE_LEFT_CORNER\x10\x18\x12\x1f\n\x1bLEFT_EYEBROW_UPPER_MIDPOINT\x10\x19\x12 \n\x1cRIGHT_EYEBROW_UPPER_MIDPOINT\x10\x1a\x12\x14\n\x10LEFT_EAR_TRAGION\x10\x1b\x12\x15\n\x11RIGHT_EAR_TRAGION\x10\x1c\x12\x12\n\x0eLEFT_EYE_PUPIL\x10\x1d\x12\x13\n\x0fRIGHT_EYE_PUPIL\x10\x1e\x12\x15\n\x11\x46OREHEAD_GLABELLA\x10\x1f\x12\x11\n\rCHIN_GNATHION\x10 \x12\x14\n\x10\x43HIN_LEFT_GONION\x10!\x12\x15\n\x11\x43HIN_RIGHT_GONION\x10\"\"4\n\x0cLocationInfo\x12$\n\x07lat_lng\x18\x01 \x01(\x0b\x32\x13.google.type.LatLng\"\'\n\x08Property\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t\"\xa7\x02\n\x10\x45ntityAnnotation\x12\x0b\n\x03mid\x18\x01 \x01(\t\x12\x0e\n\x06locale\x18\x02 \x01(\t\x12\x13\n\x0b\x64\x65scription\x18\x03 \x01(\t\x12\r\n\x05score\x18\x04 \x01(\x02\x12\x12\n\nconfidence\x18\x05 \x01(\x02\x12\x12\n\ntopicality\x18\x06 \x01(\x02\x12;\n\rbounding_poly\x18\x07 \x01(\x0b\x32$.google.cloud.vision.v1.BoundingPoly\x12\x37\n\tlocations\x18\x08 \x03(\x0b\x32$.google.cloud.vision.v1.LocationInfo\x12\x34\n\nproperties\x18\t \x03(\x0b\x32 .google.cloud.vision.v1.Property\"\xe7\x01\n\x14SafeSearchAnnotation\x12\x31\n\x05\x61\x64ult\x18\x01 \x01(\x0e\x32\".google.cloud.vision.v1.Likelihood\x12\x31\n\x05spoof\x18\x02 \x01(\x0e\x32\".google.cloud.vision.v1.Likelihood\x12\x33\n\x07medical\x18\x03 \x01(\x0e\x32\".google.cloud.vision.v1.Likelihood\x12\x34\n\x08violence\x18\x04 \x01(\x0e\x32\".google.cloud.vision.v1.Likelihood\"a\n\x0bLatLongRect\x12(\n\x0bmin_lat_lng\x18\x01 \x01(\x0b\x32\x13.google.type.LatLng\x12(\n\x0bmax_lat_lng\x18\x02 \x01(\x0b\x32\x13.google.type.LatLng\"U\n\tColorInfo\x12!\n\x05\x63olor\x18\x01 \x01(\x0b\x32\x12.google.type.Color\x12\r\n\x05score\x18\x02 \x01(\x02\x12\x16\n\x0epixel_fraction\x18\x03 \x01(\x02\"M\n\x18\x44ominantColorsAnnotation\x12\x31\n\x06\x63olors\x18\x01 \x03(\x0b\x32!.google.cloud.vision.v1.ColorInfo\"\\\n\x0fImageProperties\x12I\n\x0f\x64ominant_colors\x18\x01 \x01(\x0b\x32\x30.google.cloud.vision.v1.DominantColorsAnnotation\"x\n\x08\x43ropHint\x12;\n\rbounding_poly\x18\x01 \x01(\x0b\x32$.google.cloud.vision.v1.BoundingPoly\x12\x12\n\nconfidence\x18\x02 \x01(\x02\x12\x1b\n\x13importance_fraction\x18\x03 \x01(\x02\"K\n\x13\x43ropHintsAnnotation\x12\x34\n\ncrop_hints\x18\x01 \x03(\x0b\x32 .google.cloud.vision.v1.CropHint\"(\n\x0f\x43ropHintsParams\x12\x15\n\raspect_ratios\x18\x01 \x03(\x02\"\xa6\x01\n\x0cImageContext\x12:\n\rlat_long_rect\x18\x01 \x01(\x0b\x32#.google.cloud.vision.v1.LatLongRect\x12\x16\n\x0elanguage_hints\x18\x02 \x03(\t\x12\x42\n\x11\x63rop_hints_params\x18\x04 \x01(\x0b\x32\'.google.cloud.vision.v1.CropHintsParams\"\xb4\x01\n\x14\x41nnotateImageRequest\x12,\n\x05image\x18\x01 \x01(\x0b\x32\x1d.google.cloud.vision.v1.Image\x12\x31\n\x08\x66\x65\x61tures\x18\x02 \x03(\x0b\x32\x1f.google.cloud.vision.v1.Feature\x12;\n\rimage_context\x18\x03 \x01(\x0b\x32$.google.cloud.vision.v1.ImageContext\"\xfc\x05\n\x15\x41nnotateImageResponse\x12@\n\x10\x66\x61\x63\x65_annotations\x18\x01 \x03(\x0b\x32&.google.cloud.vision.v1.FaceAnnotation\x12\x46\n\x14landmark_annotations\x18\x02 \x03(\x0b\x32(.google.cloud.vision.v1.EntityAnnotation\x12\x42\n\x10logo_annotations\x18\x03 \x03(\x0b\x32(.google.cloud.vision.v1.EntityAnnotation\x12\x43\n\x11label_annotations\x18\x04 \x03(\x0b\x32(.google.cloud.vision.v1.EntityAnnotation\x12\x42\n\x10text_annotations\x18\x05 \x03(\x0b\x32(.google.cloud.vision.v1.EntityAnnotation\x12\x44\n\x14\x66ull_text_annotation\x18\x0c \x01(\x0b\x32&.google.cloud.vision.v1.TextAnnotation\x12L\n\x16safe_search_annotation\x18\x06 \x01(\x0b\x32,.google.cloud.vision.v1.SafeSearchAnnotation\x12L\n\x1bimage_properties_annotation\x18\x08 \x01(\x0b\x32\'.google.cloud.vision.v1.ImageProperties\x12J\n\x15\x63rop_hints_annotation\x18\x0b \x01(\x0b\x32+.google.cloud.vision.v1.CropHintsAnnotation\x12;\n\rweb_detection\x18\r \x01(\x0b\x32$.google.cloud.vision.v1.WebDetection\x12!\n\x05\x65rror\x18\t \x01(\x0b\x32\x12.google.rpc.Status\"\\\n\x1a\x42\x61tchAnnotateImagesRequest\x12>\n\x08requests\x18\x01 \x03(\x0b\x32,.google.cloud.vision.v1.AnnotateImageRequest\"_\n\x1b\x42\x61tchAnnotateImagesResponse\x12@\n\tresponses\x18\x01 \x03(\x0b\x32-.google.cloud.vision.v1.AnnotateImageResponse*e\n\nLikelihood\x12\x0b\n\x07UNKNOWN\x10\x00\x12\x11\n\rVERY_UNLIKELY\x10\x01\x12\x0c\n\x08UNLIKELY\x10\x02\x12\x0c\n\x08POSSIBLE\x10\x03\x12\n\n\x06LIKELY\x10\x04\x12\x0f\n\x0bVERY_LIKELY\x10\x05\x32\xb1\x01\n\x0eImageAnnotator\x12\x9e\x01\n\x13\x42\x61tchAnnotateImages\x12\x32.google.cloud.vision.v1.BatchAnnotateImagesRequest\x1a\x33.google.cloud.vision.v1.BatchAnnotateImagesResponse\"\x1e\x82\xd3\xe4\x93\x02\x18\"\x13/v1/images:annotate:\x01*Bt\n\x1a\x63om.google.cloud.vision.v1B\x13ImageAnnotatorProtoP\x01Z`__). + NOTE: Cloud Storage object versioning is not supported. + image_uri: + Image URI which supports: 1) Google Cloud Storage image URI, + which must be in the following form: + ``gs://bucket_name/object_name`` (for details, see `Google + Cloud Storage Request URIs + `__). + NOTE: Cloud Storage object versioning is not supported. 2) + Publicly accessible image HTTP/HTTPS URL. This is preferred + over the legacy ``gcs_image_uri`` above. When both + ``gcs_image_uri`` and ``image_uri`` are specified, + ``image_uri`` takes precedence. + """, + # @@protoc_insertion_point(class_scope:google.cloud.vision.v1.ImageSource) + )) +_sym_db.RegisterMessage(ImageSource) + +Image = _reflection.GeneratedProtocolMessageType('Image', (_message.Message,), dict( + DESCRIPTOR = _IMAGE, + __module__ = 'google.cloud.proto.vision.v1.image_annotator_pb2' + , + __doc__ = """Client image to perform Google Cloud Vision API tasks over. + + + Attributes: + content: + Image content, represented as a stream of bytes. Note: as with + all ``bytes`` fields, protobuffers use a pure binary + representation, whereas JSON representations use base64. + source: + Google Cloud Storage image location. If both ``content`` and + ``source`` are provided for an image, ``content`` takes + precedence and is used to perform the image annotation + request. + """, + # @@protoc_insertion_point(class_scope:google.cloud.vision.v1.Image) + )) +_sym_db.RegisterMessage(Image) + +FaceAnnotation = _reflection.GeneratedProtocolMessageType('FaceAnnotation', (_message.Message,), dict( + + Landmark = _reflection.GeneratedProtocolMessageType('Landmark', (_message.Message,), dict( + DESCRIPTOR = _FACEANNOTATION_LANDMARK, + __module__ = 'google.cloud.proto.vision.v1.image_annotator_pb2' + , + __doc__ = """A face-specific landmark (for example, a face feature). Landmark + positions may fall outside the bounds of the image if the face is near + one or more edges of the image. Therefore it is NOT guaranteed that + ``0 <= x < width`` or ``0 <= y < height``. + """, + # @@protoc_insertion_point(class_scope:google.cloud.vision.v1.FaceAnnotation.Landmark) + )) + , + DESCRIPTOR = _FACEANNOTATION, + __module__ = 'google.cloud.proto.vision.v1.image_annotator_pb2' + , + __doc__ = """A face annotation object contains the results of face detection. + + + Attributes: + type: + Face landmark type. + position: + Face landmark position. + bounding_poly: + The bounding polygon around the face. The coordinates of the + bounding box are in the original image's scale, as returned in + ``ImageParams``. The bounding box is computed to "frame" the + face in accordance with human expectations. It is based on the + landmarker results. Note that one or more x and/or y + coordinates may not be generated in the ``BoundingPoly`` (the + polygon will be unbounded) if only a partial face appears in + the image to be annotated. + fd_bounding_poly: + The ``fd_bounding_poly`` bounding polygon is tighter than the + ``boundingPoly``, and encloses only the skin part of the face. + Typically, it is used to eliminate the face from any image + analysis that detects the "amount of skin" visible in an + image. It is not based on the landmarker results, only on the + initial face detection, hence the fd (face detection) prefix. + landmarks: + Detected face landmarks. + roll_angle: + Roll angle, which indicates the amount of clockwise/anti- + clockwise rotation of the face relative to the image vertical + about the axis perpendicular to the face. Range [-180,180]. + pan_angle: + Yaw angle, which indicates the leftward/rightward angle that + the face is pointing relative to the vertical plane + perpendicular to the image. Range [-180,180]. + tilt_angle: + Pitch angle, which indicates the upwards/downwards angle that + the face is pointing relative to the image's horizontal plane. + Range [-180,180]. + detection_confidence: + Detection confidence. Range [0, 1]. + landmarking_confidence: + Face landmarking confidence. Range [0, 1]. + joy_likelihood: + Joy likelihood. + sorrow_likelihood: + Sorrow likelihood. + anger_likelihood: + Anger likelihood. + surprise_likelihood: + Surprise likelihood. + under_exposed_likelihood: + Under-exposed likelihood. + blurred_likelihood: + Blurred likelihood. + headwear_likelihood: + Headwear likelihood. + """, + # @@protoc_insertion_point(class_scope:google.cloud.vision.v1.FaceAnnotation) + )) +_sym_db.RegisterMessage(FaceAnnotation) +_sym_db.RegisterMessage(FaceAnnotation.Landmark) + +LocationInfo = _reflection.GeneratedProtocolMessageType('LocationInfo', (_message.Message,), dict( + DESCRIPTOR = _LOCATIONINFO, + __module__ = 'google.cloud.proto.vision.v1.image_annotator_pb2' + , + __doc__ = """Detected entity location information. + + + Attributes: + lat_lng: + lat/long location coordinates. + """, + # @@protoc_insertion_point(class_scope:google.cloud.vision.v1.LocationInfo) + )) +_sym_db.RegisterMessage(LocationInfo) + +Property = _reflection.GeneratedProtocolMessageType('Property', (_message.Message,), dict( + DESCRIPTOR = _PROPERTY, + __module__ = 'google.cloud.proto.vision.v1.image_annotator_pb2' + , + __doc__ = """A ``Property`` consists of a user-supplied name/value pair. + + + Attributes: + name: + Name of the property. + value: + Value of the property. + """, + # @@protoc_insertion_point(class_scope:google.cloud.vision.v1.Property) + )) +_sym_db.RegisterMessage(Property) + +EntityAnnotation = _reflection.GeneratedProtocolMessageType('EntityAnnotation', (_message.Message,), dict( + DESCRIPTOR = _ENTITYANNOTATION, + __module__ = 'google.cloud.proto.vision.v1.image_annotator_pb2' + , + __doc__ = """Set of detected entity features. + + + Attributes: + mid: + Opaque entity ID. Some IDs may be available in `Google + Knowledge Graph Search API + `__. + locale: + The language code for the locale in which the entity textual + ``description`` is expressed. + description: + Entity textual description, expressed in its ``locale`` + language. + score: + Overall score of the result. Range [0, 1]. + confidence: + The accuracy of the entity detection in an image. For example, + for an image in which the "Eiffel Tower" entity is detected, + this field represents the confidence that there is a tower in + the query image. Range [0, 1]. + topicality: + The relevancy of the ICA (Image Content Annotation) label to + the image. For example, the relevancy of "tower" is likely + higher to an image containing the detected "Eiffel Tower" than + to an image containing a detected distant towering building, + even though the confidence that there is a tower in each image + may be the same. Range [0, 1]. + bounding_poly: + Image region to which this entity belongs. Currently not + produced for ``LABEL_DETECTION`` features. For + ``TEXT_DETECTION`` (OCR), ``boundingPoly``\ s are produced for + the entire text detected in an image region, followed by + ``boundingPoly``\ s for each word within the detected text. + locations: + The location information for the detected entity. Multiple + ``LocationInfo`` elements can be present because one location + may indicate the location of the scene in the image, and + another location may indicate the location of the place where + the image was taken. Location information is usually present + for landmarks. + properties: + Some entities may have optional user-supplied ``Property`` + (name/value) fields, such a score or string that qualifies the + entity. + """, + # @@protoc_insertion_point(class_scope:google.cloud.vision.v1.EntityAnnotation) + )) +_sym_db.RegisterMessage(EntityAnnotation) + +SafeSearchAnnotation = _reflection.GeneratedProtocolMessageType('SafeSearchAnnotation', (_message.Message,), dict( + DESCRIPTOR = _SAFESEARCHANNOTATION, + __module__ = 'google.cloud.proto.vision.v1.image_annotator_pb2' + , + __doc__ = """Set of features pertaining to the image, computed by computer vision + methods over safe-search verticals (for example, adult, spoof, medical, + violence). + + + Attributes: + adult: + Represents the adult content likelihood for the image. + spoof: + Spoof likelihood. The likelihood that an modification was made + to the image's canonical version to make it appear funny or + offensive. + medical: + Likelihood that this is a medical image. + violence: + Violence likelihood. + """, + # @@protoc_insertion_point(class_scope:google.cloud.vision.v1.SafeSearchAnnotation) + )) +_sym_db.RegisterMessage(SafeSearchAnnotation) + +LatLongRect = _reflection.GeneratedProtocolMessageType('LatLongRect', (_message.Message,), dict( + DESCRIPTOR = _LATLONGRECT, + __module__ = 'google.cloud.proto.vision.v1.image_annotator_pb2' + , + __doc__ = """Rectangle determined by min and max ``LatLng`` pairs. + + + Attributes: + min_lat_lng: + Min lat/long pair. + max_lat_lng: + Max lat/long pair. + """, + # @@protoc_insertion_point(class_scope:google.cloud.vision.v1.LatLongRect) + )) +_sym_db.RegisterMessage(LatLongRect) + +ColorInfo = _reflection.GeneratedProtocolMessageType('ColorInfo', (_message.Message,), dict( + DESCRIPTOR = _COLORINFO, + __module__ = 'google.cloud.proto.vision.v1.image_annotator_pb2' + , + __doc__ = """Color information consists of RGB channels, score, and the fraction of + the image that the color occupies in the image. + + + Attributes: + color: + RGB components of the color. + score: + Image-specific score for this color. Value in range [0, 1]. + pixel_fraction: + The fraction of pixels the color occupies in the image. Value + in range [0, 1]. + """, + # @@protoc_insertion_point(class_scope:google.cloud.vision.v1.ColorInfo) + )) +_sym_db.RegisterMessage(ColorInfo) + +DominantColorsAnnotation = _reflection.GeneratedProtocolMessageType('DominantColorsAnnotation', (_message.Message,), dict( + DESCRIPTOR = _DOMINANTCOLORSANNOTATION, + __module__ = 'google.cloud.proto.vision.v1.image_annotator_pb2' + , + __doc__ = """Set of dominant colors and their corresponding scores. + + + Attributes: + colors: + RGB color values with their score and pixel fraction. + """, + # @@protoc_insertion_point(class_scope:google.cloud.vision.v1.DominantColorsAnnotation) + )) +_sym_db.RegisterMessage(DominantColorsAnnotation) + +ImageProperties = _reflection.GeneratedProtocolMessageType('ImageProperties', (_message.Message,), dict( + DESCRIPTOR = _IMAGEPROPERTIES, + __module__ = 'google.cloud.proto.vision.v1.image_annotator_pb2' + , + __doc__ = """Stores image properties, such as dominant colors. + + + Attributes: + dominant_colors: + If present, dominant colors completed successfully. + """, + # @@protoc_insertion_point(class_scope:google.cloud.vision.v1.ImageProperties) + )) +_sym_db.RegisterMessage(ImageProperties) + +CropHint = _reflection.GeneratedProtocolMessageType('CropHint', (_message.Message,), dict( + DESCRIPTOR = _CROPHINT, + __module__ = 'google.cloud.proto.vision.v1.image_annotator_pb2' + , + __doc__ = """Single crop hint that is used to generate a new crop when serving an + image. + + + Attributes: + bounding_poly: + The bounding polygon for the crop region. The coordinates of + the bounding box are in the original image's scale, as + returned in ``ImageParams``. + confidence: + Confidence of this being a salient region. Range [0, 1]. + importance_fraction: + Fraction of importance of this salient region with respect to + the original image. + """, + # @@protoc_insertion_point(class_scope:google.cloud.vision.v1.CropHint) + )) +_sym_db.RegisterMessage(CropHint) + +CropHintsAnnotation = _reflection.GeneratedProtocolMessageType('CropHintsAnnotation', (_message.Message,), dict( + DESCRIPTOR = _CROPHINTSANNOTATION, + __module__ = 'google.cloud.proto.vision.v1.image_annotator_pb2' + , + __doc__ = """Set of crop hints that are used to generate new crops when serving + images. + """, + # @@protoc_insertion_point(class_scope:google.cloud.vision.v1.CropHintsAnnotation) + )) +_sym_db.RegisterMessage(CropHintsAnnotation) + +CropHintsParams = _reflection.GeneratedProtocolMessageType('CropHintsParams', (_message.Message,), dict( + DESCRIPTOR = _CROPHINTSPARAMS, + __module__ = 'google.cloud.proto.vision.v1.image_annotator_pb2' + , + __doc__ = """Parameters for crop hints annotation request. + + + Attributes: + aspect_ratios: + Aspect ratios in floats, representing the ratio of the width + to the height of the image. For example, if the desired aspect + ratio is 4/3, the corresponding float value should be 1.33333. + If not specified, the best possible crop is returned. The + number of provided aspect ratios is limited to a maximum of + 16; any aspect ratios provided after the 16th are ignored. + """, + # @@protoc_insertion_point(class_scope:google.cloud.vision.v1.CropHintsParams) + )) +_sym_db.RegisterMessage(CropHintsParams) + +ImageContext = _reflection.GeneratedProtocolMessageType('ImageContext', (_message.Message,), dict( + DESCRIPTOR = _IMAGECONTEXT, + __module__ = 'google.cloud.proto.vision.v1.image_annotator_pb2' + , + __doc__ = """Image context and/or feature-specific parameters. + + + Attributes: + lat_long_rect: + lat/long rectangle that specifies the location of the image. + language_hints: + List of languages to use for TEXT\_DETECTION. In most cases, + an empty value yields the best results since it enables + automatic language detection. For languages based on the Latin + alphabet, setting ``language_hints`` is not needed. In rare + cases, when the language of the text in the image is known, + setting a hint will help get better results (although it will + be a significant hindrance if the hint is wrong). Text + detection returns an error if one or more of the specified + languages is not one of the `supported languages + `__. + crop_hints_params: + Parameters for crop hints annotation request. + """, + # @@protoc_insertion_point(class_scope:google.cloud.vision.v1.ImageContext) + )) +_sym_db.RegisterMessage(ImageContext) + +AnnotateImageRequest = _reflection.GeneratedProtocolMessageType('AnnotateImageRequest', (_message.Message,), dict( + DESCRIPTOR = _ANNOTATEIMAGEREQUEST, + __module__ = 'google.cloud.proto.vision.v1.image_annotator_pb2' + , + __doc__ = """Request for performing Google Cloud Vision API tasks over a + user-provided image, with user-requested features. + + + Attributes: + image: + The image to be processed. + features: + Requested features. + image_context: + Additional context that may accompany the image. + """, + # @@protoc_insertion_point(class_scope:google.cloud.vision.v1.AnnotateImageRequest) + )) +_sym_db.RegisterMessage(AnnotateImageRequest) + +AnnotateImageResponse = _reflection.GeneratedProtocolMessageType('AnnotateImageResponse', (_message.Message,), dict( + DESCRIPTOR = _ANNOTATEIMAGERESPONSE, + __module__ = 'google.cloud.proto.vision.v1.image_annotator_pb2' + , + __doc__ = """Response to an image annotation request. + + + Attributes: + face_annotations: + If present, face detection has completed successfully. + landmark_annotations: + If present, landmark detection has completed successfully. + logo_annotations: + If present, logo detection has completed successfully. + label_annotations: + If present, label detection has completed successfully. + text_annotations: + If present, text (OCR) detection or document (OCR) text + detection has completed successfully. + full_text_annotation: + If present, text (OCR) detection or document (OCR) text + detection has completed successfully. This annotation provides + the structural hierarchy for the OCR detected text. + safe_search_annotation: + If present, safe-search annotation has completed successfully. + image_properties_annotation: + If present, image properties were extracted successfully. + crop_hints_annotation: + If present, crop hints have completed successfully. + web_detection: + If present, web detection has completed successfully. + error: + If set, represents the error message for the operation. Note + that filled-in image annotations are guaranteed to be correct, + even when ``error`` is set. + """, + # @@protoc_insertion_point(class_scope:google.cloud.vision.v1.AnnotateImageResponse) + )) +_sym_db.RegisterMessage(AnnotateImageResponse) + +BatchAnnotateImagesRequest = _reflection.GeneratedProtocolMessageType('BatchAnnotateImagesRequest', (_message.Message,), dict( + DESCRIPTOR = _BATCHANNOTATEIMAGESREQUEST, + __module__ = 'google.cloud.proto.vision.v1.image_annotator_pb2' + , + __doc__ = """Multiple image annotation requests are batched into a single service + call. + + + Attributes: + requests: + Individual image annotation requests for this batch. + """, + # @@protoc_insertion_point(class_scope:google.cloud.vision.v1.BatchAnnotateImagesRequest) + )) +_sym_db.RegisterMessage(BatchAnnotateImagesRequest) + +BatchAnnotateImagesResponse = _reflection.GeneratedProtocolMessageType('BatchAnnotateImagesResponse', (_message.Message,), dict( + DESCRIPTOR = _BATCHANNOTATEIMAGESRESPONSE, + __module__ = 'google.cloud.proto.vision.v1.image_annotator_pb2' + , + __doc__ = """Response to a batch image annotation request. + + + Attributes: + responses: + Individual responses to image annotation requests within the + batch. + """, + # @@protoc_insertion_point(class_scope:google.cloud.vision.v1.BatchAnnotateImagesResponse) + )) +_sym_db.RegisterMessage(BatchAnnotateImagesResponse) + + +DESCRIPTOR.has_options = True +DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('\n\032com.google.cloud.vision.v1B\023ImageAnnotatorProtoP\001Z=0.15.0.""" + """Service that performs Google Cloud Vision API detection tasks over client + images, such as face, landmark, logo, label, and text detection. The + ImageAnnotator service returns detected entities from the images. + """ + def BatchAnnotateImages(self, request, context): + """Run image detection and annotation for a batch of images. + """ + context.code(beta_interfaces.StatusCode.UNIMPLEMENTED) + + + class BetaImageAnnotatorStub(object): + """The Beta API is deprecated for 0.15.0 and later. + + It is recommended to use the GA API (classes and functions in this + file not marked beta) for all further purposes. This class was generated + only to ease transition from grpcio<0.15.0 to grpcio>=0.15.0.""" + """Service that performs Google Cloud Vision API detection tasks over client + images, such as face, landmark, logo, label, and text detection. The + ImageAnnotator service returns detected entities from the images. + """ + def BatchAnnotateImages(self, request, timeout, metadata=None, with_call=False, protocol_options=None): + """Run image detection and annotation for a batch of images. + """ + raise NotImplementedError() + BatchAnnotateImages.future = None + + + def beta_create_ImageAnnotator_server(servicer, pool=None, pool_size=None, default_timeout=None, maximum_timeout=None): + """The Beta API is deprecated for 0.15.0 and later. + + It is recommended to use the GA API (classes and functions in this + file not marked beta) for all further purposes. This function was + generated only to ease transition from grpcio<0.15.0 to grpcio>=0.15.0""" + request_deserializers = { + ('google.cloud.vision.v1.ImageAnnotator', 'BatchAnnotateImages'): BatchAnnotateImagesRequest.FromString, + } + response_serializers = { + ('google.cloud.vision.v1.ImageAnnotator', 'BatchAnnotateImages'): BatchAnnotateImagesResponse.SerializeToString, + } + method_implementations = { + ('google.cloud.vision.v1.ImageAnnotator', 'BatchAnnotateImages'): face_utilities.unary_unary_inline(servicer.BatchAnnotateImages), + } + server_options = beta_implementations.server_options(request_deserializers=request_deserializers, response_serializers=response_serializers, thread_pool=pool, thread_pool_size=pool_size, default_timeout=default_timeout, maximum_timeout=maximum_timeout) + return beta_implementations.server(method_implementations, options=server_options) + + + def beta_create_ImageAnnotator_stub(channel, host=None, metadata_transformer=None, pool=None, pool_size=None): + """The Beta API is deprecated for 0.15.0 and later. + + It is recommended to use the GA API (classes and functions in this + file not marked beta) for all further purposes. This function was + generated only to ease transition from grpcio<0.15.0 to grpcio>=0.15.0""" + request_serializers = { + ('google.cloud.vision.v1.ImageAnnotator', 'BatchAnnotateImages'): BatchAnnotateImagesRequest.SerializeToString, + } + response_deserializers = { + ('google.cloud.vision.v1.ImageAnnotator', 'BatchAnnotateImages'): BatchAnnotateImagesResponse.FromString, + } + cardinalities = { + 'BatchAnnotateImages': cardinality.Cardinality.UNARY_UNARY, + } + stub_options = beta_implementations.stub_options(host=host, metadata_transformer=metadata_transformer, request_serializers=request_serializers, response_deserializers=response_deserializers, thread_pool=pool, thread_pool_size=pool_size) + return beta_implementations.dynamic_stub(channel, 'google.cloud.vision.v1.ImageAnnotator', cardinalities, options=stub_options) +except ImportError: + pass +# @@protoc_insertion_point(module_scope) diff --git a/vision/google/cloud/proto/vision/v1/image_annotator_pb2_grpc.py b/vision/google/cloud/proto/vision/v1/image_annotator_pb2_grpc.py new file mode 100644 index 0000000000000..e9e49175d4d35 --- /dev/null +++ b/vision/google/cloud/proto/vision/v1/image_annotator_pb2_grpc.py @@ -0,0 +1,50 @@ +# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! +import grpc + +import google.cloud.proto.vision.v1.image_annotator_pb2 as google_dot_cloud_dot_proto_dot_vision_dot_v1_dot_image__annotator__pb2 + + +class ImageAnnotatorStub(object): + """Service that performs Google Cloud Vision API detection tasks over client + images, such as face, landmark, logo, label, and text detection. The + ImageAnnotator service returns detected entities from the images. + """ + + def __init__(self, channel): + """Constructor. + + Args: + channel: A grpc.Channel. + """ + self.BatchAnnotateImages = channel.unary_unary( + '/google.cloud.vision.v1.ImageAnnotator/BatchAnnotateImages', + request_serializer=google_dot_cloud_dot_proto_dot_vision_dot_v1_dot_image__annotator__pb2.BatchAnnotateImagesRequest.SerializeToString, + response_deserializer=google_dot_cloud_dot_proto_dot_vision_dot_v1_dot_image__annotator__pb2.BatchAnnotateImagesResponse.FromString, + ) + + +class ImageAnnotatorServicer(object): + """Service that performs Google Cloud Vision API detection tasks over client + images, such as face, landmark, logo, label, and text detection. The + ImageAnnotator service returns detected entities from the images. + """ + + def BatchAnnotateImages(self, request, context): + """Run image detection and annotation for a batch of images. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + +def add_ImageAnnotatorServicer_to_server(servicer, server): + rpc_method_handlers = { + 'BatchAnnotateImages': grpc.unary_unary_rpc_method_handler( + servicer.BatchAnnotateImages, + request_deserializer=google_dot_cloud_dot_proto_dot_vision_dot_v1_dot_image__annotator__pb2.BatchAnnotateImagesRequest.FromString, + response_serializer=google_dot_cloud_dot_proto_dot_vision_dot_v1_dot_image__annotator__pb2.BatchAnnotateImagesResponse.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + 'google.cloud.vision.v1.ImageAnnotator', rpc_method_handlers) + server.add_generic_rpc_handlers((generic_handler,)) diff --git a/vision/google/cloud/proto/vision/v1/text_annotation_pb2.py b/vision/google/cloud/proto/vision/v1/text_annotation_pb2.py new file mode 100644 index 0000000000000..923a2bc3e0cfd --- /dev/null +++ b/vision/google/cloud/proto/vision/v1/text_annotation_pb2.py @@ -0,0 +1,742 @@ +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: google/cloud/proto/vision/v1/text_annotation.proto + +import sys +_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) +from google.protobuf import descriptor as _descriptor +from google.protobuf import message as _message +from google.protobuf import reflection as _reflection +from google.protobuf import symbol_database as _symbol_database +from google.protobuf import descriptor_pb2 +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + +from google.api import annotations_pb2 as google_dot_api_dot_annotations__pb2 +from google.cloud.proto.vision.v1 import geometry_pb2 as google_dot_cloud_dot_proto_dot_vision_dot_v1_dot_geometry__pb2 + + +DESCRIPTOR = _descriptor.FileDescriptor( + name='google/cloud/proto/vision/v1/text_annotation.proto', + package='google.cloud.vision.v1', + syntax='proto3', + serialized_pb=_b('\n2google/cloud/proto/vision/v1/text_annotation.proto\x12\x16google.cloud.vision.v1\x1a\x1cgoogle/api/annotations.proto\x1a+google/cloud/proto/vision/v1/geometry.proto\"\x96\x04\n\x0eTextAnnotation\x12+\n\x05pages\x18\x01 \x03(\x0b\x32\x1c.google.cloud.vision.v1.Page\x12\x0c\n\x04text\x18\x02 \x01(\t\x1a=\n\x10\x44\x65tectedLanguage\x12\x15\n\rlanguage_code\x18\x01 \x01(\t\x12\x12\n\nconfidence\x18\x02 \x01(\x02\x1a\xd5\x01\n\rDetectedBreak\x12L\n\x04type\x18\x01 \x01(\x0e\x32>.google.cloud.vision.v1.TextAnnotation.DetectedBreak.BreakType\x12\x11\n\tis_prefix\x18\x02 \x01(\x08\"c\n\tBreakType\x12\x0b\n\x07UNKNOWN\x10\x00\x12\t\n\x05SPACE\x10\x01\x12\x0e\n\nSURE_SPACE\x10\x02\x12\x12\n\x0e\x45OL_SURE_SPACE\x10\x03\x12\n\n\x06HYPHEN\x10\x04\x12\x0e\n\nLINE_BREAK\x10\x05\x1a\xb1\x01\n\x0cTextProperty\x12S\n\x12\x64\x65tected_languages\x18\x01 \x03(\x0b\x32\x37.google.cloud.vision.v1.TextAnnotation.DetectedLanguage\x12L\n\x0e\x64\x65tected_break\x18\x02 \x01(\x0b\x32\x34.google.cloud.vision.v1.TextAnnotation.DetectedBreak\"\x9b\x01\n\x04Page\x12\x45\n\x08property\x18\x01 \x01(\x0b\x32\x33.google.cloud.vision.v1.TextAnnotation.TextProperty\x12\r\n\x05width\x18\x02 \x01(\x05\x12\x0e\n\x06height\x18\x03 \x01(\x05\x12-\n\x06\x62locks\x18\x04 \x03(\x0b\x32\x1d.google.cloud.vision.v1.Block\"\xd2\x02\n\x05\x42lock\x12\x45\n\x08property\x18\x01 \x01(\x0b\x32\x33.google.cloud.vision.v1.TextAnnotation.TextProperty\x12:\n\x0c\x62ounding_box\x18\x02 \x01(\x0b\x32$.google.cloud.vision.v1.BoundingPoly\x12\x35\n\nparagraphs\x18\x03 \x03(\x0b\x32!.google.cloud.vision.v1.Paragraph\x12;\n\nblock_type\x18\x04 \x01(\x0e\x32\'.google.cloud.vision.v1.Block.BlockType\"R\n\tBlockType\x12\x0b\n\x07UNKNOWN\x10\x00\x12\x08\n\x04TEXT\x10\x01\x12\t\n\x05TABLE\x10\x02\x12\x0b\n\x07PICTURE\x10\x03\x12\t\n\x05RULER\x10\x04\x12\x0b\n\x07\x42\x41RCODE\x10\x05\"\xbb\x01\n\tParagraph\x12\x45\n\x08property\x18\x01 \x01(\x0b\x32\x33.google.cloud.vision.v1.TextAnnotation.TextProperty\x12:\n\x0c\x62ounding_box\x18\x02 \x01(\x0b\x32$.google.cloud.vision.v1.BoundingPoly\x12+\n\x05words\x18\x03 \x03(\x0b\x32\x1c.google.cloud.vision.v1.Word\"\xba\x01\n\x04Word\x12\x45\n\x08property\x18\x01 \x01(\x0b\x32\x33.google.cloud.vision.v1.TextAnnotation.TextProperty\x12:\n\x0c\x62ounding_box\x18\x02 \x01(\x0b\x32$.google.cloud.vision.v1.BoundingPoly\x12/\n\x07symbols\x18\x03 \x03(\x0b\x32\x1e.google.cloud.vision.v1.Symbol\"\x99\x01\n\x06Symbol\x12\x45\n\x08property\x18\x01 \x01(\x0b\x32\x33.google.cloud.vision.v1.TextAnnotation.TextProperty\x12:\n\x0c\x62ounding_box\x18\x02 \x01(\x0b\x32$.google.cloud.vision.v1.BoundingPoly\x12\x0c\n\x04text\x18\x03 \x01(\tBt\n\x1a\x63om.google.cloud.vision.v1B\x13TextAnnotationProtoP\x01Z Page -> Block -> Paragraph -> Word -> Symbol Each + structural component, starting from Page, may further have their own + properties. Properties describe detected languages, breaks etc.. Please + refer to the + [google.cloud.vision.v1.TextAnnotation.TextProperty][google.cloud.vision.v1.TextAnnotation.TextProperty] + message definition below for more detail. + + + Attributes: + language_code: + The BCP-47 language code, such as "en-US" or "sr-Latn". For + more information, see http://www.unicode.org/reports/tr35/#Uni + code\_locale\_identifier. + confidence: + Confidence of detected language. Range [0, 1]. + is_prefix: + True if break prepends the element. + detected_languages: + A list of detected languages together with confidence. + detected_break: + Detected start or end of a text segment. + pages: + List of pages detected by OCR. + text: + UTF-8 text detected on the pages. + """, + # @@protoc_insertion_point(class_scope:google.cloud.vision.v1.TextAnnotation) + )) +_sym_db.RegisterMessage(TextAnnotation) +_sym_db.RegisterMessage(TextAnnotation.DetectedLanguage) +_sym_db.RegisterMessage(TextAnnotation.DetectedBreak) +_sym_db.RegisterMessage(TextAnnotation.TextProperty) + +Page = _reflection.GeneratedProtocolMessageType('Page', (_message.Message,), dict( + DESCRIPTOR = _PAGE, + __module__ = 'google.cloud.proto.vision.v1.text_annotation_pb2' + , + __doc__ = """Detected page from OCR. + + + Attributes: + property: + Additional information detected on the page. + width: + Page width in pixels. + height: + Page height in pixels. + blocks: + List of blocks of text, images etc on this page. + """, + # @@protoc_insertion_point(class_scope:google.cloud.vision.v1.Page) + )) +_sym_db.RegisterMessage(Page) + +Block = _reflection.GeneratedProtocolMessageType('Block', (_message.Message,), dict( + DESCRIPTOR = _BLOCK, + __module__ = 'google.cloud.proto.vision.v1.text_annotation_pb2' + , + __doc__ = """Logical element on the page. + + + Attributes: + property: + Additional information detected for the block. + bounding_box: + The bounding box for the block. The vertices are in the order + of top-left, top-right, bottom-right, bottom-left. When a + rotation of the bounding box is detected the rotation is + represented as around the top-left corner as defined when the + text is read in the 'natural' orientation. For example: \* + when the text is horizontal it might look like: 0----1 \| \| 3 + ----2 \* when it's rotated 180 degrees around the top-left + corner it becomes: 2----3 \| \| 1----0 and the vertice order + will still be (0, 1, 2, 3). + paragraphs: + List of paragraphs in this block (if this blocks is of type + text). + block_type: + Detected block type (text, image etc) for this block. + """, + # @@protoc_insertion_point(class_scope:google.cloud.vision.v1.Block) + )) +_sym_db.RegisterMessage(Block) + +Paragraph = _reflection.GeneratedProtocolMessageType('Paragraph', (_message.Message,), dict( + DESCRIPTOR = _PARAGRAPH, + __module__ = 'google.cloud.proto.vision.v1.text_annotation_pb2' + , + __doc__ = """Structural unit of text representing a number of words in certain order. + + + Attributes: + property: + Additional information detected for the paragraph. + bounding_box: + The bounding box for the paragraph. The vertices are in the + order of top-left, top-right, bottom-right, bottom-left. When + a rotation of the bounding box is detected the rotation is + represented as around the top-left corner as defined when the + text is read in the 'natural' orientation. For example: \* + when the text is horizontal it might look like: 0----1 \| \| 3 + ----2 \* when it's rotated 180 degrees around the top-left + corner it becomes: 2----3 \| \| 1----0 and the vertice order + will still be (0, 1, 2, 3). + words: + List of words in this paragraph. + """, + # @@protoc_insertion_point(class_scope:google.cloud.vision.v1.Paragraph) + )) +_sym_db.RegisterMessage(Paragraph) + +Word = _reflection.GeneratedProtocolMessageType('Word', (_message.Message,), dict( + DESCRIPTOR = _WORD, + __module__ = 'google.cloud.proto.vision.v1.text_annotation_pb2' + , + __doc__ = """A word representation. + + + Attributes: + property: + Additional information detected for the word. + bounding_box: + The bounding box for the word. The vertices are in the order + of top-left, top-right, bottom-right, bottom-left. When a + rotation of the bounding box is detected the rotation is + represented as around the top-left corner as defined when the + text is read in the 'natural' orientation. For example: \* + when the text is horizontal it might look like: 0----1 \| \| 3 + ----2 \* when it's rotated 180 degrees around the top-left + corner it becomes: 2----3 \| \| 1----0 and the vertice order + will still be (0, 1, 2, 3). + symbols: + List of symbols in the word. The order of the symbols follows + the natural reading order. + """, + # @@protoc_insertion_point(class_scope:google.cloud.vision.v1.Word) + )) +_sym_db.RegisterMessage(Word) + +Symbol = _reflection.GeneratedProtocolMessageType('Symbol', (_message.Message,), dict( + DESCRIPTOR = _SYMBOL, + __module__ = 'google.cloud.proto.vision.v1.text_annotation_pb2' + , + __doc__ = """A single symbol representation. + + + Attributes: + property: + Additional information detected for the symbol. + bounding_box: + The bounding box for the symbol. The vertices are in the order + of top-left, top-right, bottom-right, bottom-left. When a + rotation of the bounding box is detected the rotation is + represented as around the top-left corner as defined when the + text is read in the 'natural' orientation. For example: \* + when the text is horizontal it might look like: 0----1 \| \| 3 + ----2 \* when it's rotated 180 degrees around the top-left + corner it becomes: 2----3 \| \| 1----0 and the vertice order + will still be (0, 1, 2, 3). + text: + The actual UTF-8 representation of the symbol. + """, + # @@protoc_insertion_point(class_scope:google.cloud.vision.v1.Symbol) + )) +_sym_db.RegisterMessage(Symbol) + + +DESCRIPTOR.has_options = True +DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('\n\032com.google.cloud.vision.v1B\023TextAnnotationProtoP\001Z>> from google.cloud.vision_v1 import ImageAnnotatorClient + >>> client = ImageAnnotatorClient() + >>> request = { + ... 'image': { + ... 'source': {'image_uri': 'https://foo.com/image.jpg'}, + ... }, + ... } + >>> response = client.annotate_image(request) + + Args: + request (:class:`~.vision_v1.types.AnnotateImageRequest`) + options (:class:`google.gax.CallOptions`): Overrides the default + settings for this call, e.g, timeout, retries, etc. + + Returns: + :class:`~.vision_v1.types.AnnotateImageResponse` The API response. + """ + # If the image is a file handler, set the content. + image = protobuf.get(request, 'image') + if hasattr(image, 'read'): + img_bytes = image.read() + protobuf.set(request, 'image', {}) + protobuf.set(request, 'image.content', img_bytes) + image = protobuf.get(request, 'image') + + # If a filename is provided, read the file. + filename = protobuf.get(image, 'source.filename', default=None) + if filename: + with io.open(filename, 'rb') as img_file: + protobuf.set(request, 'image.content', img_file.read()) + protobuf.set(request, 'image.source', None) + + # This method allows features not to be specified, and you get all + # of them. + protobuf.setdefault(request, 'features', self._get_all_features()) + r = self.batch_annotate_images([request], options=options) + return r.responses[0] + + def _get_all_features(self): + """Return a list of all features. + + Returns: + list: A list of all available features. + """ + answer = [] + for key, value in self.enums.Feature.Type.__dict__.items(): + if key.upper() != key: + continue + if not isinstance(value, int) or value == 0: + continue + answer.append({'type': value}) + return answer diff --git a/vision/google/cloud/vision/image.py b/vision/google/cloud/vision/image.py index f96103d6fcdd7..efcf1dcddc16e 100644 --- a/vision/google/cloud/vision/image.py +++ b/vision/google/cloud/vision/image.py @@ -186,7 +186,7 @@ def detect_full_text(self, language_hints=None, limit=10): """Detect a full document's text. :type language_hints: list - :param language_hints: (Optional) A list of BCP-47 language codes. See: + :param language_hints: (Optional) A list of BCP-47 language codes. See https://cloud.google.com/vision/docs/languages :type limit: int diff --git a/vision/google/cloud/vision/likelihood.py b/vision/google/cloud/vision/likelihood.py index 6fffc66407393..d98033ecdcbd5 100644 --- a/vision/google/cloud/vision/likelihood.py +++ b/vision/google/cloud/vision/likelihood.py @@ -36,7 +36,7 @@ def _get_pb_likelihood(likelihood): class Likelihood(Enum): """A representation of likelihood to give stable results across upgrades. - See: + See https://cloud.google.com/vision/docs/reference/rest/v1/images/annotate#likelihood """ UNKNOWN = 'UNKNOWN' diff --git a/vision/google/cloud/vision_v1/__init__.py b/vision/google/cloud/vision_v1/__init__.py new file mode 100644 index 0000000000000..8dbabb4707240 --- /dev/null +++ b/vision/google/cloud/vision_v1/__init__.py @@ -0,0 +1,35 @@ +# Copyright 2017, Google Inc. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import absolute_import + +from google.cloud.gapic.vision.v1 import image_annotator_client as iac +from google.cloud.gapic.vision.v1 import enums + +from google.cloud.vision.decorators import add_single_feature_methods +from google.cloud.vision.helpers import VisionHelpers +from google.cloud.vision_v1 import types + + +@add_single_feature_methods +class ImageAnnotatorClient(VisionHelpers, iac.ImageAnnotatorClient): + __doc__ = iac.ImageAnnotatorClient.__doc__ + enums = enums + + +__all__ = ( + 'enums', + 'ImageAnnotatorClient', + 'types', +) diff --git a/vision/google/cloud/vision_v1/types.py b/vision/google/cloud/vision_v1/types.py new file mode 100644 index 0000000000000..b061a06b80be2 --- /dev/null +++ b/vision/google/cloud/vision_v1/types.py @@ -0,0 +1,35 @@ +# Copyright 2017, Google Inc. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import absolute_import +import sys + +from google.cloud.proto.vision.v1 import geometry_pb2 +from google.cloud.proto.vision.v1 import image_annotator_pb2 +from google.cloud.proto.vision.v1 import text_annotation_pb2 +from google.cloud.proto.vision.v1 import web_detection_pb2 + +from google.gax.utils.messages import get_messages + + +names = [] +for module in (geometry_pb2, image_annotator_pb2, + text_annotation_pb2, web_detection_pb2): + for name, message in get_messages(module).items(): + message.__module__ = 'google.cloud.vision_v1.types' + setattr(sys.modules[__name__], name, message) + names.append(name) + + +__all__ = tuple(sorted(names)) diff --git a/vision/nox.py b/vision/nox.py index 0008296bdbe37..984adfe7db007 100644 --- a/vision/nox.py +++ b/vision/nox.py @@ -19,9 +19,6 @@ import nox -LOCAL_DEPS = ('../core/',) - - @nox.session @nox.parametrize('python_version', ['2.7', '3.4', '3.5', '3.6']) def unit_tests(session, python_version): @@ -31,14 +28,14 @@ def unit_tests(session, python_version): session.interpreter = 'python{}'.format(python_version) # Install all test dependencies, then install this package in-place. - session.install('mock', 'pytest', 'pytest-cov', *LOCAL_DEPS) + session.install('mock', 'pytest', 'pytest-cov', '../core/') session.install('-e', '.') # Run py.test against the unit tests. session.run('py.test', '--quiet', - '--cov=google.cloud.vision', '--cov=tests.unit', '--cov-append', - '--cov-config=.coveragerc', '--cov-report=', '--cov-fail-under=97', - 'tests/unit', + '--cov=google.cloud.vision', '--cov=google.cloud.vision_v1', + '--cov-append', '--cov-config=.coveragerc', '--cov-report=', + 'tests/', ) @@ -51,19 +48,39 @@ def system_tests(session, python_version): if not os.environ.get('GOOGLE_APPLICATION_CREDENTIALS', ''): return - # Run the system tests against latest Python 2 and Python 3 only. + # Run unit tests against all supported versions of Python. session.interpreter = 'python{}'.format(python_version) - # Install all test dependencies, then install this package into the - # virutalenv's dist-packages. - session.install('mock', 'pytest', *LOCAL_DEPS) - session.install('../test_utils/', '../storage/') - session.install('.') + # Install all test dependencies, then install this package in-place. + session.install('pytest', '../core/', '../storage/') + session.install('../test_utils/') + session.install('-e', '.') - # Run py.test against the system tests. + # Run py.test against the unit tests. session.run('py.test', '--quiet', 'tests/system.py') +@nox.session +@nox.parametrize('python_version', ['2.7', '3.6']) +def system_tests_manual_layer(session, python_version): + """Run the system test suite for the old manual layer.""" + + # Sanity check: Only run system tests if the environment variable is set. + if not os.environ.get('GOOGLE_APPLICATION_CREDENTIALS', ''): + return + + # Run unit tests against all supported versions of Python. + session.interpreter = 'python{}'.format(python_version) + + # Install all test dependencies, then install this package in-place. + session.install('pytest', '../core/', '../storage/') + session.install('../test_utils/') + session.install('-e', '.') + + # Run py.test against the unit tests. + session.run('py.test', '--quiet', 'tests/system_old.py') + + @nox.session def lint(session): """Run flake8. @@ -72,16 +89,16 @@ def lint(session): serious code quality issues. """ session.interpreter = 'python3.6' - session.install('flake8', *LOCAL_DEPS) + session.install('flake8') session.install('.') - session.run('flake8', 'google/cloud/vision') + session.run('flake8', 'google/cloud/vision.py') @nox.session def lint_setup_py(session): """Verify that setup.py is valid (including RST check).""" session.interpreter = 'python3.6' - session.install('docutils', 'Pygments') + session.install('docutils', 'pygments') session.run( 'python', 'setup.py', 'check', '--restructuredtext', '--strict') @@ -96,5 +113,5 @@ def cover(session): session.interpreter = 'python3.6' session.chdir(os.path.dirname(__file__)) session.install('coverage', 'pytest-cov') - session.run('coverage', 'report', '--show-missing', '--fail-under=100') + session.run('coverage', 'report', '--show-missing') session.run('coverage', 'erase') diff --git a/vision/setup.py b/vision/setup.py index 6f007504fead0..3494535bddd70 100644 --- a/vision/setup.py +++ b/vision/setup.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +import io import os from setuptools import find_packages @@ -20,35 +21,8 @@ PACKAGE_ROOT = os.path.abspath(os.path.dirname(__file__)) -with open(os.path.join(PACKAGE_ROOT, 'README.rst')) as file_obj: - README = file_obj.read() - -# NOTE: This is duplicated throughout and we should try to -# consolidate. -SETUP_BASE = { - 'author': 'Google Cloud Platform', - 'author_email': 'jjg+google-cloud-python@google.com', - 'scripts': [], - 'url': 'https://github.com/GoogleCloudPlatform/google-cloud-python', - 'license': 'Apache 2.0', - 'platforms': 'Posix; MacOS X; Windows', - 'include_package_data': True, - 'zip_safe': False, - 'classifiers': [ - 'Development Status :: 4 - Beta', - 'Intended Audience :: Developers', - 'License :: OSI Approved :: Apache Software License', - 'Operating System :: OS Independent', - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.4', - 'Programming Language :: Python :: 3.5', - 'Programming Language :: Python :: 3.6', - 'Topic :: Internet', - ], -} - +with io.open(os.path.join(PACKAGE_ROOT, 'README.rst'), 'r') as readme_file: + readme = readme_file.read() REQUIREMENTS = [ 'google-cloud-core >= 0.24.0, < 0.25dev', @@ -59,16 +33,40 @@ } setup( + author='Google Cloud Platform', + author_email='googleapis-packages@google.com', name='google-cloud-vision', - version='0.24.0', + version='0.25.0', description='Python Client for Google Cloud Vision', - long_description=README, + long_description=readme, namespace_packages=[ 'google', 'google.cloud', + 'google.cloud.gapic', + 'google.cloud.gapic.vision', + 'google.cloud.proto', + 'google.cloud.proto.vision', ], packages=find_packages(exclude=('tests*',)), install_requires=REQUIREMENTS, extras_require=EXTRAS_REQUIRE, - **SETUP_BASE + url='https://github.com/GoogleCloudPlatform/google-cloud-python', + license='Apache 2.0', + platforms='Posix; MacOS X; Windows', + include_package_data=True, + zip_safe=False, + scripts=[], + classifiers=[ + 'Development Status :: 4 - Beta', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: Apache Software License', + 'Operating System :: OS Independent', + 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', + 'Topic :: Internet', + ], ) diff --git a/vision/tests/gapic/v1/test_image_annotator_client_v1.py b/vision/tests/gapic/v1/test_image_annotator_client_v1.py new file mode 100644 index 0000000000000..038a3c725f5a3 --- /dev/null +++ b/vision/tests/gapic/v1/test_image_annotator_client_v1.py @@ -0,0 +1,75 @@ +# Copyright 2017, Google Inc. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Unit tests.""" + +import mock +import unittest + +from google.gax import errors + +from google.cloud.gapic.vision.v1 import image_annotator_client +from google.cloud.proto.vision.v1 import image_annotator_pb2 + + +class CustomException(Exception): + pass + + +class TestImageAnnotatorClient(unittest.TestCase): + @mock.patch('google.gax.config.create_stub', spec=True) + def test_batch_annotate_images(self, mock_create_stub): + # Mock gRPC layer + grpc_stub = mock.Mock() + mock_create_stub.return_value = grpc_stub + + client = image_annotator_client.ImageAnnotatorClient() + + # Mock request + requests = [] + + # Mock response + expected_response = image_annotator_pb2.BatchAnnotateImagesResponse() + grpc_stub.BatchAnnotateImages.return_value = expected_response + + response = client.batch_annotate_images(requests) + self.assertEqual(expected_response, response) + + grpc_stub.BatchAnnotateImages.assert_called_once() + args, kwargs = grpc_stub.BatchAnnotateImages.call_args + self.assertEqual(len(args), 2) + self.assertEqual(len(kwargs), 1) + self.assertIn('metadata', kwargs) + actual_request = args[0] + + expected_request = image_annotator_pb2.BatchAnnotateImagesRequest( + requests=requests) + self.assertEqual(expected_request, actual_request) + + @mock.patch('google.gax.config.API_ERRORS', (CustomException, )) + @mock.patch('google.gax.config.create_stub', spec=True) + def test_batch_annotate_images_exception(self, mock_create_stub): + # Mock gRPC layer + grpc_stub = mock.Mock() + mock_create_stub.return_value = grpc_stub + + client = image_annotator_client.ImageAnnotatorClient() + + # Mock request + requests = [] + + # Mock exception response + grpc_stub.BatchAnnotateImages.side_effect = CustomException() + + self.assertRaises(errors.GaxError, client.batch_annotate_images, + requests) diff --git a/vision/tests/system.py b/vision/tests/system.py index 65d5909374bc9..0d39df8bb88cc 100644 --- a/vision/tests/system.py +++ b/vision/tests/system.py @@ -1,4 +1,4 @@ -# Copyright 2016 Google Inc. +# Copyright 2017, Google Inc. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -15,6 +15,7 @@ """System tests for Vision API.""" import functools +import io import os import unittest @@ -23,9 +24,6 @@ from google.cloud import exceptions from google.cloud import storage from google.cloud import vision -from google.cloud.vision.entity import EntityAnnotation -from google.cloud.vision.feature import Feature -from google.cloud.vision.feature import FeatureTypes from test_utils.retry import RetryErrors from test_utils.retry import RetryResult @@ -41,757 +39,88 @@ FULL_TEXT_FILE = os.path.join(_SYS_TESTS_DIR, 'data', 'full-text.jpg') -class Config(object): - CLIENT = None - TEST_BUCKET = None +class VisionSystemTestBase(unittest.TestCase): + client = None + test_bucket = None + + def setUp(self): + self.to_delete_by_case = [] + + def tearDown(self): + for value in self.to_delete_by_case: + value.delete() def setUpModule(): - Config.CLIENT = vision.Client() + VisionSystemTestBase.client = vision.ImageAnnotatorClient() storage_client = storage.Client() bucket_name = 'new' + unique_resource_id() - Config.TEST_BUCKET = storage_client.bucket(bucket_name) + VisionSystemTestBase.test_bucket = storage_client.bucket(bucket_name) + # 429 Too Many Requests in case API requests rate-limited. retry_429 = RetryErrors(exceptions.TooManyRequests) - retry_429(Config.TEST_BUCKET.create)() + retry_429(VisionSystemTestBase.test_bucket.create)() def tearDownModule(): # 409 Conflict if the bucket is full. # 429 Too Many Requests in case API requests rate-limited. bucket_retry = RetryErrors( - (exceptions.TooManyRequests, exceptions.Conflict)) - bucket_retry(Config.TEST_BUCKET.delete)(force=True) - - -class BaseVisionTestCase(unittest.TestCase): - def _assert_coordinate(self, coordinate): - if coordinate is None: - return - self.assertIsNotNone(coordinate) - self.assertIsInstance(coordinate, (int, float)) - - def _assert_likelihood(self, likelihood): - from google.cloud.vision.likelihood import Likelihood - - levels = [Likelihood.UNKNOWN, Likelihood.VERY_LIKELY, - Likelihood.UNLIKELY, Likelihood.POSSIBLE, Likelihood.LIKELY, - Likelihood.VERY_UNLIKELY] - self.assertIn(likelihood, levels) - - def _pb_not_implemented_skip(self, message): - if Config.CLIENT._use_grpc: - self.skipTest(message) - - -class TestVisionFullText(unittest.TestCase): - def setUp(self): - self.to_delete_by_case = [] - - def tearDown(self): - for value in self.to_delete_by_case: - value.delete() - - def _assert_full_text(self, full_text): - from google.cloud.vision.text import TextAnnotation - - self.assertIsInstance(full_text, TextAnnotation) - self.assertIsInstance(full_text.text, six.text_type) - self.assertEqual(len(full_text.pages), 1) - self.assertIsInstance(full_text.pages[0].width, int) - self.assertIsInstance(full_text.pages[0].height, int) - - def test_detect_full_text_content(self): - client = Config.CLIENT - with open(FULL_TEXT_FILE, 'rb') as image_file: - image = client.image(content=image_file.read()) - full_text = image.detect_full_text(language_hints=['en']) - self._assert_full_text(full_text) - - def test_detect_full_text_filename(self): - client = Config.CLIENT - image = client.image(filename=FULL_TEXT_FILE) - full_text = image.detect_full_text(language_hints=['en']) - self._assert_full_text(full_text) - - def test_detect_full_text_gcs(self): - bucket_name = Config.TEST_BUCKET.name - blob_name = 'full-text.jpg' - blob = Config.TEST_BUCKET.blob(blob_name) - self.to_delete_by_case.append(blob) # Clean-up. - with open(FULL_TEXT_FILE, 'rb') as file_obj: - blob.upload_from_file(file_obj) - - source_uri = 'gs://%s/%s' % (bucket_name, blob_name) - - client = Config.CLIENT - image = client.image(source_uri=source_uri) - full_text = image.detect_full_text(language_hints=['en']) - self._assert_full_text(full_text) - - -class TestVisionClientCropHint(BaseVisionTestCase): - def setUp(self): - self.to_delete_by_case = [] - - def tearDown(self): - for value in self.to_delete_by_case: - value.delete() - - def _assert_crop_hint(self, hint): - from google.cloud.vision.crop_hint import CropHint - from google.cloud.vision.geometry import Bounds - - self.assertIsInstance(hint, CropHint) - self.assertIsInstance(hint.bounds, Bounds) - self.assertGreater(len(hint.bounds.vertices), 1) - self.assertIsInstance(hint.confidence, (int, float)) - self.assertIsInstance(hint.importance_fraction, float) - - def test_detect_crop_hints_content(self): - client = Config.CLIENT - with open(FACE_FILE, 'rb') as image_file: - image = client.image(content=image_file.read()) - crop_hints = image.detect_crop_hints( - aspect_ratios=[1.3333, 1.7777], limit=2) - self.assertEqual(len(crop_hints), 2) - for hint in crop_hints: - self._assert_crop_hint(hint) - - def test_detect_crop_hints_filename(self): - client = Config.CLIENT - image = client.image(filename=FACE_FILE) - crop_hints = image.detect_crop_hints( - aspect_ratios=[1.3333, 1.7777], limit=2) - self.assertEqual(len(crop_hints), 2) - for hint in crop_hints: - self._assert_crop_hint(hint) - - def test_detect_crop_hints_gcs(self): - bucket_name = Config.TEST_BUCKET.name - blob_name = 'faces.jpg' - blob = Config.TEST_BUCKET.blob(blob_name) - self.to_delete_by_case.append(blob) # Clean-up. - with open(FACE_FILE, 'rb') as file_obj: - blob.upload_from_file(file_obj) + (exceptions.TooManyRequests, exceptions.Conflict), + ) + bucket_retry(VisionSystemTestBase.test_bucket.delete)(force=True) - source_uri = 'gs://%s/%s' % (bucket_name, blob_name) - client = Config.CLIENT - image = client.image(source_uri=source_uri) - crop_hints = image.detect_crop_hints( - aspect_ratios=[1.3333, 1.7777], limit=2) - self.assertEqual(len(crop_hints), 2) - for hint in crop_hints: - self._assert_crop_hint(hint) +class TestVisionClientLogo(VisionSystemTestBase): + def test_detect_logos_content(self): + # Read the file. + with io.open(LOGO_FILE, 'rb') as image_file: + content = image_file.read() -class TestVisionClientLogo(unittest.TestCase): - def setUp(self): - self.to_delete_by_case = [] + # Make the request. + response = self.client.logo_detection({ + 'content': content, + }) - def tearDown(self): - for value in self.to_delete_by_case: - value.delete() + # Check to ensure we got what we expect. + assert len(response.logo_annotations) == 1 + assert response.logo_annotations[0].description == 'Google' - def _assert_logo(self, logo): - self.assertIsInstance(logo, EntityAnnotation) - self.assertEqual(logo.description, 'Google') - self.assertEqual(len(logo.bounds.vertices), 4) - self.assertEqual(logo.bounds.vertices[0].x_coordinate, 40) - self.assertEqual(logo.bounds.vertices[0].y_coordinate, 40) - self.assertEqual(logo.bounds.vertices[1].x_coordinate, 959) - self.assertEqual(logo.bounds.vertices[1].y_coordinate, 40) - self.assertEqual(logo.bounds.vertices[2].x_coordinate, 959) - self.assertEqual(logo.bounds.vertices[2].y_coordinate, 302) - self.assertEqual(logo.bounds.vertices[3].x_coordinate, 40) - self.assertEqual(logo.bounds.vertices[3].y_coordinate, 302) - self.assertTrue(logo.score > 0.25) + def test_detect_logos_file_handler(self): + # Get a file handler, and make the request using it. + with io.open(LOGO_FILE, 'rb') as image_file: + response = self.client.logo_detection(image_file) - def test_detect_logos_content(self): - client = Config.CLIENT - with open(LOGO_FILE, 'rb') as image_file: - image = client.image(content=image_file.read()) - logos = image.detect_logos() - self.assertEqual(len(logos), 1) - logo = logos[0] - self._assert_logo(logo) + # Check to ensure we got what we expect. + assert len(response.logo_annotations) == 1 + assert response.logo_annotations[0].description == 'Google' def test_detect_logos_filename(self): - client = Config.CLIENT - image = client.image(filename=LOGO_FILE) - logos = image.detect_logos() - self.assertEqual(len(logos), 1) - logo = logos[0] - self._assert_logo(logo) + # Make the request with the filename directly. + response = self.client.logo_detection({ + 'source': {'filename': LOGO_FILE}, + }) + + # Check to ensure we got what we expect. + assert len(response.logo_annotations) == 1 + assert response.logo_annotations[0].description == 'Google' def test_detect_logos_gcs(self): - bucket_name = Config.TEST_BUCKET.name + # Upload the image to Google Cloud Storage. blob_name = 'logo.png' - blob = Config.TEST_BUCKET.blob(blob_name) - self.to_delete_by_case.append(blob) # Clean-up. - with open(LOGO_FILE, 'rb') as file_obj: - blob.upload_from_file(file_obj) - - source_uri = 'gs://%s/%s' % (bucket_name, blob_name) - - client = Config.CLIENT - image = client.image(source_uri=source_uri) - logos = image.detect_logos() - self.assertEqual(len(logos), 1) - logo = logos[0] - self._assert_logo(logo) - - -class TestVisionClientFace(BaseVisionTestCase): - def setUp(self): - self.to_delete_by_case = [] - - def tearDown(self): - for value in self.to_delete_by_case: - value.delete() - - def _assert_landmarks(self, landmarks): - from google.cloud.vision.face import Landmark - from google.cloud.vision.face import LandmarkTypes - from google.cloud.vision.face import Position - - for landmark in LandmarkTypes: - if landmark is not LandmarkTypes.UNKNOWN_LANDMARK: - feature = getattr(landmarks, landmark.name.lower()) - self.assertIsInstance(feature, Landmark) - self.assertIsInstance(feature.position, Position) - self._assert_coordinate(feature.position.x_coordinate) - self._assert_coordinate(feature.position.y_coordinate) - self._assert_coordinate(feature.position.z_coordinate) - - def _assert_face(self, face): - from google.cloud.vision.face import Bounds - from google.cloud.vision.face import FDBounds - from google.cloud.vision.face import Face - from google.cloud.vision.face import Landmarks - from google.cloud.vision.geometry import Vertex - - self.assertIsInstance(face, Face) - self.assertGreater(face.detection_confidence, 0.0) - self._assert_likelihood(face.anger) - self._assert_likelihood(face.joy) - self._assert_likelihood(face.sorrow) - self._assert_likelihood(face.surprise) - self._assert_likelihood(face.image_properties.blurred) - self._assert_likelihood(face.image_properties.underexposed) - self._assert_likelihood(face.headwear) - self.assertNotEqual(face.angles.roll, 0.0) - self.assertNotEqual(face.angles.pan, 0.0) - self.assertNotEqual(face.angles.tilt, 0.0) - - self.assertIsInstance(face.bounds, Bounds) - for vertex in face.bounds.vertices: - self.assertIsInstance(vertex, Vertex) - self._assert_coordinate(vertex.x_coordinate) - self._assert_coordinate(vertex.y_coordinate) - - self.assertIsInstance(face.fd_bounds, FDBounds) - for vertex in face.fd_bounds.vertices: - self.assertIsInstance(vertex, Vertex) - self._assert_coordinate(vertex.x_coordinate) - self._assert_coordinate(vertex.y_coordinate) - - self.assertIsInstance(face.landmarks, Landmarks) - self._assert_landmarks(face.landmarks) - - def test_detect_faces_content(self): - client = Config.CLIENT - with open(FACE_FILE, 'rb') as image_file: - image = client.image(content=image_file.read()) - faces = image.detect_faces() - self.assertEqual(len(faces), 5) - for face in faces: - self._assert_face(face) - - def test_detect_faces_gcs(self): - bucket_name = Config.TEST_BUCKET.name - blob_name = 'faces.jpg' - blob = Config.TEST_BUCKET.blob(blob_name) - self.to_delete_by_case.append(blob) # Clean-up. - with open(FACE_FILE, 'rb') as file_obj: - blob.upload_from_file(file_obj) - - source_uri = 'gs://%s/%s' % (bucket_name, blob_name) - client = Config.CLIENT - image = client.image(source_uri=source_uri) - faces = image.detect_faces() - self.assertEqual(len(faces), 5) - for face in faces: - self._assert_face(face) - - def test_detect_faces_filename(self): - client = Config.CLIENT - image = client.image(filename=FACE_FILE) - faces = image.detect_faces() - self.assertEqual(len(faces), 5) - for face in faces: - self._assert_face(face) - - -class TestVisionClientLabel(BaseVisionTestCase): - DESCRIPTIONS = ( - 'car', - 'vehicle', - 'land vehicle', - 'automotive design', - 'wheel', - 'automobile make', - 'luxury vehicle', - 'sports car', - 'performance car', - 'automotive exterior', - ) - - def setUp(self): - self.to_delete_by_case = [] - - def tearDown(self): - for value in self.to_delete_by_case: - value.delete() - - def _assert_label(self, label): - self.assertIsInstance(label, EntityAnnotation) - self.assertIn(label.description, self.DESCRIPTIONS) - self.assertIsInstance(label.mid, six.text_type) - self.assertGreater(label.score, 0.0) - - def test_detect_labels_content(self): - client = Config.CLIENT - with open(LABEL_FILE, 'rb') as image_file: - image = client.image(content=image_file.read()) - labels = image.detect_labels() - self.assertEqual(len(labels), 10) - for label in labels: - self._assert_label(label) - - def test_detect_labels_gcs(self): - bucket_name = Config.TEST_BUCKET.name - blob_name = 'car.jpg' - blob = Config.TEST_BUCKET.blob(blob_name) - self.to_delete_by_case.append(blob) # Clean-up. - with open(LABEL_FILE, 'rb') as file_obj: - blob.upload_from_file(file_obj) - - source_uri = 'gs://%s/%s' % (bucket_name, blob_name) - - client = Config.CLIENT - image = client.image(source_uri=source_uri) - labels = image.detect_labels() - self.assertEqual(len(labels), 10) - for label in labels: - self._assert_label(label) - - def test_detect_labels_filename(self): - client = Config.CLIENT - image = client.image(filename=LABEL_FILE) - labels = image.detect_labels() - self.assertEqual(len(labels), 10) - for label in labels: - self._assert_label(label) - - -class TestVisionClientLandmark(BaseVisionTestCase): - DESCRIPTIONS = ('Mount Rushmore',) - - def setUp(self): - self.to_delete_by_case = [] - - def tearDown(self): - for value in self.to_delete_by_case: - value.delete() - - def _assert_landmark(self, landmark): - self.assertIsInstance(landmark, EntityAnnotation) - self.assertIn(landmark.description, self.DESCRIPTIONS) - self.assertEqual(len(landmark.locations), 1) - location = landmark.locations[0] - self._assert_coordinate(location.latitude) - self._assert_coordinate(location.longitude) - for vertex in landmark.bounds.vertices: - self._assert_coordinate(vertex.x_coordinate) - self._assert_coordinate(vertex.y_coordinate) - self.assertGreater(landmark.score, 0.2) - self.assertIsInstance(landmark.mid, six.text_type) - - def test_detect_landmark_content(self): - client = Config.CLIENT - with open(LANDMARK_FILE, 'rb') as image_file: - image = client.image(content=image_file.read()) - landmarks = image.detect_landmarks() - self.assertEqual(len(landmarks), 1) - landmark = landmarks[0] - self._assert_landmark(landmark) - - def test_detect_landmark_gcs(self): - bucket_name = Config.TEST_BUCKET.name - blob_name = 'landmark.jpg' - blob = Config.TEST_BUCKET.blob(blob_name) - self.to_delete_by_case.append(blob) # Clean-up. - with open(LANDMARK_FILE, 'rb') as file_obj: - blob.upload_from_file(file_obj) - - source_uri = 'gs://%s/%s' % (bucket_name, blob_name) - - client = Config.CLIENT - image = client.image(source_uri=source_uri) - landmarks = image.detect_landmarks() - self.assertEqual(len(landmarks), 1) - landmark = landmarks[0] - self._assert_landmark(landmark) - - def test_detect_landmark_filename(self): - client = Config.CLIENT - image = client.image(filename=LANDMARK_FILE) - landmarks = image.detect_landmarks() - self.assertEqual(len(landmarks), 1) - landmark = landmarks[0] - self._assert_landmark(landmark) - - -class TestVisionClientSafeSearch(BaseVisionTestCase): - def setUp(self): - self.to_delete_by_case = [] - - def tearDown(self): - for value in self.to_delete_by_case: - value.delete() - - def _assert_safe_search(self, safe_search): - from google.cloud.vision.safe_search import SafeSearchAnnotation - - self.assertIsInstance(safe_search, SafeSearchAnnotation) - self._assert_likelihood(safe_search.adult) - self._assert_likelihood(safe_search.spoof) - self._assert_likelihood(safe_search.medical) - self._assert_likelihood(safe_search.violence) - - def test_detect_safe_search_content(self): - client = Config.CLIENT - with open(FACE_FILE, 'rb') as image_file: - image = client.image(content=image_file.read()) - safe_search = image.detect_safe_search() - self._assert_safe_search(safe_search) - - def test_detect_safe_search_gcs(self): - bucket_name = Config.TEST_BUCKET.name - blob_name = 'faces.jpg' - blob = Config.TEST_BUCKET.blob(blob_name) - self.to_delete_by_case.append(blob) # Clean-up. - with open(FACE_FILE, 'rb') as file_obj: - blob.upload_from_file(file_obj) - - source_uri = 'gs://%s/%s' % (bucket_name, blob_name) - - client = Config.CLIENT - image = client.image(source_uri=source_uri) - safe_search = image.detect_safe_search() - self._assert_safe_search(safe_search) - - def test_detect_safe_search_filename(self): - client = Config.CLIENT - image = client.image(filename=FACE_FILE) - safe_search = image.detect_safe_search() - self._assert_safe_search(safe_search) - - -class TestVisionClientText(unittest.TestCase): - DESCRIPTIONS = ( - 'Do', - 'what', - 'is', - 'right,', - 'not', - 'what', - 'is', - 'easy', - 'Do what is\nright, not\nwhat is easy\n', - ) - - def setUp(self): - self.to_delete_by_case = [] - - def tearDown(self): - for value in self.to_delete_by_case: - value.delete() - - def _assert_text(self, text): - self.assertIsInstance(text, EntityAnnotation) - self.assertIn(text.description, self.DESCRIPTIONS) - self.assertIn(text.locale, (None, '', 'en')) - self.assertIsInstance(text.score, (type(None), float)) - - def test_detect_text_content(self): - client = Config.CLIENT - with open(TEXT_FILE, 'rb') as image_file: - image = client.image(content=image_file.read()) - texts = image.detect_text() - self.assertEqual(len(texts), 9) - for text in texts: - self._assert_text(text) - - def test_detect_text_gcs(self): - bucket_name = Config.TEST_BUCKET.name - blob_name = 'text.jpg' - blob = Config.TEST_BUCKET.blob(blob_name) - self.to_delete_by_case.append(blob) # Clean-up. - with open(TEXT_FILE, 'rb') as file_obj: - blob.upload_from_file(file_obj) - - source_uri = 'gs://%s/%s' % (bucket_name, blob_name) - - client = Config.CLIENT - image = client.image(source_uri=source_uri) - texts = image.detect_text() - self.assertEqual(len(texts), 9) - for text in texts: - self._assert_text(text) - - def test_detect_text_filename(self): - client = Config.CLIENT - image = client.image(filename=TEXT_FILE) - texts = image.detect_text() - self.assertEqual(len(texts), 9) - for text in texts: - self._assert_text(text) - - -class TestVisionClientImageProperties(BaseVisionTestCase): - def setUp(self): - self.to_delete_by_case = [] - - def tearDown(self): - for value in self.to_delete_by_case: - value.delete() - - def _assert_color(self, color): - self.assertIsInstance(color.red, float) - self.assertIsInstance(color.green, float) - self.assertIsInstance(color.blue, float) - self.assertIsInstance(color.alpha, float) - self.assertNotEqual(color.red, 0.0) - self.assertNotEqual(color.green, 0.0) - self.assertNotEqual(color.blue, 0.0) - - def _assert_properties(self, image_property): - from google.cloud.vision.color import ImagePropertiesAnnotation - - self.assertIsInstance(image_property, ImagePropertiesAnnotation) - results = image_property.colors - for color_info in results: - self._assert_color(color_info.color) - self.assertNotEqual(color_info.pixel_fraction, 0.0) - self.assertNotEqual(color_info.score, 0.0) - - def test_detect_properties_content(self): - client = Config.CLIENT - with open(FACE_FILE, 'rb') as image_file: - image = client.image(content=image_file.read()) - properties = image.detect_properties() - self._assert_properties(properties) - - def test_detect_properties_gcs(self): - client = Config.CLIENT - bucket_name = Config.TEST_BUCKET.name - blob_name = 'faces.jpg' - blob = Config.TEST_BUCKET.blob(blob_name) - self.to_delete_by_case.append(blob) # Clean-up. - with open(FACE_FILE, 'rb') as file_obj: - blob.upload_from_file(file_obj) - - source_uri = 'gs://%s/%s' % (bucket_name, blob_name) - - image = client.image(source_uri=source_uri) - properties = image.detect_properties() - self._assert_properties(properties) - - def test_detect_properties_filename(self): - client = Config.CLIENT - image = client.image(filename=FACE_FILE) - properties = image.detect_properties() - self._assert_properties(properties) - - -class TestVisionBatchProcessing(BaseVisionTestCase): - def setUp(self): - self.to_delete_by_case = [] - - def tearDown(self): - for value in self.to_delete_by_case: - value.delete() - - def test_batch_detect_gcs(self): - client = Config.CLIENT - bucket_name = Config.TEST_BUCKET.name - - # Logo GCS image. - blob_name = 'logos.jpg' - blob = Config.TEST_BUCKET.blob(blob_name) - self.to_delete_by_case.append(blob) # Clean-up. - with open(LOGO_FILE, 'rb') as file_obj: - blob.upload_from_file(file_obj) - - logo_source_uri = 'gs://%s/%s' % (bucket_name, blob_name) - - image_one = client.image(source_uri=logo_source_uri) - logo_feature = Feature(FeatureTypes.LOGO_DETECTION, 2) - - # Faces GCS image. - blob_name = 'faces.jpg' - blob = Config.TEST_BUCKET.blob(blob_name) - self.to_delete_by_case.append(blob) # Clean-up. - with open(FACE_FILE, 'rb') as file_obj: - blob.upload_from_file(file_obj) - - face_source_uri = 'gs://%s/%s' % (bucket_name, blob_name) - - image_two = client.image(source_uri=face_source_uri) - face_feature = Feature(FeatureTypes.FACE_DETECTION, 2) - - batch = client.batch() - batch.add_image(image_one, [logo_feature]) - batch.add_image(image_two, [face_feature, logo_feature]) - results = batch.detect() - self.assertEqual(len(results), 2) - self.assertIsInstance(results[0], vision.annotations.Annotations) - self.assertIsInstance(results[1], vision.annotations.Annotations) - self.assertEqual(len(results[0].logos), 1) - self.assertEqual(len(results[0].faces), 0) - - self.assertEqual(len(results[1].logos), 0) - self.assertEqual(len(results[1].faces), 2) - - -class TestVisionWebAnnotation(BaseVisionTestCase): - def setUp(self): - self.to_delete_by_case = [] - - def tearDown(self): - for value in self.to_delete_by_case: - value.delete() - - def _check_web_entity(self, web_entity): - from google.cloud.vision.web import WebEntity - - if not isinstance(web_entity, WebEntity): - return False - if not isinstance(web_entity.entity_id, six.text_type): - return False - if not isinstance(web_entity.score, float): - return False - if not isinstance(web_entity.description, six.text_type): - return False - - return True - - def _assert_web_entity(self, web_entity): - return_value = self._check_web_entity(web_entity) - self.assertTrue(return_value) - - def _check_web_image(self, web_image): - from google.cloud.vision.web import WebImage - - if not isinstance(web_image, WebImage): - return False - - if not isinstance(web_image.url, six.text_type): - return False - - if not isinstance(web_image.score, float): - return False - - return True - - def _assert_web_image(self, web_image): - return_value = self._check_web_image(web_image) - self.assertTrue(return_value) - - def _check_web_page(self, web_page): - from google.cloud.vision.web import WebPage - - if not isinstance(web_page, WebPage): - return False - - if not isinstance(web_page.url, six.text_type): - return False - - if not isinstance(web_page.score, float): - return False - - return True - - def _assert_web_page(self, web_page): - return_value = self._check_web_page(web_page) - self.assertTrue(return_value) - - def _check_web_images(self, web_images, limit): - if len(web_images.web_entities) != limit: - return False - for web_entity in web_images.web_entities: - if not self._check_web_entity(web_entity): - return False - - if len(web_images.full_matching_images) != limit: - return False - for web_image in web_images.full_matching_images: - if not self._check_web_image(web_image): - return False - - if len(web_images.partial_matching_images) != limit: - return False - for web_image in web_images.partial_matching_images: - if not self._check_web_image(web_image): - return False - - if len(web_images.pages_with_matching_images) != limit: - return False - for web_page in web_images.pages_with_matching_images: - if not self._check_web_page(web_page): - return False - - return True - - def _assert_web_images(self, web_images, limit): - return_value = self._check_web_images(web_images, limit) - self.assertTrue(return_value) - - @RetryErrors(unittest.TestCase.failureException) - def test_detect_web_images_from_content(self): - client = Config.CLIENT - with open(LANDMARK_FILE, 'rb') as image_file: - image = client.image(content=image_file.read()) - limit = 3 - web_images = image.detect_web(limit=limit) - self._assert_web_images(web_images, limit) - - def test_detect_web_images_from_gcs(self): - client = Config.CLIENT - bucket_name = Config.TEST_BUCKET.name - blob_name = 'landmark.jpg' - blob = Config.TEST_BUCKET.blob(blob_name) - self.to_delete_by_case.append(blob) # Clean-up. - with open(LANDMARK_FILE, 'rb') as file_obj: - blob.upload_from_file(file_obj) - - source_uri = 'gs://%s/%s' % (bucket_name, blob_name) - - image = client.image(source_uri=source_uri) - limit = 5 - - images_good = functools.partial(self._check_web_images, limit=limit) - images_good.__name__ = 'images_good' # partial() has no name. - retry = RetryResult(images_good) - web_images = retry(image.detect_web)(limit=limit) - - self._assert_web_images(web_images, limit) - - def test_detect_web_images_from_filename(self): - client = Config.CLIENT - image = client.image(filename=LANDMARK_FILE) - limit = 5 - web_images = image.detect_web(limit=limit) - self._assert_web_images(web_images, limit) + blob = self.test_bucket.blob(blob_name) + self.to_delete_by_case.append(blob) + with io.open(LOGO_FILE, 'rb') as image_file: + blob.upload_from_file(image_file) + + # Make the request. + response = self.client.logo_detection({ + 'source': {'image_uri': 'gs://{bucket}/{blob}'.format( + bucket=self.test_bucket.name, + blob=blob_name, + )}, + }) + + # Check the response. + assert len(response.logo_annotations) == 1 + assert response.logo_annotations[0].description == 'Google' diff --git a/vision/tests/system_old.py b/vision/tests/system_old.py new file mode 100644 index 0000000000000..cddf399ddf5f0 --- /dev/null +++ b/vision/tests/system_old.py @@ -0,0 +1,744 @@ +# Copyright 2016 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""System tests for Vision API.""" + +import os +import unittest + +import six + +from google.cloud import exceptions +from google.cloud import storage +from google.cloud import vision +from google.cloud.vision.entity import EntityAnnotation +from google.cloud.vision.feature import Feature +from google.cloud.vision.feature import FeatureTypes + +from test_utils.retry import RetryErrors +from test_utils.system import unique_resource_id + + +_SYS_TESTS_DIR = os.path.realpath(os.path.dirname(__file__)) +LOGO_FILE = os.path.join(_SYS_TESTS_DIR, 'data', 'logo.png') +FACE_FILE = os.path.join(_SYS_TESTS_DIR, 'data', 'faces.jpg') +LABEL_FILE = os.path.join(_SYS_TESTS_DIR, 'data', 'car.jpg') +LANDMARK_FILE = os.path.join(_SYS_TESTS_DIR, 'data', 'landmark.jpg') +TEXT_FILE = os.path.join(_SYS_TESTS_DIR, 'data', 'text.jpg') +FULL_TEXT_FILE = os.path.join(_SYS_TESTS_DIR, 'data', 'full-text.jpg') + + +class Config(object): + CLIENT = None + TEST_BUCKET = None + + +def setUpModule(): + Config.CLIENT = vision.Client() + storage_client = storage.Client() + bucket_name = 'new' + unique_resource_id() + Config.TEST_BUCKET = storage_client.bucket(bucket_name) + # 429 Too Many Requests in case API requests rate-limited. + retry_429 = RetryErrors(exceptions.TooManyRequests) + retry_429(Config.TEST_BUCKET.create)() + + +def tearDownModule(): + # 409 Conflict if the bucket is full. + # 429 Too Many Requests in case API requests rate-limited. + bucket_retry = RetryErrors( + (exceptions.TooManyRequests, exceptions.Conflict)) + bucket_retry(Config.TEST_BUCKET.delete)(force=True) + + +class BaseVisionTestCase(unittest.TestCase): + def _assert_coordinate(self, coordinate): + if coordinate is None: + return + self.assertIsNotNone(coordinate) + self.assertIsInstance(coordinate, (int, float)) + + def _assert_likelihood(self, likelihood): + from google.cloud.vision.likelihood import Likelihood + + levels = [Likelihood.UNKNOWN, Likelihood.VERY_LIKELY, + Likelihood.UNLIKELY, Likelihood.POSSIBLE, Likelihood.LIKELY, + Likelihood.VERY_UNLIKELY] + self.assertIn(likelihood, levels) + + def _pb_not_implemented_skip(self, message): + if Config.CLIENT._use_grpc: + self.skipTest(message) + + +class TestVisionFullText(unittest.TestCase): + def setUp(self): + self.to_delete_by_case = [] + + def tearDown(self): + for value in self.to_delete_by_case: + value.delete() + + def _assert_full_text(self, full_text): + from google.cloud.vision.text import TextAnnotation + + self.assertIsInstance(full_text, TextAnnotation) + self.assertIsInstance(full_text.text, six.text_type) + self.assertEqual(len(full_text.pages), 1) + self.assertIsInstance(full_text.pages[0].width, int) + self.assertIsInstance(full_text.pages[0].height, int) + + def test_detect_full_text_content(self): + client = Config.CLIENT + with open(FULL_TEXT_FILE, 'rb') as image_file: + image = client.image(content=image_file.read()) + full_text = image.detect_full_text(language_hints=['en']) + self._assert_full_text(full_text) + + def test_detect_full_text_filename(self): + client = Config.CLIENT + image = client.image(filename=FULL_TEXT_FILE) + full_text = image.detect_full_text(language_hints=['en']) + self._assert_full_text(full_text) + + def test_detect_full_text_gcs(self): + bucket_name = Config.TEST_BUCKET.name + blob_name = 'full-text.jpg' + blob = Config.TEST_BUCKET.blob(blob_name) + self.to_delete_by_case.append(blob) # Clean-up. + with open(FULL_TEXT_FILE, 'rb') as file_obj: + blob.upload_from_file(file_obj) + + source_uri = 'gs://%s/%s' % (bucket_name, blob_name) + + client = Config.CLIENT + image = client.image(source_uri=source_uri) + full_text = image.detect_full_text(language_hints=['en']) + self._assert_full_text(full_text) + + +class TestVisionClientCropHint(BaseVisionTestCase): + def setUp(self): + self.to_delete_by_case = [] + + def tearDown(self): + for value in self.to_delete_by_case: + value.delete() + + def _assert_crop_hint(self, hint): + from google.cloud.vision.crop_hint import CropHint + from google.cloud.vision.geometry import Bounds + + self.assertIsInstance(hint, CropHint) + self.assertIsInstance(hint.bounds, Bounds) + self.assertGreater(len(hint.bounds.vertices), 1) + self.assertIsInstance(hint.confidence, (int, float)) + self.assertIsInstance(hint.importance_fraction, float) + + def test_detect_crop_hints_content(self): + client = Config.CLIENT + with open(FACE_FILE, 'rb') as image_file: + image = client.image(content=image_file.read()) + crop_hints = image.detect_crop_hints( + aspect_ratios=[1.3333, 1.7777], limit=2) + self.assertEqual(len(crop_hints), 2) + for hint in crop_hints: + self._assert_crop_hint(hint) + + def test_detect_crop_hints_filename(self): + client = Config.CLIENT + image = client.image(filename=FACE_FILE) + crop_hints = image.detect_crop_hints( + aspect_ratios=[1.3333, 1.7777], limit=2) + self.assertEqual(len(crop_hints), 2) + for hint in crop_hints: + self._assert_crop_hint(hint) + + def test_detect_crop_hints_gcs(self): + bucket_name = Config.TEST_BUCKET.name + blob_name = 'faces.jpg' + blob = Config.TEST_BUCKET.blob(blob_name) + self.to_delete_by_case.append(blob) # Clean-up. + with open(FACE_FILE, 'rb') as file_obj: + blob.upload_from_file(file_obj) + + source_uri = 'gs://%s/%s' % (bucket_name, blob_name) + client = Config.CLIENT + image = client.image(source_uri=source_uri) + crop_hints = image.detect_crop_hints( + aspect_ratios=[1.3333, 1.7777], limit=2) + self.assertEqual(len(crop_hints), 2) + for hint in crop_hints: + self._assert_crop_hint(hint) + + +class TestVisionClientLogo(unittest.TestCase): + def setUp(self): + self.to_delete_by_case = [] + + def tearDown(self): + for value in self.to_delete_by_case: + value.delete() + + def _assert_logo(self, logo): + self.assertIsInstance(logo, EntityAnnotation) + self.assertEqual(logo.description, 'Google') + self.assertEqual(len(logo.bounds.vertices), 4) + self.assertEqual(logo.bounds.vertices[0].x_coordinate, 40) + self.assertEqual(logo.bounds.vertices[0].y_coordinate, 40) + self.assertEqual(logo.bounds.vertices[1].x_coordinate, 959) + self.assertEqual(logo.bounds.vertices[1].y_coordinate, 40) + self.assertEqual(logo.bounds.vertices[2].x_coordinate, 959) + self.assertEqual(logo.bounds.vertices[2].y_coordinate, 302) + self.assertEqual(logo.bounds.vertices[3].x_coordinate, 40) + self.assertEqual(logo.bounds.vertices[3].y_coordinate, 302) + self.assertTrue(logo.score > 0.25) + + def test_detect_logos_content(self): + client = Config.CLIENT + with open(LOGO_FILE, 'rb') as image_file: + image = client.image(content=image_file.read()) + logos = image.detect_logos() + self.assertEqual(len(logos), 1) + logo = logos[0] + self._assert_logo(logo) + + def test_detect_logos_filename(self): + client = Config.CLIENT + image = client.image(filename=LOGO_FILE) + logos = image.detect_logos() + self.assertEqual(len(logos), 1) + logo = logos[0] + self._assert_logo(logo) + + def test_detect_logos_gcs(self): + bucket_name = Config.TEST_BUCKET.name + blob_name = 'logo.png' + blob = Config.TEST_BUCKET.blob(blob_name) + self.to_delete_by_case.append(blob) # Clean-up. + with open(LOGO_FILE, 'rb') as file_obj: + blob.upload_from_file(file_obj) + + source_uri = 'gs://%s/%s' % (bucket_name, blob_name) + + client = Config.CLIENT + image = client.image(source_uri=source_uri) + logos = image.detect_logos() + self.assertEqual(len(logos), 1) + logo = logos[0] + self._assert_logo(logo) + + +class TestVisionClientFace(BaseVisionTestCase): + def setUp(self): + self.to_delete_by_case = [] + + def tearDown(self): + for value in self.to_delete_by_case: + value.delete() + + def _assert_landmarks(self, landmarks): + from google.cloud.vision.face import Landmark + from google.cloud.vision.face import LandmarkTypes + from google.cloud.vision.face import Position + + for landmark in LandmarkTypes: + if landmark is not LandmarkTypes.UNKNOWN_LANDMARK: + feature = getattr(landmarks, landmark.name.lower()) + self.assertIsInstance(feature, Landmark) + self.assertIsInstance(feature.position, Position) + self._assert_coordinate(feature.position.x_coordinate) + self._assert_coordinate(feature.position.y_coordinate) + self._assert_coordinate(feature.position.z_coordinate) + + def _assert_face(self, face): + from google.cloud.vision.face import Bounds + from google.cloud.vision.face import FDBounds + from google.cloud.vision.face import Face + from google.cloud.vision.face import Landmarks + from google.cloud.vision.geometry import Vertex + + self.assertIsInstance(face, Face) + self.assertGreater(face.detection_confidence, 0.0) + self._assert_likelihood(face.anger) + self._assert_likelihood(face.joy) + self._assert_likelihood(face.sorrow) + self._assert_likelihood(face.surprise) + self._assert_likelihood(face.image_properties.blurred) + self._assert_likelihood(face.image_properties.underexposed) + self._assert_likelihood(face.headwear) + self.assertNotEqual(face.angles.roll, 0.0) + self.assertNotEqual(face.angles.pan, 0.0) + self.assertNotEqual(face.angles.tilt, 0.0) + + self.assertIsInstance(face.bounds, Bounds) + for vertex in face.bounds.vertices: + self.assertIsInstance(vertex, Vertex) + self._assert_coordinate(vertex.x_coordinate) + self._assert_coordinate(vertex.y_coordinate) + + self.assertIsInstance(face.fd_bounds, FDBounds) + for vertex in face.fd_bounds.vertices: + self.assertIsInstance(vertex, Vertex) + self._assert_coordinate(vertex.x_coordinate) + self._assert_coordinate(vertex.y_coordinate) + + self.assertIsInstance(face.landmarks, Landmarks) + self._assert_landmarks(face.landmarks) + + def test_detect_faces_content(self): + client = Config.CLIENT + with open(FACE_FILE, 'rb') as image_file: + image = client.image(content=image_file.read()) + faces = image.detect_faces() + self.assertEqual(len(faces), 5) + for face in faces: + self._assert_face(face) + + def test_detect_faces_gcs(self): + bucket_name = Config.TEST_BUCKET.name + blob_name = 'faces.jpg' + blob = Config.TEST_BUCKET.blob(blob_name) + self.to_delete_by_case.append(blob) # Clean-up. + with open(FACE_FILE, 'rb') as file_obj: + blob.upload_from_file(file_obj) + + source_uri = 'gs://%s/%s' % (bucket_name, blob_name) + client = Config.CLIENT + image = client.image(source_uri=source_uri) + faces = image.detect_faces() + self.assertEqual(len(faces), 5) + for face in faces: + self._assert_face(face) + + def test_detect_faces_filename(self): + client = Config.CLIENT + image = client.image(filename=FACE_FILE) + faces = image.detect_faces() + self.assertEqual(len(faces), 5) + for face in faces: + self._assert_face(face) + + +class TestVisionClientLabel(BaseVisionTestCase): + DESCRIPTIONS = ( + 'car', + 'vehicle', + 'land vehicle', + 'automotive design', + 'wheel', + 'automobile make', + 'luxury vehicle', + 'sports car', + 'performance car', + 'automotive exterior', + ) + + def setUp(self): + self.to_delete_by_case = [] + + def tearDown(self): + for value in self.to_delete_by_case: + value.delete() + + def _assert_label(self, label): + self.assertIsInstance(label, EntityAnnotation) + self.assertIn(label.description, self.DESCRIPTIONS) + self.assertIsInstance(label.mid, six.text_type) + self.assertGreater(label.score, 0.0) + + def test_detect_labels_content(self): + client = Config.CLIENT + with open(LABEL_FILE, 'rb') as image_file: + image = client.image(content=image_file.read()) + labels = image.detect_labels() + self.assertEqual(len(labels), 10) + for label in labels: + self._assert_label(label) + + def test_detect_labels_gcs(self): + bucket_name = Config.TEST_BUCKET.name + blob_name = 'car.jpg' + blob = Config.TEST_BUCKET.blob(blob_name) + self.to_delete_by_case.append(blob) # Clean-up. + with open(LABEL_FILE, 'rb') as file_obj: + blob.upload_from_file(file_obj) + + source_uri = 'gs://%s/%s' % (bucket_name, blob_name) + + client = Config.CLIENT + image = client.image(source_uri=source_uri) + labels = image.detect_labels() + self.assertEqual(len(labels), 10) + for label in labels: + self._assert_label(label) + + def test_detect_labels_filename(self): + client = Config.CLIENT + image = client.image(filename=LABEL_FILE) + labels = image.detect_labels() + self.assertEqual(len(labels), 10) + for label in labels: + self._assert_label(label) + + +class TestVisionClientLandmark(BaseVisionTestCase): + DESCRIPTIONS = ('Mount Rushmore',) + + def setUp(self): + self.to_delete_by_case = [] + + def tearDown(self): + for value in self.to_delete_by_case: + value.delete() + + def _assert_landmark(self, landmark): + self.assertIsInstance(landmark, EntityAnnotation) + self.assertIn(landmark.description, self.DESCRIPTIONS) + self.assertEqual(len(landmark.locations), 1) + location = landmark.locations[0] + self._assert_coordinate(location.latitude) + self._assert_coordinate(location.longitude) + for vertex in landmark.bounds.vertices: + self._assert_coordinate(vertex.x_coordinate) + self._assert_coordinate(vertex.y_coordinate) + self.assertGreater(landmark.score, 0.2) + self.assertIsInstance(landmark.mid, six.text_type) + + def test_detect_landmark_content(self): + client = Config.CLIENT + with open(LANDMARK_FILE, 'rb') as image_file: + image = client.image(content=image_file.read()) + landmarks = image.detect_landmarks() + self.assertEqual(len(landmarks), 1) + landmark = landmarks[0] + self._assert_landmark(landmark) + + def test_detect_landmark_gcs(self): + bucket_name = Config.TEST_BUCKET.name + blob_name = 'landmark.jpg' + blob = Config.TEST_BUCKET.blob(blob_name) + self.to_delete_by_case.append(blob) # Clean-up. + with open(LANDMARK_FILE, 'rb') as file_obj: + blob.upload_from_file(file_obj) + + source_uri = 'gs://%s/%s' % (bucket_name, blob_name) + + client = Config.CLIENT + image = client.image(source_uri=source_uri) + landmarks = image.detect_landmarks() + self.assertEqual(len(landmarks), 1) + landmark = landmarks[0] + self._assert_landmark(landmark) + + def test_detect_landmark_filename(self): + client = Config.CLIENT + image = client.image(filename=LANDMARK_FILE) + landmarks = image.detect_landmarks() + self.assertEqual(len(landmarks), 1) + landmark = landmarks[0] + self._assert_landmark(landmark) + + +class TestVisionClientSafeSearch(BaseVisionTestCase): + def setUp(self): + self.to_delete_by_case = [] + + def tearDown(self): + for value in self.to_delete_by_case: + value.delete() + + def _assert_safe_search(self, safe_search): + from google.cloud.vision.safe_search import SafeSearchAnnotation + + self.assertIsInstance(safe_search, SafeSearchAnnotation) + self._assert_likelihood(safe_search.adult) + self._assert_likelihood(safe_search.spoof) + self._assert_likelihood(safe_search.medical) + self._assert_likelihood(safe_search.violence) + + def test_detect_safe_search_content(self): + client = Config.CLIENT + with open(FACE_FILE, 'rb') as image_file: + image = client.image(content=image_file.read()) + safe_search = image.detect_safe_search() + self._assert_safe_search(safe_search) + + def test_detect_safe_search_gcs(self): + bucket_name = Config.TEST_BUCKET.name + blob_name = 'faces.jpg' + blob = Config.TEST_BUCKET.blob(blob_name) + self.to_delete_by_case.append(blob) # Clean-up. + with open(FACE_FILE, 'rb') as file_obj: + blob.upload_from_file(file_obj) + + source_uri = 'gs://%s/%s' % (bucket_name, blob_name) + + client = Config.CLIENT + image = client.image(source_uri=source_uri) + safe_search = image.detect_safe_search() + self._assert_safe_search(safe_search) + + def test_detect_safe_search_filename(self): + client = Config.CLIENT + image = client.image(filename=FACE_FILE) + safe_search = image.detect_safe_search() + self._assert_safe_search(safe_search) + + +class TestVisionClientText(unittest.TestCase): + DESCRIPTIONS = ( + 'Do', + 'what', + 'is', + 'right,', + 'not', + 'what', + 'is', + 'easy', + 'Do what is\nright, not\nwhat is easy\n', + ) + + def setUp(self): + self.to_delete_by_case = [] + + def tearDown(self): + for value in self.to_delete_by_case: + value.delete() + + def _assert_text(self, text): + self.assertIsInstance(text, EntityAnnotation) + self.assertIn(text.description, self.DESCRIPTIONS) + self.assertIn(text.locale, (None, '', 'en')) + self.assertIsInstance(text.score, (type(None), float)) + + def test_detect_text_content(self): + client = Config.CLIENT + with open(TEXT_FILE, 'rb') as image_file: + image = client.image(content=image_file.read()) + texts = image.detect_text() + self.assertEqual(len(texts), 9) + for text in texts: + self._assert_text(text) + + def test_detect_text_gcs(self): + bucket_name = Config.TEST_BUCKET.name + blob_name = 'text.jpg' + blob = Config.TEST_BUCKET.blob(blob_name) + self.to_delete_by_case.append(blob) # Clean-up. + with open(TEXT_FILE, 'rb') as file_obj: + blob.upload_from_file(file_obj) + + source_uri = 'gs://%s/%s' % (bucket_name, blob_name) + + client = Config.CLIENT + image = client.image(source_uri=source_uri) + texts = image.detect_text() + self.assertEqual(len(texts), 9) + for text in texts: + self._assert_text(text) + + def test_detect_text_filename(self): + client = Config.CLIENT + image = client.image(filename=TEXT_FILE) + texts = image.detect_text() + self.assertEqual(len(texts), 9) + for text in texts: + self._assert_text(text) + + +class TestVisionClientImageProperties(BaseVisionTestCase): + def setUp(self): + self.to_delete_by_case = [] + + def tearDown(self): + for value in self.to_delete_by_case: + value.delete() + + def _assert_color(self, color): + self.assertIsInstance(color.red, float) + self.assertIsInstance(color.green, float) + self.assertIsInstance(color.blue, float) + self.assertIsInstance(color.alpha, float) + self.assertNotEqual(color.red, 0.0) + self.assertNotEqual(color.green, 0.0) + self.assertNotEqual(color.blue, 0.0) + + def _assert_properties(self, image_property): + from google.cloud.vision.color import ImagePropertiesAnnotation + + self.assertIsInstance(image_property, ImagePropertiesAnnotation) + results = image_property.colors + for color_info in results: + self._assert_color(color_info.color) + self.assertNotEqual(color_info.pixel_fraction, 0.0) + self.assertNotEqual(color_info.score, 0.0) + + def test_detect_properties_content(self): + client = Config.CLIENT + with open(FACE_FILE, 'rb') as image_file: + image = client.image(content=image_file.read()) + properties = image.detect_properties() + self._assert_properties(properties) + + def test_detect_properties_gcs(self): + client = Config.CLIENT + bucket_name = Config.TEST_BUCKET.name + blob_name = 'faces.jpg' + blob = Config.TEST_BUCKET.blob(blob_name) + self.to_delete_by_case.append(blob) # Clean-up. + with open(FACE_FILE, 'rb') as file_obj: + blob.upload_from_file(file_obj) + + source_uri = 'gs://%s/%s' % (bucket_name, blob_name) + + image = client.image(source_uri=source_uri) + properties = image.detect_properties() + self._assert_properties(properties) + + def test_detect_properties_filename(self): + client = Config.CLIENT + image = client.image(filename=FACE_FILE) + properties = image.detect_properties() + self._assert_properties(properties) + + +class TestVisionBatchProcessing(BaseVisionTestCase): + def setUp(self): + self.to_delete_by_case = [] + + def tearDown(self): + for value in self.to_delete_by_case: + value.delete() + + def test_batch_detect_gcs(self): + client = Config.CLIENT + bucket_name = Config.TEST_BUCKET.name + + # Logo GCS image. + blob_name = 'logos.jpg' + blob = Config.TEST_BUCKET.blob(blob_name) + self.to_delete_by_case.append(blob) # Clean-up. + with open(LOGO_FILE, 'rb') as file_obj: + blob.upload_from_file(file_obj) + + logo_source_uri = 'gs://%s/%s' % (bucket_name, blob_name) + + image_one = client.image(source_uri=logo_source_uri) + logo_feature = Feature(FeatureTypes.LOGO_DETECTION, 2) + + # Faces GCS image. + blob_name = 'faces.jpg' + blob = Config.TEST_BUCKET.blob(blob_name) + self.to_delete_by_case.append(blob) # Clean-up. + with open(FACE_FILE, 'rb') as file_obj: + blob.upload_from_file(file_obj) + + face_source_uri = 'gs://%s/%s' % (bucket_name, blob_name) + + image_two = client.image(source_uri=face_source_uri) + face_feature = Feature(FeatureTypes.FACE_DETECTION, 2) + + batch = client.batch() + batch.add_image(image_one, [logo_feature]) + batch.add_image(image_two, [face_feature, logo_feature]) + results = batch.detect() + self.assertEqual(len(results), 2) + self.assertIsInstance(results[0], vision.annotations.Annotations) + self.assertIsInstance(results[1], vision.annotations.Annotations) + self.assertEqual(len(results[0].logos), 1) + self.assertEqual(len(results[0].faces), 0) + + self.assertEqual(len(results[1].logos), 0) + self.assertEqual(len(results[1].faces), 2) + + +class TestVisionWebAnnotation(BaseVisionTestCase): + def setUp(self): + self.to_delete_by_case = [] + + def tearDown(self): + for value in self.to_delete_by_case: + value.delete() + + def _assert_web_entity(self, web_entity): + from google.cloud.vision.web import WebEntity + + self.assertIsInstance(web_entity, WebEntity) + self.assertIsInstance(web_entity.entity_id, six.text_type) + self.assertIsInstance(web_entity.score, float) + self.assertIsInstance(web_entity.description, six.text_type) + + def _assert_web_image(self, web_image): + from google.cloud.vision.web import WebImage + + self.assertIsInstance(web_image, WebImage) + self.assertIsInstance(web_image.url, six.text_type) + self.assertIsInstance(web_image.score, float) + + def _assert_web_page(self, web_page): + from google.cloud.vision.web import WebPage + + self.assertIsInstance(web_page, WebPage) + self.assertIsInstance(web_page.url, six.text_type) + self.assertIsInstance(web_page.score, float) + + def _assert_web_images(self, web_images, limit): + self.assertEqual(len(web_images.web_entities), limit) + for web_entity in web_images.web_entities: + self._assert_web_entity(web_entity) + + self.assertEqual(len(web_images.full_matching_images), limit) + for web_image in web_images.full_matching_images: + self._assert_web_image(web_image) + + self.assertEqual(len(web_images.partial_matching_images), limit) + for web_image in web_images.partial_matching_images: + self._assert_web_image(web_image) + + self.assertEqual(len(web_images.pages_with_matching_images), limit) + for web_page in web_images.pages_with_matching_images: + self._assert_web_page(web_page) + + @RetryErrors(unittest.TestCase.failureException) + def test_detect_web_images_from_content(self): + client = Config.CLIENT + with open(LANDMARK_FILE, 'rb') as image_file: + image = client.image(content=image_file.read()) + limit = 3 + web_images = image.detect_web(limit=limit) + self._assert_web_images(web_images, limit) + + def test_detect_web_images_from_gcs(self): + client = Config.CLIENT + bucket_name = Config.TEST_BUCKET.name + blob_name = 'landmark.jpg' + blob = Config.TEST_BUCKET.blob(blob_name) + self.to_delete_by_case.append(blob) # Clean-up. + with open(LANDMARK_FILE, 'rb') as file_obj: + blob.upload_from_file(file_obj) + + source_uri = 'gs://%s/%s' % (bucket_name, blob_name) + + image = client.image(source_uri=source_uri) + limit = 5 + web_images = image.detect_web(limit=limit) + self._assert_web_images(web_images, limit) + + def test_detect_web_images_from_filename(self): + client = Config.CLIENT + image = client.image(filename=LANDMARK_FILE) + limit = 5 + web_images = image.detect_web(limit=limit) + self._assert_web_images(web_images, limit) diff --git a/vision/tests/unit/__init__.py b/vision/tests/unit/__init__.py index 58e0d91536321..e69de29bb2d1d 100644 --- a/vision/tests/unit/__init__.py +++ b/vision/tests/unit/__init__.py @@ -1,13 +0,0 @@ -# Copyright 2016 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. diff --git a/vision/tests/unit/test_decorators.py b/vision/tests/unit/test_decorators.py new file mode 100644 index 0000000000000..8ef86b71ec612 --- /dev/null +++ b/vision/tests/unit/test_decorators.py @@ -0,0 +1,69 @@ +# Copyright 2017, Google Inc. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import absolute_import +import unittest + +import mock + +from google.auth.credentials import Credentials +from google.cloud import vision + + +class DecoratorTests(unittest.TestCase): + def test_noop_without_enums(self): + class A(object): + pass + APrime = vision.decorators.add_single_feature_methods(A) + + # It should be the same class object. + assert A is APrime + + # Nothing should have been added. + assert not hasattr(A, 'face_detection') + assert not hasattr(A, 'logo_detection') + + def test_with_enums(self): + class A(object): + enums = vision.enums + + # There should not be detection methods yet. + assert not hasattr(A, 'face_detection') + + # Add the detection methods. + APrime = vision.decorators.add_single_feature_methods(A) + assert A is APrime + + # There should be detection methods now. + assert hasattr(A, 'face_detection') + assert callable(A.face_detection) + + +class SingleFeatureMethodTests(unittest.TestCase): + @mock.patch.object(vision.ImageAnnotatorClient, 'annotate_image') + def test_runs_generic_single_image(self, ai): + ai.return_value = vision.types.AnnotateImageResponse() + + # Make a face detection request. + client = vision.ImageAnnotatorClient( + credentials=mock.Mock(spec=Credentials), + ) + image = {'source': {'image_uri': 'gs://my-test-bucket/image.jpg'}} + response = client.face_detection(image) + + # Assert that the single-image method was called as expected. + ai.assert_called_once_with({ + 'features': [{'type': vision.enums.Feature.Type.FACE_DETECTION}], + 'image': image, + }, options=None) diff --git a/vision/tests/unit/test_helpers.py b/vision/tests/unit/test_helpers.py new file mode 100644 index 0000000000000..d8e2694e7b534 --- /dev/null +++ b/vision/tests/unit/test_helpers.py @@ -0,0 +1,136 @@ +# Copyright 2017, Google Inc. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import absolute_import +import io +import unittest + +import mock + +from google.auth.credentials import Credentials + +from google.cloud.vision_v1 import ImageAnnotatorClient +from google.cloud.vision_v1 import types + + + +class TestSingleImageHelper(unittest.TestCase): + def setUp(self): + credentials = mock.Mock(spec=Credentials) + self.client = ImageAnnotatorClient(credentials=credentials) + + @mock.patch.object(ImageAnnotatorClient, 'batch_annotate_images') + def test_all_features_default(self, batch_annotate): + # Set up an image annotation request with no features. + image = types.Image(source={ + 'image_uri': 'http://foo.com/img.jpg', + }) + request = types.AnnotateImageRequest(image=image) + assert not request.features + + # Perform the single image request. + self.client.annotate_image(request) + + # Evalute the argument sent to batch_annotate_images. + assert batch_annotate.call_count == 1 + _, args, kwargs = batch_annotate.mock_calls[0] + + # Only a single request object should be sent. + assert len(args[0]) == 1 + + # Evalute the request object to ensure it looks correct. + request_sent = args[0][0] + all_features = self.client._get_all_features() + assert request_sent.image is request.image + assert len(request_sent.features) == len(all_features) + + @mock.patch.object(ImageAnnotatorClient, 'batch_annotate_images') + def test_explicit_features(self, batch_annotate): + # Set up an image annotation request with no features. + image = types.Image(source={ + 'image_uri': 'http://foo.com/img.jpg', + }) + request = types.AnnotateImageRequest( + image=image, + features=[ + types.Feature(type=1), + types.Feature(type=2), + types.Feature(type=3), + ], + ) + + # Perform the single image request. + self.client.annotate_image(request) + + # Evalute the argument sent to batch_annotate_images. + assert batch_annotate.call_count == 1 + _, args, kwargs = batch_annotate.mock_calls[0] + + # Only a single request object should be sent. + assert len(args[0]) == 1 + + # Evalute the request object to ensure it looks correct. + request_sent = args[0][0] + assert request_sent.image is request.image + assert len(request_sent.features) == 3 + for feature, i in zip(request_sent.features, range(1, 4)): + assert feature.type == i + assert feature.max_results == 0 + + @mock.patch.object(ImageAnnotatorClient, 'batch_annotate_images') + def test_image_file_handler(self, batch_annotate): + # Set up a file handler. + file_ = io.BytesIO(b'bogus==') + + # Perform the single image request. + self.client.annotate_image({'image': file_}) + + # Evaluate the argument sent to batch_annotate_images. + assert batch_annotate.call_count == 1 + _, args, kwargs = batch_annotate.mock_calls[0] + + # Only a single request object should be sent. + assert len(args[0]) == 1 + + # Evalute the request object to ensure it looks correct. + request_sent = args[0][0] + assert request_sent['image']['content'] == b'bogus==' + + @mock.patch.object(ImageAnnotatorClient, 'batch_annotate_images') + @mock.patch.object(io, 'open') + def test_image_filename(self, io_open, batch_annotate): + # Make io.open send back a mock with a read method. + file_ = mock.MagicMock(spec=io.BytesIO) + io_open.return_value = file_ + file_.__enter__.return_value = file_ + file_.read.return_value = b'imagefile==' + + # Perform the single image request using a filename. + self.client.annotate_image( + {'image': {'source': {'filename': 'image.jpeg'}}}, + ) + + # Establish that my file was opened. + io_open.assert_called_once_with('image.jpeg', 'rb') + + # Evalute the argument sent to batch_annotate_images. + assert batch_annotate.call_count == 1 + _, args, kwargs = batch_annotate.mock_calls[0] + + # Only a single request object should be sent. + assert len(args[0]) == 1 + + # Evalute the request object to ensure it looks correct. + request_sent = args[0][0] + assert request_sent['image']['content'] == b'imagefile=='