Learn Python the Hard Way: Exercise 48 - AttributeError - python

I have been attempting to work my way through Learn Python the Hard Way, and on Exercise 48 I continue to get an error when I run nosetests. I am using code that other people have verified on the site to work, but no matter what I continue to get this error:
======================================================================
ERROR: tests.ex48_tests.test_directions
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/nose/case.py", line 197, in runTest
self.test(*self.arg)
File "/Users/AlexanderMariona/Documents/Home/Programming/Python/Projects/Exercise 48/tests/ex48_tests.py", line 6, in test_directions
assert_equal(lexicon.scan("north"), [('direction', 'north')])
AttributeError: 'module' object has no attribute 'scan'
I get this error 6 times, one for each of my test functions.
Here is what I'm using for my code:
lexicon.py:
class Lexicon(object):
directions = ['north', 'south', 'east', 'west', 'down', 'up', 'down', 'right']
verbs = ['go', 'stop', 'kill', 'eat']
stops = ['the', 'in', 'at', 'of', 'from', 'at', 'it']
nouns = ['door', 'bear', 'princess', 'cabinet']
def scan(thewords):
thewords = thewords.split()
sentence = []
for i in thewords:
if i in directions:
sentence.append(('direction', i))
elif i in verbs:
sentence.append(('verb', i))
elif i in stops:
sentence.append(('stop', i))
elif i in nouns:
sentence.append(('noun', i))
elif i.isdigit():
sentence.append(('number', convert_number(i)))
else:
sentence.append(('error', i))
return sentence
def convert_number(s):
try:
return int(s)
except ValueError:
return None
lexicon = Lexicon()
(This was written by Dairylee.)
ex48_tests.py:
from nose.tools import *
from ex48 import lexicon
def test_directions():
assert_equal(lexicon.scan("north"), [('direction', 'north')])
result = lexicon.scan("north south east")
assert_equal(result, [('direction', 'north'),
('direction', 'south'),
('direction', 'east')])
def test_verbs():
assert_equal(lexicon.scan("go"), [('verb', 'go')])
result = lexicon.scan("go kill eat")
assert_equal(result, [('verb', 'go'),
('verb', 'kill'),
('verb', 'eat')])
def test_stops():
assert_equal(lexicon.scan("the"), [('stop', 'the')])
result = lexicon.scan("the in of")
assert_equal(result, [('stop', 'the'),
('stop', 'in'),
('stop', 'of')])
def test_nouns():
assert_equal(lexicon.scan("bear"), [('noun', 'bear')])
result = lexicon.scan("bear princess")
assert_equal(result, [('noun', 'bear'),
('noun', 'princess')])
def test_numbers():
assert_equal(lexicon.scan("1234"), [('number', 1234)])
result = lexicon.scan("3 91234")
assert_equal(result, [('number', 3),
('number', 91234)])
def test_errors():
assert_equal(lexicon.scan("ASDFADFASDF"), [('error', 'ASDFADFASDF')])
result = lexicon.scan("bear IAS princess")
assert_equal(result, [('noun', 'bear'),
('error', 'IAS'),
('noun', 'princess')])
(This is copied verbatim from LPTHW.)
setup.py:
try:
from setuptools import setup
except ImportError:
from distutils.core import setup
config = {
'name': 'Excercise 48',
'description': 'LPTHW',
'version': '0.1',
'author': 'My Name',
'author_email': 'My E-Mail',
'url': 'None',
'download_url': 'None',
'packages': ['ex48'],
'scripts': [],
'install_requires': ['nose']
}
setup(**config)
And here is the directory of the package:
Exercise 48/
bin/
docs/
ex48/
__init__.py
lexicon.py
setup.py
tests/
__init__.py
ex48_tests.py
What exactly is causing this error?

This error happens because there's no function scan in the module lexicon. There's a method in the class Lexicon, then it should be called like a method (note that self argument is missing).
On the other hand, Lexicon does not have to exist as a class at all, scan can be a module-level function.

Related

During debugging of python code how can we see the values of variables in python classes

This is my code:
class starter:
def __init__(self, file_name):
self.__table_name = file_name
self.__path = dirname(dirname(realpath(__file__)))
self.__file_config.log['Folder'] = self.__path+self.__file_config.log['Folder']
self.__logging = self.__file_config.log
def start_script(self,fl_name):
try:
self.__logging.info("Script Started")
if __name__ == '__main__':
try:
if not (starter("samplefile").start_script(str(os.path.basename(__file__)))):
raise Exception ('error')
except Exception as e:
print(e)
When debugging the start_script function, I want to check the value of self.__logging.
Can someone help me with this.
you can use p self._starter__logging.info
-> self.start_script("args")
(Pdb) p self._starter__logging
__variable name is user defined private variable
example:-
class Box:
... var=10
...
dir(Box)
['_Box__var', '__class', 'delattr', 'dict', 'dir', 'doc', 'eq', 'fo
rmat', 'ge', 'getattribute', 'gt', 'hash', 'init', 'init_subclass
', 'le', 'lt', 'module', 'ne', 'new', 'reduce', 'reduce_ex', '_
_repr__', 'setattr', 'sizeof', 'str', 'subclasshook', 'weakref']
dir(Box)[0]
'_Box__var'

Lemmatize string according to pos nlp

I'm trying to lemmatize a string according to the part of speech but at the final stage, i'm getting an error. My code:
import nltk
from nltk.stem import *
from nltk.tokenize import sent_tokenize, word_tokenize
from nltk.corpus import wordnet
wordnet_lemmatizer = WordNetLemmatizer()
text = word_tokenize('People who help the blinging lights are the way of the future and are heading properly to their goals')
tagged = nltk.pos_tag(text)
def get_wordnet_pos(treebank_tag):
if treebank_tag.startswith('J'):
return wordnet.ADJ
elif treebank_tag.startswith('V'):
return wordnet.VERB
elif treebank_tag.startswith('N'):
return wordnet.NOUN
elif treebank_tag.startswith('R'):
return wordnet.ADV
else:
return ''
for word in tagged: print(wordnet_lemmatizer.lemmatize(word,pos='v'), end=" ")
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-40-afb22c78f770> in <module>()
----> 1 for word in tagged: print(wordnet_lemmatizer.lemmatize(word,pos='v'), end=" ")
E:\Miniconda3\envs\uol1\lib\site-packages\nltk\stem\wordnet.py in lemmatize(self, word, pos)
38
39 def lemmatize(self, word, pos=NOUN):
---> 40 lemmas = wordnet._morphy(word, pos)
41 return min(lemmas, key=len) if lemmas else word
42
E:\Miniconda3\envs\uol1\lib\site-packages\nltk\corpus\reader\wordnet.py in _morphy(self, form, pos)
1710
1711 # 1. Apply rules once to the input to get y1, y2, y3, etc.
-> 1712 forms = apply_rules([form])
1713
1714 # 2. Return all that are in the database (and check the original too)
E:\Miniconda3\envs\uol1\lib\site-packages\nltk\corpus\reader\wordnet.py in apply_rules(forms)
1690 def apply_rules(forms):
1691 return [form[:-len(old)] + new
-> 1692 for form in forms
1693 for old, new in substitutions
1694 if form.endswith(old)]
E:\Miniconda3\envs\uol1\lib\site-packages\nltk\corpus\reader\wordnet.py in <listcomp>(.0)
1692 for form in forms
1693 for old, new in substitutions
-> 1694 if form.endswith(old)]
1695
1696 def filter_forms(forms):
I want to be able to lemmatize that string based on each word's part of speech all at once. Please help.
Firstly, try not to mix top-level, absolute and relative imports like these:
import nltk
from nltk.stem import *
from nltk import pos_tag, word_tokenize
This would be better:
from nltk import sent_tokenize, word_tokenize
from nltk.stem import WordNetLemmatizer
from nltk.corpus import wordnet as wn
(See Absolute vs. explicit relative import of Python module)
The error you're getting is most probably because you are feeding in the outputs of pos_tag as the input to the WordNetLemmatizer.lemmatize(), i.e. :
>>> from nltk import pos_tag
>>> from nltk.stem import WordNetLemmatizer
>>> wnl = WordNetLemmatizer()
>>> sent = 'People who help the blinging lights are the way of the future and are heading properly to their goals'.split()
>>> pos_tag(sent)
[('People', 'NNS'), ('who', 'WP'), ('help', 'VBP'), ('the', 'DT'), ('blinging', 'NN'), ('lights', 'NNS'), ('are', 'VBP'), ('the', 'DT'), ('way', 'NN'), ('of', 'IN'), ('the', 'DT'), ('future', 'NN'), ('and', 'CC'), ('are', 'VBP'), ('heading', 'VBG'), ('properly', 'RB'), ('to', 'TO'), ('their', 'PRP$'), ('goals', 'NNS')]
>>> pos_tag(sent)[0]
('People', 'NNS')
>>> first_word = pos_tag(sent)[0]
>>> wnl.lemmatize(first_word)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python2.7/dist-packages/nltk/stem/wordnet.py", line 40, in lemmatize
lemmas = wordnet._morphy(word, pos)
File "/usr/local/lib/python2.7/dist-packages/nltk/corpus/reader/wordnet.py", line 1712, in _morphy
forms = apply_rules([form])
File "/usr/local/lib/python2.7/dist-packages/nltk/corpus/reader/wordnet.py", line 1694, in apply_rules
if form.endswith(old)]
AttributeError: 'tuple' object has no attribute 'endswith'
The input to WordNetLemmatizer.lemmatize() should be str not a tuple, so if you do:
>>> tagged_sent = pos_tag(sent)
>>> def penn2morphy(penntag, returnNone=False):
... morphy_tag = {'NN':wn.NOUN, 'JJ':wn.ADJ,
... 'VB':wn.VERB, 'RB':wn.ADV}
... try:
... return morphy_tag[penntag[:2]]
... except:
... return None if returnNone else ''
...
>>> for word, tag in tagged_sent:
... wntag = penn2morphy(tag)
... if wntag:
... print wnl.lemmatize(word, pos=wntag)
... else:
... print word
...
People
who
help
the
blinging
light
be
the
way
of
the
future
and
be
head
properly
to
their
goal
Or if you like an easy way out:
pip install pywsd
Then:
>>> from pywsd.utils import lemmatize, lemmatize_sentence
>>> sent = 'People who help the blinging lights are the way of the future and are heading properly to their goals'
>>> lemmatize_sentence(sent)
['people', 'who', 'help', 'the', u'bling', u'light', u'be', 'the', 'way', 'of', 'the', 'future', 'and', u'be', u'head', 'properly', 'to', 'their', u'goal']

How to store ner result in json/ database

import nltk
from itertools import groupby
def get_continuous_chunks(tagged_sent):
continuous_chunk = []
current_chunk = []
for token, tag in tagged_sent:
if tag != "O":
current_chunk.append((token, tag))
else:
if current_chunk: # if the current chunk is not empty
continuous_chunk.append(current_chunk)
current_chunk = []
# Flush the final current_chunk into the continuous_chunk, if any.
if current_chunk:
continuous_chunk.append(current_chunk)
return continuous_chunk
ne_tagged_sent = [('Rami', 'PERSON'), ('Eid', 'PERSON'), ('is', 'O'), ('studying', 'O'), ('at', 'O'), ('Stony', 'ORGANIZATION'), ('Brook', 'ORGANIZATION'), ('University', 'ORGANIZATION'), ('in', 'O'), ('NY', 'LOCATION')]
named_entities = get_continuous_chunks(ne_tagged_sent)
named_entities = get_continuous_chunks(ne_tagged_sent)
named_entities_str = [" ".join([token for token, tag in ne]) for ne in named_entities]
named_entities_str_tag = [(" ".join([token for token, tag in ne]), ne[0][1]) for ne in named_entities]
def parser(n,string):
for i in named_entities_str_tag[n]:
if i==string:
pass
else:
return i
print named_entities_str_tag
print
I got this output from the above code:
('PERSON ', 'Rami Eid')
('ORGANIZATION', 'Stony Brook University')
('LOCATION ', 'NY')
('PERSON ', 'GuruRaj Bagali')
('ORGANIZATION', 'Christ University')
But I want it should be map like PERSON WITH ORGANIZATION AND LOCATION I want to store it in json format.
It's not very clear what ne_tagged_sent list contains (Is there a LOCATION for each PERSON, ORGANIZATION ?), you must clarify it that we could answer your question.
You should format your data as a dictionary, each entry corresponds to a person like:
import json
data = {
'Rami Eid':{'job': 'engineer', 'location':'NY'},
'GuruRaj Bagali':{'job': 'professor', 'location': 'NY'}
}
#Save it in a json file
json.dump(data, open('path/to_your_file', 'w')

AssertionError when using nosetests

On exercise 48 of Learn Python the Hard Way, I'm asked to create a module to be tested by this one, lexicon_tests.py:
from nose.tools import *
from ex48 import lexicon
def test_directions():
assert_equal(lexicon.scan("north"), [('direction', 'north')])
result = lexicon.scan("north south east")
assert_equal(result, [('direction', 'north'),
('direction', 'south'),
('direction', 'east')])
def test_verbs():
assert_equal(lexicon.scan("go"), [('verb', 'go')])
result = lexicon.scan("go kill eat")
assert_equal(result, [('verb', 'go'),
('verb', 'kill'),
('verb', 'eat')])
def test_stops():
assert_equal(lexicon.scan("the"), [('stop', 'the')])
result = lexicon.scan("the in of")
assert_equal(result, [('stop', 'the'),
('stop', 'in'),
('stop', 'of')])
def test_nouns():
assert_equal(lexicon.scan("bear"), [('noun', 'bear')])
result = lexicon.scan("bear princess")
assert_equal(result, [('noun', 'bear'),
('noun', 'princess')])
def test_numbers():
assert_equal(lexicon.scan("1234"), [('number', 1234)])
result = lexicon.scan("3 91234")
assert_equal(result, [('number', 3),
('number', 91234)])
def test_errors():
assert_equal(lexicon.scan("ASDFADFASDF"), [('error', 'ASDFADFASDF')])
result = lexicon.scan("bear IAS princess")
assert_equal(result, [('noun', 'bear'),
('error', 'IAS'),
('noun', 'princess')])
So I created the module, lexicon.py, to be tested here:
def scan(words):
directions = ['north', 'south', 'east', 'west', 'down', 'up', 'left', 'right', 'back']
verbs = ['go', 'stop', 'kill', 'eat']
stop_words = ['the', 'in', 'of', 'from', 'at', 'it']
nouns = ['door', 'bear', 'princess', 'cabinet']
lex = words.split()
list1 = []
for i in lex:
if i in directions:
list1.append(('direction', i))
elif i in verbs:
list1.append(('verb', i))
elif i in stop_words:
list1.append(('stop-word', i))
elif i in nouns:
list1.append(('noun', i))
elif i.isdigit():
list1.append(('number', convert_number(i)))
else:
list1.append(('error', i))
print list1
def convert_number(s):
try:
return int(s)
except ValueError:
return None
However when I run nosetests in powershell I get this AssertionError:
Traceback (most recent call last):
File "G:\Python27\lib\site-packages\nose\case.py", line 197, in runTest
self.test(*self.arg)
File "G:\Users\Charles\dropbox\programming\lexicon_test\skeleton\tests\lexicon_tests.py", line 6, in test_directions
assert_equal(lexicon.scan("north"), [('direction', 'north')])
AssertionError: None != [('direction', 'north')]
-------------------- >> begin captured stdout << ---------------------
[('direction', 'north')]
That's the same error message I get for each test run, six of them for the six functions in lexicon_tests.py. What does this error mean? It's been irritating be for a while now. Thanks in advance.
The assert_equal function takes two arguments, and throws an error if the arguments aren't equal to each other. In this case, the result of lexicon.scan("north") is None, and since this isn't equal to [('direction', 'north')], it's throwing an error.
In other words, your lexicon.scan function isn't working properly. It might have something to do with it missing a return statement.

Learn Python the Hard Way, Exercise 48

I've been all day trying to solve the test_errors() function in "Exercise 48: Advanced User Input" of the book Learn Python The Hard Way.
assert_equal(), a function in the tests asks me for the tuples in order and I haven't been able to code it that way.
My loops always returns first the nouns and last the error tuples, I don't know how to break the loop so it starts again but with the right values to continue or whatever is necessary to sort this tuples in the order they should be.
Here's the code:
class Lexicon(object):
def scan(self, stringo):
vocabulary = [[('direction', 'north'), ('direction', 'south'), ('direction', 'east'), ('direction', 'west')],
[('verb', 'go'), ('verb', 'kill'), ('verb', 'eat')],
[('stop', 'the'), ('stop', 'in'), ('stop', 'of')],
[('noun', 'bear'), ('noun', 'princess')], # Remember numbers
[('error', 'ASDFADFASDF'), ('error', 'IAS')],
[('number', '1234'), ('number','3'), ('number', '91234')]]
self.stringo = stringo
got_word = ''
value = []
rompe = self.stringo.split() #split rompe en los espacios
for asigna in vocabulary:
for encuentra in asigna:
if encuentra[1] in rompe:
value.append(encuentra)
return value
eLexicon = Lexicon()
from nose.tools import *
from ex48.ex48 import eLexicon
def test_directions():
assert_equal(eLexicon.scan("north"), [('direction', 'north')])
result = eLexicon.scan("north south east")
assert_equal(result, [('direction', 'north'),
('direction', 'south'),
('direction', 'east')])
def test_verbs():
assert_equal(eLexicon.scan("go"), [('verb', 'go')])
result = eLexicon.scan("go kill eat")
assert_equal(result, [('verb', 'go'),
('verb', 'kill'),
('verb', 'eat')])
def test_stops():
assert_equal(eLexicon.scan("the"), [('stop', 'the')])
result = eLexicon.scan("the in of")
assert_equal(result, [('stop', 'the'),
('stop', 'in'),
('stop', 'of')])
def test_nouns():
assert_equal(eLexicon.scan("bear"), [('noun', 'bear')])
result = eLexicon.scan("bear princess")
assert_equal(result, [('noun', 'bear'),
('noun', 'princess')])
#def test_numbers():
# assert_equal(lexicon.scan("1234"), [('number', 1234)])
# result = lexicon.scan("3 91234")
# assert_equal(result, [('number', 3),
# ('number', 91234)])
def test_errors():
assert_equal(eLexicon.scan("ASDFADFASDF"), [('error', 'ASDFADFASDF')])
result = eLexicon.scan("bear IAS princess")
assert_equal(result, [('noun', 'bear'),
('error', 'IAS'),
('noun', 'princess')])
======================================================================
FAIL: tests.ex48_tests.test_errors
----------------------------------------------------------------------
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/nose/case.py", line 197, in runTest
self.test(*self.arg)
File "/home/totoro/Desktop/Python/projects/ex48/tests/ex48_tests.py", line 43, in test_errors
('noun', 'princess')])
AssertionError: Lists differ: [('noun', 'bear'), ('noun', 'p... != [('noun', 'bear'), ('error', '...
First differing element 1:
('noun', 'princess')
('error', 'IAS')
- [('noun', 'bear'), ('noun', 'princess'), ('error', 'IAS')]
+ [('noun', 'bear'), ('error', 'IAS'), ('noun', 'princess')]
----------------------------------------------------------------------
Ran 5 tests in 0.006s
Many thanks in advance for taking the time.
The words in the test are in the same order going in as coming out. As such you need to re-order your for-loops to iterate over the input first:
value = []
for rompe in stringo.split():
for asigna in vocabulary:
for encuentra in asigna:
if encuentra[1] == rompe:
value.append(encuentra)
This will return the encuentras in the correct order.
Note 1: You should not be hard-coding the numbers or errors.
Note 2: You can drastically reduce the complexity of this algorithm by using dictionary or two.
Example:
vocabulary = {
'direction': 'north east south west up down left right back'.split(),
'noun': 'bear princess door cabinet'.split(),
'stop': 'the in of from at it'.split(),
'verb': 'go kill eat stop'.split(),
}
'''
This creates a lookup using a dictionary-comprehension:
{'at': 'stop',
# [...]
'up': 'direction',
'west': 'direction'}
'''
classifications = {i: k for k, v in vocabulary.iteritems() for i in v}
def classify(word):
try:
return 'number', int(word)
except ValueError:
return classifications.get(word, 'error'), word
def scan(words):
return [classify(word) for word in words.split()]
for word in self.stringo.split():
for pair in vocabulary:
if pair[0][1] == word:
value.append(pair[0])
elif pair[1][1] == word:
value.append(pair[1])
elif pair[2][1] == word:
value.append(pair[2])
elif pair[3][1] == word:
value.append(pair[3])
I just finished this exercise, hope this gives some new ideas to some of you.
This is my solution:
#Set up datastructure
direction = ["north", "east", "south", "west", "up", "right", "down", "left", "back"]
verb = ["go", "stop", "kill", "eat"]
stop = ["the", "in", "of", "from", "at", "it"]
noun = ["door", "bear", "princess", "cabinet"]
vocabulary = [(direction, 'direction'), (verb, 'verb'), (stop, 'stop'), (noun, 'noun')]
def scan(sentence):
#searches the words in the datastructure, if not found checks if it is an integer, if not returns error.
results = []
words = sentence.split()
for word in words:
found = False
for category in vocabulary:
if word.lower() in category[0]:
results.append((category[1], word))
found = True
else:
pass
if found is False and isInt_str(word) is True:
results.append(('number', int(word)))
elif found is False and isInt_str(word) is False:
results.append(('error', word))
elif found is True:
pass
else:
print("I'm terribly sorry, but something you entered is neither a word nor a number.")
return results
def isInt_str(string):
#returns True or False if string equals an integer. (i.e. 2 = True, 2*-2 = True 2**0,5 = False)
string = str(string).strip()
return string=='0' or (string if string.find('..') > -1 else string.lstrip('-+').rstrip('0').rstrip('.')).isdigit()

Categories