Compare commits

...

10 commits

Author SHA1 Message Date
Lance Edgar
a0b35dfadb Remove custom PyPI stuff from Fabric release task. 2014-04-28 14:28:54 -07:00
Lance Edgar
8fabdf8b72 update changelog 2014-04-28 14:27:32 -07:00
Lance Edgar
73978ffeb7 Allow config file to prevent logging configuration from happening. 2014-04-28 14:26:21 -07:00
Lance Edgar
183530afc9 update changelog 2014-01-28 09:13:45 -08:00
Lance Edgar
8a0f300fc0 Add minimum version requirement for pytz. 2013-07-31 22:36:54 -07:00
Lance Edgar
ee9c6622ff Add mock import for testing on Linux. 2013-06-18 22:46:58 -07:00
Lance Edgar
4fe5ad9bf0 Prepare for tests.
This doesn't add any actual tests but it should pave the way for that.  Tests
may be run like so:

.. code-block:: sh

   python setup.py nosetests --with-coverage
2013-06-18 22:19:52 -07:00
Lance Edgar
25611f1e68 Tweaked Fabric `release` command. 2013-05-22 18:09:51 -07:00
Lance Edgar
4ed6b09a24 update changelog 2013-05-21 22:30:03 -07:00
Lance Edgar
3766dbfff1 Updated `repr()` output for model classes. 2013-05-17 12:21:39 -07:00
15 changed files with 124 additions and 56 deletions

View file

@ -1,4 +1,29 @@
0.1.2
-----
* Allow config file to prevent logging configuration from happening.
0.1.1
-----
* Some random things required in production at MaMa Jean's...
Specifically this is known to replace occurrences of e.g. ``edbob.User`` with
a more standard (properly imported) reference to ``User``.
0.1a29
------
* Removed ``setup.cfg`` file.
* Changed some logging instances from ``INFO`` to ``DEBUG``.
* Updated ``repr()`` output for model classes.
0.1a28 0.1a28
------ ------

View file

@ -1 +1 @@
__version__ = '0.1a28' __version__ = '0.1.2'

View file

@ -51,7 +51,8 @@ class Permission(Base):
permission = Column(String(50), primary_key=True) permission = Column(String(50), primary_key=True)
def __repr__(self): def __repr__(self):
return "<Permission: %s, %s>" % (self.role, self.permission) return "Permission(role_uuid={0}, permission={1})".format(
repr(self.role_uuid), repr(self.permission))
def __unicode__(self): def __unicode__(self):
return unicode(self.permission or '') return unicode(self.permission or '')
@ -69,7 +70,7 @@ class UserRole(Base):
role_uuid = Column(String(32), ForeignKey('roles.uuid')) role_uuid = Column(String(32), ForeignKey('roles.uuid'))
def __repr__(self): def __repr__(self):
return "<UserRole: %s : %s>" % (self.user, self.role) return "UserRole(uuid={0})".format(repr(self.uuid))
class Role(Base): class Role(Base):
@ -97,7 +98,7 @@ class Role(Base):
getset_factory=getset_factory) getset_factory=getset_factory)
def __repr__(self): def __repr__(self):
return "<Role: %s>" % self.name return "Role(uuid={0})".format(repr(self.uuid))
def __unicode__(self): def __unicode__(self):
return unicode(self.name or '') return unicode(self.name or '')
@ -124,7 +125,7 @@ class User(Base):
getset_factory=getset_factory) getset_factory=getset_factory)
def __repr__(self): def __repr__(self):
return "<User: %s>" % self.username return "User(uuid={0})".format(repr(self.uuid))
def __unicode__(self): def __unicode__(self):
return unicode(self.username or '') return unicode(self.username or '')

View file

@ -72,7 +72,8 @@ class PhoneNumber(Base):
__mapper_args__ = {'polymorphic_on': parent_type} __mapper_args__ = {'polymorphic_on': parent_type}
def __repr__(self): def __repr__(self):
return "<%s: %s>" % (self.__class__.__name__, self.number) return "{0}(uuid={1})".format(
self.__class__.__name__, repr(self.uuid))
def __unicode__(self): def __unicode__(self):
return unicode(self.number) return unicode(self.number)
@ -103,7 +104,8 @@ class EmailAddress(Base):
__mapper_args__ = {'polymorphic_on': parent_type} __mapper_args__ = {'polymorphic_on': parent_type}
def __repr__(self): def __repr__(self):
return "<%s: %s>" % (self.__class__.__name__, self.address) return "{0}(uuid={1})".format(
self.__class__.__name__, repr(self.uuid))
def __unicode__(self): def __unicode__(self):
return unicode(self.address) return unicode(self.address)
@ -131,7 +133,7 @@ class Person(Base):
display_name = Column(String(100), default=get_person_display_name) display_name = Column(String(100), default=get_person_display_name)
def __repr__(self): def __repr__(self):
return "<Person: %s>" % self.display_name return "Person(uuid={0})".format(repr(self.uuid))
def __unicode__(self): def __unicode__(self):
return unicode(self.display_name or '') return unicode(self.display_name or '')

View file

@ -54,7 +54,7 @@ class ActiveExtension(Base):
name = Column(String(50), primary_key=True) name = Column(String(50), primary_key=True)
def __repr__(self): def __repr__(self):
return "<ActiveExtension: %s>" % self.name return "ActiveExtension(name={0})".format(repr(self.name))
def __str__(self): def __str__(self):
return str(self.name or '') return str(self.name or '')
@ -71,4 +71,4 @@ class Setting(Base):
value = Column(Text) value = Column(Text)
def __repr__(self): def __repr__(self):
return "<Setting: %s>" % self.name return "Setting(name={0})".format(repr(self.name))

View file

@ -28,11 +28,19 @@
import sys import sys
import os.path import os.path
import pyinotify
import threading import threading
import Queue import Queue
import logging import logging
try:
import pyinotify
except ImportError:
# Mock out for testing on Windows.
class Dummy(object):
pass
pyinotify = Dummy()
pyinotify.ProcessEvent = Dummy
import edbob import edbob
from edbob import filemon from edbob import filemon
from edbob.daemon import Daemon from edbob.daemon import Daemon

View file

@ -89,7 +89,8 @@ def init(appname='edbob', *args, **kwargs):
shell = kwargs.get('shell', False) shell = kwargs.get('shell', False)
for paths in config_paths: for paths in config_paths:
config.read(paths, recurse=not shell) config.read(paths, recurse=not shell)
config.configure_logging() if config.getboolean('edbob', 'configure_logging', default=True):
config.configure_logging()
default_modules = 'edbob.time' default_modules = 'edbob.time'
modules = config.get('edbob', 'init', default=default_modules) modules = config.get('edbob', 'init', default=default_modules)

View file

@ -33,37 +33,38 @@ from sqlalchemy import and_
# from formalchemy import Field # from formalchemy import Field
import edbob
# from edbob.pyramid import filters # from edbob.pyramid import filters
# from edbob.pyramid import forms # from edbob.pyramid import forms
# from edbob.pyramid import grids # from edbob.pyramid import grids
# from edbob.pyramid import Session # from edbob.pyramid import Session
from edbob.pyramid.views import SearchableAlchemyGridView, CrudView from edbob.pyramid.views import SearchableAlchemyGridView, CrudView
from edbob.db.extensions.contact.model import (
Person, PersonEmailAddress, PersonPhoneNumber)
class PeopleGrid(SearchableAlchemyGridView): class PeopleGrid(SearchableAlchemyGridView):
mapped_class = edbob.Person mapped_class = Person
config_prefix = 'people' config_prefix = 'people'
sort = 'first_name' sort = 'first_name'
def join_map(self): def join_map(self):
return { return {
'email': 'email':
lambda q: q.outerjoin(edbob.PersonEmailAddress, and_( lambda q: q.outerjoin(PersonEmailAddress, and_(
edbob.PersonEmailAddress.parent_uuid == edbob.Person.uuid, PersonEmailAddress.parent_uuid == Person.uuid,
edbob.PersonEmailAddress.preference == 1)), PersonEmailAddress.preference == 1)),
'phone': 'phone':
lambda q: q.outerjoin(edbob.PersonPhoneNumber, and_( lambda q: q.outerjoin(PersonPhoneNumber, and_(
edbob.PersonPhoneNumber.parent_uuid == edbob.Person.uuid, PersonPhoneNumber.parent_uuid == Person.uuid,
edbob.PersonPhoneNumber.preference == 1)), PersonPhoneNumber.preference == 1)),
} }
def filter_map(self): def filter_map(self):
return self.make_filter_map( return self.make_filter_map(
ilike=['first_name', 'last_name'], ilike=['first_name', 'last_name'],
email=self.filter_ilike(edbob.PersonEmailAddress.address), email=self.filter_ilike(PersonEmailAddress.address),
phone=self.filter_ilike(edbob.PersonPhoneNumber.number)) phone=self.filter_ilike(PersonPhoneNumber.number))
def filter_config(self): def filter_config(self):
return self.make_filter_config( return self.make_filter_config(
@ -77,8 +78,8 @@ class PeopleGrid(SearchableAlchemyGridView):
def sort_map(self): def sort_map(self):
return self.make_sort_map( return self.make_sort_map(
'first_name', 'last_name', 'first_name', 'last_name',
email=self.sorter(edbob.PersonEmailAddress.address), email=self.sorter(PersonEmailAddress.address),
phone=self.sorter(edbob.PersonPhoneNumber.number)) phone=self.sorter(PersonPhoneNumber.number))
def grid(self): def grid(self):
g = self.make_grid() g = self.make_grid()
@ -97,7 +98,7 @@ class PeopleGrid(SearchableAlchemyGridView):
class PersonCrud(CrudView): class PersonCrud(CrudView):
mapped_class = edbob.Person mapped_class = Person
home_route = 'people' home_route = 'people'
def fieldset(self, model): def fieldset(self, model):

View file

@ -32,10 +32,10 @@ import formalchemy
from webhelpers.html import tags from webhelpers.html import tags
from webhelpers.html.builder import HTML from webhelpers.html.builder import HTML
import edbob
from edbob.db import auth from edbob.db import auth
from edbob.pyramid import Session from edbob.pyramid import Session
from edbob.pyramid.views import SearchableAlchemyGridView, CrudView from edbob.pyramid.views import SearchableAlchemyGridView, CrudView
from edbob.db.extensions.auth.model import Role
default_permissions = [ default_permissions = [
@ -68,7 +68,7 @@ default_permissions = [
class RolesGrid(SearchableAlchemyGridView): class RolesGrid(SearchableAlchemyGridView):
mapped_class = edbob.Role mapped_class = Role
config_prefix = 'roles' config_prefix = 'roles'
sort = 'name' sort = 'name'
@ -161,7 +161,7 @@ def PermissionsFieldRenderer(permissions, *args, **kwargs):
class RoleCrud(CrudView): class RoleCrud(CrudView):
mapped_class = edbob.Role mapped_class = Role
home_route = 'roles' home_route = 'roles'
permissions = default_permissions permissions = default_permissions

View file

@ -32,28 +32,29 @@ from webhelpers.html.builder import HTML
import formalchemy import formalchemy
from formalchemy.fields import SelectFieldRenderer from formalchemy.fields import SelectFieldRenderer
import edbob
from edbob.db import auth from edbob.db import auth
from edbob.pyramid import Session from edbob.pyramid import Session
from edbob.pyramid.views import SearchableAlchemyGridView, CrudView from edbob.pyramid.views import SearchableAlchemyGridView, CrudView
from edbob.db.extensions.auth.model import User, Role
from edbob.db.extensions.contact.model import Person
class UsersGrid(SearchableAlchemyGridView): class UsersGrid(SearchableAlchemyGridView):
mapped_class = edbob.User mapped_class = User
config_prefix = 'users' config_prefix = 'users'
sort = 'username' sort = 'username'
def join_map(self): def join_map(self):
return { return {
'person': 'person':
lambda q: q.outerjoin(edbob.Person), lambda q: q.outerjoin(Person),
} }
def filter_map(self): def filter_map(self):
return self.make_filter_map( return self.make_filter_map(
ilike=['username'], ilike=['username'],
person=self.filter_ilike(edbob.Person.display_name)) person=self.filter_ilike(Person.display_name))
def filter_config(self): def filter_config(self):
return self.make_filter_config( return self.make_filter_config(
@ -65,7 +66,7 @@ class UsersGrid(SearchableAlchemyGridView):
def sort_map(self): def sort_map(self):
return self.make_sort_map( return self.make_sort_map(
'username', 'username',
person=self.sorter(edbob.Person.display_name)) person=self.sorter(Person.display_name))
def grid(self): def grid(self):
g = self.make_grid() g = self.make_grid()
@ -92,7 +93,7 @@ def RolesFieldRenderer(request):
class RolesFieldRenderer(SelectFieldRenderer): class RolesFieldRenderer(SelectFieldRenderer):
def render_readonly(self, **kwargs): def render_readonly(self, **kwargs):
roles = Session.query(edbob.Role) roles = Session.query(Role)
html = '' html = ''
for uuid in self.value: for uuid in self.value:
role = roles.get(uuid) role = roles.get(uuid)
@ -117,15 +118,15 @@ class RolesField(formalchemy.Field):
return [x.uuid for x in user.roles] return [x.uuid for x in user.roles]
def get_options(self): def get_options(self):
q = Session.query(edbob.Role.name, edbob.Role.uuid) q = Session.query(Role.name, Role.uuid)
q = q.filter(edbob.Role.uuid != auth.guest_role(Session()).uuid) q = q.filter(Role.uuid != auth.guest_role(Session()).uuid)
q = q.order_by(edbob.Role.name) q = q.order_by(Role.name)
return q.all() return q.all()
def sync(self): def sync(self):
if not self.is_readonly(): if not self.is_readonly():
user = self.model user = self.model
roles = Session.query(edbob.Role) roles = Session.query(Role)
data = self.renderer.deserialize() data = self.renderer.deserialize()
user.roles = [roles.get(x) for x in data] user.roles = [roles.get(x) for x in data]
@ -140,7 +141,7 @@ class _ProtectedPersonRenderer(formalchemy.FieldRenderer):
def ProtectedPersonRenderer(uuid): def ProtectedPersonRenderer(uuid):
person = Session.query(edbob.Person).get(uuid) person = Session.query(Person).get(uuid)
assert person assert person
return type('ProtectedPersonRenderer', (_ProtectedPersonRenderer,), return type('ProtectedPersonRenderer', (_ProtectedPersonRenderer,),
{'person': person}) {'person': person})
@ -187,7 +188,7 @@ class PasswordField(formalchemy.Field):
class UserCrud(CrudView): class UserCrud(CrudView):
mapped_class = edbob.User mapped_class = User
home_route = 'users' home_route = 'users'
def fieldset(self, user): def fieldset(self, user):
@ -213,7 +214,7 @@ class UserCrud(CrudView):
del fs.confirm_password del fs.confirm_password
# if fs.edit and user.person: # if fs.edit and user.person:
if isinstance(user, edbob.User) and user.person: if isinstance(user, User) and user.person:
fs.person.set(readonly=True, fs.person.set(readonly=True,
renderer=LinkedPersonRenderer(self.request)) renderer=LinkedPersonRenderer(self.request))

19
edbob/tests/__init__.py Normal file
View file

@ -0,0 +1,19 @@
import unittest
from pyramid import testing
class TestCase(unittest.TestCase):
"""
Base class for all test suites.
"""
def setUp(self):
self.config = testing.setUp()
def tearDown(self):
testing.tearDown()
def test_something(self):
self.assertTrue(1)

View file

@ -38,9 +38,17 @@ if sys.platform == 'win32': # docs should build for everyone
import win32file import win32file
import win32print import win32print
import win32service import win32service
import win32serviceutil
import winerror import winerror
try:
import win32serviceutil
except ImportError:
# Mock out for testing on Linux.
class Object(object):
pass
win32serviceutil = Object()
win32serviceutil.ServiceFramework = Object
import edbob import edbob

16
fabfile.py vendored
View file

@ -22,25 +22,15 @@
# #
################################################################################ ################################################################################
import os.path import shutil
from fabric.api import * from fabric.api import *
execfile(os.path.join(os.path.dirname(__file__), 'edbob', '_version.py'))
@task @task
def release(): def release():
""" """
Release a new version of 'edbob'. Release a new version of 'edbob'.
""" """
shutil.rmtree('edbob.egg-info')
local("python setup.py egg_info --tag-build='' sdist --formats=gztar") local('python setup.py sdist --formats=gztar register upload')
filename = 'edbob-{0}.tar.gz'.format(__version__)
put(os.path.join('dist', filename), '/srv/pypi/{0}'.format(filename))
with cd('/srv/pypi'):
run('rm --recursive --force simple')
run('compoze index')

7
setup.cfg Normal file
View file

@ -0,0 +1,7 @@
[nosetests]
nocapture = 1
cover-package = edbob
cover-erase = 1
cover-inclusive = 1
cover-html = 1
cover-html-dir = htmlcov

View file

@ -73,7 +73,10 @@ requires = [
'decorator', # 3.3.2 'decorator', # 3.3.2
'lockfile', # 0.9.1 'lockfile', # 0.9.1
'progressbar', # 2.3 'progressbar', # 2.3
'pytz', # 2012b
# Hardcode ``pytz`` minimum since apparently it isn't (any longer?) enough
# to simply require the library.
'pytz>=2013b', # 2013b
] ]
if sys.version_info < (2, 7): if sys.version_info < (2, 7):
@ -209,6 +212,8 @@ setup(
install_requires = requires, install_requires = requires,
extras_require = extras, extras_require = extras,
tests_require = requires + ['nose'],
test_suite = 'nose.collector',
packages = find_packages(), packages = find_packages(),
include_package_data = True, include_package_data = True,