How to make a global inside two functions - python-3.x

import getpass
from passlib.hash import sha256_crypt
def register():
username = str(input('username '))
password = str(getpass.getpass('password ',stream=None))
exec('global '+username)
exec(username+'=user('+"'"+username+"'"+','+"'"+password+"'"+')')
def hashPassword(password):
Passhash = sha256_crypt.hash(password)
return Passhash
def verifyPassword(password,hashpass):
return sha256_crypt.verify(password,hashpass)
class user(object):
users=[]
def __init__(self, username, password):
password = str(password)
if len(password) <= 20:
self.username = username
user.users.append(username)
self.password = hashPassword(password)
else:
print("No more than 20 characters in the password")
def login(username, passsword):
if username in user.users:
if verifyPassword(password,exec(username+'.password'))==True:
print('logged in.')
else:
print('wrong password')
else:
print('unknown user.')
I am trying to make a text based login/register system since I am fairly new to coding. For some reason something with the register() function doesn't correctly register a user because when I go to login verifypassword() it says
if verifyPassword(password,exec(username+'.password'))==True:
File "<string>", line 1, in <module>
NameError: name 'test' is not defined
>>>
if someone could tell me what is happening. I think it it something with global variables but I don't know how to fix it

global in exec doesn't work.
Use globals()[var_name] = var_value to set dynamic variable names in global scope.
exec is gererally a (very) bad idea if called with user-supplied input.
It also has (more or less) unexpected bahaviour in functions, see this example:
def f():
exec('a=3')
print(a)
>>> f()
Traceback [...]
NameError: name 'a' is not defined
(This has something to do with local scope being known at compile-time, see here or here)
Also, you might consider storing the actual user objects in user.users -- this prevents users picking names that you actually use inside your code and prevents unexpected behavior
Edit: Elaboration on the "local scope known at compile-time"
Since the compiler knows what local variables you are using, access is by the bytecode STORE_FAST and LOAD_FAST instructions, which store and load to and from a kind of array (you can look at local variable names via f.__code__.co_varnames), you can't just add stuff dynamically.
Why is this relevant for global?
Well, as said above, the STORE_FAST and LOAD_FAST instructions are used (you guessed it, for speed), the bytecode for following function will be:
>>> def f():
exec('global x')
x = 3
>>> dis.dis(f)
2 0 LOAD_GLOBAL 0 (exec)
2 LOAD_CONST 1 ('global x')
4 CALL_FUNCTION 1
6 POP_TOP
3 8 LOAD_CONST 2 (3)
10 STORE_FAST 0 (x)
12 LOAD_CONST 0 (None)
14 RETURN_VALUE
The first part deals with calling exec. The second part is the assignment. STORE_FAST assigns to a local variable x, no matter what exec just did.
This is also the reason creating new local variables in exec doesn't work: there just isn't space for them. Note this isn't valid for local variables set in exec but also "normally", they will have space assigned nevertheless.

In python, there is a dictionary of global-variables, that you can access by calling globals(). I'm not sure why exec(...) doesn't work, but I would consider a different solution than storing users as variables, named by username. But to solve your problem, keeping this design-choice, you can set the global user like this: globals()[username] = user(username, password) and when loggin in, do verifyPassword(password, globals()[username].password).
But since globals is really just a dictionary, it might be better practice to maintain a dictionary of users yourself. A user could potentially overwrite a global variable, by choosing a username that clashes with another global variable. You could then also eliminate the static users list on your user class. It could look like this, where repository is your dictionary with users:
import hashlib
import base64
import uuid
import getpass
from passlib.hash import sha256_crypt
repository = {}
def register():
username = str(input('username '))
password = str(getpass.getpass('password ',stream=None))
repository[username] = user(username, password)
def hashPassword(password):
Passhash = sha256_crypt.hash(password)
return Passhash
def verifyPassword(password,hashpass):
return sha256_crypt.verify(password,hashpass)
class user(object):
def __init__(self,username,password):
password = str(password)
if len(password) <= 20:
self.username = username
self.password = hashPassword(password)
else:
print("No more than 20 characters in the password")
def loginUser(username):
if username == 'exit':
start()
if username in repository:
if loginPass(username)==True:
print('success')
else:
print('passfail')
else:
print('incorrect login USERNAME NOT IN USER.USERS LIST')
def loginPass(username):
password = getpass.getpass('password ',stream=None)
if verifyPassword(password, repository[username].password) == True:
return True
else:
return False
def start():
while 1:
key1=input('login or register (l/r)')
if key1=='register':
del key1
register()
elif key1=='r':
del key1
register()
elif key1=='l':
del key1
loginUser(input('username or exit to got to l/r screen '))
else:
print('ERROR string not reconised among ifs')
start()

Related

Testing recursive class methods using unit testing python

class Login:
def admin_login(self):
user_name = input('Enter UserName: -')
password = input('please enter password:- ')
try:
with open(r'/home/Downloads/amis/config.yaml') as file:
credentials = yaml.load(file)
if credentials['userid'] == user_name and credentials['password'] == password:
admin_op = AdminOps(credentials)
admin_op.admin_ops()
else:
print("please enter correct login creds")
self.admin_login()
except:
print('err')
self.admin_login()
I am testing this class method and i am trying to mock the method then it is not even going into this method for testing. Can anyone help me writing unit test for this class method.
I tried this for the wrong credentials.
#mock.patch('users.logins.input', create=True)
def test_admin_login_fail(self,ext, inp1):
inp1.side_effect = ['qqq', 'qqq']
login_cls = Login()
login_cls.admin_login()
with mock.patch('file path') as mock_login:
assert mock_login.called
reproducible problem
Admittedly I don't know much about pytest but the problems I see are generic ones and not linked to use of a specific language or library. I'm going to simplify the problem a little bit. Hopefully it can show us a path forward -
def login(creds = {}):
u = input("username:")
p = input("password:")
if u in creds and creds[u] == p:
print(f"{u} logged in")
else:
print(f"invalid login. please retry...")
login(creds)
login({"ripley": "password1"})
I run the program -
username:foo
password:bar
invalid login. please retry...
username:ripley
password:password1
ripley logged in
how to test?
Okay, it works but I still have a testing problem. When an invalid login is provided, login loops endlessly. However, this is not a testing problem, it's a problem with how we wrote our program. The program has a problem of mixing concerns. We already separated one concern by passing credentials as an argument to the login function. Already, if there's a read or yaml.parse error, we don't have to deal with those inside of login. But there's additional concern of input and print side effects...
def login(creds = {}, u = "", p = ""):
return u in creds and creds[u] == p
creds = {"ripley": "password1"}
print(login(creds, "foo", "bar")) # False
print(login(creds, "ripley", "password1")) # True
Now testing is basic login functionality is easy -
def test_login(self):
assert login({}, "foo", "bar") == False
assert login({"foo": "bar"}, "foo", "bar") == True
creds, user, and pass are all arguments to the login function so we can verify our function's behavior without worrying about read or yaml.parse
write functions with parameters
Okay, but what if we want to test login in a looping procedure? Again, we apply what we learned above and write functions that accept arguments -
class ui:
def __init__(self, creds, I, O): # <-- params: creds, input, output
self.creds = creds
self.I = I
self.O = O
self.user = None
def login(self, exit = None): # <-- param: exit handler
u = self.I("user:")
p = self.I("pass:")
if (login(self.creds, u, p)):
self.O(f"{u} logged in")
self.user = u
elif exit is None:
self.O("invalid login")
self.login()
else: exit()
In production, we might run our program like this -
creds = {"ripley": "password1"}
app = ui(creds, input, print) # <-- args: creds, input, output
app.login()
In testing, we could write test_ui_login_failure like this -
def test_ui_login_failure():
def I (prompt): # input
if prompt == "user:":
return "foo"
elif prompt == "pass:":
return "bar"
def O (s): # output
assert s == "invalid login"
app = ui({}, I, O) # <-- args: empty creds, input, and output
app.login(lambda: None) # <-- args: exit handler
Writing test_ui_login_success might look like this -
def test_ui_login_success():
def I (prompt):
if prompt == "user:":
return "foo"
elif prompt == "pass:":
return "bar"
def O (s):
assert s == "foo logged in"
app = ui({"foo": "bar"}, I, O)
app.login(lambda: None)
higher-order control
Adding the exit parameter to ui.login gives us the control we need in the testing environment and it let's us implement a more sophisticated login routine, if needed -
def retry (n = 0, f = lambda _: None):
if n <= 1:
return lambda: None
else:
return lambda: f(retry(n - 1, f))
class ui:
def __init__(self, creds, I, O):
# ...
def login(self, exit = None):
# ...
if (login(self.creds, u, p)):
# ...
elif exit is None:
self.O("invalid login")
self.login(retry(2, self.login)) # <-- retry login twice more
else:
self.O("invalid login")
exit()
We can run ui.login same as last time -
creds = {"ripley": "password1"}
app = ui(creds, input, print)
app.login()
The loop stops after 3 failed attempts -
user:foo
pass:bar
invalid login
user:spaghet
pass:meatbal
invalid login
user:ada
pass:lovelace
invalid login
Our previous tests test_ui_login_failure and test_ui_login_success still pass. Of course you could write a test to verify the retry behaviour as well. This exercise is left for the reader.
remarks
Hopefully these techniques help show that subtle differences in how we write a program can results in dramatic differences in how we test it.

Can't call a variable from another file

I have two files. The first file, we'll call it "a.py". The second, "b.py".
Here's an example of "a.py":
#!/usr/bin/env python
# coding=utf-8
CHOOSE = input ('''
\033[1;35m choose 1 or 2:\033[0m
1)tom
2)jack
''')
a = 666
b = "bbb"
def f():
print("this is a test")
return "function"
if __name__ == '__main__':
if CHOOSE == '1':
username = 'tom'
print(username)
elif CHOOSE == '2':
username = 'jack'
print(username)
else:
print('wrong choice,scipt is exit...')
Here's an example of "b.py":
#!/usr/bin/env python
# coding=utf-8
import a
from a import b,f,CHOOSE,username
a = a.a
f()
print(b,a,CHOOSE,username)
when i run python b.py,system feedback error:
wherem am i wrong?how to fix it?
Because this snippet:
if __name__ == '__main__':
if CHOOSE == '1':
username = 'tom'
print(username)
elif CHOOSE == '2':
username = 'jack'
print(username)
else:
print('wrong choice,scipt is exit...')
Will get executed only if the a.py run as the main python file not imported from other module, so username will not be defined so you can not import it. Here how to fix it:
a.py:
...
def foo(CHOOSE):
if CHOOSE == '1':
username = 'tom'
elif CHOOSE == '2':
username = 'jack'
else:
username = None
return username
b.py:
from a import foo
CHOOSE = input ('''
\033[1;35m choose 1 or 2:\033[0m
1)tom
2)jack
''')
username = foo(CHOOSE)
if username:
print(username)
else:
print('Wrong choice')
Explanation: First you need to extract the code that calculate the name into something reusable. Function are meant for code reusability so I defined one which take one parameter and it return the corresponding value. This function is then used (imported then invoked) in b.py.
Usually if __name__ == '__main__': is placed in the module that you consider your entry-point, so if you want to use it maybe b.py is a better place.
The block if __name__ == '__main__' only triggers if the script is run with a.py being the main module (e.g. you ran it using the command python a.py). If anything else was used as the main module, and a was imported, then this condition is not met and the code inside of it does not run.
The variable username is created and added to a's namespace in the if __name__ == '__main__' block. When you do python b.py, the code inside this block does not execute, and as a result username never gets added to the namespace. So when you try to import it, immediately after loading the file a, you get an error saying that the 'username' doesn't exist - it was never created.

Defining a main_menu function to be called from other methods within a class in Python

I have a class with several methods to assign attributes from user input, and three methods that will add, delete, or update a nested dictionary with the input.
I would like to add a main_menu function so that the user can access the add, delete, and update methods and then choose to either continue adding/deleting/updating the dictionary, or go back to the main menu.
When I tried to make a main_menu function, I receive NameError: name 'command' is not defined. The program will loop through as expected if the main_menu is not a function, but once I tried to turn it into a function, I get the error. I've tried different levels of indentation, but I'm new to Python and don't know what else to try.
class MyClass:
def __init__(self):
self.x = 0
self.y = 0
self.z = 0
def get_x(self):
#code to get x from user input
def get_y(self):
#code to get y from user
def get_z(self):
#code to get z from user
def add_info(self):
store_info = {}
id = 0
while command = '1':
new_info = {}
new_id = len(store_info) + 1
store_info[new_id] = new_info
x = h.get_x()
new_info['x'] = x
y = h.get_y()
new_info['y'] = y
z = h.get_z()
new_info['z'] = z
print('Your info has been updated.\n', store_info)
choice = input('To add more info, type 1. To return to the main menu, type 2')
if choice == '1':
continue
elif choice == '2':
main_menu()
else:
print('The End')
break
def delete_info(self):
#code to delete, with an option at the end to return to main_menu
def update_info(self):
#code to update, with option for main_menu
def main_menu():
main_menu_option = """Type 1 to add.
Type 2 to delete.
Type 3 to update.
Type any other key to quit.\n"""
h = MyClass()
command = input(main_menu_option)
if command == '1':
h.add_info()
elif command == '2':
h.delete_info()
elif command == '3':
h.update_info()
else:
print('Good bye.')
main_menu()
When I run the program, I get the main menu and type 1, but then receive the NameError for command.
Before I tried to make the main_menu a function, I could access the add method to add info to the nested dictionary.
In Python methods/functions only have access to variable in their scope or parent scopes. For example:
command = 1 # A
def foo():
print(command)
def bar():
command = 2 # B
print(command)
foo()
bar()
print(command)
prints out 1 and then 2 and then 1. This works because when we call foo, python looks at the local variables and realises there is no command variable there so it looks at the scope above and sees the command variable at label A. Then when we call bar() we add a variable called command (label B) to the local variables of bar and then print that, notice that python doesn't look at the global variables here so it prints 2 without changing the initial command variable (label A) as we can see when we finally print(command) at the end of the script.
It is because of this that your program is failing, your add_info method is trying to access a variable called command however none exists in its local variable or its global scope. The fix for this would be to add command to the add_info local variables by passing it as an argument to the method from main_menu.
# in main_menu
if command == '1':
h.add_info(command)
# in add_info
def add_info(self, command):
...

How do I pass an attribute to a function in the same class?

I am having trouble with this code. The goal is to "encrypt" a message that the user inputs by reversing the input. The lesson was originally written as a functional block of code, but I wanted to convert it to object-oriented programming and now I get an error. Please let me know if I have any other issues in this code.
This is the code
class Encrypt:
def __init__(self,message,translated):
self.message = message # user input
self.translated = translated # encrypted result
def encryptionProcess(self,message): # encrypting functino
i = len(message) - 1
while i >= 0:
self.translated = self.translated + self.message[i]
i = i - 1
m1 = Encrypt(input(),'') # setting the class attributes
m1.encryptionProcess(message) # calling the function
print(Encrypt.translated) # printing the result
This is the error
Traceback (most recent call last):
File "oopEncrypt.py", line 13, in <module>
m1.encryptionProcess(message)
NameError: name 'message' is not defined
Accessing class instance attributes is done with the self parameter, passed as the first parameter to the class instance method.
Try this:
class Encrypt:
def __init__(self, message):
self.message = message # user input
def encryptionProcess(self): # encrypting functin
translated = "".join(reversed(self.message))
return translated
m1 = Encrypt(input("Enter word to encrypt > "))
translated = m1.encryptionProcess()
print("Encrypted Word:", translated)
self is the instance of the current class.
You may find the python 3 class docs a useful reference: https://docs.python.org/3.6/tutorial/classes.html

'SyntaxError: invalid syntax' in python 3 IDLE

Why is this a syntax error? And how do I fix it?
class Queue:
#Queue is basicliy a List:
def __init__(self):
self.queue = []
#add to the top of the list (the left side)
def Enqueue(self, num):
if isinstance(num, int):
self.queue.append(num)
#remove from the top of the list and return it to user
def Dequeue(self):
return self.queue.pop(0)
#this function gets inputs from user, and adds them to queue,
#until it gets 0.
def addToQueue(queue, num):
num = input()
while num != 0:
queue.Enqueue(num)
num = input()
The interactive mode (with the >>> prompt) only accepts one statement at a time. You've entered two to be processed at once.
After you've entered the class definition, be sure to add an extra blank line so that the interactive prompt knows you're done. Once you're prompted with a >>>, you'll know it is ready for the function definition.
The rest of your code looks fine. Happy computing :-)

Resources