extended commit (see note)

- Slight overhaul of init() system; added ``edbob.init_modules()`` function.

- Added ``read_service()`` method to ``AppConfigParser`` class, for use with
  Windows services.

- Added generic ``Service`` class to ``edbob.win32`` module.  (File monitor now
  inherits from it.)

- Tweaked ``edbob.db`` initialization somewhat.  (``Base.metadata`` no longer
  binds to ``edbob.db.engine``.)

- Fixed guest role bug in ``edbob.db.auth.has_permission()`` function.

- Added "automagical" enumeration support for database extensions.

- Added ``EMAIL_PREFERENCE`` enum to ``contact`` database extension.

- Tweaked ``edbob.pyramid.includeme()``.

- Tweaked ``people`` Pyramid views.
This commit is contained in:
Lance Edgar 2012-09-17 11:43:13 -07:00
parent 526ff5dd6b
commit c7e0bfef6a
18 changed files with 457 additions and 248 deletions

View file

@ -34,6 +34,3 @@ from edbob.files import *
from edbob.modules import * from edbob.modules import *
from edbob.configuration import * from edbob.configuration import *
from edbob.initialization import * from edbob.initialization import *
inited = False

View file

@ -289,6 +289,25 @@ class AppConfigParser(ConfigParser.SafeConfigParser):
self.paths_loaded.append(path) self.paths_loaded.append(path)
log.info("Read config file: %s" % path) log.info("Read config file: %s" % path)
def read_service(self, service, paths):
"""
"Special" version of :meth:`read()` which will first inspect the
file(s) for a service-specific directive, the presence of which
indicates the *true* config file to be used for the service.
This method is pretty much a hack to get around certain limitations of
Windows service implementations; it is not used otherwise.
"""
config = ConfigParser.SafeConfigParser()
config.read(paths)
if (config.has_section('edbob.service_config')
and config.has_option('edbob.service_config', service)):
paths = eval(config.get('edbob.service_config', service))
self.read(paths, recurse=True)
def require(self, section, option, msg=None): def require(self, section, option, msg=None):
""" """
Convenience method which will raise an exception if the given option Convenience method which will raise an exception if the given option

View file

@ -37,7 +37,6 @@ import edbob
__all__ = ['engines', 'engine', 'Session', 'get_setting', 'save_setting'] __all__ = ['engines', 'engine', 'Session', 'get_setting', 'save_setting']
inited = False
engines = None engines = None
engine = None engine = None
Session = sessionmaker() Session = sessionmaker()
@ -71,36 +70,36 @@ def init(config):
from edbob.db import enum from edbob.db import enum
from edbob.db.extensions import extend_framework from edbob.db.extensions import extend_framework
global inited, engines, engine global engines, engine
keys = config.get('edbob.db', 'sqlalchemy.keys') keys = config.get('edbob.db', 'keys')
if keys: if keys:
keys = keys.split() keys = keys.split(',')
else: else:
keys = ['default'] keys = ['default']
engines = {} engines = {}
cfg = config.get_dict('edbob.db') cfg = config.get_dict('edbob.db')
for key in keys: for key in keys:
key = key.strip()
try: try:
engines[key] = engine_from_config(cfg, 'sqlalchemy.%s.' % key) engines[key] = engine_from_config(cfg, '%s.' % key)
except KeyError: except KeyError:
if key == 'default': if key == 'default':
try: try:
engines[key] = engine_from_config(cfg) engines[key] = engine_from_config(cfg, 'sqlalchemy.')
except KeyError: except KeyError:
pass pass
engine = engines.get('default') engine = engines.get('default')
if engine: if engine:
Base.metadata.bind = engine Session.configure(bind=engine)
extend_framework() extend_framework()
edbob.graft(edbob, edbob.db) edbob.graft(edbob, edbob.db)
edbob.graft(edbob, model) edbob.graft(edbob, model)
edbob.graft(edbob, enum) edbob.graft(edbob, enum)
inited = True
def get_setting(name, session=None): def get_setting(name, session=None):

View file

@ -85,12 +85,12 @@ def guest_role(session):
""" """
uuid = 'f8a27c98965a11dfaff7001143047286' uuid = 'f8a27c98965a11dfaff7001143047286'
admin = session.query(edbob.Role).get(uuid) guest = session.query(edbob.Role).get(uuid)
if admin: if guest:
return admin return guest
admin = edbob.Role(uuid=uuid, name='Guest') guest = edbob.Role(uuid=uuid, name='Guest')
session.add(admin) session.add(guest)
return admin return guest
def grant_permission(role, permission, session=None): def grant_permission(role, permission, session=None):
@ -114,7 +114,7 @@ def has_permission(obj, perm, session=None):
""" """
if isinstance(obj, edbob.User): if isinstance(obj, edbob.User):
roles = obj.roles roles = list(obj.roles)
elif isinstance(obj, edbob.Role): elif isinstance(obj, edbob.Role):
roles = [obj] roles = [obj]
elif obj is None: elif obj is None:

View file

@ -76,6 +76,11 @@ class Extension(edbob.Object):
# :meth:`Extension.get_models_module()` for more info). # :meth:`Extension.get_models_module()` for more info).
model_module = '' model_module = ''
# You can set this to any dotted module path you like. If unset a default
# will be assumed, of the form ``<path.to.extension>.enum`` (see
# :meth:`Extension.get_enum_module()` for more info).
enum_module = ''
# @property # @property
# @requires_impl(is_property=True) # @requires_impl(is_property=True)
# def name(self): # def name(self):
@ -119,6 +124,9 @@ class Extension(edbob.Object):
""" """
edbob.graft(edbob, self.get_model_module()) edbob.graft(edbob, self.get_model_module())
enum = self.get_enum_module()
if enum:
edbob.graft(edbob, enum)
# def extend_mappers(self, metadata): # def extend_mappers(self, metadata):
# """ # """
@ -144,6 +152,26 @@ class Extension(edbob.Object):
self.populate_metadata(meta, recurse) self.populate_metadata(meta, recurse)
return meta return meta
def get_enum_module(self):
"""
Imports and returns a reference to the Python module providing
enumeration data for the extension (if one exists).
:attr:`Extension.enum_module` is first consulted to determine the
dotted module path. If nothing is found there, a default path is
constructed by appending ``'.enum'`` to the extension module's own
dotted path.
"""
if self.enum_module:
module = self.enum_module
else:
module = str(self.__class__.__module__) + '.enum'
try:
return import_module_path(module)
except ImportError:
return None
def get_model_module(self): def get_model_module(self):
""" """
Imports and returns a reference to the Python module providing schema Imports and returns a reference to the Python module providing schema

View file

@ -0,0 +1,40 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
################################################################################
#
# edbob -- Pythonic Software Framework
# Copyright © 2010-2012 Lance Edgar
#
# This file is part of edbob.
#
# edbob is free software: you can redistribute it and/or modify it under the
# terms of the GNU Affero General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your option)
# any later version.
#
# edbob is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
# more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with edbob. If not, see <http://www.gnu.org/licenses/>.
#
################################################################################
"""
``edbob.db.extensions.contact.enum`` -- Enumerations
"""
EMAIL_PREFERENCE_NONE = 0
EMAIL_PREFERENCE_TEXT = 1
EMAIL_PREFERENCE_HTML = 2
EMAIL_PREFERENCE_MOBILE = 3
EMAIL_PREFERENCE = {
EMAIL_PREFERENCE_NONE : "No Emails",
EMAIL_PREFERENCE_TEXT : "Text",
EMAIL_PREFERENCE_HTML : "HTML",
EMAIL_PREFERENCE_MOBILE : "Mobile",
}

View file

@ -35,7 +35,7 @@ import threading
import edbob import edbob
from edbob.errors import email_exception from edbob.errors import email_exception
from edbob.filemon import get_monitor_profiles from edbob.filemon import get_monitor_profiles
from edbob.win32 import file_is_free from edbob.win32 import Service, file_is_free
if sys.platform == 'win32': # docs should build for everyone if sys.platform == 'win32': # docs should build for everyone
import win32api import win32api
@ -50,36 +50,23 @@ if sys.platform == 'win32': # docs should build for everyone
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
class FileMonitorService(win32serviceutil.ServiceFramework): class FileMonitorService(Service):
""" """
Implements edbob's file monitor Windows service. Implements edbob's file monitor Windows service.
""" """
_svc_name_ = "Edbob File Monitor" _svc_name_ = 'EdbobFileMonitor'
_svc_display_name_ = "Edbob : File Monitoring Service" _svc_display_name_ = "Edbob : File Monitoring Service"
_svc_description_ = ("Monitors one or more folders for incoming files, " _svc_description_ = ("Monitors one or more folders for incoming files, "
"and performs configured actions as new files arrive.") "and performs configured actions as new files arrive.")
appname = 'edbob'
def __init__(self, args):
"""
Constructor.
"""
# super(FileMonitorService, self).__init__(args)
win32serviceutil.ServiceFramework.__init__(self, args)
# Create "wait stop" event, for main worker loop.
self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
def Initialize(self): def Initialize(self):
""" """
Service initialization. Service initialization.
""" """
# Read configuration file(s). if not Service.Initialize(self):
edbob.init(self.appname) return False
# Read monitor profile(s) from config. # Read monitor profile(s) from config.
self.monitored = get_monitor_profiles(self.appname) self.monitored = get_monitor_profiles(self.appname)
@ -118,50 +105,6 @@ class FileMonitorService(win32serviceutil.ServiceFramework):
return True return True
def SvcDoRun(self):
"""
This method is invoked when the service starts.
"""
import servicemanager
# Write start occurrence to Windows Event Log.
servicemanager.LogMsg(
servicemanager.EVENTLOG_INFORMATION_TYPE,
servicemanager.PYS_SERVICE_STARTED,
(self._svc_name_, ''))
# Figure out what we're supposed to be doing.
if self.Initialize():
# Wait infinitely for stop request, while threads do their thing.
log.info("SvcDoRun: All threads started; waiting for stop request.")
win32event.WaitForSingleObject(self.hWaitStop, win32event.INFINITE)
log.info("SvcDoRun: Stop request received.")
else: # Nothing to be done...
msg = "Nothing to do! No valid monitor profiles found in config."
servicemanager.LogWarningMsg(msg)
log.warning("SvcDoRun: %s" % msg)
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
# Write stop occurrence to Windows Event Log.
servicemanager.LogMsg(
servicemanager.EVENTLOG_INFORMATION_TYPE,
servicemanager.PYS_SERVICE_STOPPED,
(self._svc_name_, ''))
def SvcStop(self):
"""
This method is invoked when the service is requested to stop itself.
"""
# Let the SCM know we're trying to stop.
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
# Let worker loop know its job is done.
win32event.SetEvent(self.hWaitStop)
def monitor_files(queue, path, profile): def monitor_files(queue, path, profile):
""" """

View file

@ -38,7 +38,9 @@ from edbob.configuration import (
from edbob.exceptions import InitError from edbob.exceptions import InitError
__all__ = ['init'] __all__ = ['init', 'init_modules', 'inited']
inited = []
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -80,22 +82,40 @@ def init(appname='edbob', *args, **kwargs):
else: else:
config_paths = default_system_paths(appname) + default_user_paths(appname) config_paths = default_system_paths(appname) + default_user_paths(appname)
shell = bool(kwargs.get('shell')) service = kwargs.get('service')
for paths in config_paths: if service:
config.read(paths, recurse=not shell) config.read_service(service, config_paths)
else:
shell = kwargs.get('shell', False)
for paths in config_paths:
config.read(paths, recurse=not shell)
config.configure_logging() 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)
if modules: if modules:
for name in modules.split(','): modules = modules.split(',')
name = name.strip() init_modules(modules, config)
edbob.graft(edbob, locals(), 'config')
inited.append('edbob')
def init_modules(names, config=None):
"""
Initialize the given modules. ``names`` should be a sequence of strings,
each of which should be a dotted module name. If ``config`` is not
specified, :attr:`edbob.config` is assumed.
"""
if config is None:
config = edbob.config
for name in names:
name = name.strip()
if name not in inited:
module = __import__(name, globals(), locals(), fromlist=['init']) module = __import__(name, globals(), locals(), fromlist=['init'])
if not hasattr(module, 'init'): if not hasattr(module, 'init'):
raise InitError(module) raise InitError(module)
getattr(module, 'init')(config) getattr(module, 'init')(config)
# config.inited.append(name) inited.append(name)
# config.inited.append('edbob')
edbob.graft(edbob, locals(), 'config')
edbob.inited = True

View file

@ -29,6 +29,8 @@
from sqlalchemy.orm import sessionmaker, scoped_session from sqlalchemy.orm import sessionmaker, scoped_session
from zope.sqlalchemy import ZopeTransactionExtension from zope.sqlalchemy import ZopeTransactionExtension
import edbob
__all__ = ['Session'] __all__ = ['Session']
@ -56,6 +58,7 @@ def includeme(config):
config.include('pyramid_tm') config.include('pyramid_tm')
# Configure SQLAlchemy session. # Configure SQLAlchemy session.
Session.configure(bind=edbob.engine)
Session.configure(extension=ZopeTransactionExtension()) Session.configure(extension=ZopeTransactionExtension())
# Configure user authentication / authorization. # Configure user authentication / authorization.
@ -69,3 +72,6 @@ def includeme(config):
# Add static views. # Add static views.
config.include('edbob.pyramid.static') config.include('edbob.pyramid.static')
# Add subscriber hooks.
config.include('edbob.pyramid.subscribers')

View file

@ -74,12 +74,10 @@ def EnumFieldRenderer(enum):
return '' return ''
if value in enum: if value in enum:
return enum[value] return enum[value]
return value return str(value)
def render(self, **kwargs): def render(self, **kwargs):
opts = [] opts = [(enum[x], x) for x in sorted(enum)]
for value in sorted(enum):
opts.append((enum[value], value))
return formalchemy.fields.SelectFieldRenderer.render(self, opts, **kwargs) return formalchemy.fields.SelectFieldRenderer.render(self, opts, **kwargs)
return Renderer return Renderer

View file

@ -1,5 +1,5 @@
<%inherit file="/form.mako" /> <%inherit file="/form.mako" />
<%def name="title()">${"New "+form.pretty_name if form.creating else form.pretty_name+' : '+str(form.fieldset.model)}</%def> <%def name="title()">${"New "+form.pretty_name if form.creating else form.pretty_name+' : '+h.literal(str(form.fieldset.model))}</%def>
${parent.body()} ${parent.body()}

View file

@ -1,2 +0,0 @@
<%inherit file="/base.mako" />
${parent.body()}

View file

@ -0,0 +1,28 @@
<%inherit file="/crud.mako" />
<%def name="crud_name()">Person</%def>
<%def name="context_menu_items()">
<li>${h.link_to("Back to People", url('people'))}</li>
</%def>
${parent.body()}
## % if fieldset.edit:
## <h2>User Info</h2>
## % if user:
## ${user.render()|n}
## <div class="buttons">
## <button type="button" onclick="location.href = '${url('user.edit', uuid=user.model.uuid)}';">Edit User</button>
## </div>
## % else:
## <p>This person does not have a user account.</p>
## ${h.form(url('user.new'))}
## ${h.hidden('User--person_uuid', value=fieldset.model.uuid)}
## ${h.hidden('User--username')}
## <div class="buttons">
## ${h.submit('submit', "Create User")}
## </div>
## ${h.end_form()}
## % endif
## % endif

View file

@ -1,12 +1,11 @@
<%inherit file="/people/base.mako" /> <%inherit file="/grid.mako" />
<%inherit file="/index.mako" />
<%def name="title()">People</%def> <%def name="title()">People</%def>
<%def name="context_menu_items()"> <%def name="context_menu_items()">
% if request.has_perm('people.create'): ## % if request.has_perm('people.create'):
<li>${h.link_to("Create a new Person", url('person.new'))}</li> ## <li>${h.link_to("Create a new Person", url('person.new'))}</li>
% endif ## % endif
</%def> </%def>
${parent.body()} ${parent.body()}

View file

@ -1,29 +0,0 @@
<%inherit file="/people/base.mako" />
<%inherit file="/crud.mako" />
<%def name="crud_name()">Person</%def>
<%def name="menu()">
<p>${h.link_to("Back to People", url('people.list'))}</p>
</%def>
${parent.body()}
% if fieldset.edit:
<h2>User Info</h2>
% if user:
${user.render()|n}
<div class="buttons">
<button type="button" onclick="location.href = '${url('user.edit', uuid=user.model.uuid)}';">Edit User</button>
</div>
% else:
<p>This person does not have a user account.</p>
${h.form(url('user.new'))}
${h.hidden('User--person_uuid', value=fieldset.model.uuid)}
${h.hidden('User--username')}
<div class="buttons">
${h.submit('submit', "Create User")}
</div>
${h.end_form()}
% endif
% endif

View file

@ -26,155 +26,239 @@
``edbob.pyramid.views.people`` -- Person Views ``edbob.pyramid.views.people`` -- Person Views
""" """
import transaction from sqlalchemy import and_
from pyramid.httpexceptions import HTTPFound
from formalchemy import Field # import transaction
# from pyramid.httpexceptions import HTTPFound
# from formalchemy import Field
import edbob 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
def filter_map(): class PeopleGrid(SearchableAlchemyGridView):
return filters.get_filter_map(
edbob.Person,
ilike=['first_name', 'last_name', 'display_name'])
def search_config(request, fmap): mapped_class = edbob.Person
return filters.get_search_config( config_prefix = 'people'
'people.list', request, fmap, sort = 'first_name'
include_filter_display_name=True,
filter_type_display_name='lk')
def search_form(config): def join_map(self):
return filters.get_search_form(config) return {
'email':
lambda q: q.outerjoin(edbob.PersonEmailAddress, and_(
edbob.PersonEmailAddress.parent_uuid == edbob.Person.uuid,
edbob.PersonEmailAddress.preference == 1)),
'phone':
lambda q: q.outerjoin(edbob.PersonPhoneNumber, and_(
edbob.PersonPhoneNumber.parent_uuid == edbob.Person.uuid,
edbob.PersonPhoneNumber.preference == 1)),
}
def grid_config(request, search, fmap): def filter_map(self):
return grids.get_grid_config( return self.make_filter_map(
'people.list', request, search, ilike=['first_name', 'last_name'],
filter_map=fmap, sort='display_name') email=self.filter_ilike(edbob.PersonEmailAddress.address),
phone=self.filter_ilike(edbob.PersonPhoneNumber.number))
def sort_map(): def filter_config(self):
return grids.get_sort_map( return self.make_filter_config(
edbob.Person, include_filter_first_name=True,
['first_name', 'last_name', 'display_name']) filter_type_first_name='lk',
include_filter_last_name=True,
filter_type_last_name='lk',
filter_label_phone="Phone Number",
filter_label_email="Email Address")
def query(config): def sort_map(self):
smap = sort_map() return self.make_sort_map(
q = Session.query(edbob.Person) 'first_name', 'last_name',
q = filters.filter_query(q, config) email=self.sorter(edbob.PersonEmailAddress.address),
q = grids.sort_query(q, config, smap) phone=self.sorter(edbob.PersonPhoneNumber.number))
return q
def grid(self):
g = self.make_grid()
g.configure(
include=[
g.first_name,
g.last_name,
g.phone.label("Phone Number"),
g.email.label("Email Address"),
],
readonly=True)
g.clickable = True
g.click_route_name = 'person.read'
return g
def people(context, request): class PersonCrud(CrudView):
fmap = filter_map() mapped_class = edbob.Person
config = search_config(request, fmap) home_route = 'people'
search = search_form(config)
config = grid_config(request, search, fmap)
people = grids.get_pager(query, config)
g = forms.AlchemyGrid( def fieldset(self, model):
edbob.Person, people, config, fs = self.make_fieldset(model)
gridurl=request.route_url('people.list'), fs.configure(
objurl='person.edit') include=[
fs.first_name,
g.configure( fs.last_name,
include=[ fs.phone.label("Phone Number"),
g.first_name, fs.email.label("Email Address"),
g.last_name, ])
g.display_name, return fs
],
readonly=True)
grid = g.render(class_='clickable people')
return grids.render_grid(request, grid, search)
def person_fieldset(person, request): # def filter_map():
fs = forms.make_fieldset(person, url=request.route_url, # return filters.get_filter_map(
url_action=request.current_route_url(), # edbob.Person,
route_name='people.list') # ilike=['first_name', 'last_name', 'display_name'])
fs.configure(
include=[ # def search_config(request, fmap):
fs.first_name, # return filters.get_search_config(
fs.last_name, # 'people.list', request, fmap,
fs.display_name, # include_filter_display_name=True,
]) # filter_type_display_name='lk')
return fs
# def search_form(config):
# return filters.get_search_form(config)
# def grid_config(request, search, fmap):
# return grids.get_grid_config(
# 'people.list', request, search,
# filter_map=fmap, sort='display_name')
# def sort_map():
# return grids.get_sort_map(
# edbob.Person,
# ['first_name', 'last_name', 'display_name'])
# def query(config):
# smap = sort_map()
# q = Session.query(edbob.Person)
# q = filters.filter_query(q, config)
# q = grids.sort_query(q, config, smap)
# return q
def new_person(context, request): # def people(context, request):
fs = person_fieldset(edbob.Person, request) # fmap = filter_map()
if not fs.readonly and request.POST: # config = search_config(request, fmap)
fs.rebind(data=request.params) # search = search_form(config)
if fs.validate(): # config = grid_config(request, search, fmap)
# people = grids.get_pager(query, config)
with transaction.manager: # g = forms.AlchemyGrid(
fs.sync() # edbob.Person, people, config,
Session.add(fs.model) # gridurl=request.route_url('people.list'),
Session.flush() # objurl='person.edit')
request.session.flash("%s \"%s\" has been %s." % (
fs.crud_title, fs.get_display_text(),
'updated' if fs.edit else 'created'))
return HTTPFound(location=request.route_url('people.list')) # g.configure(
# include=[
# g.first_name,
# g.last_name,
# g.display_name,
# ],
# readonly=True)
return {'fieldset': fs, 'crud': True} # grid = g.render(class_='clickable people')
# return grids.render_grid(request, grid, search)
def edit_person(request): # def person_fieldset(person, request):
""" # fs = forms.make_fieldset(person, url=request.route_url,
View for editing a :class:`edbob.Person` instance. # url_action=request.current_route_url(),
""" # route_name='people.list')
# fs.configure(
# include=[
# fs.first_name,
# fs.last_name,
# fs.display_name,
# ])
# return fs
from edbob.pyramid.views.users import user_fieldset
uuid = request.matchdict['uuid'] # def new_person(context, request):
person = Session.query(edbob.Person).get(uuid) if uuid else None
assert person
fs = person_fieldset(person, request) # fs = person_fieldset(edbob.Person, request)
if request.POST: # if not fs.readonly and request.POST:
fs.rebind(data=request.params) # fs.rebind(data=request.params)
if fs.validate(): # if fs.validate():
with transaction.manager: # with transaction.manager:
fs.sync() # fs.sync()
fs.model = Session.merge(fs.model) # Session.add(fs.model)
request.session.flash("%s \"%s\" has been %s." % ( # Session.flush()
fs.crud_title, fs.get_display_text(), # request.session.flash("%s \"%s\" has been %s." % (
'updated' if fs.edit else 'created')) # fs.crud_title, fs.get_display_text(),
home = request.route_url('people.list') # 'updated' if fs.edit else 'created'))
return HTTPFound(location=home) # return HTTPFound(location=request.route_url('people.list'))
user = fs.model.user # return {'fieldset': fs, 'crud': True}
if user:
user = user_fieldset(user, request)
user.readonly = True
del user.person
del user.password
del user.confirm_password
return {'fieldset': fs, 'crud': True, 'user': user}
# def edit_person(request):
# """
# View for editing a :class:`edbob.Person` instance.
# """
# from edbob.pyramid.views.users import user_fieldset
# uuid = request.matchdict['uuid']
# person = Session.query(edbob.Person).get(uuid) if uuid else None
# assert person
# fs = person_fieldset(person, request)
# if request.POST:
# fs.rebind(data=request.params)
# if fs.validate():
# with transaction.manager:
# fs.sync()
# fs.model = Session.merge(fs.model)
# request.session.flash("%s \"%s\" has been %s." % (
# fs.crud_title, fs.get_display_text(),
# 'updated' if fs.edit else 'created'))
# home = request.route_url('people.list')
# return HTTPFound(location=home)
# user = fs.model.user
# if user:
# user = user_fieldset(user, request)
# user.readonly = True
# del user.person
# del user.password
# del user.confirm_password
# return {'fieldset': fs, 'crud': True, 'user': user}
def includeme(config): def includeme(config):
config.add_route('people.list', '/people') config.add_route('people', '/people')
config.add_view(people, route_name='people.list', renderer='/people/index.mako', config.add_view(PeopleGrid, route_name='people',
permission='people.list', http_cache=0) renderer='/people/index.mako',
permission='people.list')
config.add_route('person.new', '/people/new') # config.add_route('people.list', '/people')
config.add_view(new_person, route_name='person.new', renderer='/people/person.mako', # config.add_view(people, route_name='people.list', renderer='/people/index.mako',
permission='people.create', http_cache=0) # permission='people.list', http_cache=0)
config.add_route('person.edit', '/people/{uuid}/edit') config.add_route('person.read', '/people/{uuid}')
config.add_view(edit_person, route_name='person.edit', renderer='/people/person.mako', config.add_view(PersonCrud, attr='read', route_name='person.read',
permission='people.edit', http_cache=0) renderer='/people/crud.mako',
permission='people.read')
# config.add_route('person.new', '/people/new')
# config.add_view(new_person, route_name='person.new', renderer='/people/person.mako',
# permission='people.create', http_cache=0)
# config.add_route('person.edit', '/people/{uuid}/edit')
# config.add_view(edit_person, route_name='person.edit', renderer='/people/person.mako',
# permission='people.edit', http_cache=0)

View file

@ -69,7 +69,6 @@ setup(
], ],
install_requires = requires, install_requires = requires,
tests_require = requires,
packages = find_packages(), packages = find_packages(),
include_package_data = True, include_package_data = True,

View file

@ -28,16 +28,96 @@
import sys import sys
import subprocess import subprocess
import logging
if sys.platform == 'win32': # docs should build for everyone if sys.platform == 'win32': # docs should build for everyone
import pywintypes import pywintypes
import win32api import win32api
import win32con import win32con
import win32event
import win32file import win32file
import win32print import win32print
import win32service import win32service
import win32serviceutil
import winerror import winerror
import edbob
log = logging.getLogger(__name__)
class Service(win32serviceutil.ServiceFramework):
"""
Base class for Windows service implementations.
"""
appname = 'edbob'
def __init__(self, args):
"""
Constructor.
"""
win32serviceutil.ServiceFramework.__init__(self, args)
# Create "wait stop" event, for main worker loop.
self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
def Initialize(self):
"""
Service initialization.
"""
# Read configuration file(s).
edbob.init(self.appname, service=self._svc_name_)
return True
def SvcDoRun(self):
"""
This method is invoked when the service starts.
"""
import servicemanager
# Write start occurrence to Windows Event Log.
servicemanager.LogMsg(
servicemanager.EVENTLOG_INFORMATION_TYPE,
servicemanager.PYS_SERVICE_STARTED,
(self._svc_name_, ''))
# Figure out what we're supposed to be doing.
if self.Initialize():
# Wait infinitely for stop request, while threads do their thing.
log.info("SvcDoRun: All threads started; waiting for stop request.")
win32event.WaitForSingleObject(self.hWaitStop, win32event.INFINITE)
log.info("SvcDoRun: Stop request received.")
else: # Nothing to be done...
msg = "Nothing to do! (Initialization failed.)"
servicemanager.LogWarningMsg(msg)
log.warning("SvcDoRun: %s" % msg)
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
# Write stop occurrence to Windows Event Log.
servicemanager.LogMsg(
servicemanager.EVENTLOG_INFORMATION_TYPE,
servicemanager.PYS_SERVICE_STOPPED,
(self._svc_name_, ''))
def SvcStop(self):
"""
This method is invoked when the service is requested to stop itself.
"""
# Let the SCM know we're trying to stop.
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
# Let worker loop know its job is done.
win32event.SetEvent(self.hWaitStop)
def RegDeleteTree(key, subkey): def RegDeleteTree(key, subkey):
""" """