Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 90 additions & 5 deletions language/google/cloud/language/syntax.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -20,7 +20,62 @@


class PartOfSpeech(object):
"""Part of speech of a :class:`Token`."""
"""A Google Cloud Natural Language API Part of speech object.

These are the grammatical categories of the matched token in
the sentence. https://cloud.google.com/natural-language/docs\
/reference/rest/v1/Token#PartOfSpeech

:type aspect: str
:param aspect: The grammatical aspect. https://cloud.google\
.com/natural-language/docs/reference/rest/v1/\
Token#Aspect

:type reciprocity: str
:param reciprocity: The grammatical reciprocity. https://\
cloud.google.com/natural-language/docs/reference\
/rest/v1/Token#Reciprocity

:type case: str
:param case: The grammatical case. https://cloud.google.com/\
natural-language/docs/reference/rest/v1/Token#Case

:type mood: str
:param mood: The grammatical mood. https://cloud.google.com/\
natural-language/docs/reference/rest/v1/Token#Mood

:type tag: str
:param tag: The part of speech tag. https://cloud.google.com/natural\
-language/docs/reference/rest/v1/Token#Tag

:type person: str
:param person: The grammatical person. https://cloud.google.com/\
natural-language/docs/reference/rest/v1/Token#Person

:type number: str
:param number: The grammatical number. https://cloud.google.com/natural\
-language/docs/reference/rest/v1/Token#Number

:type tense: str
:param tense: The grammatical tense. https://cloud.google.com/natural\
-language/docs/reference/rest/v1/Token#Tense

:type form: str
:param form: The grammatical form. https://cloud.google.com/natural\
-language/docs/reference/rest/v1/Token#Form

:type proper: str
:param proper: The grammatical properness. https://cloud.google.com/\
natural-language/docs/reference/rest/v1/Token#Proper

:type voice: str
:param voice: The grammatical voice. https://cloud.google.com/\
natural-language/docs/reference/rest/v1/Token#Voice

:type gender: str
:param gender: The grammatical gender. https://cloud.google.com/\
natural-language/docs/reference/rest/v1/Token#Gender
"""

UNKNOWN = 'UNKNOWN'
"""Unknown part of speech."""
Expand DownExpand Up@@ -81,6 +136,36 @@ class PartOfSpeech(object):
'AFFIX': 'AFFIX',
}

def __init__(self, aspect, reciprocity, case, mood, tag, person,
number, tense, form, proper, voice, gender):
self.aspect = aspect
self.reciprocity = reciprocity
self.case = case
self.mood = mood
self.tag = tag
self.person = person
self.number = number
self.tense = tense
self.form = form
self.proper = proper
self.voice = voice
self.gender = gender

@classmethod
def from_api_repr(cls, payload):
return PartOfSpeech(aspect=payload['aspect'],
reciprocity=payload['reciprocity'],
case=payload['case'],
mood=payload['mood'],
tag=payload['tag'],
person=payload['person'],
number=payload['number'],
tense=payload['tense'],
form=payload['form'],
proper=payload['proper'],
voice=payload['voice'],
gender=payload['gender'])

@classmethod
def reverse(cls, tag):
"""Reverses the API's enum name for the one on this class.
Expand DownExpand Up@@ -118,9 +203,9 @@ class Token(object):
document according to the encoding type specified
in the API request.

:type part_of_speech: str
:param part_of_speech: The part of speech of the token. See
:class:`PartOfSpeech` for possible values.
:type part_of_speech: PartOfSpeech
:param part_of_speech: An object representing the Part of Speech of the
token with it's properties.

:type edge_index: int
:param edge_index: The head of this token in the dependency tree. This is
Expand DownExpand Up@@ -159,7 +244,7 @@ def from_api_repr(cls, payload):
text_span = payload['text']
text_content = text_span['content']
text_begin = text_span['beginOffset']
part_of_speech = payload['partOfSpeech']['tag']
part_of_speech = PartOfSpeech.from_api_repr(payload['partOfSpeech'])
edge = payload['dependencyEdge']
edge_index = edge['headTokenIndex']
edge_label = edge['label']
Expand Down
39 changes: 36 additions & 3 deletions language/tests/unit/test_api_responses.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -115,14 +115,37 @@ def _verify_sentiment_response(self, sentiment_response):

class TestSyntaxResponse(unittest.TestCase):
SENTENCE_DICT = copy(TestSentimentResponse.SENTENCE_DICT)
aspect = 'ASPECT_UNKNOWN'
reciprocity = 'RECIPROCITY_UNKNOWN'
case = 'NOMINATIVE'
mood = 'MOOD_UNKNOWN'
tag = 'PRON'
person = 'FIRST'
number = 'SINGULAR'
tense = 'TENSE_UNKNOWN'
form = 'FORM_UNKNOWN'
proper = 'PROPER_UNKNOWN'
voice = 'VOICE_UNKNOWN'
gender = 'GENDER_UNKNOWN'
TOKEN_DICT = {
'dependencyEdge': {
'headTokenIndex': 0,
'label': 'NSUBJ',
},
'lemma': 'it',
'partOfSpeech': {
'tag': 'PRON',
'aspect': aspect,
'reciprocity': reciprocity,
'case': case,
'mood': mood,
'tag': tag,
'person': person,
'number': number,
'tense': tense,
'form': form,
'proper': proper,
'voice': voice,
'gender': gender
},
'text': {
'beginOffset': 0,
Expand DownExpand Up@@ -156,7 +179,6 @@ def test_api_repr_factory(self):

def _verify_syntax_response(self, syntax_response):
from google.cloud.language.sentiment import Sentiment
from google.cloud.language.syntax import PartOfSpeech

self.assertEqual(syntax_response.language, 'en')

Expand All@@ -169,7 +191,18 @@ def _verify_syntax_response(self, syntax_response):
token = syntax_response.tokens[0]
self.assertEqual(token.text_content, 'It')
self.assertEqual(token.text_begin, 0)
self.assertEqual(token.part_of_speech, PartOfSpeech.PRONOUN)
self.assertEqual(token.part_of_speech.aspect, 'ASPECT_UNKNOWN')
self.assertEqual(token.part_of_speech.reciprocity, 'RECIPROCITY_UNKNOWN')
self.assertEqual(token.part_of_speech.case, 'NOMINATIVE')
self.assertEqual(token.part_of_speech.mood, 'MOOD_UNKNOWN')
self.assertEqual(token.part_of_speech.tag, 'PRON')
self.assertEqual(token.part_of_speech.person, 'FIRST')
self.assertEqual(token.part_of_speech.number, 'SINGULAR')
self.assertEqual(token.part_of_speech.tense, 'TENSE_UNKNOWN')
self.assertEqual(token.part_of_speech.form, 'FORM_UNKNOWN')
self.assertEqual(token.part_of_speech.proper, 'PROPER_UNKNOWN')
self.assertEqual(token.part_of_speech.voice, 'VOICE_UNKNOWN')
self.assertEqual(token.part_of_speech.gender, 'GENDER_UNKNOWN')
self.assertEqual(token.edge_index, 0)
self.assertEqual(token.edge_label, 'NSUBJ')
self.assertEqual(token.lemma, 'it')
67 changes: 61 additions & 6 deletions language/tests/unit/test_document.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -14,7 +14,6 @@

import unittest


ANNOTATE_NAME = 'Moon'
ANNOTATE_CONTENT = 'A cow jumped over the %s.' % (ANNOTATE_NAME,)
ANNOTATE_SCORE = 1
Expand All@@ -29,7 +28,20 @@ def _make_token_json(name, part_of_speech, head, edge_label):
'content': name,
'beginOffset': -1,
},
'partOfSpeech': {'tag': part_of_speech},
'partOfSpeech': {
'aspect': 'ASPECT_UNKNOWN',
'reciprocity': 'RECIPROCITY_UNKNOWN',
'case': 'NOMINATIVE',
'mood': 'MOOD_UNKNOWN',
'tag': part_of_speech,
'person': 'FIRST',
'number': 'SINGULAR',
'tense': 'TENSE_UNKNOWN',
'form': 'FORM_UNKNOWN',
'proper': 'PROPER_UNKNOWN',
'voice': 'VOICE_UNKNOWN',
'gender': 'GENDER_UNKNOWN',
},
'dependencyEdge': {
'headTokenIndex': head,
'label': edge_label,
Expand DownExpand Up@@ -120,7 +132,6 @@ def test_default_low_maxunicode(self):


class TestDocument(unittest.TestCase):

@staticmethod
def _get_target_class():
from google.cloud.language.document import Document
Expand DownExpand Up@@ -424,12 +435,12 @@ def test_analyze_sentiment(self):
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):
def _verify_token(self, token, text_content, part_of_speech_tag, 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.part_of_speech.tag, part_of_speech_tag)
self.assertEqual(token.lemma, lemma)

def test_analyze_syntax(self):
Expand DownExpand Up@@ -457,7 +468,18 @@ def test_analyze_syntax(self):
'beginOffset': -1,
},
'partOfSpeech': {
'aspect': 'ASPECT_UNKNOWN',
'reciprocity': 'RECIPROCITY_UNKNOWN',
'case': 'CASE_UNKNOWN',
'mood': 'MOOD_UNKNOWN',
'tag': 'NOUN',
'person': 'PERSON_UNKNOWN',
'number': 'SINGULAR',
'tense': 'TENSE_UNKNOWN',
'form': 'FORM_UNKNOWN',
'proper': 'PROPER',
'voice': 'VOICE_UNKNOWN',
'gender': 'GENDER_UNKNOWN'
},
'dependencyEdge': {
'headTokenIndex': 0,
Expand All@@ -471,7 +493,18 @@ def test_analyze_syntax(self):
'beginOffset': -1,
},
'partOfSpeech': {
'aspect': 'ASPECT_UNKNOWN',
'reciprocity': 'RECIPROCITY_UNKNOWN',
'case': 'CASE_UNKNOWN',
'mood': 'MOOD_UNKNOWN',
'tag': 'ADP',
'person': 'PERSON_UNKNOWN',
'number': 'NUMBER_UNKNOWN',
'tense': 'TENSE_UNKNOWN',
'form': 'FORM_UNKNOWN',
'proper': 'PROPER_UNKNOWN',
'voice': 'VOICE_UNKNOWN',
'gender': 'GENDER_UNKNOWN'
},
'dependencyEdge': {
'headTokenIndex': 0,
Expand All@@ -485,7 +518,18 @@ def test_analyze_syntax(self):
'beginOffset': -1,
},
'partOfSpeech': {
'aspect': 'ASPECT_UNKNOWN',
'reciprocity': 'RECIPROCITY_UNKNOWN',
'case': 'CASE_UNKNOWN',
'mood': 'MOOD_UNKNOWN',
'tag': 'DET',
'person': 'PERSON_UNKNOWN',
'number': 'NUMBER_UNKNOWN',
'tense': 'TENSE_UNKNOWN',
'form': 'FORM_UNKNOWN',
'proper': 'PROPER_UNKNOWN',
'voice': 'VOICE_UNKNOWN',
'gender': 'GENDER_UNKNOWN'
},
'dependencyEdge': {
'headTokenIndex': 3,
Expand All@@ -499,7 +543,18 @@ def test_analyze_syntax(self):
'beginOffset': -1,
},
'partOfSpeech': {
'aspect': 'ASPECT_UNKNOWN',
'reciprocity': 'RECIPROCITY_UNKNOWN',
'case': 'CASE_UNKNOWN',
'mood': 'MOOD_UNKNOWN',
'tag': 'NOUN',
'person': 'PERSON_UNKNOWN',
'number': 'SINGULAR',
'tense': 'TENSE_UNKNOWN',
'form': 'FORM_UNKNOWN',
'proper': 'PROPER',
'voice': 'VOICE_UNKNOWN',
'gender': 'GENDER_UNKNOWN'
},
'dependencyEdge': {
'headTokenIndex': 1,
Expand DownExpand Up@@ -553,7 +608,7 @@ def _verify_tokens(self, annotations, token_info):
self.assertIsInstance(token, Token)
self.assertEqual(token.text_content, info[0])
self.assertEqual(token.text_begin, -1)
self.assertEqual(token.part_of_speech, info[1])
self.assertEqual(token.part_of_speech.tag, info[1])
self.assertEqual(token.edge_index, info[2])
self.assertEqual(token.edge_label, info[3])
self.assertEqual(token.lemma, info[0])
Expand Down
Loading