launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #04616
[Merge] lp:~lifeless/python-oops/extraction into lp:python-oops
Robert Collins has proposed merging lp:~lifeless/python-oops/extraction into lp:python-oops.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~lifeless/python-oops/extraction/+merge/71644
Fixes the template to be safe with lists / dicts in it; provide a filtering API for the filtering we do in LP; permit a context to be passed through create() to the on_create hooks, which permits splitting up the monolithic _makeReport in Launchpad.
--
https://code.launchpad.net/~lifeless/python-oops/extraction/+merge/71644
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~lifeless/python-oops/extraction into lp:python-oops.
=== modified file 'README'
--- README 2011-08-15 08:41:43 +0000
+++ README 2011-08-16 07:06:22 +0000
@@ -54,7 +54,7 @@
>>> from oops import Config
>>> config = Config()
-* New report will be based on the template::
+* New reports will be based on the template report::
>>> config.template
{}
@@ -68,13 +68,18 @@
when the oops is created, or to override / tweak the information gathered by an
earlier callback)::
- >>> mycallback = lambda report: None
+ >>> mycallback = lambda report, context: None
>>> config.on_create.append(mycallback)
+The context parameter is also just dict, and is passed to all the on_create
+callbacks similarly to the report. This is used to support passing information
+to the on_create hooks. For instance, the exc_info key is used to pass in
+information about the exception being logged (if one was caught).
+
* Later on, when something has gone wrong and you want to create an OOPS
report::
- >>> report = config.create()
+ >>> report = config.create(context=dict(exc_info=sys.exc_info()))
>>> report
{'appname': 'demo', 'branch_nick': 'mybranch'}
@@ -88,6 +93,9 @@
to the repository). Publishers should try to use report['id'] for the id, if it
is set. This is automatically set to the id returned by the previous publisher.
+If publish returns None, then the report was filtered (see the api docs for
+more information).
+
>>> 'id' in report
False
>>> def demo_publish(report):
@@ -98,7 +106,7 @@
>>> report['id']
'id 1'
-* The oops_datedir_repo package contains a local disk based repository which
+* The related project oops_datedir_repo contains a local disk based repository which
can be used as a publisher.
More coming soon.
=== modified file 'oops/__init__.py'
--- oops/__init__.py 2011-08-15 06:42:14 +0000
+++ oops/__init__.py 2011-08-16 07:06:22 +0000
@@ -25,7 +25,7 @@
# established at this point, and setup.py will use a version of next-$(revno).
# If the releaselevel is 'final', then the tarball will be major.minor.micro.
# Otherwise it is major.minor.micro~$(revno).
-__version__ = (0, 0, 4, 'beta', 0)
+__version__ = (0, 0, 5, 'beta', 0)
__all__ = [
'Config'
=== modified file 'oops/config.py'
--- oops/config.py 2011-08-15 08:41:43 +0000
+++ oops/config.py 2011-08-16 07:06:22 +0000
@@ -70,13 +70,20 @@
__metaclass__ = type
+from copy import deepcopy
+
class Config:
"""The configuration for the OOPS system.
:ivar on_create: A list of callables to call when making a new report. Each
- will be called in series with the new report, and its return value will
- be ignored.
+ will be called in series with the new report and a creation context
+ dict. The return value of the callbacks is ignored.
+ :ivar filters: A list of callables to call when filtering a report. Each
+ will be called in series with a report that is about to be published.
+ If the filter returns true (that is not None, 0, '' or False), then
+ the report will not be published, and the call to publish will return
+ None to the user.
:ivar publishers: A list of callables to call when publishing a report.
Each will be called in series with the report to publish. Their return
value will be assigned to the reports 'id' key : if a publisher
@@ -86,22 +93,30 @@
"""
def __init__(self):
+ self.filters = []
self.on_create = []
self.template = {}
self.publishers = []
- def create(self):
+ def create(self, context=None):
"""Create an OOPS.
- The current template used copied to make the new report, and it is
- passed to all the on_create callbacks for population.
+ The current template is copied to make the new report, and the new
+ report is then passed to all the on_create callbacks for population.
If a callback raises an exception, that will propgate to the caller.
+ :param context: A dict of information that the on_create callbacks can
+ use in populating the report. For instance, the attach_exception
+ callback looks for an exc_info key in the context and uses that
+ to add information to the report. If context is None, an empty dict
+ is created and used with the callbacks.
:return: A fresh OOPS.
"""
- result = dict(self.template)
- [callback(result) for callback in self.on_create]
+ if context is None:
+ context = {}
+ result = deepcopy(self.template)
+ [callback(result, context) for callback in self.on_create]
return result
def publish(self, report):
@@ -119,6 +134,9 @@
:return: A list of the allocated ids.
"""
+ for report_filter in self.filters:
+ if report_filter(report):
+ return None
result = []
for publisher in self.publishers:
id = publisher(report)
=== modified file 'oops/tests/test_config.py'
--- oops/tests/test_config.py 2011-08-15 08:41:43 +0000
+++ oops/tests/test_config.py 2011-08-16 07:06:22 +0000
@@ -36,21 +36,32 @@
def test_on_create_called(self):
calls = []
- def capture(id, report):
- calls.append((id, report))
+ def capture(id, report, context):
+ calls.append((id, report, context))
config = Config()
config.on_create.append(partial(capture, '1'))
config.on_create.append(partial(capture, '2'))
- report = config.create()
+ report = config.create('2')
self.assertThat(report, Is(calls[0][1]))
self.assertThat(report, Is(calls[1][1]))
- self.assertEqual([('1', {}), ('2', {})], calls)
+ self.assertEqual([('1', {}, '2'), ('2', {}, '2')], calls)
+
+ def test_on_create_no_context(self):
+ calls = []
+ def capture(report, context):
+ calls.append((report, context))
+ config = Config()
+ config.on_create.append(capture)
+ report = config.create()
+ self.assertEqual([({}, {})], calls)
def test_create_template(self):
config = Config()
config.template['base'] = True
+ config.template['list'] = []
report = config.create()
- self.assertEqual({'base': True}, report)
+ self.assertEqual({'base': True, 'list': []}, report)
+ self.assertIsNot(report['list'], config.template['list'])
def test_publish_calls_publishers(self):
calls = []
@@ -66,3 +77,21 @@
self.assertEqual(['1', '2'], config.publish(report))
self.assertEqual({'id': '2'}, report)
+ def test_publish_filters_first(self):
+ calls = []
+ def filter_ok(report):
+ calls.append('ok')
+ def filter_block(report):
+ calls.append('block')
+ return True
+ def pub(report):
+ calls.append('pub')
+ return '1'
+ config = Config()
+ config.filters.append(filter_ok)
+ config.filters.append(filter_block)
+ config.filters.append(filter_ok)
+ config.publishers.append(pub)
+ report = {}
+ self.assertEqual(None, config.publish(report))
+ self.assertEqual(['ok', 'block'], calls)
=== modified file 'setup.py'
--- setup.py 2011-08-15 08:41:43 +0000
+++ setup.py 2011-08-16 07:06:22 +0000
@@ -23,7 +23,7 @@
os.path.join(os.path.dirname(__file__), 'README'), 'rb').read()
setup(name="oops",
- version="0.0.4",
+ version="0.0.5",
description=\
"OOPS report model and default allocation/[de]serialization.",
long_description=description,