diff --git a/CHANGES.txt b/CHANGES.txt
index fbe7946..f09870a 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,5 +1,34 @@
+0.1a6
+-----
+
+- Fixed MANIFEST.in file.
+
+0.1a5
+-----
+
+- Added :mod:`edbob.csv` module.
+
+- Tweaked logging configuration and initialization semantics.
+
+0.1a4
+-----
+
+- Fixed call to sleep() in filemon service.
+
+0.1a3
+-----
+
+- Various tweaks to Pyramid code.
+
+0.1a2
+-----
+
+- Add ``win32.send_data_to_printer()`` function.
+
+- Various tweaks to Pyramid code.
+
0.1a1
-----
-- Initial version
+- Initial version
diff --git a/MANIFEST.in b/MANIFEST.in
index 7dc6232..a4c1d15 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,2 +1,18 @@
-include *.txt
+include COPYING.txt README.txt CHANGES.txt
include ez_setup.py
+
+include edbob/pyramid/static/favicon.ico
+include edbob/pyramid/static/robots.txt
+include edbob/pyramid/static/css/*.css
+include edbob/pyramid/static/js/*.js
+
+include edbob/scaffolds/edbob/CHANGES.txt
+include edbob/scaffolds/edbob/+package+/pyramid/static/favicon.ico
+include edbob/scaffolds/edbob/+package+/pyramid/static/robots.txt
+
+recursive-include edbob/pyramid/static/img *.jpg *.png
+recursive-include edbob/pyramid/templates *.mako
+
+recursive-include edbob/scaffolds/edbob *.py
+recursive-include edbob/scaffolds/edbob *_tmpl
+recursive-include edbob/scaffolds/edbob/+package+/pyramid/templates *.mako
diff --git a/edbob/_version.py b/edbob/_version.py
index ce39c68..fdb6c79 100644
--- a/edbob/_version.py
+++ b/edbob/_version.py
@@ -1 +1 @@
-__version__ = '0.1a3'
+__version__ = '0.1a7'
diff --git a/edbob/configuration.py b/edbob/configuration.py
index b35611c..9b2880a 100644
--- a/edbob/configuration.py
+++ b/edbob/configuration.py
@@ -70,15 +70,17 @@ class AppConfigParser(ConfigParser.SafeConfigParser):
file, and passes that to ``logging.config.fileConfig()``.
"""
- if self.getboolean(self.appname, 'basic_logging', default=False):
- edbob.basic_logging(self.appname)
- path = edbob.temp_path(suffix='.conf')
- self.save(path)
- try:
- logging.config.fileConfig(path)
- except ConfigParser.NoSectionError:
- pass
- os.remove(path)
+ if self.getboolean('edbob', 'basic_logging', default=False):
+ edbob.basic_logging()
+ if self.getboolean('edbob', 'configure_logging', default=False):
+ path = edbob.temp_path(suffix='.conf')
+ self.save(path)
+ try:
+ logging.config.fileConfig(path, disable_existing_loggers=False)
+ except ConfigParser.NoSectionError:
+ pass
+ os.remove(path)
+ log.debug("Configured logging")
def get(self, section, option, raw=False, vars=None, default=None):
"""
@@ -243,7 +245,6 @@ class AppConfigParser(ConfigParser.SafeConfigParser):
config.has_option('edbob', 'include_config')):
include = config.get('edbob', 'include_config')
if include:
- log.debug("Including config: %s" % include)
for p in eval(include):
self.read_path(os.path.abspath(p))
ConfigParser.SafeConfigParser.read(self, path)
diff --git a/edbob/core.py b/edbob/core.py
index f100cf8..04a00ea 100644
--- a/edbob/core.py
+++ b/edbob/core.py
@@ -71,7 +71,9 @@ def basic_logging():
handler = logging.StreamHandler()
handler.setFormatter(logging.Formatter(
'%(levelname)-5.5s [%(name)s][%(threadName)s] %(message)s'))
- logging.getLogger().addHandler(handler)
+ root = logging.getLogger()
+ root.addHandler(handler)
+ root.setLevel(logging.INFO)
def get_uuid():
diff --git a/edbob/csv.py b/edbob/csv.py
new file mode 100644
index 0000000..77518c9
--- /dev/null
+++ b/edbob/csv.py
@@ -0,0 +1,71 @@
+#!/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 .
+#
+################################################################################
+
+"""
+``edbob.csv`` -- CSV File Utilities
+"""
+
+from __future__ import absolute_import
+
+import codecs
+import csv
+
+
+class UTF8Recoder(object):
+ """
+ Iterator that reads an encoded stream and reencodes the input to UTF-8.
+
+ .. note::
+ This class was stolen from the Python 2.7 documentation.
+ """
+
+ def __init__(self, fileobj, encoding):
+ self.reader = codecs.getreader(encoding)(fileobj)
+
+ def __iter__(self):
+ return self
+
+ def next(self):
+ return self.reader.next().encode('utf_8')
+
+
+class UnicodeReader(object):
+ """
+ A CSV reader which will iterate over lines in a CSV file, which is encoded
+ in the given encoding.
+
+ .. note::
+ This class was stolen from the Python 2.7 documentation.
+ """
+
+ def __init__(self, fileobj, dialect=csv.excel, encoding='utf_8', **kwargs):
+ fileobj = UTF8Recoder(fileobj, encoding)
+ self.reader = csv.reader(fileobj, dialect=dialect, **kwargs)
+
+ def __iter__(self):
+ return self
+
+ def next(self):
+ row = self.reader.next()
+ return [unicode(x, 'utf_8') for x in row]
diff --git a/edbob/db/__init__.py b/edbob/db/__init__.py
index 18d6888..0fd3018 100644
--- a/edbob/db/__init__.py
+++ b/edbob/db/__init__.py
@@ -1,184 +1,184 @@
-#!/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 .
-#
-################################################################################
-
-"""
-``edbob.db`` -- Database Framework
-"""
-
-from __future__ import absolute_import
-
-from sqlalchemy import engine_from_config, MetaData
-from sqlalchemy.orm import sessionmaker
-from sqlalchemy.ext.declarative import declarative_base
-
-import edbob
-
-
-# __all__ = ['engines', 'engine', 'Session', 'metadata',
-# 'get_setting', 'save_setting']
-
-__all__ = ['engines', 'engine', 'Session', 'get_setting', 'save_setting']
-
-inited = False
-engines = None
-engine = None
-Session = sessionmaker()
-Base = declarative_base()
-# metadata = None
-
-
-def init(config):
- """
- Initializes the database connection(s); called by :func:`edbob.init()` if
- config includes something like::
-
- .. highlight:: ini
-
- [edbob]
- init = ['edbob.db']
-
- [edbob.db]
- sqlalchemy.urls = {
- 'default': 'postgresql://user:pass@localhost/edbob,
- }
-
- This function reads connection info from ``config`` and builds a dictionary
- or :class:`sqlalchemy.Engine` instances accordingly. It also extends the
- root ``edbob`` namespace with the ORM classes (:class:`edbob.Person`,
- :class:`edbob.User`, etc.), as well as a few other things
- (e.g. :attr:`edbob.engine`, :attr:`edbob.Session`, :attr:`edbob.metadata`).
- """
-
- import edbob.db
- # from edbob.db import classes
- from edbob.db import model
- from edbob.db import enum
- # from edbob.db.model import get_metadata
- # from edbob.db.mappers import make_mappers
- from edbob.db.extensions import extend_framework
-
- # global inited, engines, engine, metadata
- global inited, engines, engine
-
- keys = config.get('edbob.db', 'sqlalchemy.keys')
- if keys:
- keys = keys.split()
- else:
- keys = ['default']
-
- engines = {}
- cfg = config.get_dict('edbob.db')
- for key in keys:
- try:
- engines[key] = engine_from_config(cfg, 'sqlalchemy.%s.' % key)
- except KeyError:
- if key == 'default':
- try:
- engines[key] = engine_from_config(cfg)
- except KeyError:
- pass
-
- engine = engines.get('default')
- if engine:
- Base.metadata.bind = engine
-
- # metadata = get_metadata(bind=engine)
- # make_mappers(metadata)
- extend_framework()
-
- edbob.graft(edbob, edbob.db)
- # edbob.graft(edbob, classes)
- edbob.graft(edbob, model)
- edbob.graft(edbob, enum)
- inited = True
-
-
-def get_setting(name, session=None):
- """
- Returns a setting from the database.
- """
-
- _session = session
- if not session:
- session = Session()
- setting = session.query(edbob.Setting).get(name)
- if setting:
- setting = setting.value
- if not _session:
- session.close()
- return setting
-
-
-def save_setting(name, value, session=None):
- """
- Saves a setting to the database.
- """
-
- _session = session
- if not session:
- session = Session()
- setting = session.query(edbob.Setting).get(name)
- if not setting:
- setting = edbob.Setting(name=name)
- session.add(setting)
- setting.value = value
- if not _session:
- session.commit()
- session.close()
-
-
-def get_core_metadata():
- """
- Returns a :class:`sqlalchemy.MetaData` instance containing only those
- :class:`sqlalchemy.Table`s which are part of the core ``edbob`` schema.
- """
-
- from edbob.db import model
-
- meta = MetaData()
- for name in model.__all__:
- if name != 'Base':
- obj = getattr(model, name)
- if isinstance(obj, type) and issubclass(obj, model.Base):
- obj.__table__.tometadata(meta)
- return meta
-
-
-def needs_session(func):
- """
- Decorator which adds helpful session handling.
- """
-
- def wrapped(*args, **kwargs):
- session = kwargs.pop('session', None)
- _orig_session = session
- if not session:
- session = Session()
- res = func(session, *args, **kwargs)
- if not _orig_session:
- session.commit()
- session.close()
- return res
-
- return wrapped
+#!/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 .
+#
+################################################################################
+
+"""
+``edbob.db`` -- Database Framework
+"""
+
+from __future__ import absolute_import
+
+from sqlalchemy import engine_from_config, MetaData
+from sqlalchemy.orm import sessionmaker
+from sqlalchemy.ext.declarative import declarative_base
+
+import edbob
+
+
+# __all__ = ['engines', 'engine', 'Session', 'metadata',
+# 'get_setting', 'save_setting']
+
+__all__ = ['engines', 'engine', 'Session', 'get_setting', 'save_setting']
+
+inited = False
+engines = None
+engine = None
+Session = sessionmaker()
+Base = declarative_base()
+# metadata = None
+
+
+def init(config):
+ """
+ Initializes the database connection(s); called by :func:`edbob.init()` if
+ config includes something like::
+
+ .. highlight:: ini
+
+ [edbob]
+ init = ['edbob.db']
+
+ [edbob.db]
+ sqlalchemy.urls = {
+ 'default': 'postgresql://user:pass@localhost/edbob,
+ }
+
+ This function reads connection info from ``config`` and builds a dictionary
+ or :class:`sqlalchemy.Engine` instances accordingly. It also extends the
+ root ``edbob`` namespace with the ORM classes (:class:`edbob.Person`,
+ :class:`edbob.User`, etc.), as well as a few other things
+ (e.g. :attr:`edbob.engine`, :attr:`edbob.Session`, :attr:`edbob.metadata`).
+ """
+
+ import edbob.db
+ # from edbob.db import classes
+ from edbob.db import model
+ from edbob.db import enum
+ # from edbob.db.model import get_metadata
+ # from edbob.db.mappers import make_mappers
+ from edbob.db.extensions import extend_framework
+
+ # global inited, engines, engine, metadata
+ global inited, engines, engine
+
+ keys = config.get('edbob.db', 'sqlalchemy.keys')
+ if keys:
+ keys = keys.split()
+ else:
+ keys = ['default']
+
+ engines = {}
+ cfg = config.get_dict('edbob.db')
+ for key in keys:
+ try:
+ engines[key] = engine_from_config(cfg, 'sqlalchemy.%s.' % key)
+ except KeyError:
+ if key == 'default':
+ try:
+ engines[key] = engine_from_config(cfg)
+ except KeyError:
+ pass
+
+ engine = engines.get('default')
+ if engine:
+ Base.metadata.bind = engine
+
+ # metadata = get_metadata(bind=engine)
+ # make_mappers(metadata)
+ extend_framework()
+
+ edbob.graft(edbob, edbob.db)
+ # edbob.graft(edbob, classes)
+ edbob.graft(edbob, model)
+ edbob.graft(edbob, enum)
+ inited = True
+
+
+def get_setting(name, session=None):
+ """
+ Returns a setting from the database.
+ """
+
+ _session = session
+ if not session:
+ session = Session()
+ setting = session.query(edbob.Setting).get(name)
+ if setting:
+ setting = setting.value
+ if not _session:
+ session.close()
+ return setting
+
+
+def save_setting(name, value, session=None):
+ """
+ Saves a setting to the database.
+ """
+
+ _session = session
+ if not session:
+ session = Session()
+ setting = session.query(edbob.Setting).get(name)
+ if not setting:
+ setting = edbob.Setting(name=name)
+ session.add(setting)
+ setting.value = value
+ if not _session:
+ session.commit()
+ session.close()
+
+
+def get_core_metadata():
+ """
+ Returns a :class:`sqlalchemy.MetaData` instance containing only those
+ :class:`sqlalchemy.Table`s which are part of the core ``edbob`` schema.
+ """
+
+ from edbob.db import model
+
+ meta = MetaData()
+ for name in model.__all__:
+ if name != 'Base':
+ obj = getattr(model, name)
+ if isinstance(obj, type) and issubclass(obj, model.Base):
+ obj.__table__.tometadata(meta)
+ return meta
+
+
+def needs_session(func):
+ """
+ Decorator which adds helpful session handling.
+ """
+
+ def wrapped(*args, **kwargs):
+ session = kwargs.pop('session', None)
+ _orig_session = session
+ if not session:
+ session = Session()
+ res = func(session, *args, **kwargs)
+ if not _orig_session:
+ session.commit()
+ session.close()
+ return res
+
+ return wrapped
diff --git a/edbob/db/alembic.ini b/edbob/db/alembic.ini
index 891ae32..0bebfc7 100644
--- a/edbob/db/alembic.ini
+++ b/edbob/db/alembic.ini
@@ -1,46 +1,46 @@
-# A generic, single database configuration.
-
-[alembic]
-# path to migration scripts
-script_location = schema
-
-# template used to generate migration files
-# file_template = %%(rev)s_%%(slug)s
-
-sqlalchemy.url = driver://user:pass@localhost/dbname
-
-
-# Logging configuration
-[loggers]
-keys = root,sqlalchemy,alembic
-
-[handlers]
-keys = console
-
-[formatters]
-keys = generic
-
-[logger_root]
-level = WARN
-handlers = console
-qualname =
-
-[logger_sqlalchemy]
-level = WARN
-handlers =
-qualname = sqlalchemy.engine
-
-[logger_alembic]
-level = INFO
-handlers =
-qualname = alembic
-
-[handler_console]
-class = StreamHandler
-args = (sys.stderr,)
-level = NOTSET
-formatter = generic
-
-[formatter_generic]
-format = %(levelname)-5.5s [%(name)s] %(message)s
-datefmt = %H:%M:%S
+# A generic, single database configuration.
+
+[alembic]
+# path to migration scripts
+script_location = schema
+
+# template used to generate migration files
+# file_template = %%(rev)s_%%(slug)s
+
+sqlalchemy.url = driver://user:pass@localhost/dbname
+
+
+# Logging configuration
+[loggers]
+keys = root,sqlalchemy,alembic
+
+[handlers]
+keys = console
+
+[formatters]
+keys = generic
+
+[logger_root]
+level = WARN
+handlers = console
+qualname =
+
+[logger_sqlalchemy]
+level = WARN
+handlers =
+qualname = sqlalchemy.engine
+
+[logger_alembic]
+level = INFO
+handlers =
+qualname = alembic
+
+[handler_console]
+class = StreamHandler
+args = (sys.stderr,)
+level = NOTSET
+formatter = generic
+
+[formatter_generic]
+format = %(levelname)-5.5s [%(name)s] %(message)s
+datefmt = %H:%M:%S
diff --git a/edbob/filemon_server.py b/edbob/filemon_server.py
index 881c7b1..8071a51 100644
--- a/edbob/filemon_server.py
+++ b/edbob/filemon_server.py
@@ -109,7 +109,7 @@ class FileMonitorService(win32serviceutil.ServiceFramework):
while not file_is_free(path):
# TODO: Add configurable timeout so long-open files can't hijack
# our prcessing.
- time.sleep(0.25)
+ win32api.SleepEx(250, True)
for action in self.monitored[key].actions:
if isinstance(action, tuple):
func = action[0]
diff --git a/edbob/initialization.py b/edbob/initialization.py
index e27c7fb..e4c8ede 100644
--- a/edbob/initialization.py
+++ b/edbob/initialization.py
@@ -1,98 +1,98 @@
-#!/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 .
-#
-################################################################################
-
-"""
-``edbob.initialization`` -- Initialization Framework
-"""
-
-import os
-import logging
-
-import edbob
-from edbob.configuration import (
- AppConfigParser,
- default_system_paths,
- default_user_paths,
- )
-
-
-__all__ = ['init']
-
-log = logging.getLogger(__name__)
-
-
-def init(appname='edbob', *args, **kwargs):
- """
- Initializes the edbob framework, typically by first reading some config
- file(s) to determine which interfaces to engage. This must normally be
- called prior to doing anything really useful, as it is responsible for
- extending the live API in-place.
-
- The meaning of ``args`` is as follows:
-
- If ``args`` is empty, the ``EDBOB_CONFIG`` environment variable is first
- consulted. If it is nonempty, then its value is split according to
- ``os.pathsep`` and the resulting sequence is passed to
- ``edbob.config.read()``.
-
- If both ``args`` and ``EDBOB_CONFIG`` are empty, the "standard" locations
- are assumed, and the results of calling both
- :func:`edbob.configuration.default_system_paths()` and
- :func:`edbob.configuration.default_user_paths()` are passed on to
- ``edbob.config.read()``.
-
- Any other values in ``args`` will be passed directly to
- ``edbob.config.read()`` and so will be interpreted there. Basically they
- are assumed to be either strings, or sequences of strings, which represent
- paths to various config files, each being read in the order in which it
- appears within ``args``. (Configuration is thereby cascaded such that the
- file read last will override those before it.)
- """
-
- config = AppConfigParser(appname)
-
- if args:
- config_paths = list(args)
- elif os.environ.get('EDBOB_CONFIG'):
- config_paths = os.environ['EDBOB_CONFIG'].split(os.pathsep)
- else:
- config_paths = default_system_paths(appname) + default_user_paths(appname)
-
- shell = bool(kwargs.get('shell'))
- for paths in config_paths:
- config.read(paths, recurse=not shell)
- config.configure_logging()
-
- default_modules = 'edbob.time'
- modules = config.get('edbob', 'init', default=default_modules)
- if modules:
- for name in modules.split(','):
- name = name.strip()
- module = __import__(name, globals(), locals(), fromlist=['init'])
- getattr(module, 'init')(config)
- # config.inited.append(name)
-
- # config.inited.append('edbob')
- edbob.graft(edbob, locals(), 'config')
- edbob.inited = True
+#!/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 .
+#
+################################################################################
+
+"""
+``edbob.initialization`` -- Initialization Framework
+"""
+
+import os
+import logging
+
+import edbob
+from edbob.configuration import (
+ AppConfigParser,
+ default_system_paths,
+ default_user_paths,
+ )
+
+
+__all__ = ['init']
+
+log = logging.getLogger(__name__)
+
+
+def init(appname='edbob', *args, **kwargs):
+ """
+ Initializes the edbob framework, typically by first reading some config
+ file(s) to determine which interfaces to engage. This must normally be
+ called prior to doing anything really useful, as it is responsible for
+ extending the live API in-place.
+
+ The meaning of ``args`` is as follows:
+
+ If ``args`` is empty, the ``EDBOB_CONFIG`` environment variable is first
+ consulted. If it is nonempty, then its value is split according to
+ ``os.pathsep`` and the resulting sequence is passed to
+ ``edbob.config.read()``.
+
+ If both ``args`` and ``EDBOB_CONFIG`` are empty, the "standard" locations
+ are assumed, and the results of calling both
+ :func:`edbob.configuration.default_system_paths()` and
+ :func:`edbob.configuration.default_user_paths()` are passed on to
+ ``edbob.config.read()``.
+
+ Any other values in ``args`` will be passed directly to
+ ``edbob.config.read()`` and so will be interpreted there. Basically they
+ are assumed to be either strings, or sequences of strings, which represent
+ paths to various config files, each being read in the order in which it
+ appears within ``args``. (Configuration is thereby cascaded such that the
+ file read last will override those before it.)
+ """
+
+ config = AppConfigParser(appname)
+
+ if args:
+ config_paths = list(args)
+ elif os.environ.get('EDBOB_CONFIG'):
+ config_paths = os.environ['EDBOB_CONFIG'].split(os.pathsep)
+ else:
+ config_paths = default_system_paths(appname) + default_user_paths(appname)
+
+ shell = bool(kwargs.get('shell'))
+ for paths in config_paths:
+ config.read(paths, recurse=not shell)
+ config.configure_logging()
+
+ default_modules = 'edbob.time'
+ modules = config.get('edbob', 'init', default=default_modules)
+ if modules:
+ for name in modules.split(','):
+ name = name.strip()
+ module = __import__(name, globals(), locals(), fromlist=['init'])
+ getattr(module, 'init')(config)
+ # config.inited.append(name)
+
+ # config.inited.append('edbob')
+ edbob.graft(edbob, locals(), 'config')
+ edbob.inited = True
diff --git a/edbob/scaffolds/edbob/+package+/pyramid/__init__.py_tmpl b/edbob/scaffolds/edbob/+package+/pyramid/__init__.py_tmpl
index 134e5ab..202366b 100644
--- a/edbob/scaffolds/edbob/+package+/pyramid/__init__.py_tmpl
+++ b/edbob/scaffolds/edbob/+package+/pyramid/__init__.py_tmpl
@@ -51,7 +51,6 @@ def main(global_config, **settings):
# Configure edbob. Note that this is done last, primarily to allow logging
# to leverage edbob's config inheritance.
- edbob.basic_logging()
edbob.init('{{package}}', os.path.abspath(settings['edbob.config']))
return config.make_wsgi_app()
diff --git a/edbob/scaffolds/edbob/development.ini_tmpl b/edbob/scaffolds/edbob/development.ini_tmpl
index ffec311..300d5d4 100644
--- a/edbob/scaffolds/edbob/development.ini_tmpl
+++ b/edbob/scaffolds/edbob/development.ini_tmpl
@@ -27,10 +27,7 @@ whatever = you like
use = egg:{{package}}
pyramid.reload_templates = true
-pyramid.debug_authorization = false
-pyramid.debug_notfound = false
-pyramid.debug_routematch = false
-pyramid.debug_templates = true
+pyramid.debug_all = true
pyramid.default_locale_name = en
pyramid.includes =
pyramid_debugtoolbar
@@ -51,9 +48,6 @@ port = 6543
[edbob]
include_config = ['%(here)s/production.ini']
-[edbob.db]
-sqlalchemy.url = sqlite:///{{package}}.sqlite
-
####################
# logging
@@ -62,8 +56,5 @@ sqlalchemy.url = sqlite:///{{package}}.sqlite
[logger_root]
level = INFO
-[logger_edbob]
-level = INFO
-
[logger_{{package_logger}}]
level = DEBUG
diff --git a/edbob/scaffolds/edbob/production.ini_tmpl b/edbob/scaffolds/edbob/production.ini_tmpl
index c42110b..c5bfdbd 100644
--- a/edbob/scaffolds/edbob/production.ini_tmpl
+++ b/edbob/scaffolds/edbob/production.ini_tmpl
@@ -21,10 +21,7 @@ whatever = you like
use = egg:{{package}}
pyramid.reload_templates = false
-pyramid.debug_authorization = false
-pyramid.debug_notfound = false
-pyramid.debug_routematch = false
-pyramid.debug_templates = false
+pyramid.debug_all = false
pyramid.default_locale_name = en
# Hack so edbob can find this file from within WSGI app.
@@ -56,6 +53,8 @@ sqlalchemy.url = postgresql://user:pass@localhost/{{package}}
[edbob]
init = edbob.time, edbob.db
+basic_logging = True
+configure_logging = True
# shell.python = ipython
[edbob.db]
@@ -82,7 +81,7 @@ timezone = US/Central
####################
[loggers]
-keys = root, edbob, {{package_logger}}
+keys = root, {{package_logger}}
[handlers]
keys = file, console, email
@@ -95,15 +94,10 @@ keys = generic, console
handlers = file, console
level = WARNING
-[logger_edbob]
-qualname = edbob
-handlers =
-# level = INFO
-
[logger_{{package_logger}}]
qualname = {{package}}
handlers =
-level = WARNING
+# level = NOTSET
[handler_file]
class = FileHandler
@@ -114,12 +108,10 @@ formatter = generic
class = StreamHandler
args = (sys.stderr,)
formatter = console
-# level = NOTSET
[handler_email]
class = handlers.SMTPHandler
-args = ('mail.example.com', '{{package}}@example.com', ['support@example.com'], '[{{project}} error]',
- ('user', 'pass'))
+args = ('mail.example.com', '{{package}}@example.com', ['support@example.com'], '[{{project}} error]', ('user', 'pass'))
level = ERROR
formatter = generic
diff --git a/edbob/time.py b/edbob/time.py
index c9b7d04..1f0d63a 100644
--- a/edbob/time.py
+++ b/edbob/time.py
@@ -47,7 +47,7 @@ def init(config):
tz = config.get('edbob.time', 'timezone')
if tz:
set_timezone(tz)
- log.debug("Timezone set to '%s'" % tz)
+ log.info("Timezone set to '%s'" % tz)
else:
log.warning("No timezone configured; falling back to US/Central")
set_timezone('US/Central')
diff --git a/setup.py b/setup.py
index a18574d..75dff85 100644
--- a/setup.py
+++ b/setup.py
@@ -121,7 +121,7 @@ setup(
#
# package # low high
- 'alembic', # 0.2.1
+ 'alembic', # 0.3.4
'py-bcrypt', # 0.2
'SQLAlchemy', # 0.7.6
'Tempita', # 0.5.1