Skip to content

Commit bba3c86

Browse files
lukesneeringerdhermes
authored andcommitted
Send back the complete API responses. (#3059)
* 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.
1 parent 4d2b91d commit bba3c86

File tree

14 files changed

+516
-178
lines changed

14 files changed

+516
-178
lines changed

docs/language-responses.rst

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,20 @@
11
Natural Language Response Classes
22
=================================
33

4+
Responses
5+
~~~~~~~~~
6+
7+
.. automodule:: google.cloud.language.api_responses
8+
:members:
9+
:show-inheritance:
10+
11+
Sentences
12+
~~~~~~~~~
13+
14+
.. automodule:: google.cloud.language.sentence
15+
:members:
16+
:show-inheritance:
17+
418
Entity
519
~~~~~~
620

docs/language-usage.rst

Lines changed: 10 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -78,15 +78,8 @@ the document's type is plain text:
7878
>>> document.doc_type == language.Document.PLAIN_TEXT
7979
True
8080
81-
In addition, the document's language defaults to the language on
82-
the client
83-
84-
.. code-block:: python
85-
86-
>>> document.language
87-
'en-US'
88-
>>> document.language == client.language
89-
True
81+
The document's language defaults to ``None``, which will cause the API to
82+
auto-detect the language.
9083

9184
In addition, the
9285
:meth:`~google.cloud.language.client.Client.document_from_html`,
@@ -161,31 +154,27 @@ metadata and other properties.
161154
>>> text_content = ("Michelangelo Caravaggio, Italian painter, is "
162155
... "known for 'The Calling of Saint Matthew'.")
163156
>>> document = client.document(text_content)
164-
>>> entities = document.analyze_entities()
165-
>>> for entity in entities:
157+
>>> entity_response = document.analyze_entities()
158+
>>> for entity in entity_response.entities:
166159
... print('=' * 20)
167160
... print(' name: %s' % (entity.name,))
168161
... print(' type: %s' % (entity.entity_type,))
169-
... print('wikipedia_url: %s' % (entity.wikipedia_url,))
170162
... print(' metadata: %s' % (entity.metadata,))
171163
... print(' salience: %s' % (entity.salience,))
172164
====================
173165
name: Michelangelo Caravaggio
174166
type: PERSON
175-
wikipedia_url: http://en.wikipedia.org/wiki/Caravaggio
176-
metadata: {}
167+
metadata: {'wikipedia_url': 'http://en.wikipedia.org/wiki/Caravaggio'}
177168
salience: 0.7615959
178169
====================
179170
name: Italian
180171
type: LOCATION
181-
wikipedia_url: http://en.wikipedia.org/wiki/Italy
182-
metadata: {}
172+
metadata: {'wikipedia_url': 'http://en.wikipedia.org/wiki/Caravaggio'}
183173
salience: 0.19960518
184174
====================
185175
name: The Calling of Saint Matthew
186176
type: EVENT
187-
wikipedia_url: http://en.wikipedia.org/wiki/The_Calling_of_St_Matthew_(Caravaggio)
188-
metadata: {}
177+
metadata: {'wikipedia_url': 'http://en.wikipedia.org/wiki/Caravaggio'}
189178
salience: 0.038798928
190179
191180
Analyze Sentiment
@@ -200,7 +189,8 @@ only supports English text.
200189
201190
>>> text_content = "Jogging isn't very fun."
202191
>>> document = client.document(text_content)
203-
>>> sentiment = document.analyze_sentiment()
192+
>>> sentiment_response = document.analyze_sentiment()
193+
>>> sentiment = sentiment_response.sentiment
204194
>>> print(sentiment.score)
205195
-1
206196
>>> print(sentiment.magnitude)
@@ -265,14 +255,12 @@ the response is :data:`None`.
265255
... print('=' * 20)
266256
... print(' name: %s' % (entity.name,))
267257
... print(' type: %s' % (entity.entity_type,))
268-
... print('wikipedia_url: %s' % (entity.wikipedia_url,))
269258
... print(' metadata: %s' % (entity.metadata,))
270259
... print(' salience: %s' % (entity.salience,))
271260
====================
272261
name: Moon
273262
type: LOCATION
274-
wikipedia_url: http://en.wikipedia.org/wiki/Natural_satellite
275-
metadata: {}
263+
metadata: {'wikipedia_url': 'http://en.wikipedia.org/wiki/Natural_satellite'}
276264
salience: 0.11793101
277265
278266
.. _Features: https://cloud.google.com/natural-language/reference/rest/v1beta1/documents/annotateText#Features
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
# Copyright 2017 Google Inc.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
"""Response types from the Natural Language API."""
16+
17+
from google.cloud.language.entity import Entity
18+
from google.cloud.language.sentence import Sentence
19+
from google.cloud.language.sentiment import Sentiment
20+
from google.cloud.language.syntax import Token
21+
22+
23+
class EntityResponse(object):
24+
"""Object representation of entity responses.
25+
26+
A representation of a response sent back from the
27+
``analyzeEntites`` request to the Google Natural language API.
28+
29+
:type entities: list
30+
:param entities: A list of :class:`~.language.entity.Entity` objects.
31+
32+
:type language: str
33+
:param language: The language used for analysis.
34+
"""
35+
def __init__(self, entities, language):
36+
self.entities = entities
37+
self.language = language
38+
39+
@classmethod
40+
def from_api_repr(cls, payload):
41+
"""Return an entity response from a JSON representation.
42+
43+
:type payload: dict
44+
:param payload: A dictionary representing the response.
45+
46+
:rtype: :class:`~.language.entity.Entity`
47+
:returns: An ``Entity`` object.
48+
"""
49+
return cls(
50+
entities=[Entity.from_api_repr(i) for i in payload['entities']],
51+
language=payload['language'],
52+
)
53+
54+
55+
class SentimentResponse(object):
56+
"""Object representation of sentiment responses.
57+
58+
A representation of a response to an ``analyzeSentiment`` request
59+
to the Google Natural Language API.
60+
61+
:type sentiment: :class:`~.language.sentiment.Sentiment`
62+
:param sentiment: A Sentiment object.
63+
64+
:type language: str
65+
:param language: The language used for analyzing sentiment.
66+
67+
:type sentences: list
68+
:param sentences: A list of :class:`~.language.syntax.Sentence` objects.
69+
"""
70+
def __init__(self, sentiment, language, sentences):
71+
self.sentiment = sentiment
72+
self.language = language
73+
self.sentences = sentences
74+
75+
@classmethod
76+
def from_api_repr(cls, payload):
77+
"""Return an sentiment response from a JSON representation.
78+
79+
:type payload: dict
80+
:param payload: A dictionary representing the response.
81+
82+
:rtype: `~.language.sentiment.Sentiment`
83+
:returns: A ``Sentiment`` object.
84+
"""
85+
return cls(
86+
language=payload.get('language'),
87+
sentences=[Sentence.from_api_repr(sentence) for sentence
88+
in payload.get('sentences', ())],
89+
sentiment=Sentiment.from_api_repr(payload['documentSentiment']),
90+
)
91+
92+
93+
class SyntaxResponse(object):
94+
"""Object representation of syntax responses.
95+
96+
A representation of a response to an ``analyzeSyntax`` request
97+
to the Google Natural Language API.
98+
99+
:type tokens: list
100+
:param tokens: A list of :class:`~.language.syntax.Token` objects.
101+
102+
:type language: str
103+
:param language: The language used for analyzing sentiment.
104+
105+
:type sentences: list
106+
:param sentences: A list of :class:`~.language.syntax.Sentence` objects.
107+
"""
108+
def __init__(self, tokens, language, sentences):
109+
self.tokens = tokens
110+
self.language = language
111+
self.sentences = sentences
112+
113+
@classmethod
114+
def from_api_repr(cls, payload):
115+
"""Return an syntax response from a JSON representation.
116+
117+
:type payload: dict
118+
:param payload: A dictionary representing the response.
119+
120+
:rtype: `~.language.syntax.Syntax`
121+
:returns: A ``Syntax`` object.
122+
"""
123+
return cls(
124+
language=payload.get('language'),
125+
sentences=[Sentence.from_api_repr(sentence) for sentence in
126+
payload.get('sentences', ())],
127+
tokens=[Token.from_api_repr(token) for token in
128+
payload.get('tokens', ())]
129+
)

language/google/cloud/language/document.py

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2016 Google Inc.
1+
# Copyright 2016-2017 Google Inc.
22
#
33
# Licensed under the Apache License, Version 2.0 (the "License");
44
# you may not use this file except in compliance with the License.
@@ -19,15 +19,16 @@
1919

2020
import collections
2121

22+
from google.cloud.language import api_responses
2223
from google.cloud.language.entity import Entity
2324
from google.cloud.language.sentiment import Sentiment
24-
from google.cloud.language.syntax import Sentence
25+
from google.cloud.language.sentence import Sentence
2526
from google.cloud.language.syntax import Token
2627

2728

2829
Annotations = collections.namedtuple(
2930
'Annotations',
30-
'sentences tokens sentiment entities')
31+
['sentences', 'tokens', 'sentiment', 'entities', 'language'])
3132
"""Annotations for a document.
3233
3334
:type sentences: list
@@ -42,6 +43,9 @@
4243
:type entities: list
4344
:param entities: List of :class:`~.language.entity.Entity`
4445
found in a document.
46+
47+
:type language: str
48+
:param language: The language used for the annotation.
4549
"""
4650

4751

@@ -156,18 +160,16 @@ def analyze_entities(self):
156160
157161
See `analyzeEntities`_.
158162
159-
:rtype: list
160-
:returns: A list of :class:`~.language.entity.Entity` returned from
161-
the API.
163+
:rtype: :class:`~.language.entity.EntityResponse`
164+
:returns: A representation of the entity response.
162165
"""
163166
data = {
164167
'document': self._to_dict(),
165168
'encodingType': self.encoding,
166169
}
167170
api_response = self.client._connection.api_request(
168171
method='POST', path='analyzeEntities', data=data)
169-
return [Entity.from_api_repr(entity)
170-
for entity in api_response['entities']]
172+
return api_responses.EntityResponse.from_api_repr(api_response)
171173

172174
def analyze_sentiment(self):
173175
"""Analyze the sentiment in the current document.
@@ -177,13 +179,13 @@ def analyze_sentiment(self):
177179
178180
See `analyzeSentiment`_.
179181
180-
:rtype: :class:`.Sentiment`
181-
:returns: The sentiment of the current document.
182+
:rtype: :class:`.SentimentResponse`
183+
:returns: A representation of the sentiment response.
182184
"""
183185
data = {'document': self._to_dict()}
184186
api_response = self.client._connection.api_request(
185187
method='POST', path='analyzeSentiment', data=data)
186-
return Sentiment.from_api_repr(api_response['documentSentiment'])
188+
return api_responses.SentimentResponse.from_api_repr(api_response)
187189

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

209210
def annotate_text(self, include_syntax=True, include_entities=True,
210211
include_sentiment=True):
@@ -271,9 +272,10 @@ def annotate_text(self, include_syntax=True, include_entities=True,
271272
entities = [Entity.from_api_repr(entity)
272273
for entity in api_response['entities']]
273274
annotations = Annotations(
275+
entities=entities,
276+
language=api_response.get('language'),
274277
sentences=sentences,
275-
tokens=tokens,
276278
sentiment=sentiment,
277-
entities=entities,
279+
tokens=tokens,
278280
)
279281
return annotations

language/google/cloud/language/entity.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2016 Google Inc.
1+
# Copyright 2016-2017 Google Inc.
22
#
33
# Licensed under the Apache License, Version 2.0 (the "License");
44
# you may not use this file except in compliance with the License.
@@ -53,10 +53,6 @@ class Entity(object):
5353
an organization, or location. The API associates information, such as
5454
salience and mentions, with entities.
5555
56-
The only supported metadata (as of August 2016) is ``wikipedia_url``,
57-
so this value will be removed from the passed in ``metadata``
58-
and put in its own property.
59-
6056
.. _Entity message: https://cloud.google.com/natural-language/\
6157
reference/rest/v1/Entity
6258
.. _EntityType enum: https://cloud.google.com/natural-language/\
@@ -84,7 +80,6 @@ class Entity(object):
8480
def __init__(self, name, entity_type, metadata, salience, mentions):
8581
self.name = name
8682
self.entity_type = entity_type
87-
self.wikipedia_url = metadata.pop('wikipedia_url', None)
8883
self.metadata = metadata
8984
self.salience = salience
9085
self.mentions = mentions

0 commit comments

Comments
 (0)