Skip to content

Commit

Permalink
Merge pull request #2798 from jmdobry/language-v1
Browse files Browse the repository at this point in the history
Switch NL from v1beta1 to v1. Fixes #2747.
  • Loading branch information
dhermes authored Dec 3, 2016
2 parents 7c73b58 + f34e0a8 commit a02ac50
Show file tree
Hide file tree
Showing 8 changed files with 185 additions and 33 deletions.
2 changes: 1 addition & 1 deletion language/google/cloud/language/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class Connection(_http.JSONConnection):
API_BASE_URL = 'https://language.googleapis.com'
"""The base of the API call URL."""

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

API_URL_TEMPLATE = '{api_base_url}/{api_version}/documents:{path}'
Expand Down
27 changes: 24 additions & 3 deletions language/google/cloud/language/document.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ def analyze_entities(self):
other properties.
.. _analyzeEntities: https://cloud.google.com/natural-language/\
reference/rest/v1beta1/documents/analyzeEntities
reference/rest/v1/documents/analyzeEntities
See `analyzeEntities`_.
Expand All @@ -176,7 +176,7 @@ def analyze_sentiment(self):
"""Analyze the sentiment in the current document.
.. _analyzeSentiment: https://cloud.google.com/natural-language/\
reference/rest/v1beta1/documents/analyzeSentiment
reference/rest/v1/documents/analyzeSentiment
See `analyzeSentiment`_.
Expand All @@ -188,6 +188,27 @@ def analyze_sentiment(self):
method='POST', path='analyzeSentiment', data=data)
return Sentiment.from_api_repr(api_response['documentSentiment'])

def analyze_syntax(self):
"""Analyze the syntax in the current document.
.. _analyzeSyntax: https://cloud.google.com/natural-language/\
reference/rest/v1/documents/analyzeSyntax
See `analyzeSyntax`_.
:rtype: list
:returns: A list of :class:`~.language.syntax.Token` returned from
the API.
"""
data = {
'document': self._to_dict(),
'encodingType': self.encoding,
}
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', ())]

def annotate_text(self, include_syntax=True, include_entities=True,
include_sentiment=True):
"""Advanced natural language API: document syntax and other features.
Expand All @@ -205,7 +226,7 @@ def annotate_text(self, include_syntax=True, include_entities=True,
learning and need in-depth text features to build upon.
.. _annotateText: https://cloud.google.com/natural-language/\
reference/rest/v1beta1/documents/annotateText
reference/rest/v1/documents/annotateText
See `annotateText`_.
Expand Down
4 changes: 2 additions & 2 deletions language/google/cloud/language/entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,9 @@ class Entity(object):
and put in its own property.
.. _Entity message: https://cloud.google.com/natural-language/\
reference/rest/v1beta1/Entity
reference/rest/v1/Entity
.. _EntityType enum: https://cloud.google.com/natural-language/\
reference/rest/v1beta1/Entity#Type
reference/rest/v1/Entity#Type
See `Entity message`_.
Expand Down
16 changes: 8 additions & 8 deletions language/google/cloud/language/sentiment.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,24 +22,24 @@ class Sentiment(object):
"""A Google Cloud Natural Language API sentiment object.
.. _Sentiment message: https://cloud.google.com/natural-language/\
reference/rest/v1beta1/Sentiment
reference/rest/v1/Sentiment
.. _Sentiment basics: https://cloud.google.com/natural-language/\
docs/basics#sentiment-analysis-values
See `Sentiment message`_ and `Sentiment basics`_.
:type polarity: float
:param polarity: Polarity of the sentiment in the ``[-1.0, 1.0]`` range.
:type score: float
:param score: Score of the sentiment in the ``[-1.0, 1.0]`` range.
Larger numbers represent more positive sentiments.
:type magnitude: float
:param magnitude: A non-negative number in the ``[0, +inf)`` range, which
represents the absolute magnitude of sentiment
regardless of polarity (positive or negative).
regardless of score (positive or negative).
"""

def __init__(self, polarity, magnitude):
self.polarity = polarity
def __init__(self, score, magnitude):
self.score = score
self.magnitude = magnitude

@classmethod
Expand All @@ -52,6 +52,6 @@ def from_api_repr(cls, payload):
:rtype: :class:`Sentiment`
:returns: The sentiment parsed from the API representation.
"""
polarity = payload['polarity']
score = payload['score']
magnitude = payload['magnitude']
return cls(polarity, magnitude)
return cls(score, magnitude)
8 changes: 4 additions & 4 deletions language/google/cloud/language/syntax.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,10 +103,10 @@ class Token(object):
"""A Google Cloud Natural Language API token object.
.. _Token message: https://cloud.google.com/natural-language/reference\
/rest/v1beta1/documents/annotateText#Token
/rest/v1/documents/annotateText#Token
.. _Lemma: https://en.wikipedia.org/wiki/Lemma_(morphology)
.. _Label enum: https://cloud.google.com/natural-language/reference/\
rest/v1beta1/documents/annotateText#Label
rest/v1/documents/annotateText#Label
See `Token message`_.
Expand Down Expand Up @@ -148,7 +148,7 @@ def __init__(self, text_content, text_begin, part_of_speech,

@classmethod
def from_api_repr(cls, payload):
"""Convert a token from the JSON API into a :class:`Sentiment`.
"""Convert a token from the JSON API into a :class:`Token`.
:param payload: dict
:type payload: The value from the backend.
Expand All @@ -172,7 +172,7 @@ class Sentence(object):
"""A Google Cloud Natural Language API sentence object.
.. _Sentence message: https://cloud.google.com/natural-language/reference\
/rest/v1beta1/documents/annotateText#Sentence
/rest/v1/documents/annotateText#Sentence
See `Sentence message`_.
Expand Down
121 changes: 113 additions & 8 deletions language/unit_tests/test_document.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

ANNOTATE_NAME = 'Moon'
ANNOTATE_CONTENT = 'A cow jumped over the %s.' % (ANNOTATE_NAME,)
ANNOTATE_POLARITY = 1
ANNOTATE_SCORE = 1
ANNOTATE_MAGNITUDE = 0.2
ANNOTATE_SALIENCE = 0.11793101
ANNOTATE_WIKI_URL = 'http://en.wikipedia.org/wiki/Natural_satellite'
Expand Down Expand Up @@ -286,20 +286,20 @@ def test_analyze_entities(self):
client._connection.api_request.assert_called_once_with(
path='analyzeEntities', method='POST', data=expected)

def _verify_sentiment(self, sentiment, polarity, magnitude):
def _verify_sentiment(self, sentiment, score, magnitude):
from google.cloud.language.sentiment import Sentiment

self.assertIsInstance(sentiment, Sentiment)
self.assertEqual(sentiment.polarity, polarity)
self.assertEqual(sentiment.score, score)
self.assertEqual(sentiment.magnitude, magnitude)

def test_analyze_sentiment(self):
content = 'All the pretty horses.'
polarity = 1
score = 1
magnitude = 0.6
response = {
'documentSentiment': {
'polarity': polarity,
'score': score,
'magnitude': magnitude,
},
'language': 'en-US',
Expand All @@ -308,13 +308,118 @@ def test_analyze_sentiment(self):
document = self._make_one(client, content)

sentiment = document.analyze_sentiment()
self._verify_sentiment(sentiment, polarity, magnitude)
self._verify_sentiment(sentiment, score, magnitude)

# Verify the request.
expected = self._expected_data(content)
client._connection.api_request.assert_called_once_with(
path='analyzeSentiment', method='POST', data=expected)

def _verify_token(self, token, text_content, part_of_speech, lemma):
from google.cloud.language.syntax import Token

self.assertIsInstance(token, Token)
self.assertEqual(token.text_content, text_content)
self.assertEqual(token.part_of_speech, part_of_speech)
self.assertEqual(token.lemma, lemma)

def test_analyze_syntax(self):
from google.cloud.language.document import Encoding
from google.cloud.language.syntax import PartOfSpeech

name1 = 'R-O-C-K'
name2 = 'USA'
content = name1 + ' in the ' + name2
response = {
'sentences': [
{
'text': {
'content': 'R-O-C-K in the USA',
'beginOffset': -1,
},
'sentiment': None,
}
],
'tokens': [
{
'text': {
'content': 'R-O-C-K',
'beginOffset': -1,
},
'partOfSpeech': {
'tag': 'NOUN',
},
'dependencyEdge': {
'headTokenIndex': 0,
'label': 'ROOT',
},
'lemma': 'R-O-C-K',
},
{
'text': {
'content': 'in',
'beginOffset': -1,
},
'partOfSpeech': {
'tag': 'ADP',
},
'dependencyEdge': {
'headTokenIndex': 0,
'label': 'PREP',
},
'lemma': 'in',
},
{
'text': {
'content': 'the',
'beginOffset': -1,
},
'partOfSpeech': {
'tag': 'DET',
},
'dependencyEdge': {
'headTokenIndex': 3,
'label': 'DET',
},
'lemma': 'the',
},
{
'text': {
'content': 'USA',
'beginOffset': -1,
},
'partOfSpeech': {
'tag': 'NOUN',
},
'dependencyEdge': {
'headTokenIndex': 1,
'label': 'POBJ',
},
'lemma': 'USA',
},
],
'language': 'en-US',
}
client = make_mock_client(response)
document = self._make_one(client, content)

tokens = document.analyze_syntax()
self.assertEqual(len(tokens), 4)
token1 = tokens[0]
self._verify_token(token1, name1, PartOfSpeech.NOUN, name1)
token2 = tokens[1]
self._verify_token(token2, 'in', PartOfSpeech.ADPOSITION, 'in')
token3 = tokens[2]
self._verify_token(token3, 'the', PartOfSpeech.DETERMINER, 'the')
token4 = tokens[3]
self._verify_token(token4, name2, PartOfSpeech.NOUN, name2)

# Verify the request.
expected = self._expected_data(
content, encoding_type=Encoding.UTF8)
client._connection.api_request.assert_called_once_with(
path='analyzeSyntax', method='POST', data=expected)

def _verify_sentences(self, include_syntax, annotations):
from google.cloud.language.syntax import Sentence

Expand Down Expand Up @@ -357,7 +462,7 @@ def _annotate_text_helper(self, include_sentiment,
}
if include_sentiment:
response['documentSentiment'] = {
'polarity': ANNOTATE_POLARITY,
'score': ANNOTATE_SCORE,
'magnitude': ANNOTATE_MAGNITUDE,
}

Expand All @@ -375,7 +480,7 @@ def _annotate_text_helper(self, include_sentiment,
# Sentiment
if include_sentiment:
self._verify_sentiment(annotations.sentiment,
ANNOTATE_POLARITY, ANNOTATE_MAGNITUDE)
ANNOTATE_SCORE, ANNOTATE_MAGNITUDE)
else:
self.assertIsNone(annotations.sentiment)
# Entity
Expand Down
12 changes: 6 additions & 6 deletions language/unit_tests/test_sentiment.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,20 @@ def _make_one(self, *args, **kw):
return self._get_target_class()(*args, **kw)

def test_constructor(self):
polarity = 1
score = 1
magnitude = 2.3
sentiment = self._make_one(polarity, magnitude)
self.assertEqual(sentiment.polarity, polarity)
sentiment = self._make_one(score, magnitude)
self.assertEqual(sentiment.score, score)
self.assertEqual(sentiment.magnitude, magnitude)

def test_from_api_repr(self):
klass = self._get_target_class()
polarity = -1
score = -1
magnitude = 5.55
payload = {
'polarity': polarity,
'score': score,
'magnitude': magnitude,
}
sentiment = klass.from_api_repr(payload)
self.assertEqual(sentiment.polarity, polarity)
self.assertEqual(sentiment.score, score)
self.assertEqual(sentiment.magnitude, magnitude)
28 changes: 27 additions & 1 deletion system_tests/language.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,5 +121,31 @@ def test_analyze_sentiment(self):
positive_msg = 'Jogging is fun'
document = Config.CLIENT.document_from_text(positive_msg)
sentiment = document.analyze_sentiment()
self.assertEqual(sentiment.polarity, 1)
self.assertEqual(sentiment.score, 0.5)
self.assertTrue(0.0 < sentiment.magnitude < 1.5)

def _verify_token(self, token, text_content, part_of_speech, lemma):
from google.cloud.language.syntax import Token

self.assertIsInstance(token, Token)
self.assertEqual(token.text_content, text_content)
self.assertEqual(token.part_of_speech, part_of_speech)
self.assertEqual(token.lemma, lemma)

def _check_analyze_syntax_result(self, tokens):
from google.cloud.language.syntax import PartOfSpeech

self.assertEqual(len(tokens), 3)
token1, token2, token3 = tokens
# Verify token 1.
self._verify_token(token1, 'Jogging', PartOfSpeech.NOUN, 'Jogging')
# Verify token 2.
self._verify_token(token2, 'is', PartOfSpeech.VERB, 'be')
# Verify token 3.
self._verify_token(token3, 'fun', PartOfSpeech.ADJECTIVE, 'fun')

def test_analyze_syntax(self):
positive_msg = 'Jogging is fun'
document = Config.CLIENT.document_from_text(positive_msg)
tokens = document.analyze_syntax()
self._check_analyze_syntax_result(tokens)

0 comments on commit a02ac50

Please sign in to comment.