Class variables will not overwritten by funktions - python

I'm trying to read out a database for a login-portal. This part is working in a class dbreader.
The username and password will be saved in the variables cUsername and cUserpass. Before they get overwritten by a function the variables are defined as empty strings "". \
But when I try this: username = dbreader().cUsername, I get an empty string.
Here is the code:
class dbreader:
db_path = "Home-Tool/UserDB"
cUsername = ""
cUserpass = ""
cName = ""
id_range_bool = False
iddb = 1
def __init__(self):
self.connection = _sqlite3.connect(self.db_path)
self.c = self.connection.cursor()
def close(self):
self.connection.close()
def run_sqlCommand(self):
while True:
sqlcom = "SELECT * FROM userinfos WHERE id = " + str(self.iddb)
self.c.execute(sqlcom)
self.connection.commit()
for row in self.c.fetchall(): # self.c = tuble(4)
self.cID = str(row[0])
self.cUsername = str(row[1])
self.cUserpass = str(row[2])
self.cName = str(row[3])
if self.cUsername == cEntryUsername:
break
if not self.id_range_bool:
break
else:
self.id_range_bool = False
self.iddb += 1
dbreader().run_sqlCommand()
username = dbreader.cUsername
userpass = dbreader.cUserpass
name = dbreader.cName

Since dbreader is a class, accessing an attribute will return it as a class variable, not as an instance. The way you have it set up, dbreader.cUsername and dbreader.cPassword will never change, because nothing overwrites them.
On a particular instance of a dbreader, these attributes are overwritten. But you have to use the same instance:
dbreader_instance = dbreader() # create an instance, save the instance to a variable
dbreader_instance.run_sqlCommand()
username = dbreader_instance.cUsername
userpass = dbreader_instance.cUserpass
name = dbreader_instance.cName
You could then create another, separate instance of dbreader, and it might have a different cUsername and cUserpass from the one above.

Related

Python Class Object not callable after loop

I'm using a class object for building a database. I'm using the object in two separate loops, such that when I start the second iteration of the first loop (after having gone through both once), I get a TypeError message saying class "object" not callable. How do I fix this?
import xml.etree.ElementTree as ET
import datetime
import re
import sqlite3
import os
import pathlib
class parameter:
# defines object
def __init__(self, id, value):
self.id = id
self.value = value
# defines equility for eliminating duplicates further on
def __eq__(self, other):
if (isinstance(other, parameter)):
return self.id == other.id and self.value == other.value
return False
db_path = "/Users/miguelnobremenezes/Documents/Code/xml_echo_script/echo.db"
filepath = "/Users/miguelnobremenezes/Documents/Code/xml_echo_script/xml_files"
conn = sqlite3.connect(db_path)
db = conn.cursor()
# Deletes old table
db.execute("DROP TABLE IF EXISTS echo")
# Creates new table with unique ID column
db.execute("CREATE TABLE echo (UNIQUE_ID)")
# Creates a list for adding parameters ie columns to DB
parameter_ids_added_to_db = []
#tree = ET.parse("/Users/mbp2013/Library/Mobile Documents/com~apple~CloudDocs/Documents/Code/xml_echo_script/exemplo.xml")
"""Extracts parameter_value pairs for each XML in directory i.e. patient AND adds unique parameter ids only if non-existent"""
# Iterating every file and respective directory on root folder
for root, dirs, files in os.walk(filepath):
for filename in files:
individual_filepath = os.path.join(root, filename)
print("File name:", filename)
print("File path:", individual_filepath)
tree = ET.parse(individual_filepath)
print("Found XML file\n")
parameters = []
unique_parameters = []
parameter_unique_ids = []
counter_elem = 0
counter_display = 0
for elem in tree.iter():
print("looping")
if elem.tag == "Birthdate":
new_id = elem.tag
new_id = re.sub("[^\w\s]", "_", new_id)
new_id = new_id.replace(" ", "_")
new_id = "pt" + "_" + str(new_id)
print(new_id)
if new_id not in parameter_unique_ids:
parameter_unique_ids.append(new_id)
counter_elem +=1
new_value = elem.text
print(new_value)
counter_display += 1
new_parameter = parameter(new_id, new_value)
print("added")
parameters.append(new_parameter)
print("added")
if elem.tag == "StudyInstanceUID":
unique_ID = elem.text
db.execute("INSERT INTO echo (UNIQUE_ID) VALUES (:value)",
{"value": unique_ID})
temp_ids = []
for parameter in parameters:
if parameter.id not in temp_ids:
temp_ids.append(parameter.id)
unique_parameters.append(parameter)
"""Inserts data into database"""
# Adds columns to DB if they don't already exist
for parameter_unique_id in parameter_unique_ids:
if parameter_unique_id not in parameter_ids_added_to_db:
db.execute('''ALTER TABLE echo ADD COLUMN ''' + parameter_unique_id)
parameter_ids_added_to_db.append(parameter_unique_id)
# Inserts values in specific column for each case
for unique_parameter in unique_parameters:
#print(unique_parameter.id)
#print(unique_parameter.value)
db.execute("UPDATE echo SET ("+unique_parameter.id+") = :value WHERE UNIQUE_ID = :unique_ID",
{"value": unique_parameter.value, "unique_ID": unique_ID})
# Confirm changes to database and close it
conn.commit()
conn.close()
The error is TypeError: 'parameter' object is not callable
I know the problem comes from lines:
temp_ids = []
for parameter in parameters:
if parameter.id not in temp_ids:
temp_ids.append(parameter.id)
unique_parameters.append(parameter)
You have
class parameter: ...
Then you have the loop:
for parameter in parameters:
inside an outer loop.
In the second iteration of the outer loop, the name parameter still refers to the variable from the last iteration of for parameter in parameters.
This means that any attempt to use parameter to refer to the class again, ie
new_parameter = parameter(new_id, new_value)
will fail.
The solution is to change either one of the parameter variables to another name (preferably the class name, as it violates PEP8 anyway).

How to update an instance variable when another variable is changed?

I have the following class and I want the instance variable api_id_bytes to update.
class ExampleClass:
def __init__(self):
self.api_key = ""
self.api_id = ""
self.api_id_bytes = self.api_key.encode('utf-8')
I'd like to be able to have this outcome:
>>>conn = ExampleClass()
>>>conn.api_key = "123"
>>>conn.api_id = "abc"
>>>print(conn.api_id_bytes)
b'123'
>>>
I basically need the self.api_key.encode('utf-8') to run when an api_id is entered but it doesn't, it only does through the initial conn = ExampleClass().
I'm not sure what this is called so searching didn't find an answer.
Here's how you could do it by making api_id_bytes a property.
class ExampleClass:
def __init__(self):
self.api_key = ""
self.api_id = ""
#property
def api_id_bytes(self):
return self.api_key.encode('utf-8')
Now conn.api_id_bytes will always be correct for the current value of conn.api_key.

Global variable in Python : Getting NameError while performing a comparison [duplicate]

This question already has answers here:
Using global variables in a function
(25 answers)
Closed 5 years ago.
I am trying to implement SAX parser in python. Reading the XML and creating objects. Below is my code.
import xml.sax
class Employee :
def __init__(self, id):
self.id = id
class EmployeeHandler(xml.sax.ContentHandler):
emp = None
emplist = []
fName = False
lName = False
age = False
company = False
def __init__(self):
xml.sax.ContentHandler.__init__(self)
def startElement(self, name, attrs):
print("startElement '" + name + "'")
if name == "Employees" :
global emplist
emplist = []
if name == "Employee":
global emp
emp = Employee(attrs.getValue("id"))
elif name == "FirstName":
global fName
fName = True
elif name == "LastName":
global lName
lName = True
elif name == "Age":
global age
age = True
elif name == "Company":
global company
company = True
def characters(self, content):
print("characters '" + content + "'")
global fName, lName, age, company
if fName is True:
emp.firstName = content
elif lName is True:
emp.lastName = content
elif age is True:
emp.age = content
elif company is True:
emp.company = content
def endElement(self, name):
print("endElement '" + name + "'")
if name == "Employee":
#global emplist : To use list methods global is not required
emplist.append(emp)
def main(sourceFileName):
source = open(sourceFileName)
xml.sax.parse(source, EmployeeHandler())
if __name__ == "__main__":
main("EmployeeData")
print("Ids ", emplist[0].id , emplist[1].id)
While executing the code I am getting the below error :
File "C:/Users/611834094/PycharmProjects/PractiseProject/xml_pratise/saxparser.py", line 47, in characters
if fName is True:
NameError: name 'fName' is not defined
To be precise the below block is raising the error :
def characters(self, content):
print("characters '" + content + "'")
global fName, lName, age, company
if fName is True:
emp.firstName = content
The variable fName (along with other global variables) are defined with an initial value which is getting changed in the startElement() method of the handler, in the characters method, I am trying to compare the value of fName against True (boolean), I am getting the error as mentioned above.
Thank you
I'll just take some fragments of your code:
class EmployeeHandler(xml.sax.ContentHandler):
....
fName = False
....
elif name == "FirstName":
global fName
fName = True
....
global fName, lName, age, company
if fName is True:
The global keyword makes fName to be global outside the class. To use the class variable fName you should prefix it with the class name:
elif name == "FirstName":
EmployeeHandler.fName = True
....
if EmployeeHandler.fName is True:
Having said that, none of those variables appear to be suitable as class variables, it would seem that they should actually be object instance variables, i.e. attached to self as described by #JesseBakker. They appear to be properties of each single Employee, not to the whole class.
The reason this does not work is that you don't have any global variables defined. Instead you have class members defined, which are not globally scoped, but scoped in the object. These can be accessed through the self parameter, which is the class instance:
if self.fName:
self.emp.firstName = content
etc

Taking list of elements as param in Class method

I have a class Dbcrud() that I will outline below.
I want to take several parameters from a method: db_select() one being selected_fields which would be a list of fields.
Im having trouble forming my method db_select() to allow multiple fields to be defined for selected_fields.
Can someone help?
Thank you
UPDATED
class DbCrud:
query_stmt_list = ['SELECT','INSERT','UPDATE','DELETE','FROM','WHERE']
def __init__(self):
self.query_stmt_list = DbCrud.query_stmt_list
self.query_stmt_list = query_stmt_list
def set_db_settings(self, host, username, passwd, database):
self.host = host
self.username = username
self.passwd = passwd
self.database = database
db = pymysql.connect(host=host, user=username, passwd=passwd, db=database)
return db
def db_select(self, selected_fields, table, where_field):
self.selected_fields = selected_fields
self.table = table
self.where_field = where_field
try:
with db.cursor() as cursor:
sql_tld_id_query = self.query_stmt_list[0] + selected_fields* + self.query_stmt_list[4] + table + self.query_stmt_list[5] + where_field + '=' + %s
cursor.execute(sql_tld_id_query, (self.site_search_url,))
tld_id_value = cursor.fetchone()
except:
db.rollback()
pass
You have few issues here:
1.
You need that row at the init method (as this is the c'tor of the class)
Also as query_stmt_list is a static member, you should access him with the class name as prefix.
def __init__(self):
self.query_stmt_list = DbCrud.query_stmt_list
2.
You can't define a function param with selected_fields[], it's a syntax error, you can pass to selected_fields whatever you like.
def db_select(self, selected_fields, table, where_field):
3.
When you try to use the variable query_stmt_list (at the following line of code i've attached), do you mean you want the class member or the instance member?
If instance you should change it to self.query_stmt_list
If the class member, you should change it to DbCrud.query_stmt_list
sql_tld_id_query = query_stmt_list[0] + selected_fields* + query_stmt_list[4] + table + query_stmt_list[5] + where_field + '=' + %s
Also, in order to loop though the selected_fields you could do:
query_stmt_list[0] + ", ".join(item for item in self.selected_fields) + query_stmt_list[4] ...
You can always expect selected_fields to be a list so you can use ', '.join:
def db_select(self, selected_fields, table, where_field):
query = 'select {selected_fields} {table} where {where_field} = 1'
query = query.format(selected_fields=', '.join(selected_fields),
table=table, where_field=where_field)
.
.
obj.db_select(['col_a'], 'table_a', 'where_field_a')
Note that this is vulnerable to SQL injection, but so is your original code (if it wasn't for the syntax errors it currently has).

Python OOP Factory Pattern

I am still learning OOP Design Pattern and everything I have read so far says that Factory Patterns are commonly used. I am still trying to learn this pattern. For my program I am creating an Abstract Factory called "person" and my factory called "personFactory" should let you create different types of people (Users, Customers, Plumbers, etc...). With my current code I am getting this error:
AttributeError: 'NoneType' object has no attribute 'fName'
This is my code:
person.py
import abc
class person:
__metaclass__ = abc.ABCMeta
fName = ""
mName = ""
lName = ""
address = ""
city = ""
state = ""
zipcode = ""
email = ""
phone = ""
dob = None
personFactory.py
from person import person
class personFactory(person):
def createUser(self):
uName = ""
password = ""
role = ""
def __init__(self,uName,password,role):
self.uName = uName
self.password = password
self.role = role
def login(uName,password):
if(uName == self.uName and password == self.password):
return "Logged In"
else:
return "Did not log in"
def logout():
return "Logout"
def createCustomer(self):
items = []
balace = 0
def __init__(self,balance):
self.balance = balance
def AddToCart(item):
self.items.append(item)
print("Item added")
def Order(items):
totalprice = 0
for item in items:
totalprice =+ item.price
return totalprice
def Pay(payment):
self.balance =- payment
return self.balance
main.py
import personFactory
class main():
pf = personFactory.personFactory()
user1 = pf.createUser()
user1.fName = "John"
user1.lName = "Smith"
user1.uName = "jSmith"
user1.password = "Jamestown"
customer1 = pf.createCustomer()
customer1.fName = "George"
customer1.lName = "Washington"
customer1.balance = 100
main()
I'm not sure why fName is a NoneType. What am I doing wrong? Any help would be greatly appreciated!
You have the constructor inside the create_user method. As Ignacio was saying the init function must be outside of the create_user function, in order for you to pass the name, pass and role to the person_factory object at creation.
Or alternatively you could pass all those value to the create_user method as arguments and leave the class constructor out of the work.
Could be something like this...
class personFactory(person):
def __init__(self,uName,password,role):
self.uName = uName
self.password = password
self.role = role
def createUser(self):
user = Person()
user.type = "user"
user.uName = self.uName
user.password = self.password
user.role = role
return user
Or...
class personFactory(person):
def createUser(self, uName, password, role):
user = Person()
user.type = "user"
user.uName = uName
user.password = password
user.role = role
return user
I would also suggest that you made use of inheritance and made concrete classes based on your abstract classes that represent each of your objects.
Like...
class User(Person):
def __init__(name, password, role):
self.name = name
self.type = "User"
self.password = password
So you can have a User class, and a Customer class, and each method of your factory can create the corresponding object, instead of a regular Person.

Categories

Resources