Python class instance most recent overwriting all others - python

I've got an assignment where I have to create a class for Employees, read in a text file containing employee information to store as an object, read in an hours worked file and the create a payment information dictionary out of the files. So, far it seems to be working fine as long as their is only one employee in the employee text file but as soon as I include a second, the first is overwritten and the information for the second is what's created. This is some of the information I have so far:
class Staff:
staffData = {}
def __init__(self, EmpID, LName, FName, RHours, HRate, OTMult, TaxC, SBand, Date, HrsWorked):
self.EmpID = EmpID
self.LName = LName
self.FName = FName
self.RHours = RHours
self.HRate = HRate
self.OTMult = OTMult
self.TaxC = TaxC
self.SBand = SBand
self.Date = Date
self.HrsWorked = HrsWorked
Staff.staffData[EmpID] = self
def setup(staff ,hrs): # staff and hrs are text files
with open(staff) as empFile:
for line in empFile:
SID, LN, FN, RH, HR, OTM, TC, SB = line.split()
with open(hrs) as hFile:
for line in hFile:
SID, date, HrsWorked = line.split()
stf = Staff(SID, LN, FN, int(RH), int(HR), float(OTM), int(TC), int(SB),date, HrsWorked)
return stf
def paySlip(self,HrsWorked, date):
paymentDict = {}
#creates paySlip using information from instance and creates others by performing
calculations
return paymentDict
jg = Staff.setup('Staff.txt', 'Hrs.txt')
dic = jg.paySlip(42,'31/10/2021')
print(dic)
This is what I have so far, and it returns the correct output, but when I include a second line with a second staff member that is where I get the issues. Also, just a note, the parameters for paySlip have got to be date and hours worked from the hours text file and not just the text file. I'm quite new to programming so apologies if this is a basic fix, I've spent the last 3 days trying to figure it out by visiting different boards and websites. Any help would be greatly appreciated.

the line
return stf
return from the setup funktion after readin the first line no matter what. If you want to store all line in a list of Staff objects you need to build that list and then return it. something like that
with open(hrs) as hFile:
stf = []
for line in hFile:
SID, date, HrsWorked = line.split()
stf.append(Staff(SID, LN, FN, int(RH), int(HR), float(OTM), int(TC), int(SB),date, HrsWorked))
return stf
then you should get all lines in hFile. That said the way this is build is just stange. you build a staff object to breat a list of staff objects ?
you might wanna restructure your code into a Staff class and StaffMember class? this way you have a Staff object that has Members with hours. But i can be wrong here since i dont see the full picture
cheers
Markus

Related

Modify a function from another function in Python

I hope everyone's having a good day!
So I have this code that loads a text file, reads all the data, assigns each line to a different variable. I want to be able to change (for example) the current_user.config(text=User1) in FileRead function to current_user.config(text=User2) whenever I call the function NextAccount so I can sort of print each set of user and pass on screen (or do something with them).
Edit: Should've mentioned I'm a beginner so I'm probably not doing this the best way. My program is basically supposed to read around 30 combinations of user/pass and I want to display the first one first and then use a button to navigate through (Next account, previous account). I wanted to assign each to a different variable just because I want to use pyautogui to copy paste these combinations to a field in another program
from tkinter import *
from tkinter import filedialog as fd
file_path = ''
datalist = []
def OpenFile():
global file_path
file_path = fd.askopenfilename()
FileRead()
def FileRead():
data = open(file_path)
datalist = data.readlines()
User1 = datalist[0]
Pass1 = datalist[1]
User2 = datalist[2]
Pass2 = datalist[3]
User3 = datalist[4]
Pass3 = datalist[5]
#.....so on
current_user.config(text=User1) #<<<THESE TWO VALUES WHEN function NextAccount is called
current_pass.config(text=Pass1) #<<<
data.close()
def NextAccount():
#I want THIS func to be able to change the FileRead function...
window = Tk()
window.geometry('600x600')
window.config(bg='black')
file_button = Button(window,text='Select File', command=OpenFile)
file_button.pack()
current_user = Label(window)
current_user.pack()
current_pass = Label(window)
current_pass.pack()
next_acc_button = Button(window,command= NextAcc)
window.mainloop()
One way of accomplishing what you're after might be for NextAccount to pop the first user/password from the list. This is easier IMO if your OpenFile function gives you a list of [(user1, pass1), ...] rather than [user1, pass1, ...].
I might structure it something like this:
datalist = []
def FileRead(file_path: str) -> list[tuple[str, str]]:
"""Reads file_path, returns list of (user, passwd) tuples."""
with open(file_path) as data:
datalist = data.readlines()
return [
(user, passwd)
for user, passwd in zip(datalist[::2], datalist[1::2])
]
def OpenFile() -> None:
"""Asks user for a filename, read user/password data, and
add all data from the file into datalist."""
file_path = fd.askopenfilename()
datalist.extend(FileRead(file_path))
def NextAccount() -> None:
"""Print the current user/password and pop it from datalist."""
print(datalist.pop(0))
I'm not sure to understand well what are you asking for.
First of all, if you read a config file, maybe you should have a look on configparser, your code will be more readable as it is a json like way to get config.
If I understand well, you want to go through all the users you get with your config file and change which one you call ?
If yes, put your users into a list and create an interator on that list.
user1 = {"username": "user1", "password": "1234"}
user2 = {"username": "user2", "password": "4567"}
users = [user1, user2]
itr_users = iter(users)
then, when you call your function, just call itr_users.next() to get the next item of the users list and do your stuff. You should be able to access users informations this way
def next_item():
curr_user = next(itr_users)
curr_user["username"]
# First call
# > user1
# Second call
# > user2
In this scenario, I would rather try to:
Give the FileRead function a parameter that indicates which User and Pass to use, like:
def FileRead(n):
data = open(file_path)
datalist = data.readlines()
user_pass_list = [(datalist[i], datalist[i+1]) for i in range( ... )]
#.....so on
current_user.config(text=user_pass_list[n][0]) #<<<THESE TWO VALUES WHEN function NextAccount is called
current_pass.config(text=user_pass_list[n][1]) #<<<
data.close()
Or set a global variable that the FileRead function will use:
n_user_pass = 0
def FileRead():
data = open(file_path)
datalist = data.readlines()
user_pass_list = [(datalist[i], datalist[i+1]) for i in range( ... )]
#.....so on
current_user.config(text=user_pass_list[n][0]) #<<<THESE TWO VALUES WHEN function NextAccount is called
current_pass.config(text=user_pass_list[n][1]) #<<<
data.close()
def NextAccount():
global n_user_pass
n_user_pass = ...
I changed the way you stored your user and passes, to make it into a list [(user1, pass1), ... ] that you can access through indices

Error with reading JSON file lines in Django app

I have this code but I have some lines in my JSON file with empty lines. And I get this error.
This is a Custom Command and I get this error. I want to create a list of jobs in The database of my Django app, I am using a For loop. Thank a lot for your help
raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 2 column 1 (char 2)
from django.core.management.base import BaseCommand
from jobs.models import Job
import json
class Command(BaseCommand):
help = 'Set up the database'
def handle(self, *args: str, **options: str):
with open('static/joblist03112020.json', 'r') as handle:
for line in handle.readlines():
print(line)
line = json.loads(line)
existing_job = Job.objects.filter(
job_title = line['job_title'],
company = line['company'],
company_url = line['company_url'],
description = line['description'],
salary = line['salary'],
city = line['city'],
district = line['district'],
url = line['url'],
job_type = line['job_type'],
)
if existing_job.exists() is False:
Job.objects.create(
job_title = line['job_title'],
company = line['company'],
company_url = line['company_url'],
description = line['description'],
salary = line['salary'],
city = line['city'],
district = line['district'],
url = line['url'],
job_type = line['job_type'],
)
Job.save()
self.stdout.write(self.style.SUCCES('added jobs!add'))
You'll probably want to load the entire JSON file instead of loading line-by-line. Not every line in a JSON file is guaranteed to be parseable in itself as a valid JSON object.
Here is the spirit of what I think you want to do:
with open('static/joblist03112020.json') as f:
job_list = json.load(f)
Note that opening with 'r' for read is the default, so I removed it.
Now you can iterate through each job in the list, and apply the filter. If your JSON object keys match the columns of your model, you may be able to simplify that code as well:
for job in job_list:
existing_job = Job.objects.filter(**job)
if not existing_job.exists():
Job.objects.create(**job)
Note that you will not need to call .save() since create includes saving. Also, the .save() method is only defined on an instance of the class anyway.
someone out of this platform helps me with my problem. this is what I did. and solve the problem. I needed to work with big JSON
def handle(self, *args: str, **options: str):
with open('static/data.json', 'r') as handle:
big_json = json.loads(handle.read())
for item in big_json:
existing_job = Job.objects.filter(

Aggregating/optimizing object.save()?

I'm working on import feature which allows user to create django database models from selected csv file.
Models are related which each other with foreign keys and many-to-many fields.
There is a lot
object.save()
and Object.objects.get(...) in my code which, I suppose, cause it to run so slow.
When an error (for example integrity error) occurs, I need all the changes in database to be rolled back. So I'm using
transaction.atomic
decorator on my view and it works fine.
The problem is, my import is really slow. Parsing file containing ~2000 lines (which could possibly add about 1000 objects to my database) takes about 3 minutes, which is too long.
Is there a way to make it faster? I've read about
bulk_create
function, but "It does not work with many-to-many relationships.".
If this is important, I'm using postgresql.
EDIT:
File structure looks like this:
subject_name
day [A/B] begins_at - ends_at;lecturer_info
Then multiple lines like:
student_uid;student_info
Ok, here's the code.
def csv_import(market, csv_file):
lines = [line.strip().decode('utf-8') for line in csv_file.readlines()]
lines = [line for line in lines if line]
pattern = re.compile(r'[0-9]+;.+')
week_days = {
'monday': 0,
.
.
.
}
term, subject, lecturer, student = None, None, None, None
for number, line in enumerate(lines):
if not ';' in line:
subject = Subject(subject_id=number, name=line, market=market)
subject.save()
elif not pattern.match(line):
term_info, lecturer_info = line.split(';') # term_info - 'day begins_at - ends_at', lecturer_info - lecturer
term_info = term_info.replace(' - ', ' ').split()
term = Term(term_id=number, subject=subject, day=week_days[term_info[0]], begin_at=term_info[-2],
ends_at=term_info[-1])
if len(term_info) == 4:
term.week = term_info[1]
lecturer_info = lecturer_info.rsplit(' ', 1)
try:
lecturer = Lecturer.objects.get(first_name=lecturer_info[0], last_name=lecturer_info[1])
except Lecturer.DoesNotExist:
lecturer = Lecturer(first_name=lecturer_info[0], last_name=lecturer_info[1])
lecturer.save()
term.lecturer = lecturer
term.save()
else:
gradebook_id, student_info = line.split(';')
student_info = student_info.rsplit(' ', 1)
try:
student = TMUser.objects.get(uid=int(gradebook_id))
except TMUser.DoesNotExist:
student = TMUser(uid=int(gradebook_id), username='student'+gradebook_id, first_name=student_info[0],
last_name=student_info[1], password=make_password('passwd'), user_group='user')
student.save()
student.terms.add(term)
student.save()
This is some pseudo code to show you the basic idea of what I meant by caching results:
cache = {}
for number, line in enumerate(lines):
...
elif not pattern.match(line):
...
term = Term(term_id=number, subject=subject, ...)
lecturer_id = (lecturer_info[0], lecturer_info[1]) #first name and last
if cache[lecturer_id]:
#retrieve from cache
lecturer = cache[lecturer_id]
else:
try:
lecturer = Lecturer.objects.get(first_name= lecturer_id[0], last_name= lecturer_id[1])
except Lecturer.DoesNotExist:
lecturer = Lecturer(first_name= lecturer_id[0], last_name= lecturer_id[1])
lecturer.save()
#add to cache
cache[lecturer_id] = lecturer
term.lecturer = lecturer
term.save()
#etc.

Trying to check if 2 values match in a file

this is a code from a chat bot, and it's purpose is to save into a file all information about an user. That will work fine as long as it's only in 1 room, but if i want to save information of the same user in 2 different rooms, i got a problem. The bot won't just update the information getting the user and the room, instead it will always create new and new lines of that user and that room.
It's getting annoying and i would really like to not break this code a lot, so i'd like to know where it fails and how to fix it in a proper way without using dicts. (You can read all the comments inside the code to understand how i think it works).
Thank you for your time.
#First of all it reads the file
leyendoestadisticas = open("listas\Estadisticas.txt", "r")
bufferestadisticas = leyendoestadisticas.read()
leyendoestadisticas.close()
if not '"'+user.name+'"' in bufferestadisticas: #If the name of the user is not there, it adds all the information.
escribiendoestadisticas = open("listas\Estadisticas.txt", 'a')
escribiendoestadisticas.write(json.dumps([user.name, palabrasdelafrase, letrasdelafrase,
"1", user.nameColor, user.fontColor, user.fontFace, user.fontSize,
message.body.replace('"', "'"), room.name, 0, "primermensajitodeesapersona", fixedrooms])+"\n")
escribiendoestadisticas.close()
else: #If the name it's there, it will do the next:
#First of all, get all rooms where the name is saved, to do that...
listadesalas = []
for line in open("listas\Estadisticas.txt", 'r'):
retrieved3 = json.loads(line)
if retrieved3[0] == user.name: #If the name is found
if not retrieved3[9] == room.name: #But room is diferent
listadesalas.append(retrieved3[9]) #Adds the room to a temporal list
#Now that we got a list with all different lines of that user based on rooms... we do the next code
data = []
hablaenunanuevasala = "no"
with open('listas\Estadisticas.txt', 'r+') as f:
for line in f:
data_line = json.loads(line)
if data_line[0] == user.name: #If name is there
if data_line[9] == room.name: #And the room matches with actual room, then update that line.
data_line[1] = int(data_line[1])+int(palabrasdelafrase)
data_line[2] = int(data_line[2])+int(letrasdelafrase)
data_line[3] = int(data_line[3])+1
data_line[4] = user.nameColor
data_line[5] = user.fontColor
data_line[6] = user.fontFace
data_line[7] = user.fontSize
data_line[11] = data_line[8]
data_line[8] = message.body.replace('"', "'")
data_line[9] = room.name
data_line[12] = fixedrooms
else: #but if the user is there and room NOT matches, we want to add a new line to the file with the same user but a new room.
if not room.name in listadesalas: #And here is where i believe is the problem of my code.
hablaenunanuevasala = "si" #needed since i didn't found a way to properly add a new line inside this loop, so must be done outside the loop later.
data.append(data_line)
f.seek(0)
f.writelines(["%s\n" % json.dumps(i) for i in data])
f.truncate()
#Outside the loop - This would work if the program noticed it's a room that is not saved yet in the file for that user.
if hablaenunanuevasala == "si":
escribiendoestadisticas2 = open("listas\Estadisticas.txt", 'a')
escribiendoestadisticas2.write(json.dumps([user.name, palabrasdelafrase, letrasdelafrase,
"1", user.nameColor, user.fontColor, user.fontFace, user.fontSize,
message.body.replace('"', "'"), room.name, 0, "primermensajitodeesapersona", fixedrooms])+"\n")
escribiendoestadisticas2.close()
So... that's what i tried, and it works perfect as long as it's 1 room, it updates the info all the time. When i speak in a second room, it adds me a new record with that second room (perfect). But then if i speak again in ANY of those 2 rooms, the bot will add 2 more lines of code to the file instead of updating the information of the room where i did speak.
Edit Let me summarize it:
Let's say I speak in "whenever" room, the file will save a record
["saelyth", "whenever", "more info"]
If i speak in another room, the file should save a record
["saelyth", "anotherroom", "more info"]
It works great... but then it doesn't update the info. If now i speak in any of those 2 rooms, instead of updating the proper line, the bot will add more new lines into the file, wich is the problem.
Fix done... somehow.
I did choose to save info into different files for each room, that works.

Sorting error with google-docs-api indices must be integer

This is quite a long question and I may miss something out, so if more information is needed ask.
Iv been scraping data from google scholar using scaperwiki and up till recently I was just giving putting all the urls in like this.
elec_urls = """http://1.hidemyass.com/ip-5/encoded/Oi8vc2Nob2xhci5nb29nbGUuY29tL2NpdGF0aW9ucz91c2VyPWo0YnRpeXNBQUFBSiZobD1lbg%3D%3D&f=norefer
http://4.hidemyass.com/ip-1/encoded/Oi8vc2Nob2xhci5nb29nbGUuY29tL2NpdGF0aW9ucz91c2VyPVZXaFJiZEFBQUFBSiZobD1lbg%3D%3D&f=norefer
http://4.hidemyass.com/ip-2/encoded/Oi8vc2Nob2xhci5nb29nbGUuY29tL2NpdGF0aW9ucz91c2VyPV84X09JSWNBQUFBSiZobD1lbg%3D%3D&f=norefer
http://1.hidemyass.com/ip-4/encoded/Oi8vc2Nob2xhci5nb29nbGUuY29tL2NpdGF0aW9ucz91c2VyPUh3WHdmTGtBQUFBSiZobD1lbg%3D%3D&f=norefer
http://4.hidemyass.com/ip-1/encoded/Oi8vc2Nob2xhci5nb29nbGUuY29tL2NpdGF0aW9ucz91c2VyPXU1NWFWZEFBQUFBSiZobD1lbg%3D%3D&f=norefer
""".strip()
elec_urls = elec_urls.splitlines()
I then scrape each page and put the information I want in a list of dicts, sort it once, remove the duplicates and then sort it again using a different key, I then export information I want to a google docs spreadsheet. This works 100%.
I have tried to change it so that I can have another Google docs spreadsheet and from here I can put all the urls in and it will do the same thing. Below is what I have done so far.
def InputUrls(Entered_doc, EnteredURL):
username = 'myemail'
password = 'mypassword'
doc_name = Entered_doc
spreadsheet_id = Entered_doc
worksheet_id = 'od6'
# Connect to Google
gd_client = gdata.spreadsheet.service.SpreadsheetsService()
gd_client.email = username
gd_client.password = password
gd_client.source = EnteredURL
gd_client.ProgrammaticLogin()
#Now that we're connected, we query the spreadsheet by name, and extract the unique spreadsheet and worksheet IDs.
rows = gd_client.GetListFeed(spreadsheet_id, worksheet_id).entry
#At this point, you have a row iterator which will yield rows for the spreadsheet. This example will print everything out, keyed by column names:
urlslist = []
for row in rows:
for key in row.custom:
urlslist.append(row.custom[key].text)
return urlslist
def URLStoScrape(ToScrape):
Dep = []
for i in range(0,len(ToScrape)):
Department_urls = ToScrape[i].strip()
Department_urls = Department_urls.splitlines()
Done = MainScraper(Department_urls)
Dep.append(Done)
return Dep
ElectricalDoc = '0AkGb10ekJtfQdG9EOHN0VzRDdVhWaG1kNVEtdVpyRlE'
ElectricalUrl = 'https://docs.google.com/spreadsheet/ccc? '
ToScrape_Elec = InputUrls(ElectricalDoc, ElectricalUrl)
This seems to scrape fine but then when the program goes to sort I get the below error.
Traceback (most recent call last):
File "./code/scraper", line 230, in <module>
Total_and_Hindex_Electrical = GetTotalCitations(Electrical)
File "./code/scraper", line 89, in GetTotalCitations
Wrt_CitationURL = Sorting(Department, "CitationURL")
File "./code/scraper", line 15, in Sorting
SortedData = sorted(Unsorted, reverse = True, key = lambda k: k[pivot])
File "./code/scraper", line 15, in <lambda>
SortedData = sorted(Unsorted, reverse = True, key = lambda k: k[pivot])
TypeError: list indices must be integers, not str
I think, almost sure, that it has something to do with the URLStoScrape function, but i don't know how to fix it, any help would be great.
Thanks let me know if more info in needed
I think the problem is in the line 89,
GetTotalCitations Wrt_CitationURL = Sorting(Department, "CitationURL")
Either "CitationUrl" should be an integer index, or the value of value passed to the
key function in the sorted() should be a dictionary.

Categories

Resources