diff --git a/.travis.yml b/.travis.yml index 6d3b8fb43b0a..9a599d006c74 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,6 +18,7 @@ script: - (cd error_reporting && tox -e py27) - (cd resource_manager && tox -e py27) - (cd monitoring && tox -e py27) + - (cd vision && tox -e py27) - tox -e py34 - (cd core && tox -e py34) - (cd bigtable && tox -e py34) @@ -31,6 +32,7 @@ script: - (cd error_reporting && tox -e py34) - (cd resource_manager && tox -e py34) - (cd monitoring && tox -e py34) + - (cd vision && tox -e py34) - tox -e lint - tox -e cover - (cd core && tox -e cover) @@ -45,6 +47,7 @@ script: - (cd error_reporting && tox -e cover) - (cd resource_manager && tox -e cover) - (cd monitoring && tox -e cover) + - (cd vision && tox -e cover) - tox -e system-tests - tox -e system-tests3 - scripts/update_docs.sh diff --git a/scripts/verify_included_modules.py b/scripts/verify_included_modules.py index de0506979d7c..6d6f4f3a62ec 100644 --- a/scripts/verify_included_modules.py +++ b/scripts/verify_included_modules.py @@ -71,6 +71,7 @@ 'pubsub', 'resource_manager', 'storage', + 'vision', ) diff --git a/setup.py b/setup.py index 1d9683c75295..9fc3c3410752 100644 --- a/setup.py +++ b/setup.py @@ -62,6 +62,7 @@ 'google-cloud-pubsub', 'google-cloud-resource-manager', 'google-cloud-storage', + 'google-cloud-vision', ] setup( diff --git a/tox.ini b/tox.ini index 20cde1811837..97048c9ad3e6 100644 --- a/tox.ini +++ b/tox.ini @@ -16,6 +16,7 @@ deps = {toxinidir}/error_reporting {toxinidir}/resource_manager {toxinidir}/monitoring + {toxinidir}/vision pytest covercmd = py.test --quiet \ @@ -95,6 +96,12 @@ covercmd = --cov-append \ --cov-config {toxinidir}/.coveragerc \ monitoring/unit_tests + py.test --quiet \ + --cov=google.cloud \ + --cov=unit_tests \ + --cov-append \ + --cov-config {toxinidir}/.coveragerc \ + vision/unit_tests coverage report --show-missing --fail-under=100 [testenv] diff --git a/vision/.coveragerc b/vision/.coveragerc new file mode 100644 index 000000000000..a54b99aa14b7 --- /dev/null +++ b/vision/.coveragerc @@ -0,0 +1,11 @@ +[run] +branch = True + +[report] +fail_under = 100 +show_missing = True +exclude_lines = + # Re-enable the standard pragma + pragma: NO COVER + # Ignore debug-only repr + def __repr__ diff --git a/vision/MANIFEST.in b/vision/MANIFEST.in new file mode 100644 index 000000000000..cb3a2b9ef4fa --- /dev/null +++ b/vision/MANIFEST.in @@ -0,0 +1,4 @@ +include README.rst +graft google +graft unit_tests +global-exclude *.pyc diff --git a/vision/README.rst b/vision/README.rst new file mode 100644 index 000000000000..35902b4cf303 --- /dev/null +++ b/vision/README.rst @@ -0,0 +1,52 @@ +Python Client for Google Cloud Vision +===================================== + + Python idiomatic client for `Google Cloud Vision`_ + +.. _Google Cloud Vision: https://cloud.google.com/vision/ + +- `Homepage`_ +- `API Documentation`_ + +.. _Homepage: https://googlecloudplatform.github.io/google-cloud-python/ +.. _API Documentation: http://googlecloudplatform.github.io/google-cloud-python/ + +Quick Start +----------- + +:: + + $ pip install --upgrade google-cloud-vision + +Authentication +-------------- + +With ``google-cloud-python`` we try to make authentication as painless as +possible. Check out the `Authentication section`_ in our documentation to +learn more. You may also find the `authentication document`_ shared by all +the ``google-cloud-*`` libraries to be helpful. + +.. _Authentication section: http://google-cloud-python.readthedocs.io/en/latest/google-cloud-auth.html +.. _authentication document: https://github.com/GoogleCloudPlatform/gcloud-common/tree/master/authentication + +Using the API +------------- + +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/ + +See the ``google-cloud-python`` API `Vision documentation`_ to learn +how to analyze images using this library. + +.. _Vision documentation: https://google-cloud-python.readthedocs.io/en/stable/vision-usage.html diff --git a/vision/google/__init__.py b/vision/google/__init__.py new file mode 100644 index 000000000000..b2b833373882 --- /dev/null +++ b/vision/google/__init__.py @@ -0,0 +1,20 @@ +# 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. + +try: + import pkg_resources + pkg_resources.declare_namespace(__name__) +except ImportError: + import pkgutil + __path__ = pkgutil.extend_path(__path__, __name__) diff --git a/vision/google/cloud/__init__.py b/vision/google/cloud/__init__.py new file mode 100644 index 000000000000..8ac7b74af136 --- /dev/null +++ b/vision/google/cloud/__init__.py @@ -0,0 +1,20 @@ +# Copyright 2014 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. + +try: + import pkg_resources + pkg_resources.declare_namespace(__name__) +except ImportError: + import pkgutil + __path__ = pkgutil.extend_path(__path__, __name__) diff --git a/google/cloud/vision/__init__.py b/vision/google/cloud/vision/__init__.py similarity index 100% rename from google/cloud/vision/__init__.py rename to vision/google/cloud/vision/__init__.py diff --git a/google/cloud/vision/client.py b/vision/google/cloud/vision/client.py similarity index 100% rename from google/cloud/vision/client.py rename to vision/google/cloud/vision/client.py diff --git a/google/cloud/vision/color.py b/vision/google/cloud/vision/color.py similarity index 100% rename from google/cloud/vision/color.py rename to vision/google/cloud/vision/color.py diff --git a/google/cloud/vision/connection.py b/vision/google/cloud/vision/connection.py similarity index 100% rename from google/cloud/vision/connection.py rename to vision/google/cloud/vision/connection.py diff --git a/google/cloud/vision/entity.py b/vision/google/cloud/vision/entity.py similarity index 100% rename from google/cloud/vision/entity.py rename to vision/google/cloud/vision/entity.py diff --git a/google/cloud/vision/face.py b/vision/google/cloud/vision/face.py similarity index 100% rename from google/cloud/vision/face.py rename to vision/google/cloud/vision/face.py diff --git a/google/cloud/vision/feature.py b/vision/google/cloud/vision/feature.py similarity index 100% rename from google/cloud/vision/feature.py rename to vision/google/cloud/vision/feature.py diff --git a/google/cloud/vision/geometry.py b/vision/google/cloud/vision/geometry.py similarity index 100% rename from google/cloud/vision/geometry.py rename to vision/google/cloud/vision/geometry.py diff --git a/google/cloud/vision/image.py b/vision/google/cloud/vision/image.py similarity index 100% rename from google/cloud/vision/image.py rename to vision/google/cloud/vision/image.py diff --git a/google/cloud/vision/likelihood.py b/vision/google/cloud/vision/likelihood.py similarity index 100% rename from google/cloud/vision/likelihood.py rename to vision/google/cloud/vision/likelihood.py diff --git a/google/cloud/vision/safe.py b/vision/google/cloud/vision/safe.py similarity index 100% rename from google/cloud/vision/safe.py rename to vision/google/cloud/vision/safe.py diff --git a/vision/setup.py b/vision/setup.py new file mode 100644 index 000000000000..8bd417801166 --- /dev/null +++ b/vision/setup.py @@ -0,0 +1,68 @@ +# 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. + +import os + +from setuptools import find_packages +from setuptools import setup + + +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', + 'Topic :: Internet', + ], +} + + +REQUIREMENTS = [ + 'google-cloud-core', +] + +setup( + name='google-cloud-vision', + version='0.20.0dev', + description='Python Client for Google Cloud Vision', + long_description=README, + namespace_packages=[ + 'google', + 'google.cloud', + ], + packages=find_packages(), + install_requires=REQUIREMENTS, + **SETUP_BASE +) diff --git a/vision/tox.ini b/vision/tox.ini new file mode 100644 index 000000000000..7202958b4940 --- /dev/null +++ b/vision/tox.ini @@ -0,0 +1,30 @@ +[tox] +envlist = + py27,py34,py35,cover + +[testing] +deps = + {toxinidir}/../core + pytest +covercmd = + py.test --quiet \ + --cov=google.cloud.vision \ + --cov=unit_tests \ + --cov-config {toxinidir}/.coveragerc \ + unit_tests + +[testenv] +commands = + py.test --quiet {posargs} unit_tests +deps = + {[testing]deps} + +[testenv:cover] +basepython = + python2.7 +commands = + {[testing]covercmd} +deps = + {[testenv]deps} + coverage + pytest-cov diff --git a/unit_tests/vision/__init__.py b/vision/unit_tests/__init__.py similarity index 100% rename from unit_tests/vision/__init__.py rename to vision/unit_tests/__init__.py diff --git a/unit_tests/vision/_fixtures.py b/vision/unit_tests/_fixtures.py similarity index 100% rename from unit_tests/vision/_fixtures.py rename to vision/unit_tests/_fixtures.py diff --git a/unit_tests/vision/test_client.py b/vision/unit_tests/test_client.py similarity index 92% rename from unit_tests/vision/test_client.py rename to vision/unit_tests/test_client.py index 31c7b4829cb8..e9ac5bbd84f4 100644 --- a/unit_tests/vision/test_client.py +++ b/vision/unit_tests/test_client.py @@ -40,7 +40,7 @@ def test_ctor(self): def test_face_annotation(self): from google.cloud.vision.feature import Feature, FeatureTypes - from unit_tests.vision._fixtures import FACE_DETECTION_RESPONSE + from unit_tests._fixtures import FACE_DETECTION_RESPONSE RETURNED = FACE_DETECTION_RESPONSE REQUEST = { @@ -82,7 +82,7 @@ def test_image_with_client(self): def test_face_detection_from_source(self): from google.cloud.vision.face import Face - from unit_tests.vision._fixtures import FACE_DETECTION_RESPONSE + from unit_tests._fixtures import FACE_DETECTION_RESPONSE RETURNED = FACE_DETECTION_RESPONSE credentials = _Credentials() client = self._makeOne(project=self.PROJECT, credentials=credentials) @@ -99,7 +99,7 @@ def test_face_detection_from_source(self): def test_face_detection_from_content(self): from google.cloud.vision.face import Face - from unit_tests.vision._fixtures import FACE_DETECTION_RESPONSE + from unit_tests._fixtures import FACE_DETECTION_RESPONSE RETURNED = FACE_DETECTION_RESPONSE credentials = _Credentials() client = self._makeOne(project=self.PROJECT, credentials=credentials) @@ -116,8 +116,9 @@ def test_face_detection_from_content(self): def test_label_detection_from_source(self): from google.cloud.vision.entity import EntityAnnotation - from unit_tests.vision._fixtures import (LABEL_DETECTION_RESPONSE as - RETURNED) + from unit_tests._fixtures import ( + LABEL_DETECTION_RESPONSE as RETURNED) + credentials = _Credentials() client = self._makeOne(project=self.PROJECT, credentials=credentials) client.connection = _Connection(RETURNED) @@ -137,8 +138,9 @@ def test_label_detection_from_source(self): def test_landmark_detection_from_source(self): from google.cloud.vision.entity import EntityAnnotation - from unit_tests.vision._fixtures import (LANDMARK_DETECTION_RESPONSE as - RETURNED) + from unit_tests._fixtures import ( + LANDMARK_DETECTION_RESPONSE as RETURNED) + credentials = _Credentials() client = self._makeOne(project=self.PROJECT, credentials=credentials) client.connection = _Connection(RETURNED) @@ -158,8 +160,9 @@ def test_landmark_detection_from_source(self): def test_landmark_detection_from_content(self): from google.cloud.vision.entity import EntityAnnotation - from unit_tests.vision._fixtures import (LANDMARK_DETECTION_RESPONSE as - RETURNED) + from unit_tests._fixtures import ( + LANDMARK_DETECTION_RESPONSE as RETURNED) + credentials = _Credentials() client = self._makeOne(project=self.PROJECT, credentials=credentials) client.connection = _Connection(RETURNED) @@ -175,7 +178,7 @@ def test_landmark_detection_from_content(self): def test_logo_detection_from_source(self): from google.cloud.vision.entity import EntityAnnotation - from unit_tests.vision._fixtures import LOGO_DETECTION_RESPONSE + from unit_tests._fixtures import LOGO_DETECTION_RESPONSE RETURNED = LOGO_DETECTION_RESPONSE credentials = _Credentials() client = self._makeOne(project=self.PROJECT, credentials=credentials) @@ -192,7 +195,7 @@ def test_logo_detection_from_source(self): def test_logo_detection_from_content(self): from google.cloud.vision.entity import EntityAnnotation - from unit_tests.vision._fixtures import LOGO_DETECTION_RESPONSE + from unit_tests._fixtures import LOGO_DETECTION_RESPONSE RETURNED = LOGO_DETECTION_RESPONSE credentials = _Credentials() client = self._makeOne(project=self.PROJECT, credentials=credentials) @@ -209,8 +212,9 @@ def test_logo_detection_from_content(self): def test_text_detection_from_source(self): from google.cloud.vision.entity import EntityAnnotation - from unit_tests.vision._fixtures import (TEXT_DETECTION_RESPONSE as - RETURNED) + from unit_tests._fixtures import ( + TEXT_DETECTION_RESPONSE as RETURNED) + credentials = _Credentials() client = self._makeOne(project=self.PROJECT, credentials=credentials) client.connection = _Connection(RETURNED) @@ -230,7 +234,7 @@ def test_text_detection_from_source(self): def test_safe_search_detection_from_source(self): from google.cloud.vision.safe import SafeSearchAnnotation - from unit_tests.vision._fixtures import SAFE_SEARCH_DETECTION_RESPONSE + from unit_tests._fixtures import SAFE_SEARCH_DETECTION_RESPONSE RETURNED = SAFE_SEARCH_DETECTION_RESPONSE credentials = _Credentials() @@ -250,7 +254,7 @@ def test_safe_search_detection_from_source(self): def test_image_properties_detection_from_source(self): from google.cloud.vision.color import ImagePropertiesAnnotation - from unit_tests.vision._fixtures import IMAGE_PROPERTIES_RESPONSE + from unit_tests._fixtures import IMAGE_PROPERTIES_RESPONSE RETURNED = IMAGE_PROPERTIES_RESPONSE credentials = _Credentials() diff --git a/unit_tests/vision/test_connection.py b/vision/unit_tests/test_connection.py similarity index 100% rename from unit_tests/vision/test_connection.py rename to vision/unit_tests/test_connection.py diff --git a/unit_tests/vision/test_entity.py b/vision/unit_tests/test_entity.py similarity index 94% rename from unit_tests/vision/test_entity.py rename to vision/unit_tests/test_entity.py index b76559fd05ea..7efb1f78b97c 100644 --- a/unit_tests/vision/test_entity.py +++ b/vision/unit_tests/test_entity.py @@ -21,7 +21,7 @@ def _getTargetClass(self): return EntityAnnotation def test_logo_annotation(self): - from unit_tests.vision._fixtures import LOGO_DETECTION_RESPONSE + from unit_tests._fixtures import LOGO_DETECTION_RESPONSE LOGO = LOGO_DETECTION_RESPONSE['responses'][0]['logoAnnotations'][0] entity_class = self._getTargetClass() diff --git a/unit_tests/vision/test_face.py b/vision/unit_tests/test_face.py similarity index 97% rename from unit_tests/vision/test_face.py rename to vision/unit_tests/test_face.py index 753c6bc6e2e4..775effd1fc6a 100644 --- a/unit_tests/vision/test_face.py +++ b/vision/unit_tests/test_face.py @@ -21,7 +21,7 @@ def _getTargetClass(self): return Face def setUp(self): - from unit_tests.vision._fixtures import FACE_DETECTION_RESPONSE + from unit_tests._fixtures import FACE_DETECTION_RESPONSE self.FACE_ANNOTATIONS = FACE_DETECTION_RESPONSE['responses'][0] self.face_class = self._getTargetClass() self.face = self.face_class.from_api_repr( diff --git a/unit_tests/vision/test_feature.py b/vision/unit_tests/test_feature.py similarity index 100% rename from unit_tests/vision/test_feature.py rename to vision/unit_tests/test_feature.py diff --git a/unit_tests/vision/test_image.py b/vision/unit_tests/test_image.py similarity index 100% rename from unit_tests/vision/test_image.py rename to vision/unit_tests/test_image.py