Skip to content

Commit

Permalink
Merge pull request #72 from davidism/egstore_filename
Browse files Browse the repository at this point in the history
Moving file created with EgStore causes problems.  Thank you for your work davidism.  There is another pull request regarding egstore.  If you are willing, I'd appreciate your review of those changes once I commit them to develop
  • Loading branch information
robertlugg committed Jun 4, 2015
2 parents df07270 + 836e5cf commit d53bf30
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 111 deletions.
164 changes: 71 additions & 93 deletions easygui/boxes/egstore.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,81 +6,72 @@
Version |release|
"""


import errno
import os
import pickle


# -----------------------------------------------------------------------
#
# class EgStore
#
# -----------------------------------------------------------------------
class EgStore:
class EgStore(object):
"""
A class to support persistent storage.
r"""
A class to support persistent storage.
You can use ``EgStore`` to support the storage and retrieval
of user settings for an EasyGui application.
You can use EgStore to support the storage and retrieval
of user settings for an EasyGui application.
**Example A: define a class named Settings as a subclass of EgStore** ::
**Example A: define a class named Settings as a subclass of EgStore**
::
class Settings(EgStore):
def __init__(self, filename): # filename is required
# specify default values for variables that this application wants to remember
self.user_id = ''
self.target_server = ''
class Settings(EgStore):
def __init__(self, filename): # filename is required
#-------------------------------------------------
# Specify default/initial values for variables that
# this particular application wants to remember.
#-------------------------------------------------
self.userId = ""
self.targetServer = ""
# call super **after** setting defaults
super(Settings, self).__init__(filename)
#-------------------------------------------------
# For subclasses of EgStore, these must be
# the last two statements in __init__
#-------------------------------------------------
self.filename = filename # this is required
self.restore() # restore values from the storage file if possible
**Example B: create settings, a persistent Settings object** ::
**Example B: create settings, a persistent Settings object**
::
settings = Settings('app_settings')
settings.user_id = 'obama_barak'
settings.targetServer = 'whitehouse1'
settings.store()
settingsFile = "myApp_settings.txt"
settings = Settings(settingsFile)
# run code that gets a new value for user_id, and persist the settings
settings.user_id = 'biden_joe'
settings.store()
user = "obama_barak"
server = "whitehouse1"
settings.userId = user
settings.targetServer = server
settings.store() # persist the settings
**Example C: recover the Settings instance, change an attribute, and store it again.** ::
# run code that gets a new value for userId, and persist the settings
user = "biden_joe"
settings.userId = user
settings.store()
settings = Settings('app_settings')
settings.user_id = 'vanrossum_g'
settings.store()
"""

**Example C: recover the Settings instance, change an attribute, and store it again.**
::
def __init__(self, filename):
"""Initialize a store with the given filename and try to load stored values.
If the filename doesn't exist yet, the restore is skipped.
settings = Settings(settingsFile)
settings.userId = "vanrossum_g"
settings.store()
Only attributes defined here will be stored.
Subclasses should initialize any attributes they want to store here, then call ``super``.
"""
:param filename: the file that backs this store for saving and loading
"""

self._filename = filename

def __init__(self, filename): # obtaining filename is required
self.filename = None
raise NotImplementedError()
try:
self.restore()
except IOError as e:
if e.errno != errno.ENOENT:
raise

def restore(self):
"""
Set the values of whatever attributes are recoverable
from the pickle file.
Populate the attributes (the __dict__) of the EgStore object
from the attributes (the __dict__) of the pickled object.
from the attributes (the __dict__) of the pickled object.
If the pickled object has attributes that have been initialized
in the EgStore object, then those attributes of the EgStore object
Expand All @@ -104,55 +95,42 @@ def restore(self):
Where possible, those attributes will have values recovered
from the pickled object.
"""
if not os.path.exists(self.filename):
return self
if not os.path.isfile(self.filename):
return self

try:
with open(self.filename, "rb") as f:
unpickledObject = pickle.load(f)

for key in list(self.__dict__.keys()):
default = self.__dict__[key]
self.__dict__[key] = unpickledObject.__dict__.get(key, default)
except:
pass
with open(self._filename, 'rb') as f:
store = pickle.load(f)

self.__dict__.update((key, value) for key, value in store.__dict__.items() if key in self.__dict__)
return self

def store(self):
"""Save this store to a pickle file.
All directories in :attr:`filename` must already exist.
"""
Save the attributes of the EgStore object to a pickle file.
Note that if the directory for the pickle file does not already exist,
the store operation will fail.
"""
with open(self.filename, "wb") as f:

with open(self._filename, 'wb') as f:
pickle.dump(self, f)

def kill(self):
"""
Delete my persistent file (i.e. pickle file), if it exists.
"""
if os.path.isfile(self.filename):
os.remove(self.filename)
return
"""Delete this store's file if it exists."""

if os.path.isfile(self._filename):
os.remove(self._filename)

def __getstate__(self):
state = self.__dict__.copy()
del state['_filename']
return state

def __setstate__(self, state):
if '_filename' in state:
del state['_filename']

self.__dict__.update(state)

def __str__(self):
"""
return my contents as a string in an easy-to-read format.
"""
# find the length of the longest attribute name
longest_key_length = 0
keys = list()
for key in self.__dict__.keys():
keys.append(key)
longest_key_length = max(longest_key_length, len(key))

keys.sort() # sort the attribute names
lines = list()
for key in keys:
value = self.__dict__[key]
key = key.ljust(longest_key_length)
lines.append("%s : %s\n" % (key, repr(value)))
return "".join(lines) # return a string showing the attributes
""""Format this store as "key : value" pairs, one per line."""

width = max(len(key) for key in self.__dict__ if key != '_filename')
return '\n'.join('{0} : {1!r}'.format(key.ljust(width), value) for key, value in sorted(self.__dict__.keys()) if key != '_filename')

def __repr__(self):
return '{0}({1!r})'.format(self.__class__.__name__, self._filename)
31 changes: 13 additions & 18 deletions sphinx/tutorial.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,19 @@ Here is a simple demo program using easygui. The screens that it produces are sh
.. doctest::
from easygui import *
import sys

while 1:
msgbox("Hello, world!")

msg ="What is your favorite flavor?"
title = "Ice Cream Survey"
choices = ["Vanilla", "Chocolate", "Strawberry", "Rocky Road"]
choice = choicebox(msg, title, choices)

# note that we convert choice to string, in case
# the user cancelled the choice, and we got None.
msgbox("You chose: " + str(choice), "Survey Result")

msg = "Do you want to continue?"
title = "Please Confirm"
if ccbox(msg, title): # show a Continue/Cancel dialog
Expand Down Expand Up @@ -56,7 +56,7 @@ In order to use EasyGui, you must import it. The simplest import statment is::
If you use this form, then to access the EasyGui functions, you must prefix them with the name "easygui", this way::

easygui.msgbox(...)

One alternative is to import EasyGui this way::

from easygui import *
Expand Down Expand Up @@ -160,7 +160,7 @@ Here are a couple of examples::
if ccbox(msg, title): # show a Continue/Cancel dialog
pass # user chose Continue
else: # user chose Cancel
sys.exit(0)
sys.exit(0)

.. image:: _static/tutorial//screenshot_ccbox.png
:align: center
Expand Down Expand Up @@ -295,7 +295,7 @@ Here is some example code, that shows how values returned from multenterbox can
if fieldValues[i].strip() == "":
errmsg = errmsg + ('"%s" is a required field.\n\n' % fieldNames[i])
if errmsg == "": break # no problems found
fieldValues = multenterbox(errmsg, title, fieldNames, fieldValues)
fieldValues = multenterbox(errmsg, title, fieldNames, fieldValues)
print "Reply was:", fieldValues

Here is some example code, that shows how values returned from multpasswordbox can be checked for validity before they are accepted::
Expand All @@ -314,7 +314,7 @@ Here is some example code, that shows how values returned from multpasswordbox c
if fieldValues[i].strip() == "":
errmsg = errmsg + ('"%s" is a required field.\n\n' % fieldNames[i])
if errmsg == "": break # no problems found
fieldValues = multpasswordbox(errmsg, title, fieldNames, fieldValues)
fieldValues = multpasswordbox(errmsg, title, fieldNames, fieldValues)
print "Reply was:", fieldValues

Letting the user enter password information
Expand Down Expand Up @@ -395,21 +395,16 @@ Here is an example of code to create the Settings class::
# define a class named Settings as a subclass of EgStore
#-----------------------------------------------------------------------
class Settings(EgStore):

def __init__(self, filename): # filename is required
#-------------------------------------------------
# Specify default/initial values for variables that
# this particular application wants to remember.
#-------------------------------------------------
self.userId = ""
self.targetServer = ""
#-------------------------------------------------
# For subclasses of EgStore, these must be
# the last two statements in __init__
#-------------------------------------------------
self.filename = filename # this is required
self.restore() # restore values from the storage file if possible

super(EgStore, self).__init__(filename)

Here is an example of code to create the settings object. Simply creating the settings object will restore its values from the settingsFile, if the settingsFile exists::

Expand All @@ -427,12 +422,12 @@ And here is example code of using the settings object::
# In a real application, we'd probably have the user enter them via enterbox
user = "obama_barak"
server = "whitehouse1"

# we save the variables as attributes of the "settings" object
settings.userId = user
settings.targetServer = server
settings.store() # persist the settings

# run code that gets a new value for userId
# then persist the settings with the new value
user = "biden_joe"
Expand Down

0 comments on commit d53bf30

Please sign in to comment.