Skip to content

Commit

Permalink
Re-add old manual layer.
Browse files Browse the repository at this point in the history
  • Loading branch information
Luke Sneeringer committed May 9, 2017
1 parent cab525d commit 29ae515
Show file tree
Hide file tree
Showing 40 changed files with 8,135 additions and 19 deletions.
34 changes: 34 additions & 0 deletions vision/google/cloud/vision/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,40 @@
# See the License for the specific language governing permissions and
# limitations under the License.

# -----------------------------------------------------------------------------
# TRANSITION CODE
# -----------------------------------------------------------------------------
# The old Vision manual layer is now deprecated, but to allow
# users the time to move from the manual layer to the mostly auto-generated
# layer, they are both living side by side for a few months.
#
# Instantiating the old manual layer (`google.cloud.vision.Client`) will
# issue a DeprecationWarning.
#
# When it comes time to remove the old layer, everything in this directory
# should go away EXCEPT __init__.py, decorators.py, and helpers.py.
# Additionally, the import and export of `Client` should be removed from this
# file (along with this note), and the rest should be left intact.
# -----------------------------------------------------------------------------

from __future__ import absolute_import

from pkg_resources import get_distribution
__version__ = get_distribution('google-cloud-vision').version

from google.cloud.vision.client import Client
from google.cloud.vision_v1 import *


__all__ = (
# Common
'__version__',

# Manual Layer
'Client',

# GAPIC & Partial Manual Layer
'enums',
'ImageAnnotatorClient',
'types',
)
114 changes: 114 additions & 0 deletions vision/google/cloud/vision/_gax.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
# 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.

"""GAX Client for interacting with the Google Cloud Vision API."""

from google.cloud.gapic.vision.v1 import image_annotator_client
from google.cloud.proto.vision.v1 import image_annotator_pb2

from google.cloud.vision import __version__
from google.cloud.vision.annotations import Annotations


class _GAPICVisionAPI(object):
"""Vision API for interacting with the gRPC version of Vision.
:type client: :class:`~google.cloud.vision.client.Client`
:param client: Instance of ``Client`` object.
"""
def __init__(self, client=None):
self._client = client
self._annotator_client = image_annotator_client.ImageAnnotatorClient(
credentials=client._credentials, lib_name='gccl',
lib_version=__version__)

def annotate(self, images=None, requests_pb=None):
"""Annotate images through GAX.
:type images: list
:param images: List containing pairs of
:class:`~google.cloud.vision.image.Image` and
:class:`~google.cloud.vision.feature.Feature`.
e.g. [(image, [feature_one, feature_two]),]
:type requests_pb: list
:param requests_pb: List of :class:`google.cloud.proto.vision.v1.\
image_annotator_pb2.AnnotateImageRequest`
:rtype: list
:returns: List of
:class:`~google.cloud.vision.annotations.Annotations`.
"""
if any([images, requests_pb]) is False:
return []

if requests_pb is None:
requests = []
for image, features in images:
gapic_features = [_to_gapic_feature(feature)
for feature in features]
gapic_image = _to_gapic_image(image)
request = image_annotator_pb2.AnnotateImageRequest(
image=gapic_image, features=gapic_features)
requests.append(request)
else:
requests = requests_pb

annotator_client = self._annotator_client
responses = annotator_client.batch_annotate_images(requests).responses
return [Annotations.from_pb(response) for response in responses]


def _to_gapic_feature(feature):
"""Helper function to convert a ``Feature`` to a gRPC ``Feature``.
:type feature: :class:`~google.cloud.vision.feature.Feature`
:param feature: Local ``Feature`` class to be converted to gRPC ``Feature``
instance.
:rtype: :class:`~google.cloud.proto.vision.v1.image_annotator_pb2.Feature`
:returns: gRPC ``Feature`` converted from
:class:`~google.cloud.vision.feature.Feature`.
"""
return image_annotator_pb2.Feature(
type=getattr(image_annotator_pb2.Feature, feature.feature_type),
max_results=feature.max_results)


def _to_gapic_image(image):
"""Helper function to convert an ``Image`` to a gRPC ``Image``.
:type image: :class:`~google.cloud.vision.image.Image`
:param image: Local ``Image`` class to be converted to gRPC ``Image``.
:rtype: :class:`~google.cloud.proto.vision.v1.image_annotator_pb2.Image`
:returns: gRPC ``Image`` converted from
:class:`~google.cloud.vision.image.Image`.
"""
if image.content is not None:
return image_annotator_pb2.Image(content=image.content)
if image.source is not None:
if image.source.startswith('gs://'):
return image_annotator_pb2.Image(
source=image_annotator_pb2.ImageSource(
gcs_image_uri=image.source
),
)
elif image.source.startswith(('http://', 'https://')):
return image_annotator_pb2.Image(
source=image_annotator_pb2.ImageSource(
image_uri=image.source
),
)
raise ValueError('No image content or source found.')
121 changes: 121 additions & 0 deletions vision/google/cloud/vision/_http.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
# 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.

"""HTTP Client for interacting with the Google Cloud Vision API."""

import json

from google.cloud import _http

from google.cloud.vision import __version__
from google.cloud.vision.annotations import Annotations
from google.cloud.vision.feature import Feature

from google.protobuf import json_format


_CLIENT_INFO = _http.CLIENT_INFO_TEMPLATE.format(__version__)


class Connection(_http.JSONConnection):
"""A connection to Google Cloud Vision via the JSON REST API.
:type client: :class:`~google.cloud.vision.client.Client`
:param client: The client that owns the current connection.
"""

API_BASE_URL = 'https://vision.googleapis.com'
"""The base of the API call URL."""

API_VERSION = 'v1'
"""The version of the API, used in building the API call's URL."""

API_URL_TEMPLATE = '{api_base_url}/{api_version}{path}'
"""A template for the URL of a particular API call."""

_EXTRA_HEADERS = {
_http.CLIENT_INFO_HEADER: _CLIENT_INFO,
}


class _HTTPVisionAPI(object):
"""Vision API for interacting with the JSON/HTTP version of Vision
:type client: :class:`~google.cloud.core.client.Client`
:param client: Instance of ``Client`` object.
"""

def __init__(self, client):
self._client = client
self._connection = Connection(client)

def annotate(self, images=None, requests_pb=None):
"""Annotate an image to discover it's attributes.
:type images: list of :class:`~google.cloud.vision.image.Image`
:param images: A list of ``Image``.
:rtype: list
:returns: List of :class:`~googe.cloud.vision.annotations.Annotations`.
:type requests_pb: list
:param requests_pb: List of :class:`google.cloud.proto.vision.v1.\
image_annotator_b2.AnnotateImageRequest`.
:rtype: list
:returns: List of :class:`~googe.cloud.vision.annotations.Annotations`.
"""
if any([images, requests_pb]) is False:
return []

requests = []
if requests_pb is None:
for image, features in images:
requests.append(_make_request(image, features))
else:
requests = [json.loads(json_format.MessageToJson(request))
for request in requests_pb]

data = {'requests': requests}

api_response = self._connection.api_request(
method='POST', path='/images:annotate', data=data)
responses = api_response.get('responses')
return [Annotations.from_api_repr(response) for response in responses]


def _make_request(image, features):
"""Prepare request object to send to Vision API.
:type image: :class:`~google.cloud.vision.image.Image`
:param image: Instance of ``Image``.
:type features: list of :class:`~google.cloud.vision.feature.Feature`
:param features: Either a list of ``Feature`` instances or a single
instance of ``Feature``.
:rtype: dict
:returns: Dictionary prepared to send to the Vision API.
"""
if isinstance(features, Feature):
features = [features]

feature_check = (isinstance(feature, Feature) for feature in features)
if not any(feature_check):
raise TypeError('Feature or list of Feature classes are required.')

return {
'image': image.as_dict(),
'features': [feature.as_dict() for feature in features],
}
Loading

0 comments on commit 29ae515

Please sign in to comment.