Skip to content

Commit

Permalink
Send back the complete API responses. (#3059)
Browse files Browse the repository at this point in the history
* Return full API responses for Natural Language.

* Return full API responses from NL.

* Do the hyphenated copyright thing for edited files.

* Update usage doc.

* Updates based on @dhermes feedback.

* Update system tests.

* Added system tests and Entity Response tests.

Still need explicit SyntaxResponse and SentimentResponse tests.

* Remove explcit dict.get('foo', None)

* Fix some of the pylint errors.

* Finish fixing pylint errors.

* It is 2017.

* Add SentimentResponse tests.

* Unit tests for SyntaxResponse.

* Missed a dict.get('foo', None) case.

* Use assertIsNone

* Remove wikipedia_url as an attribute.

* PEP 257 compliance.

* Add Sentiment isInstance check.

* Add API responses documentation.

* Adding sentences to docs.

* Fix typo.
  • Loading branch information
lukesneeringer authored and dhermes committed Feb 24, 2017
1 parent 50aa873 commit 77a5d94
Show file tree
Hide file tree
Showing 11 changed files with 486 additions and 151 deletions.
129 changes: 129 additions & 0 deletions packages/google-cloud-language/google/cloud/language/api_responses.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
# Copyright 2017 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.

"""Response types from the Natural Language API."""

from google.cloud.language.entity import Entity
from google.cloud.language.sentence import Sentence
from google.cloud.language.sentiment import Sentiment
from google.cloud.language.syntax import Token


class EntityResponse(object):
"""Object representation of entity responses.
A representation of a response sent back from the
``analyzeEntites`` request to the Google Natural language API.
:type entities: list
:param entities: A list of :class:`~.language.entity.Entity` objects.
:type language: str
:param language: The language used for analysis.
"""
def __init__(self, entities, language):
self.entities = entities
self.language = language

@classmethod
def from_api_repr(cls, payload):
"""Return an entity response from a JSON representation.
:type payload: dict
:param payload: A dictionary representing the response.
:rtype: :class:`~.language.entity.Entity`
:returns: An ``Entity`` object.
"""
return cls(
entities=[Entity.from_api_repr(i) for i in payload['entities']],
language=payload['language'],
)


class SentimentResponse(object):
"""Object representation of sentiment responses.
A representation of a response to an ``analyzeSentiment`` request
to the Google Natural Language API.
:type sentiment: :class:`~.language.sentiment.Sentiment`
:param sentiment: A Sentiment object.
:type language: str
:param language: The language used for analyzing sentiment.
:type sentences: list
:param sentences: A list of :class:`~.language.syntax.Sentence` objects.
"""
def __init__(self, sentiment, language, sentences):
self.sentiment = sentiment
self.language = language
self.sentences = sentences

@classmethod
def from_api_repr(cls, payload):
"""Return an sentiment response from a JSON representation.
:type payload: dict
:param payload: A dictionary representing the response.
:rtype: `~.language.sentiment.Sentiment`
:returns: A ``Sentiment`` object.
"""
return cls(
language=payload.get('language'),
sentences=[Sentence.from_api_repr(sentence) for sentence
in payload.get('sentences', ())],
sentiment=Sentiment.from_api_repr(payload['documentSentiment']),
)


class SyntaxResponse(object):
"""Object representation of syntax responses.
A representation of a response to an ``analyzeSyntax`` request
to the Google Natural Language API.
:type tokens: list
:param tokens: A list of :class:`~.language.syntax.Token` objects.
:type language: str
:param language: The language used for analyzing sentiment.
:type sentences: list
:param sentences: A list of :class:`~.language.syntax.Sentence` objects.
"""
def __init__(self, tokens, language, sentences):
self.tokens = tokens
self.language = language
self.sentences = sentences

@classmethod
def from_api_repr(cls, payload):
"""Return an syntax response from a JSON representation.
:type payload: dict
:param payload: A dictionary representing the response.
:rtype: `~.language.syntax.Syntax`
:returns: A ``Syntax`` object.
"""
return cls(
language=payload.get('language'),
sentences=[Sentence.from_api_repr(sentence) for sentence in
payload.get('sentences', ())],
tokens=[Token.from_api_repr(token) for token in
payload.get('tokens', ())]
)
32 changes: 17 additions & 15 deletions packages/google-cloud-language/google/cloud/language/document.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright 2016 Google Inc.
# Copyright 2016-2017 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
Expand All @@ -19,15 +19,16 @@

import collections

from google.cloud.language import api_responses
from google.cloud.language.entity import Entity
from google.cloud.language.sentiment import Sentiment
from google.cloud.language.syntax import Sentence
from google.cloud.language.sentence import Sentence
from google.cloud.language.syntax import Token


Annotations = collections.namedtuple(
'Annotations',
'sentences tokens sentiment entities')
['sentences', 'tokens', 'sentiment', 'entities', 'language'])
"""Annotations for a document.
:type sentences: list
Expand All @@ -42,6 +43,9 @@
:type entities: list
:param entities: List of :class:`~.language.entity.Entity`
found in a document.
:type language: str
:param language: The language used for the annotation.
"""


Expand Down Expand Up @@ -156,18 +160,16 @@ def analyze_entities(self):
See `analyzeEntities`_.
:rtype: list
:returns: A list of :class:`~.language.entity.Entity` returned from
the API.
:rtype: :class:`~.language.entity.EntityResponse`
:returns: A representation of the entity response.
"""
data = {
'document': self._to_dict(),
'encodingType': self.encoding,
}
api_response = self.client._connection.api_request(
method='POST', path='analyzeEntities', data=data)
return [Entity.from_api_repr(entity)
for entity in api_response['entities']]
return api_responses.EntityResponse.from_api_repr(api_response)

def analyze_sentiment(self):
"""Analyze the sentiment in the current document.
Expand All @@ -177,13 +179,13 @@ def analyze_sentiment(self):
See `analyzeSentiment`_.
:rtype: :class:`.Sentiment`
:returns: The sentiment of the current document.
:rtype: :class:`.SentimentResponse`
:returns: A representation of the sentiment response.
"""
data = {'document': self._to_dict()}
api_response = self.client._connection.api_request(
method='POST', path='analyzeSentiment', data=data)
return Sentiment.from_api_repr(api_response['documentSentiment'])
return api_responses.SentimentResponse.from_api_repr(api_response)

def analyze_syntax(self):
"""Analyze the syntax in the current document.
Expand All @@ -203,8 +205,7 @@ def analyze_syntax(self):
}
api_response = self.client._connection.api_request(
method='POST', path='analyzeSyntax', data=data)
return [Token.from_api_repr(token)
for token in api_response.get('tokens', ())]
return api_responses.SyntaxResponse.from_api_repr(api_response)

def annotate_text(self, include_syntax=True, include_entities=True,
include_sentiment=True):
Expand Down Expand Up @@ -271,9 +272,10 @@ def annotate_text(self, include_syntax=True, include_entities=True,
entities = [Entity.from_api_repr(entity)
for entity in api_response['entities']]
annotations = Annotations(
entities=entities,
language=api_response.get('language'),
sentences=sentences,
tokens=tokens,
sentiment=sentiment,
entities=entities,
tokens=tokens,
)
return annotations
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright 2016 Google Inc.
# Copyright 2016-2017 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -53,10 +53,6 @@ class Entity(object):
an organization, or location. The API associates information, such as
salience and mentions, with entities.
The only supported metadata (as of August 2016) is ``wikipedia_url``,
so this value will be removed from the passed in ``metadata``
and put in its own property.
.. _Entity message: https://cloud.google.com/natural-language/\
reference/rest/v1/Entity
.. _EntityType enum: https://cloud.google.com/natural-language/\
Expand Down Expand Up @@ -84,7 +80,6 @@ class Entity(object):
def __init__(self, name, entity_type, metadata, salience, mentions):
self.name = name
self.entity_type = entity_type
self.wikipedia_url = metadata.pop('wikipedia_url', None)
self.metadata = metadata
self.salience = salience
self.mentions = mentions
Expand Down
68 changes: 68 additions & 0 deletions packages/google-cloud-language/google/cloud/language/sentence.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# Copyright 2017 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.

"""Representation of Sentence objects."""

from google.cloud.language.sentiment import Sentiment


class Sentence(object):
"""A Google Cloud Natural Language API sentence object.
.. _Sentence message: https://cloud.google.com/natural-language/reference\
/rest/v1/documents/annotateText#Sentence
See `Sentence message`_.
:type content: str
:param content: The text that the sentence is composed of.
:type begin: int
:param begin: The beginning offset of the sentence in the original
document according to the encoding type specified
in the API request.
:type sentiment: :class:`~google.cloud.language.sentiment.Sentiment`
:param sentiment:
(Optional) For calls to
:meth:`~google.cloud.language.document.Document.annotate_text` where
``include_sentiment`` is set to true, this field will contain the
sentiment for the sentence.
"""
def __init__(self, content, begin, sentiment=None):
self.content = content
self.begin = begin
self.sentiment = sentiment

@classmethod
def from_api_repr(cls, payload):
"""Convert a sentence from the JSON API into a :class:`Sentence`.
:param payload: dict
:type payload: The value from the backend.
:rtype: :class:`Sentence`
:returns: The sentence parsed from the API representation.
"""
text_span = payload['text']

# The sentence may or may not have a sentiment; only attempt the
# typecast if one is present.
sentiment = None
if payload.get('sentiment') is not None:
sentiment = Sentiment.from_api_repr(payload['sentiment'])

# Return a Sentence object.
return cls(text_span['content'], text_span['beginOffset'],
sentiment=sentiment)
54 changes: 1 addition & 53 deletions packages/google-cloud-language/google/cloud/language/syntax.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright 2016 Google Inc.
# Copyright 2016-2017 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
Expand All @@ -18,8 +18,6 @@
breaks a document down into tokens and sentences.
"""

from google.cloud.language.sentiment import Sentiment


class PartOfSpeech(object):
"""Part of speech of a :class:`Token`."""
Expand Down Expand Up @@ -168,53 +166,3 @@ def from_api_repr(cls, payload):
lemma = payload['lemma']
return cls(text_content, text_begin, part_of_speech,
edge_index, edge_label, lemma)


class Sentence(object):
"""A Google Cloud Natural Language API sentence object.
.. _Sentence message: https://cloud.google.com/natural-language/reference\
/rest/v1/documents/annotateText#Sentence
See `Sentence message`_.
:type content: str
:param content: The text that the sentence is composed of.
:type begin: int
:param begin: The beginning offset of the sentence in the original
document according to the encoding type specified
in the API request.
:type sentiment: :class:`~google.cloud.language.sentiment.Sentiment`
:param sentiment:
(Optional) For calls to
:meth:`~google.cloud.language.document.Document.annotate_text` where
``include_sentiment`` is set to true, this field will contain the
sentiment for the sentence.
"""

def __init__(self, content, begin, sentiment=None):
self.content = content
self.begin = begin
self.sentiment = sentiment

@classmethod
def from_api_repr(cls, payload):
"""Convert a sentence from the JSON API into a :class:`Sentiment`.
:param payload: dict
:type payload: The value from the backend.
:rtype: :class:`Sentence`
:returns: The sentence parsed from the API representation.
"""
text_span = payload['text']

try:
sentiment = Sentiment.from_api_repr(payload['sentiment'])
except KeyError:
sentiment = None

return cls(text_span['content'], text_span['beginOffset'],
sentiment=sentiment)
2 changes: 1 addition & 1 deletion packages/google-cloud-language/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@

setup(
name='google-cloud-language',
version='0.22.2',
version='0.23.0',
description='Python Client for Google Cloud Natural Language',
long_description=README,
namespace_packages=[
Expand Down
Loading

0 comments on commit 77a5d94

Please sign in to comment.