Skip to content

Commit

Permalink
Merge pull request #74 from jjdenis/better-egstore
Browse files Browse the repository at this point in the history
Better egstore
  • Loading branch information
robertlugg committed Jun 4, 2015
2 parents 66a0226 + 452fb76 commit 62a96b8
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 60 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ For our develop version which will be released next:
This is an exciting time for easygui. We continue to make good progress with refactoring as
well as some enhancements and bug fixes here and there.

We would like to welcome Juanjo Corrales to the team. He is responsible for lots of good new work
We would like to welcome Juanjo Denis-Corrales to the team. He is responsible for lots of good new work
this release. Of course we appreciate the work of everyone who contributed.

NOTE: I decided in this release to change the API a bit. Please consult the function documentation for details.
Expand Down
2 changes: 1 addition & 1 deletion README.txt
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ For our develop version which will be released next:
This is an exciting time for easygui. We continue to make good progress with refactoring as
well as some enhancements and bug fixes here and there.

We would like to welcome Juanjo Corrales to the team. He is responsible for lots of good new work
We would like to welcome Juanjo Denis-Corrales to the team. He is responsible for lots of good new work
this release. Of course we appreciate the work of everyone who contributed.

NOTE: I decided in this release to change the API a bit. Please consult the function documentation for details.
Expand Down
2 changes: 1 addition & 1 deletion easygui/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
from .boxes.derived_boxes import passwordbox
from .boxes.multi_fillable_box import multpasswordbox
from .boxes.choice_box import multchoicebox
from .boxes.egstore import EgStore
from .boxes.egstore import EgStore, read_or_create_settings
from .boxes.about import eg_version, egversion, abouteasygui
from .boxes.demo import easygui_demo as egdemo

89 changes: 49 additions & 40 deletions easygui/boxes/egstore.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,12 @@
import errno
import os
import pickle
import datetime

def read_or_create_settings(file_name):
settings = Settings(file_name)
settings.restore()
return settings

class EgStore(object):
"""
Expand All @@ -18,20 +23,17 @@ class EgStore(object):
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** ::
**First: 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 = ''
settings.restore()
*Second: create a persistent Settings object** ::
# call super **after** setting defaults
super(Settings, self).__init__(filename)
**Example B: create settings, a persistent Settings object** ::
settings = Settings('app_settings')
settings = Settings('app_settings.txt')
settings.user_id = 'obama_barak'
settings.targetServer = 'whitehouse1'
settings.store()
Expand All @@ -42,30 +44,30 @@ def __init__(self, filename): # filename is required
**Example C: recover the Settings instance, change an attribute, and store it again.** ::
settings = Settings('app_settings')
settings = Settings('app_settings.txt')
settings.restore()
print settings
settings.user_id = 'vanrossum_g'
settings.store()
"""

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.
Only attributes defined here will be stored.
Subclasses should initialize any attributes they want to store here, then call ``super``.
"""Initialize a store with the given filename.
:param filename: the file that backs this store for saving and loading
"""

self._filename = filename
self.filename = filename

def restore(self):
try:
self.restore()
self._restore()
except IOError as e:
if e.errno != errno.ENOENT:
raise

def restore(self):

def _restore(self):
"""
Set the values of whatever attributes are recoverable
from the pickle file.
Expand All @@ -83,54 +85,61 @@ def restore(self):
of the EgStore object will retain the values that they were
initialized with.
If the pickled object has some attributes that were not
initialized in the EgStore object, then those attributes
will be ignored.
IN SUMMARY:
After the recover() operation, the EgStore object will have all,
and only, the attributes that it had when it was initialized.
Where possible, those attributes will have values recovered
Where possible, the attributes will have values recovered
from the pickled object.
"""
with open(self._filename, 'rb') as f:
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
for key, value in store.__dict__.items():
self.__dict__[key] = value

self.last_time_restored = datetime.datetime.now()


def store(self):
"""Save this store to a pickle file.
All directories in :attr:`filename` must already exist.
"""

with open(self._filename, 'wb') as f:
with open(self.filename, 'wb') as f:
self.last_time_stored = datetime.datetime.now()
pickle.dump(self, f)


def kill(self):
"""Delete this store's file if it exists."""

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

def __getstate__(self):
""" All attributes will be pickled """
state = self.__dict__.copy()
del state['_filename']
return state

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

""" Ensure filename won't be unpickled """
if 'filename' in state:
del state['filename']
self.__dict__.update(state)

def __str__(self):
""""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')
stored_values = self.__dict__
lines = []
width = max(len(key) for key in stored_values)
for key in sorted(stored_values.keys()):
value = stored_values[key]
if isinstance(value, datetime.datetime):
value = value.isoformat()
lines.append('{0} : {1!r}'.format(key.ljust(width), value))
return '\n'.join(lines)

def __repr__(self):
return '{0}({1!r})'.format(self.__class__.__name__, self._filename)
return '{0}({1!r})'.format(self.__class__.__name__, self.filename)


class Settings(EgStore):
def __init__(self, filename):
self.filename = filename
78 changes: 61 additions & 17 deletions sphinx/tutorial.rst
Original file line number Diff line number Diff line change
Expand Up @@ -385,54 +385,98 @@ In order to make the process of storing and restoring user settings, EasyGui pro

Your application must also create an object of that class (let's call the object settings).

The constructor (the __init__ method) of the Settings class must initialize all of the values that you wish to remember.
The constructor (the __init__ method) of the Settings class can initialize all of the values that you wish to remember.

Once you have done this, you can remember the settings simply by assigning values to instance variables in the settings object, and use the settings.store() method to persist the settings object to disk.

Here is an example of code to create the Settings class::
Here is an example of code using the Settings class::
from easygui import EgStore

#-----------------------------------------------------------------------
# -----------------------------------------------------------------------
# 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 = ""

super(EgStore, self).__init__(filename)
# -------------------------------------------------
# For subclasses of EgStore, these must be
# the last two statements in __init__
# -------------------------------------------------
self.filename = filename # this is required
self.restore()

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::

#-----------------------------------------------------------------------
# Create the settings object.
# If the settingsFile exists, this will restore its values
# from the settingsFile.
# create "settings", a persistent Settings object
# Note that the "filename" argument is required.
# The directory for the persistent file must already exist.
#-----------------------------------------------------------------------
settingsFilename = os.path.join("C:", "myApp", "settings.txt") # Windows example
settings = Settings(settingsFilename)

And here is example code of using the settings object::
settingsFilename = "settings.txt"
settings = Settings(settingsFilename)

# we initialize the "user" and "server" variables
# Now use the settings object.
# Initialize the "user" and "server" variables
# 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
# Save the variables as attributes of the "settings" object
settings.userId = user
settings.targetServer = server
settings.store() # persist the settings
print("\nInitial settings")
print settings

# run code that gets a new value for userId
# Run code that gets a new value for userId
# then persist the settings with the new value
user = "biden_joe"
settings.userId = user
settings.store()
print("\nSettings after modification")
print settings

# Delete setting variable
del settings.userId
print("\nSettings after deletion of userId")
print settings

Here is an example of code using a dedicated function to create the Settings class::

from easygui import read_or_create_settings

# Create the settings object.
settings = read_or_create_settings('settings1.txt')

# Save the variables as attributes of the "settings" object
settings.userId = "obama_barak"
settings.targetServer = "whitehouse1"
settings.store() # persist the settings
print("\nInitial settings")
print settings

# Run code that gets a new value for userId
# then persist the settings with the new value
user = "biden_joe"
settings.userId = user
settings.store()
print("\nSettings after modification")
print settings

# Delete setting variable
del settings.userId
print("\nSettings after deletion of userId")
print settings



Trapping Exceptions
-------------------
Expand Down

0 comments on commit 62a96b8

Please sign in to comment.