Module-wide variables python - python

I am trying to import a value from my module called SignIn and use it in a main module to apply a sqlite query to it. The variable is called username and is assigned when the user enters it in a tkinter window. I also have a database passwordDbase in the python file Password_database that has all of the usernames in it. How do I import this value into another module without circular dependency/cycle importing ('as i keep getting SignIn is not callable'). Thanks in advance.
SignIn looks like:
import tkinter
def login():
global username
username=entry_user.get()
win=tkinter.Tk()
entry_user=tkinter.Entry(win)
#with a bunch of other tkinter functions to make textboxes etc
My main programme looks like:
import sqlite3
import SignIn
import Password_database
SignIn()
Password_database()
conn = sqlite3.connect ('passwordDbase.db')
c = conn.cursor()
username=SignIn.username
username=username.strip()
c.execute('''SELECT * FROM passwordDbase WHERE employee_username=?''',(username,))
rows = c.fetchall()
row = c.fetchone()
rows=c.fetchall()
if len(rows) != 1:
message=' '
else:
message= 'correct'
conn.commit()
c.close()
conn.close()

Maybe it doesn't resolve your problem but I would organize all in different way.
Inside mydatabase.py I would keep functions which work with database
import sqlite3
def get_user(username):
conn = sqlite3.connect('passwordDbase.db')
c = conn.cursor()
c.execute('SELECT * FROM passwordDbase WHERE employee_username=?', (username,))
conn.commit()
rows = c.fetchall()
if len(rows) != 1:
message = 'error'
data = None
else:
message = 'correct'
data = rows[0]
c.close()
conn.close()
return message, data
def check_pasword(username, password):
pass
def other_function_on_database():
pass
And I would import this into code with tkinter
import tkinter as tk
import mydatabase
# --- functions ---
def login():
username = entry_username.get()
password = entry_password.get()
username = username.strip()
message, data = mydatabase.login(username)
result_label['text'] = message
#if data and data[x] == password:
# result_label['text'] = "correct"
# --- main ---
win = tk.Tk()
entry_username = tk.Entry(win)
entry_username.pack()
entry_password = tk.Entry(win)
entry_password.pack()
button_login = tk.Button(win, text="Login", command=login)
button_login.pack()
result_label = tk.Label(win, text="")
result_label.pack()
win.mainloop()
This way file with tkinter is main file and I build GUI wrapper for database functions.

First of all, to prevent code execution at import, use
#mymodule.py
class MyModule(object):
def __init__(self, *args, **kwargs):
pass
def MyFunc(myparam):
print myparam
if __name__ == "__main__":
# this code gets executed when the module is called like
# python mymodule.py
print "MyModule called, not imported"
If you want it executed at import, place it inside the module-scope, not the "if __name__ == "__main__":" scope.
Second, if you want to import "static" values from a module define them inside the module like:
#mymodule.py
MyModuleText="Text"
MyModuleList=["My", "Module", "List"]
class MyModule(object):
def __init__(self, *args, **kwargs):
pass
def MyFunc(myparam):
print myparam
if __name__ == "__main__":
# this code gets executed when the module is called like
# python mymodule.py
print "MyModule called, not imported"
then use
#!/usr/bin/python
import mymodule
print mymodule.MyModuleText
print mymodule.MyModuleList
this will access the variables from the module.
If you want to run functions from the module, call them.
To use classes, create instances.
#mymodule.py
MyModuleText="Text"
MyModuleList=["My", "Module", "List"]
class MyModule(object):
def __init__(self, *args, **kwargs):
pass
def some_method(self, text):
print "MyModule.some_func %s"%text
def MyFunc(myparam):
print myparam
if __name__ == "__main__":
# this code gets executed when the module is called like
# python mymodule.py
print "MyModule called, not imported"
#!/usr/bin/python
import mymodule
myinstance = mymodule.MyClass()
myinstance.some_method("SomeMethod from outside")
mymodule.MyFunc("MyModuleFunction called")

Related

Passing user entry to another script

I am trying to use a variable that I get from an entry field in tkinter to another script.
In short:
I want to use the user's input in an entry field in another script. This does not work at all.
Any help highly appreciated!
I tried so far for Script2:
from Script1 import App
test = App()
print(test.write_slogan(self))
TypeError: init() missing 1 required positional argument: 'master'
and
from Script1 import App
print(App.write_slogan())
write_slogan() missing 1 required positional argument: 'self'
and
from Script1 import App
print(App.write_slogan(self))
NameError: name 'self' is not defined
and
import Script1
print(Script1.App.a)
AttributeError: type object 'App' has no attribute 'a'
Script1:
from tkinter import *
class App:
a = 0
def __init__(self, master):
frame = Frame(master)
frame.pack()
self.slogan = Button(frame,
text="Hello",
command=self.write_slogan)
self.slogan.pack(side=LEFT)
self.entry1 = Entry(root, width=15)
self.entry1.pack(side=LEFT)
self.importbutton = Button(frame,
text="import",
command=self.importing)
self.importbutton.pack(side=LEFT)
def write_slogan(self):
print ("Test!")
App.a = self.entry1.get()
print(App.a)
return App.a
def importing(self):
print('Import')
import Script2
if __name__ == '__main__':
root = Tk()
app = App(root)
root.mainloop()
Script2:
import Script1
You've since fixed this I believe, but I'm remarking the information for others that may find their way here: The self within a class function is the instance python will automatically pass when calling the defs. (Unless you're using classmethod or staticmethod for which are not useful in your use case and are a slightly more advanced topic)
# -- Script1 \/
class App:
def __init__(self, master):
# self here is automatically passed
# but you need to pass the "master" arg.
frame = Frame(master)
# ... Example:
self._value = 0
def set_value(self, val):
self._value = val
def get_value(self):
return self._value
# -- Use (probably in Scipt2)
master = Tk()
app = App(master)
print (app.get_value()) # Notice how we don't pass self
>>> 0
app.set_value("my new value") # This string is the "val" arg
print (app.get_value())
>>> my new value
Scipt1.App.a issue
The main issue you're having with is most likely to do with the way python manages modules. The class is writing to App.a in Script1.App but not Script2.Script1.App.a. This is expected behavior so I recommend instead trying to work with something like:
class App:
def __init__(self, master):
# ... Make your tk widgets as you already have
def set_entry_value(self, val):
self.entry1.set(val)
def get_entry_value(self):
self._last_recieved_entry_value = self.entry1.get()
# -- Script2 \/
# The if __name__ == '__main__' is not run on imported
# scripts, only the script python starts execution on
# ~$> python Script2.py
import Script1
if __name__ == '__main__':
root = Tk()
app = Script1.App(root)
# Possibly set a default?
app.set_entry_value("Default value")
root.mainloop()
# - Some time after the mainloop is over
my_lastest_value = root.get_entry_value()
This way, you're letting the local instance of objects handle their internal values. If you're looking to set a class member of an alternate module, then doing so in Script2 may work.
if __name__ == '__main__':
root = Tk()
app = Script1.App(root)
# Do something to set the entry
Script1.App.a = app.get_entry_value()
But be warned, that may not scale across multiple modules.

Python TkInter bind breaking

I have a simple GUI which uses key binds - something like this.
import Tkinter, tkFileDialog
class Foo(object):
def __init__(self, master):
master.bind('3', self.do_bar)
master.bind('9', self.load_new_config)
self.load_config()
if not self.conf:
self.load_new_config()
else:
self.load_data()
def load_config(self):
try:
self.conf = #get stuff from known file
except FailedToGetStuff:
self.conf = None
def load_new_config(self):
path = askopenfilename(initialdir='~')
self.conf = #get stuff from file in path
self.load_data()
def load_data(self):
#get data from self.conf, process and display
def do_bar(self):
#do stuff with displayed data
if __name__ == "__main__"
root = Tk()
Foo(root)
root.mainloop()
Now, this works just fine when load_config() finds what it was looking for. I can use the binds and even after using '9' and loading new config, everything works.
Problem is, if load_config() fails, self.conf gets set to None and load_new_conf gets called from __init__, the binds are no longer operational.
I figured out that the problem is caused by tkFileDialog.askopenfilename() being called from within __init__. What I don't understand is why this happens and how to get around it.
This code works for me:
import Tkinter, tkFileDialog
class Foo(object):
def __init__(self, master):
master.bind('<KeyPress-3>', self.do_bar)
master.bind('<KeyPress-9>', self.load_new_config)
self.load_config()
if not self.conf:
master.after(1, self.load_new_config)
else:
self.load_data()
def load_config(self):
try:
self.conf = None#get stuff from known file
except FailedToGetStuff:
self.conf = None
def load_new_config(self, e = 0):
path = tkFileDialog.askopenfilename(initialdir='~')
self.conf = None#get stuff from file in path
self.load_data()
def load_data(self, e = 0):
pass
#get data from self.conf, process and display
def do_bar(self, e = 0):
print 1
#do stuff with displayed data
if __name__ == "__main__":
root = Tkinter.Tk()
Foo(root)
root.mainloop()

Why attribute doesn't update in traitsui on user input

I have a simple program that gets an text input from the user, and displays it on an instrument (Keithley). However, the attribute does not seem to change. That is, when I run the Start method, the output is "Wowee", even if I change Display in a pop-up window. Do I have to make it editable? I didn't think so. I am basically following Gael Varoquaux's intro to traits.
COntrolPanel.py:
from traits.api import *
from traitsui.api import *
import Keithley3706A_module
class ControlPanel(HasTraits):
keithley2430settings = Instance(Keithley2430.Keithley2430Settings, ())
keithley3706Asettings = Instance(Keithley3706A_module.Keithley3706ASettings, ())
start = Button("Start Measurements")
clear_3706A_display = Button("Clear K3706A Display")
k3706A_settings = Keithley3706A_module.Keithley3706ASettings()
k3706A = Keithley3706A_module.Keithley3706A()
view = View(Item('start', show_label=False,style='custom' ),
Item('clear_3706A_display', show_label=False,style='custom' ),
Item('keithley2430settings',style='custom'),
Item('keithley3706Asettings',style='simple'))
def _start_fired(self):
print "hello %s" % self.k3706A_settings.display
self.k3706A.message(self.k3706A_settings.display)
def _clear_3706A_display_fired(self):
self.k3706A.clear()
if __name__ == '__main__':
ControlPanel().configure_traits()
Keithley3706A.py:
from traits.api import *
from traitsui.api import *
import visa
import time
class Keithley3706ASettings(HasTraits):
display = String("Wowee")
class Keithley3706A(HasTraits):
def __init__(self):
self.Keithley3706AUSB = visa.instrument("USB0::0x05E6::0x3706::04019447::INSTR")
def message(self,foo):
s="display.settext('%s')" % foo
self.Keithley3706AUSB.write("display.clear()")
self.Keithley3706AUSB.write(s)
def clear(self):
self.Keithley3706AUSB.write("display.clear()")
In the ControlPanel class, you have created two different instances of Keithley3706ASettings, namely keithley3706Asettings and k3706A_settings. If I delete the latter, and replace the use of k3706A_settings with keithley3706Asettings, it works. Here's my version (with references to the 2430 device removed, the k3706A trait declared as an Instance of Keithley3706A, and a few other irrelevant UI changes):
class ControlPanel(HasTraits):
keithley3706Asettings = Instance(Keithley3706A_module.Keithley3706ASettings, ())
k3706A = Instance(Keithley3706A_module.Keithley3706A, ())
start = Button("Start Measurements")
clear_3706A_display = Button("Clear K3706A Display")
view = View(UItem('start'),
UItem('clear_3706A_display'),
Item('keithley3706Asettings', style='simple'))
def _start_fired(self):
print "hello %s" % self.keithley3706Asettings.display
self.k3706A.message(self.keithley3706Asettings.display)
def _clear_3706A_display_fired(self):
self.k3706A.clear()

Concept: Mocking DB python

I'm working with postgresql and I have used MagicMock to test, but I'm not sure that I have understanded the mock's concepts. This is my example code (I have a dbname=test, table=py_test and user = simone):
import psycopg2
import sys
from mock import Mock, patch
import unittest
from mock import MagicMock
from collections import Counter
import doctest
class db(object):
def __init__(self,database, user):
self.con = None
self.database = database
self.user = user
def test_connection(self):
"""Connection DB"""
try:
self.con = psycopg2.connect(database=self.database, user=self.user)
return True
except psycopg2.DatabaseError, e:
print 'Error %s' % e
return False
def test_empty_table(self,table):
"""empty table?"""
try:
cur = self.con.cursor()
cur.execute('SELECT * from ' + table )
ver = cur.fetchone()
return ver
except psycopg2.DatabaseError, e:
print 'Error %s' % e
def test_data_type(self, table, column):
"""data type"""
try:
cur = self.con.cursor()
cur.execute("SELECT data_type from information_schema.columns where table_name = '"+ table + "' and column_name= '"+column+"'")
ver = cur.fetchone()
return ver
except psycopg2.DatabaseError, e:
print 'Error %s' % e
def __del__(self):
if self.con:
self.con.close()
class test_db(unittest.TestCase):
def testing(self):
tdb = db('test','simone')
self.assertTrue(tdb.test_connection(), 1)
self.assertTrue(tdb.test_empty_table('py_test'), 1)
self.assertTrue(tdb.test_data_type('py_test','id'), int)
class test_mock(object):
def __init__(self, db):
self.db = db
def execute(self, nomedb, user, table, field):
self.db(nomedb, user)
self.db.test_connection()
self.db.test_empty_table(table)
self.db.test_data_type(table, field)
if __name__ == "__main__":
c = MagicMock()
d = test_mock(c)
d.execute('test','simone','py_test','id')
method_count = Counter([str(method) for method in c.method_calls])
print c.method_calls
print method_count
print c.mock_calls
Maybe I'll give You some other example of mocking using Mockito package:
import sphinxsearch
import unittest
from mockito import mock, when, unstub, verify
class SearchManagerTest(unittest.TestCase):
def setUp(self):
self.sphinx_client = mock()
when(sphinxsearch).SphinxClient().thenReturn(self.sphinx_client)
def tearDown(self):
unstub()
def test_search_manager(self):
# given
value = {'id': 142564}
expected_result = 'some value returned from SphinxSearch'
# when
search_manager = SearchManager()
result = search_manager.get(value)
# then
verify(self.sphinx_client).SetServer('127.0.0.1', 9312)
verify(self.sphinx_client).SetMatchMode(sphinxsearch.SPH_MATCH_ALL)
verify(self.sphinx_client).SetRankingMode(sphinxsearch.SPH_RANK_WORDCOUNT)
self.assertEqual(result, expected_result)
Main concept is to replace some module (mock) that is tested some where else (it has it's own unittest module) and record some behavior.
Replace module You use with mock:
self.sphinx_client = mock()
and then record on this mock that if You call specific method, this method will return some data - simple values like strings or mocked data if You need to check behavior:
when(sphinxsearch).SphinxClient().thenReturn(self.sphinx_client)
In this case You tell that if You import sphinxsearch module and call SphinxClient() on it, You get mocked object.
Then the main test comes in. You call method or object to test (SearchManager here). It's body is tested with some given values:
self.search_manager = SearchManager()
When section verifies if some actions where made:
verify(self.sphinx_client).SetServer('127.0.0.1', 9312)
verify(self.sphinx_client).SetMatchMode(sphinxsearch.SPH_MATCH_ALL)
verify(self.sphinx_client).SetRankingMode(sphinxsearch.SPH_RANK_WORDCOUNT)
Here - if SetServer was called on self.sphinx_client with parameters '127.0.0.1' and 9312. Two other lines are self explanatory like above.
And here we do normal checks:
self.assertEqual(result, expected_result)

Using var from from function A to function B

On this sample code i want to use the variables on the function db_properties at the function connect_and_query. To accomplish that I choose the return. So, using that strategy the code works perfectly. But, in this example the db.properties files only has 4 variables. That said, if the properties file had 20+ variables, should I continue using return? Or is there a most elegant/cleaner/correct way to do that?
import psycopg2
import sys
from ConfigParser import SafeConfigParser
class Main:
def db_properties(self):
cfgFile='c:\test\db.properties'
parser = SafeConfigParser()
parser.read(cfgFile)
dbHost = parser.get('database','db_host')
dbName = parser.get('database','db_name')
dbUser = parser.get('database','db_login')
dbPass = parser.get('database','db_pass')
return dbHost,dbName,dbUser,dbPass
def connect_and_query(self):
try:
con = None
dbHost=self.db_properties()[0]
dbName=self.db_properties()[1]
dbUser=self.db_properties()[2]
dbPass=self.db_properties()[3]
con = None
qry=("select star from galaxy")
con = psycopg2.connect(host=dbHost,database=dbName, user=dbUser,
password=dbPass)
cur = con.cursor()
cur.execute(qry)
data = cur.fetchall()
for result in data:
qryResult = result[0]
print "the test result is : " +qryResult
except psycopg2.DatabaseError, e:
print 'Error %s' % e
sys.exit(1)
finally:
if con:
con.close()
operation=Main()
operation.connect_and_query()
Im using python 2.7
Regards
If there are a lot of variables, or if you want to easily change the variables being read, return a dictionary.
def db_properties(self, *variables):
cfgFile='c:\test\db.properties'
parser = SafeConfigParser()
parser.read(cfgFile)
return {
variable: parser.get('database', variable) for variable in variables
}
def connect_and_query(self):
try:
con = None
config = self.db_properties(
'db_host',
'db_name',
'db_login',
'db_pass',
)
#or you can use:
# variables = ['db_host','db_name','db_login','db_pass','db_whatever','db_whatever2',...]
# config = self.db_properties(*variables)
#now you can use any variable like: config['db_host']
# ---rest of the function here---
Edit: I refactored the code so you can specify the variables you want to load in the calling function itself.
You certainly don't want to call db_properties() 4 times; just call it once and store the result.
It's also almost certainly better to return a dict rather than a tuple, since as it is the caller needs to know what the method returns in order, rather than just having access to the values by their names. As the number of values getting passed around grows, this gets even harder to maintain.
e.g.:
class Main:
def db_properties(self):
cfgFile='c:\test\db.properties'
parser = SafeConfigParser()
parser.read(cfgFile)
configDict= dict()
configDict['dbHost'] = parser.get('database','db_host')
configDict['dbName'] = parser.get('database','db_name')
configDict['dbUser'] = parser.get('database','db_login')
configDict['dbPass'] = parser.get('database','db_pass')
return configDict
def connect_and_query(self):
try:
con = None
conf = self.db_properties()
con = None
qry=("select star from galaxy")
con = psycopg2.connect(host=conf['dbHost'],database=conf['dbName'],
user=conf['dbUser'],
password=conf['dbPass'])
NB: untested
You could change your db_properties to return a dict:
from functools import partial
# call as db_properties('db_host', 'db_name'...)
def db_properties(self, *args):
parser = SafeConfigParser()
parser.read('config file')
getter = partial(parser.get, 'database')
return dict(zip(args, map(getter, args)))
But otherwise it's probably best to keep the parser as an attribute of the instance, and provide a convenience method...
class whatever(object):
def init(self, *args, **kwargs):
# blah blah blah
cfgFile='c:\test\db.properties'
self._parser = SafeConfigParser()
self._parser.read(cfgFile)
#property
def db_config(self, key):
return self._parser.get('database', key)
Then use con = psycopg2.connect(host=self.db_config('db_host')...)
I'd suggest returning a namedtuple:
from collections import namedtuple
# in db_properties()
return namedtuple("dbconfig", "host name user password")(
parser.get('database','db_host'),
parser.get('database','db_name'),
parser.get('database','db_login'),
parser.get('database','db_pass'),
)
Now you have an object that you can access either by index or by attribute.
config = self.db_properties()
print config[0] # db_host
print config.host # same

Categories

Resources