This easy python code suddenly doesn't work - python

I created a little program as part of my learning experience using python crash course and the code worked pretty well yesterday. But now that I woke up and tried to launch the thing it refuses to do anything and says that "self" is not defined. I honestly have no idea why it happens and would very much like to know exactly what causes error and where I mistaken. Sorry if the question format is wrong and thanks in advance for any help.
import json
class Save_user:
"""Greet the user if the username presents."""
"""Ask the name otherwise."""
def __init__(self):
"""Sets username; Calls greet_user()"""
self.file_path = 'username.json'
self.greet_user()
def get_stored_username(self):
"""Get the username if stored."""
try:
with open(self.file_path) as f:
self.username = json.load(f)
except FileNotFoundError:
return None
else:
return self.username
def greet_user(self):
"""Choose greet the user or store the username."""
self.get_stored_username()
if self.username:
self.if_same_user()
else:
self.store_name()
def store_name(self):
"""Store username."""
self.username = input("Enter your username: ")
with open(self.file_path, 'w') as f:
json.dump(self.username, f)
print("Great! We'll greet you next time!")
def if_same_user(self):
"""Check if the same user."""
print(f"Are you {self.username}?")
while True:
response = input("Please, Enter 'yes' or 'no': \n")
response = response.lower().strip()
if response == 'yes' or response == 'y':
print(f"Welcome back, {self.username}!")
break
elif response == 'no' or response == 'n':
self.store_name()
break
useame = Save_user()
The program should asks the user's name if the json file exists and create the file and store the name otherwise. I tried to set username to 0 in __init__ module and I could launch the thing with text editor and .py format, visual studio, however is giving me an error. Again, thanks in advance for any help!
UPD TraceBack:
Traceback (most recent call last):
File "c:\Users\Windows 10\Desktop\python_work\New folder\new.py", line 50, in <module>
username = Save_user()
^^^^^^^^^^^
File "c:\Users\Windows 10\Desktop\python_work\New folder\new.py", line 10, in __init__
self.greet_user()
File "c:\Users\Windows 10\Desktop\python_work\New folder\new.py", line 25, in greet_user
if self.username:
^^^^^^^^^^^^^
AttributeError: 'Save_user' object has no attribute 'username'

The problem arises when the file is not found: you return None, but don't actually asign it to self.username. So when you do if self.username, an error will rise. I tweaked two lines of your code, here are the functions to change:
def get_stored_username(self):
"""Get the username if stored."""
try:
with open(self.file_path) as f:
username = json.load(f)
return username
except FileNotFoundError:
return None
def greet_user(self):
"""Choose greet the user or store the username."""
self.username = self.get_stored_username()
if self.username:
self.if_same_user()
else:
self.store_name()

The traceback is very helpful here. The problem is that __init__ calls self.greet_user(), which expects self.username to exist. But self.username does not exist yet.
class Save_user:
def __init__(self):
"""Sets username; Calls greet_user()"""
self.file_path = 'username.json'
self.greet_user()
# NOTE: there is no self.username here
# ...
def greet_user(self):
"""Choose greet the user or store the username."""
self.get_stored_username() # May fail to set self.username
if self.username: # This will cause an error
self.if_same_user()
else:
self.store_name()
Typically, attempting to instantiate an object of this class when there is no file username.json will cause an AttributeError that self.username is not one of the attributes. One way to solve this would be to add a sentinel or default username, such as
# ...
def __init__(self):
self.file_path = 'username.json'
self.username = 'default'
self.greet_user()
# ...
A different default name (especially one that is not allowed to be set by standard means) would be a better choice.

Your issue is in the method get_stored_username
you are returning None instead of defining the property self.username
def get_stored_username(self):
"""Get the username if stored."""
try:
with open(self.file_path) as f:
self.username = json.load(f)
except FileNotFoundError:
return None # <- error
else: # <- not necessary
return self.username # <- not necessary
Define the property:
...
except FileNotFoundError:
self.username = None
complete method:
def get_stored_username(self):
"""Get the username if stored."""
try:
with open(self.file_path) as f:
self.username = json.load(f)
except FileNotFoundError:
self.username = None

Related

How to end a method in a class if user input is blank

I'm new to programming so bear with me please!
I'm creating a class and having trouble getting the return message to show when the users input is empty.
Instead of returning my message it's just throwing me an error.
I want my code to return "please try again" and end, if the user input is blank.
Code:
class BankAccount():
def __init__(self):
# asking for a name
self.name = str(input("Hello! Welcome to the Bank of Alex.\nWhat is your name?"))
if self.name == "":
return "please try again"
else:
print(f"\nWelcome, {self.name.title()}.")
TypeError Traceback (most recent call last)
in
----> 1 account = BankAccount()
TypeError: init() should return None, not 'str
Your program structure is incorrect for using a class. You should not create an object until you know the input is valid. Have the calling program check it:
name = ""
while name == "":
name = input("Enter your name")
if name:
acct = BankAccount(name)
break
else:
print("Please try again")
Your __init__ method then merely crates the account -- no name check. This method implicitly returns the created object; you're not allowed to return anything else.
I was able to solve this with help from #Prune. I used the while loop he mentioned and put it under __ init __
So if user input is blank it will just keep prompting for an input. Not a perfect solution but it works.
class BankAccount():
def __init__(self):
self.name = input("Hello! Welcome to the Bank.\nWhat is your name?")
while self.name == "":
self.name = input("Please enter your name")
if self.name:
print(f"\nWelcome, {self.name.title()}.")

Python : storing class instance function in dict

I try to write a ChatBot program that will respond to each user differently.
So I implement like this: When there is a new user, ask the bot to do something and my bot needs to ask user back for more information and wait for the response message, my code will register a dict with a key of user_id and value of call_back function of class User like example code below.
class User:
api_dict = {}
def __init__(self, user_id):
self.user_id = user_id
def ask_username(self,chat_env):
chat_env.send_msg(self.user_id,"Please enter your username")
api_dict[self.user_id] = self.ask_birth_date
def ask_birth_date(self,message,chat_env)
chat_env.send_msg(self.user_id,"Mr. {} what is your birth date".format(message))
# do some thing
def hook_function(user_id,message,chat_env)
if is_first_hook(user_id):
user = User(user_id)
user.ask_username()
else:
User.api_dict[user_id](message,chat_env)
But it was not working as python threw an error that it didn't receive chat_env parameter in ask_birth_date() in which I think self wasn't passed to the function.
So is there any way to make self still attach with ask_birth_date()?
I think that you must be storing all the instances of User somewhere to be able to call ask_username when a connection is first made. Therefore you can transform api_dict into a state pattern.
Users = {} # I'm guessing you already have this!
class User:
def __init__(self, user_id):
self.user_id = user_id
def ask_username(self, chat_env):
chat_env.send_msg(self.user_id, "Please enter your username")
self.current = self.ask_birth_date
def ask_next_question(self, message, chat_env)
self.current(message, chat_env)
def ask_birth_date(self, message, chat_env)
chat_env.send_msg(self.user_id, "Mr. {} what is your birth date".format(message))
self.current = self.record_birth_date # for example
# There must be code that does this already
def new_connection(user_id, chat_env):
Users[user_id] = User(user_id)
Users[user_id].ask_username(chat_env)
# I assume this is called for every message that arrives from a user
def hook_function(user_id, message, chat_env)
Users[user_id].ask_next_question(message, chat_env)
Update:
Your hook function doesn't call ask_username() properly. That is why you are getting the error. That is why you should post all your code and the whole of the stack trace!
This code should fix your call site:
def hook_function(user_id, message, chat_env)
if is_first_hook(user_id):
user = User(user_id)
user.ask_username(chat_env) # add param here!
# btw the user instance here is thrown away!
else:
User.api_dict[user_id](message, chat_env)
If the above fixes your problems, then that means that the User class is unnecessary. You could just have api_dict as a global and the methods can become free functions.
Your code can be reduced to this:
api_dict = {}
def ask_username(chat_env, user_id):
chat_env.send_msg(user_id, "Please enter your username")
api_dict[user_id] = ask_birth_date
def ask_birth_date(chat_env, user_id, message)
chat_env.send_msg(user_id, "Mr. {} what is your birth date".format(message))
# do some thing
def hook_function(user_id, message, chat_env)
if is_first_hook(user_id):
ask_username(chat_env, user_id)
else:
api_dict[user_id](chat_env, user_id, message)

while loop in a python class [duplicate]

This question already has answers here:
Asking the user for input until they give a valid response
(22 answers)
Closed 6 years ago.
I am trying to incorporate a regex check for user input in my class. I want a scenario where users can't proceed to enter their name until they enter a valid email address. The current code i have isn't working as expected.
I suppose a while-loop is in order here but i am struggling to implement that in this class. Any assistance is much appreciated.
class test:
def __init__(self):
self.email = input("Enter your email: ")
email_check = re.search(r'[\w.-]+#[\w.-]+.\w+', self.email)
if email_check:
print ('email valid')
else:
print ('email not valid')
self.email = input("Enter your email: ")
sys.exit(0)
self.name = input("Enter your name: ")
You can do it like this.
while True:
self.email = input ("Enter email:")
if valid_email:
break
Substitute valid_email with your way of validating the email address.
You may also be interested in Python check for valid email address? for ways to validate an email address.
First of all - you should not implement any activity of this kind into __init__ method, as one is intended for object fields initialization first place. Consider dedicated 'check_email' method, or whatever name applies best.
Now, regarding your case:
class test:
def __init(self):
# whatever initialization applies
pass
def init_emails():
emails = []
proceed = True
# if you really in need of do/while loop
while proceed:
email = self.input_email()
# your logic for input
if email is not None:
emails.append(email)
# invalid input or cancel
else:
proceed = False
return input
def input_email(self):
value = input('Enter your email:')
# TODO: validate/check input
return proper_value
class test:
def __init__(self):
self.email = self.get_name()
def get_name(self) :
while True:
x = input("Enter your email: ")
if (re.search(r'[\w.-]+#[\w.-]+.\w+', x)) :
return x
This script functions as described, in the end printing the name and email. If you need to use python2.7, use raw_input instead of input. I used for i in range instead of while True to avoid an endless loop.
#!/usr/bin/env python3
import re
import sys
class Test(object):
def __init__(self):
self.email = None
self.name = None
def get_email(self):
for i in range(3):
email = input('Enter your email: ')
if re.search('[\w.-]+#[\w.-]+.\w+', email):
return email
print('Too many failed attempts!')
sys.exit(1)
def get_name(self):
for i in range(3):
name = input('Enter your name: ')
if name:
return name
print('Too many failed attempts!')
sys.exit(1)
def initialize(self):
self.email = self.get_email()
self.name = self.get_name()
print('"{}" <{}>'.format(self.name, self.email))
if __name__ == '__main__':
t = Test()
t.initialize()
Instead of input, try to use raw_input. Like this:
self.email = raw_input("Enter your email:")
There'll be no error anymore.
Hope this helps.

Unable to load files using pickle and multiple modules

I'm trying to create a user system, which uses a setting and Gui module, and when the GUI module requests for the file to load up using pickle, I keep getting an attribute error. this is from the settings module:
import pickle
import hashlib
class User(object):
def __init__(self, fname, lname, dob, gender):
self.firstname = fname
self.lastname = lname
self._dob = dob
self.gender = gender
self.type = 'General'
self._username = ''
self._hashkey = ''
def Report(self):
print("Full Name: {0} {1}\nDate of Birth: {2}\nGender: {3}\nAccess Level: {4}".format(self.firstname,self.lastname, self._dob, self.gender, self.type))
print(self._username)
def Genusername(self):
self._username = str(str(self._dob)[:2] + self.firstname[:2] + self.lastname[:2])
saveUsers(users)
def Genhashkey(self, password):
encoded = password.encode('utf-8','strict')
return hashlib.sha256(encoded).hexdigest()
def Verifypassword(self, password):
if self._hashkey == self.Genhashkey(password):
return True
else:
return False
class SAdmin(User):
def __init__(self, fname, lname, dob, gender):
super().__init__(fname, lname, dob, gender)
self.type = 'Stock Admin'
class Manager(User):
def __init__(self, fname, lname, dob, gender):
super().__init__(fname, lname, dob, gender)
self.type = 'Manager'
def saveUsers(users):
with open('user_data.pkl', 'wb') as file:
pickle.dump(users, file, -1) # PICKLE HIGHEST LEVEL PROTOCOL
def loadUsers(users):
try:
with open('user_data.pkl', 'rb') as file:
temp = pickle.load(file)
for item in temp:
users.append(item)
except IOError:
saveUsers([])
def userReport(users):
for user in users:
print(user.firstname, user.lastname)
def addUser(users):
fname = input('What is your First Name?\n > ')
lname = input('What is your Last Name?\n > ')
dob = int(input('Please enter your date of birth in the following format, example 12211996\n> '))
gender = input("What is your gender? 'M' or 'F'\n >")
level = input("Enter the access level given to this user 'G', 'A', 'M'\n > ")
password = input("Enter a password:\n > ")
if level == 'G':
usertype = User
if level == 'A':
usertype = SAdmin
if level == 'M':
usertype = Manager
users.append(usertype(fname, lname, dob, gender))
user = users[len(users)-1]
user.Genusername()
user._hashkey = user.Genhashkey(password)
saveUsers(users)
def deleteUser(users):
userReport(users)
delete = input('Please type in the First Name of the user do you wish to delete:\n > ')
for user in users:
if user.firstname == delete:
users.remove(user)
saveUsers(users)
def changePass(users):
userReport(users)
change = input('Please type in the First Name of the user you wish to change the password for :\n > ')
for user in users:
if user.firstname == change:
oldpass = input('Please type in your old password:\n > ')
newpass = input('Please type in your new password:\n > ')
if user.Verifypassword(oldpass):
user._hashkey = user.Genhashkey(newpass)
saveUsers(users)
else:
print('Your old password does not match!')
def verifyUser(username, password):
for user in users:
if user._username == username and user.Verifypassword(password):
return True
else:
return False
if __name__ == '__main__':
users = []
loadUsers(users)
and this is the GUI module:
from PyQt4 import QtGui, QtCore
import Settings
class loginWindow(QtGui.QDialog):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.lbl1 = QtGui.QLabel('Username')
self.lbl2 = QtGui.QLabel('Password')
self.username = QtGui.QLineEdit()
self.password = QtGui.QLineEdit()
self.okButton = QtGui.QPushButton("OK")
self.okButton.clicked.connect(self.tryLogin)
self.cancelButton = QtGui.QPushButton("Cancel")
grid = QtGui.QGridLayout()
grid.setSpacing(10)
grid.addWidget(self.lbl1, 1, 0)
grid.addWidget(self.username, 1, 1)
grid.addWidget(self.lbl2, 2, 0)
grid.addWidget(self.password, 2, 1)
grid.addWidget(self.okButton, 3, 1)
grid.addWidget(self.cancelButton, 3, 0)
self.setLayout(grid)
self.setGeometry(300, 300, 2950, 150)
self.setWindowTitle('Login')
self.show()
def tryLogin(self):
print(self.username.text(), self.password.text())
if Settings.verifyUser(self.username.text(),self.password.text()):
print('it Woks')
else:
QtGui.QMessageBox.warning(
self, 'Error', 'Incorrect Username or Password')
class Window(QtGui.QMainWindow):
def __init__(self):
super().__init__()
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
users = []
Settings.loadUsers(users)
if loginWindow().exec_() == QtGui.QDialog.Accepted:
window = Window()
window.show()
sys.exit(app.exec_())
each user is a class and are put into a list and then the list is saved using pickle when I load up just the settings file and verify the login everything works fine but when I open up the GUI module and try to verify it doesn't let me, the error I'm getting:
Traceback (most recent call last):
File "C:\Users`Program\LoginGUI.py", line 53, in <module>
Settings.loadUsers(users)
File "C:\Users\Program\Settings.py", line 51, in loadUsers
temp = pickle.load(file)
AttributeError: Can't get attribute 'Manager' on <module '__main__' (built-in)>
The issue is that you're pickling objects defined in Settings by actually running the 'Settings' module, then you're trying to unpickle the objects from the GUI module.
Remember that pickle doesn't actually store information about how a class/object is constructed, and needs access to the class when unpickling. See wiki on using Pickle for more details.
In the pkl data, you see that the object being referenced is __main__.Manager, as the 'Settings' module was main when you created the pickle file (i.e. you ran the 'Settings' module as the main script to invoke the addUser function).
Then, you try unpickling in 'Gui' - so that module has the name __main__, and you're importing Setting within that module. So of course the Manager class will actually be Settings.Manager. But the pkl file doesn't know this, and looks for the Manager class within __main__, and throws an AttributeError because it doesn't exist (Settings.Manager does, but __main__.Manager doesn't).
Here's a minimal code set to demonstrate.
The class_def.py module:
import pickle
class Foo(object):
def __init__(self, name):
self.name = name
def main():
foo = Foo('a')
with open('test_data.pkl', 'wb') as f:
pickle.dump([foo], f, -1)
if __name__=='__main__':
main()
You run the above to generate the pickle data.
The main_module.py module:
import pickle
import class_def
if __name__=='__main__':
with open('test_data.pkl', 'rb') as f:
users = pickle.load(f)
You run the above to attempt to open the pickle file, and this throws roughly the same error that you were seeing. (Slightly different, but I'm guessing that's because I'm on Python 2.7)
The solution is either:
You make the class available within the namespace of the top-level module (i.e. GUI or main_module) through an explicit import, or
You create the pickle file from the same top-level module as the one that you will open it in (i.e. call Settings.addUser from GUI, or class_def.main from main_module). This means that the pkl file will save the objects as Settings.Manager or class_def.Foo, which can then be found in the GUI`main_module` namespace.
Option 1 example:
import pickle
import class_def
from class_def import Foo # Import Foo into main_module's namespace explicitly
if __name__=='__main__':
with open('test_data.pkl', 'rb') as f:
users = pickle.load(f)
Option 2 example:
import pickle
import class_def
if __name__=='__main__':
class_def.main() # Objects are being pickled with main_module as the top-level
with open('test_data.pkl', 'rb') as f:
users = pickle.load(f)
Please first read the answer mentioned by zehnpaard to know the reason for the attribute error. Other than the solution he already provided, in python3 you can use the pickle.Unpickler class and override the find_class method as mentioned below:
import pickle
class CustomUnpickler(pickle.Unpickler):
def find_class(self, module, name):
if name == 'Manager':
from settings import Manager
return Manager
return super().find_class(module, name)
pickle_data = CustomUnpickler(open('file_path.pkl', 'rb')).load()
If you're still getting this error even after importing the appropriate classes in the loading module (zehnpaard's solution #1), then the find_class function of pickle.Unpickler can be overwritten and explicitly directed to look in the current module's namespace.
import pickle
from settings import Manager
class CustomUnpickler(pickle.Unpickler):
def find_class(self, module, name):
try:
return super().find_class(__name__, name)
except AttributeError:
return super().find_class(module, name)
pickle_data = CustomUnpickler(open('file_path.pkl', 'rb')).load()
## No exception trying to get 'Manager'
Note: This method loses the relative-import path information stored in module. So, be careful of namespace collisions in your pickled classes.
If you have a class defined outside the module, whose object is in pickle data,
you have to import the class
from outside_module import DefinedClass1, DefinedClass2, DefinedClass3
with open('pickle_file.pkl', 'rb') as f:
pickle_data = pickle.load(f)
if you use dill dump/load model will work
import dill
from sklearn.preprocessing import FunctionTransformer
sp_clf = FunctionTransformer(lambda X:X.astype('float').fillna(0).applymap(abs))
with open('temp.joblib','wb') as io:
dill.dump(sp_clf,io)
with open('temp.joblib','rb') as io:
dd=dill.load(io)

Simplest way to handle and display errors in a Python Pylons controller without a helper class

I have a class User() that throw exceptions when attributes are incorrectly set. I am currently passing the exceptions from the models through the controller to the templates by essentially catching exceptions two times for each variable.
Is this a correct way of doing it? Is there a better (but still simple) way? I prefer not to use any third party error or form handlers due to the extensive database queries we already have in place in our classes.
Furthermore, how can I "stop" the chain of processing in the class if one of the values is invalid? Is there like a "break" syntax or something?
Thanks.
>>> u = User()
>>> u.name = 'Jason Mendez'
>>> u.password = '1234'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "topic/model/user.py", line 79, in password
return self._password
ValueError: Your password must be greater than 6 characters
In my controller "register," I have:
class RegisterController(BaseController):
def index(self):
if request.POST:
c.errors = {}
u = User()
try:
u.name = c.name = request.POST['name']
except ValueError, error:
c.errors['name'] = error
try:
u.email = c.email = request.POST['email']
except ValueError, error:
c.errors['email'] = error
try:
u.password = c.password = request.POST['password']
except ValueError, error:
c.errors['password'] = error
try:
u.commit()
except ValueError, error:
pass
return render('/register.mako')
You could remove repetition from the code as a semi-measure:
class RegisterController(BaseController):
def index(self):
if request.POST:
c.errors = {}
u = User()
for key in "name email password".split():
try:
value = request.POST[key]
for o in (u, c):
setattr(o, key, value)
except ValueError, error:
c.errors[key] = error
u.commit() # allow to propagate (show 500 on error if no middleware)
return render('/register.mako')
Form Handling page from Pylons docs describes several simple approaches to form validating that you could adapt for your project.
class RegisterController(BaseController):
#save(User, commit=True)
# `save` uses filled c.form_result to create User()
#validate(schema=register_schema, form='register')
# `validate` fills c.form_errors, c.form_result dictionaries
def create(self):
return render('/register.mako')
Where validate() is similar to Pylons validate() decorator and save() could be implemented as follows (using decorator module):
def save(klass, commit=False):
def call(action, *args, **kwargs):
obj = klass()
for attr in c.form_result:
if attr in obj.setable_attrs():
setattr(obj, attr, c.form_result[attr])
if commit:
obj.commit()
return action(*args, **kwargs)
return decorator.decorator(call)

Categories

Resources