I am just trying to print my raw text from bs4. However, I cant access the attribute from inside one of my methods. But I can access the attribute just fine from outside the class.
import requests
from bs4 import BeautifulSoup
from pprint import pp
import datetime
import time
stocklist = ["wish","clov","baba","pltr",'mu','nio','sofi','tsla','gme','clne',]
class Stock:
def __init__(self,stocklist,s):
self.address = Stock.AG(stocklist,s)
self.soup = Stock.Soup(stocklist,s)
self.volume = Stock.Volume(stocklist,s)
self.price = Stock.Price(stocklist,s)
def AG(stocklist,s):
stockurl = str(('https://robinhood.com/stocks/'+stocklist[s]))
return(stockurl)
def Soup(stocklist,s):
r = requests.get('https://robinhood.com/stocks/'+stocklist[s])
soup = str(BeautifulSoup(r.content, 'lxml'))
return(soup)
def Volume(stocklist,s):
print(stocklist[s].soup) # does not work
def Price(stocklist,s):
pass
for s in range(len(stocklist)):
stocklist[s] = Stock(stocklist,s)
print(stocklist[s].address)
print(stocklist[s].volume)
print(stocklist[s].soup) #works
So this is because when you are calling the volume function stocklist[s] still refers to the string not to the object. Think about when you are calling the init method and hows it being called before the list is overwritten.
The very quick and dirty solution I came up with which should not be deployed but highlights the problem is to change you init method to this.
def __init__(self,stocklist,s):
self.address = Stock.AG(stocklist,s)
self.soup = Stock.Soup(stocklist,s)
stocklist[s] = self
self.volume = Stock.Volume(stocklist,s)
self.price = Stock.Price(stocklist,s)
Related
I have a file myfunctions.py in directory mypythonlib
from requests_html import HTMLSession
import requests
def champs_info(champname:str, tier_str:int):
url = f"https://auntm.ai/champions/{champname}/tier/{tier_str}"
session = HTMLSession()
r = session.get(url)
r.html.render(sleep=1, keep_page=True, scrolldown=1)
information = r.html.find("div.sc-hiSbYr.XqbgT")
sig = r.html.find('div.sc-fbNXWD.iFMyOV')
tier_access = information[0]
tier = tier_access.text
I want to access the variable tier through another file- test_myfunctions.py
but the thing is I also have to give parameters to the function champs_info so that it could access the url accordingly.
from mypythonlib import myfunctions
def test_champs_info():
return myfunctions.champs_info("abomination",6).tier
But while running this code, I am getting the error-
./tests/test_myfunctions.py::test_champs_info Failed: [undefined]AttributeError: 'NoneType' object has no attribute 'tier'
def test_champs_info():
> return myfunctions.champs_info("abomination",6).tier
E AttributeError: 'NoneType' object has no attribute 'tier'
tests/test_myfunctions.py:3: AttributeError
Any Solution for this and why is this code not able to access the variable?
I wrote myfunctions.champs_info("abomination",6).tier in hope for that it's gonna take the tier variable from the champs_info function while giving it the parameters required all from the myfunctions file :(
You can access the value of a variable in a function by 1) returning the value in the function, 2) use a global variable in the module, or 3) define a class.
If only want to access a single variable local to a function then the function should return that value. A benefit of the class definition is that you may define as many variables as you need to access.
1. Return value
def champs_info(champname:str, tier_str:int):
...
tier = tier_access.text
return tier
2. global
tier = None
def champs_info(champname:str, tier_str:int):
global tier
...
tier = tier_access.text
Global tier vairable is accessed.
from mypythonlib import myfunctions
def test_champs_info():
myfunctions.champs_info("abomination", 6)
return myfunctions.tier
print(test_champs_info())
3. class definition:
class Champ:
def __init__(self):
self.tier = None
def champs_info(self, champname:str, tier_str:int):
...
self.tier = tier_access.text
test_functions.py can call champs_info() in this manner.
from mypythonlib import myfunctions
def test_champs_info():
info = myfunctions.Champ()
info.champs_info("abomination", 6)
return info.tier
print(test_champs_info())
In myfunctions.champs_info() add a return tier
and in the script test_myfunctions.py remove .tier
You just have to return tier from champs_info() function
Just like this:
myfunctions.py
from requests_html import HTMLSession
import requests
def champs_info(champname:str, tier_str:int):
url = f"https://auntm.ai/champions/{champname}/tier/{tier_str}"
session = HTMLSession()
r = session.get(url)
r.html.render(sleep=1, keep_page=True, scrolldown=1)
information = r.html.find("div.sc-hiSbYr.XqbgT")
sig = r.html.find('div.sc-fbNXWD.iFMyOV')
tier_access = information[0]
tier = tier_access.text
return tier # <---- Focus Here
test_myfunctions.py
import myfunctions
print(temp.champs_info("americachavez", 6))
Just it. You're done.
Background:
I created a class to extract info from google. This class searches the search term and suggest correction if there is any spelling error with the search term.
class gs:
url_part1 = "https://www.googleapis.com/customsearch/v1?key="
key = "some_key"
cse = 'some_key'
suggestion = 'None'
def __init__(self, search):
self.search = search
self.url = gs.url_part1 + gs.key + gs.cse + self.search
#gs.suggestion = 'None'
def get_suggestion(self):
r = requests.get(url=self.url)
r_json = r.json()
if 'spelling' in r_json.keys():
gs.suggestion = r_json.get('spelling').get('correctedQuery')
return gs.suggestion
For example if I search for paytn (correct name is paytm) then this class suggestion correction for paytn which is paytm
gs_1 = gs(search='paytn')
suggestion_1 = gs_1.get_suggestion()
print(suggestion_1) #suggestion for incorrect name
'paytm'
Instead of searching for paytn if I search for 'paytm' then gs class suggests nothing.
gs_2 = gs(search='paytm')
suggestion_2 = gs_2.get_suggestion()
print(suggestion_2) #no suggestion for correct name
'None'
Now while creating unittest case for gs class I observed a very strange behavior. self.gs_2 is picking up the the values from self.gs_1
and failing the below test.
from search import gs
import unittest
class TestSearch(unittest.TestCase):
def setUp(self):
self.gs_1 = gs(search='paytn')
self.gs_2 = gs(search='paytm')
def test_get_suggestion(self):
self.assertEqual(self.gs_1.get_suggestion(), 'paytm')
self.assertEqual(self.gs_2.get_suggestion(), 'None')
if __name__ == '__main__':
unittest.main()
Upon inspection it is clear that self.gs_2 is acquiring value from first instance of class gs. Please refer to the output below
import search
suggestion 1 in setUp paytm
suggestion 2 in setUp paytm
F
======================================================================
FAIL: test_get_suggestion (test.TestSearch)
----------------------------------------------------------------------
Traceback (most recent call last):
File "D:\YBL\test.py", line 15, in test_get_suggestion
self.assertEqual(self.gs_2.get_suggestion(), 'None')
AssertionError: 'paytm' != 'None'
- paytm
+ None
----------------------------------------------------------------------
Ran 1 test in 3.028s
FAILED (failures=1)
Can anyone help me to understand
1) whether my understanding is correct or not ?
2) Why it is getting values from gs_1 instead of creating a new instance ?
class gs:
url_part1 = "https://www.googleapis.com/customsearch/v1?key="
key = "some_key"
cse = 'some_key'
def __init__(self, search):
self.search = search
self.url = gs.url_part1 + gs.key + gs.cse + self.search
self.suggestion = 'None'
def get_suggestion(self):
r = requests.get(url=self.url)
r_json = r.json()
if 'spelling' in r_json.keys():
self.suggestion = r_json.get('spelling').get('correctedQuery')
return self.suggestion
You used suggestion in gs (same for the whole class), rather than self.suggestion that is instance-specific. You can see it in a way you accessed the value - gs.suggestion means it belongs to gs, self.suggestion means it belongs to the current instance that was passed to the method. ;)
In your case, 1st pass overwrote the gs.suggestion and the 2nd didn't, so it returned the previous value.
import random
import requests
from bs4 import BeautifulSoup
import random
import time
class Game(object):
def __init__(self):
words = []
finalWords = []
def getWords(self,url):
sourceCode = requests.get(url).text
soup = BeautifulSoup(sourceCode, 'html.parser')
words = soup.get_text().lower().split()
[finalWords.append(item) for item in words if item not in finalWords]
print(finalWords)
game = Game()
game.getWords("http://members.optusnet.com.au/charles57/Creative/Techniques/random_words.htm")
when I call game.getWords I get an error that says finalWords is not defined, how do I avoid this? I'm new to using classes. Thanks.
You define finalWords in __init__ but then __init__ ends, and that local variable disappears. You probably want to store it as an attribute of the instance, by using self.finalWords throughout.
BTW, your use of a list comprehension in getWords creates a list of None which you then throw away. Don't use a list comprehension for its side effects. You should use a regular for loop instead, or a set if order isn't important (since a set can contain a particular item only once).
Your finalWords is a local variable in your constructor, not an instance field.
Unlike in Java or C#, you have to always qualify your instance fields with the actual instance, which in methods is normally named self.
This will work:
def __init__(self):
self.words = []
self.finalWords = []
def getWords(self, url):
# your code....
self.finalWords.append(...)
print self.finalWords
Make words and finalWords instance attributes. Like this:
import random
import requests
from bs4 import BeautifulSoup
import random
import time
class Game(object):
def __init__(self):
self.words = []
self.finalWords = []
def getWords(self,url):
sourceCode = requests.get(url).text
soup = BeautifulSoup(sourceCode, 'html.parser')
self.words = soup.get_text().lower().split()
[self.finalWords.append(item) for item in self.words if item not in self.finalWords]
print(self.finalWords)
game = Game()
game.getWords("http://members.optusnet.com.au/charles57/Creative/Techniques/random_words.htm")
on the begin I'll say that I was looking for the answer but can't find it and sorry for so basic question.I created program with TTS. I created global variable called "list_merge", but most of you said that global variables are BAD. So I decided to put this list in init. PS. ignore whitespaces, they exist only because I copied it here.
the error is:
AttributeError: 'Ver2ProjectWithTTS' object has no attribute 'list_merge'
import json
import pyttsx
from openpyxl import load_workbook
class Ver2ProjectWithTTS(object):
def __init__(self):
self.read_json_file()
self.read_xml_file()
self.say_something()
self.list_merge = []
def read_json_file(self):
with open("json-example.json", 'r') as df:
json_data = json.load(df)
df.close()
for k in json_data['sentences']:
text_json = k['text']
speed_json = int(k['speed'])
volume_json = float(k['volume'])
dict_json = {'text': text_json, 'speed': speed_json, 'volume': volume_json}
self.list_merge.append(dict_json)
def read_xml_file(self):
tree = et.parse('xml-example.xml')
root = tree.getroot()
for k in range(0, len(root)):
text_xml = root[k][0].text
speed_xml = int(root[k][1].text)
volume_xml = float(root[k][2].text)
dict_xml = {'text': text_xml, 'speed': speed_xml, 'volume': volume_xml}
self.list_merge.append(dict_xml)
def say_something(self):
for item in self.list_merge:
engine = pyttsx.init()
engine.getProperty('rate')
engine.getProperty('volume')
engine.setProperty('rate', item['speed'])
engine.setProperty('volume', item['volume'])
engine.say(cleared_text)
engine.runAndWait()
if __name__ == '__main__':
a = Ver2ProjectWithTTS()
I'm getting
AttributeError: 'Ver2ProjectWithTTS' object has no attribute 'list_merge'
Any ideas how to avoid this error? Well i'm not good in objectivity and I just cant move on without fixing this. PS. with global variable before init def it worked properly.
Thanks for help :)
You have to set if first before you use it:
class Ver2ProjectWithTTS(object):
def __init__(self):
# first set it
self.list_merge = []
self.read_json_file()
self.read_xml_file()
self.say_something()
Anyway don't do any advanced logic in constructors, it's not a good practice. Make a method instead:
class Ver2ProjectWithTTS(object):
def __init__(self):
# first set it
self.list_merge = []
def do_the_job(self):
self.read_json_file()
self.read_xml_file()
self.say_something()
...
instance = Ver2ProjectWithTTS()
instance.do_the_job()
I am trying to get the variable - clipFileInfo in which it came from an import module. I run the following code:
from Library import libmaya
publishClip = libmaya.ClipPublish()
clip = publishClip.getClip()
print clip.clipFileInfo
But it will give me an error saying that # AttributeError: 'list' object has no attribute 'clipFileInfo' #
This is the portion of code that I am deriving from
class ClipPublish( lib.ClipPublish ):
...
...
def __getclipFileInfo( self ):
'''
Return list of dicts to pass through to writeClip function
'''
clipFileInfo = []
for rig in self.rigList.Rigs():
actor = rig.pop( 'actor', None )
if actor:
clipFileInfo = {}
clipFileInfo['actor'] = actor
clipFileInfo['rig'] = rig
clipFileInfo['name'] = self.__unit.get( rig['name'] )
clipFileInfo.append( clipFileInfo )
return clipFileInfo
def getClip( self ):
clipFileInfo = self.__getclipFileInfo()
if clipFileInfo:
start = self.frameRange.startFrame()
end = self.frameRange.endFrame()
clipFile = writeC.writeclip( clipFileInfo, start, end )
if clipFile == None:
return None
return clipFile[0] if self.isSingle() else clipFile
return []
Is this possible to do so in the first place?
It looks like you are trying to pull a local variable out of a function. Unless the function returns this local variable, it is not possible.
Instead, as the comment says, you should call publishClip.__getclipFileInfo() to get the value of that variable, since that function does return it.
To be more explicit, try the following code.
from Library import libmaya
publishClip = libmaya.ClipPublish()
info = publishClip.__getclipFileInfo()
print info