[Checkins] SVN: GenericSetup/branches/1.3/ Ignore import and export
step handlers that we can not resolve. Remove some
Wichert Akkerman
wichert at wiggy.net
Thu Sep 6 18:54:11 EDT 2007
Log message for revision 79508:
Ignore import and export step handlers that we can not resolve. Remove some
dotted name lookup/resolve cycles by modifying the registry to take a dotted
name as a handler.
Restore the import context after running steps from a profile so we do not
break on nested calls.
Changed:
U GenericSetup/branches/1.3/CHANGES.txt
U GenericSetup/branches/1.3/registry.py
U GenericSetup/branches/1.3/tests/test_registry.py
U GenericSetup/branches/1.3/tool.py
U GenericSetup/branches/1.3/utils.py
U GenericSetup/branches/1.3/www/sutImportSteps.zpt
-=-
Modified: GenericSetup/branches/1.3/CHANGES.txt
===================================================================
--- GenericSetup/branches/1.3/CHANGES.txt 2007-09-06 19:22:39 UTC (rev 79507)
+++ GenericSetup/branches/1.3/CHANGES.txt 2007-09-06 22:54:10 UTC (rev 79508)
@@ -3,6 +3,11 @@
GenericSetup 1.3.2 (unreleased)
+ - Ignore import and export step handlers that we can not resolve.
+
+ - Restore the import context after running steps from a profile
+ so we do not break on nested calls.
+
- components: Provide log output when purging utilities or adapters.
- components: Fixed an undefined variable name in a log message.
Modified: GenericSetup/branches/1.3/registry.py
===================================================================
--- GenericSetup/branches/1.3/registry.py 2007-09-06 19:22:39 UTC (rev 79507)
+++ GenericSetup/branches/1.3/registry.py 2007-09-06 22:54:10 UTC (rev 79508)
@@ -111,8 +111,11 @@
if info is None:
return default
- return info.copy()
+ result = info.copy()
+ result['invalid'] = _resolveDottedName( result[ 'handler' ] ) is None
+ return result
+
security.declareProtected( ManagePortal, 'listStepMetadata' )
def listStepMetadata( self ):
@@ -171,7 +174,8 @@
- Attempting to register an older one after a newer one results
in a KeyError.
- o 'handler' should implement IImportPlugin.
+ o 'handler' is the dottoed name of a handler which should implement
+ IImportPlugin.
o 'dependencies' is a tuple of step ids which have to run before
this step in order to be able to run at all. Registration of
@@ -192,16 +196,23 @@
raise KeyError( 'Existing registration for step %s, version %s'
% ( id, already[ 'version' ] ) )
+ if not isinstance(handler, str):
+ handler = _getDottedName( handler )
+
if title is None or description is None:
- t, d = _extractDocstring( handler, id, '' )
+ method = _resolveDottedName(handler)
+ if method is None:
+ t,d = id, ''
+ else:
+ t, d = _extractDocstring( method, id, '' )
title = title or t
description = description or d
info = { 'id' : id
, 'version' : version
- , 'handler' : _getDottedName( handler )
+ , 'handler' : handler
, 'dependencies' : dependencies
, 'title' : title
, 'description' : description
@@ -326,8 +337,11 @@
if info is None:
return default
- return info.copy()
+ result = info.copy()
+ result['invalid'] = _resolveDottedName( result[ 'handler' ] ) is None
+ return result
+
security.declareProtected( ManagePortal, 'listStepMetadata' )
def listStepMetadata( self ):
@@ -370,7 +384,8 @@
o 'id' is the unique identifier for this step
- o 'step' should implement IExportPlugin.
+ o 'handler' is the dottoed name of a handler which should implement
+ IImportPlugin.
o 'title' is a one-line UI description for this step.
If None, the first line of the documentation string of the step
@@ -380,15 +395,22 @@
If None, the remaining line of the documentation string of
the step is used, or default to ''.
"""
+ if not isinstance(handler, str):
+ handler = _getDottedName( handler )
+
if title is None or description is None:
- t, d = _extractDocstring( handler, id, '' )
+ method = _resolveDottedName(handler)
+ if method is None:
+ t,d = id, ''
+ else:
+ t, d = _extractDocstring( method, id, '' )
title = title or t
description = description or d
info = { 'id' : id
- , 'handler' : _getDottedName( handler )
+ , 'handler' : handler
, 'title' : title
, 'description' : description
}
Modified: GenericSetup/branches/1.3/tests/test_registry.py
===================================================================
--- GenericSetup/branches/1.3/tests/test_registry.py 2007-09-06 19:22:39 UTC (rev 79507)
+++ GenericSetup/branches/1.3/tests/test_registry.py 2007-09-06 22:54:10 UTC (rev 79508)
@@ -38,13 +38,18 @@
def TWO_FUNC( context ): pass
def THREE_FUNC( context ): pass
def FOUR_FUNC( context ): pass
+def DOC_FUNC( site ):
+ """This is the first line.
+ This is the second line.
+ """
+
ONE_FUNC_NAME = '%s.%s' % ( __name__, ONE_FUNC.__name__ )
TWO_FUNC_NAME = '%s.%s' % ( __name__, TWO_FUNC.__name__ )
THREE_FUNC_NAME = '%s.%s' % ( __name__, THREE_FUNC.__name__ )
FOUR_FUNC_NAME = '%s.%s' % ( __name__, FOUR_FUNC.__name__ )
+DOC_FUNC_NAME = '%s.%s' % ( __name__, DOC_FUNC.__name__ )
-
#==============================================================================
# SSR tests
#==============================================================================
@@ -91,49 +96,35 @@
def test_registerStep_docstring( self ):
- def func_with_doc( site ):
- """This is the first line.
-
- This is the second line.
- """
- FUNC_NAME = '%s.%s' % ( __name__, func_with_doc.__name__ )
-
registry = self._makeOne()
registry.registerStep( id='docstring'
, version='1'
- , handler=func_with_doc
+ , handler=DOC_FUNC
, dependencies=()
)
info = registry.getStepMetadata( 'docstring' )
self.assertEqual( info[ 'id' ], 'docstring' )
- self.assertEqual( info[ 'handler' ], FUNC_NAME )
+ self.assertEqual( info[ 'handler' ], DOC_FUNC_NAME )
self.assertEqual( info[ 'dependencies' ], () )
self.assertEqual( info[ 'title' ], 'This is the first line.' )
self.assertEqual( info[ 'description' ] , 'This is the second line.' )
def test_registerStep_docstring_override( self ):
- def func_with_doc( site ):
- """This is the first line.
-
- This is the second line.
- """
- FUNC_NAME = '%s.%s' % ( __name__, func_with_doc.__name__ )
-
registry = self._makeOne()
registry.registerStep( id='docstring'
, version='1'
- , handler=func_with_doc
+ , handler=DOC_FUNC
, dependencies=()
, title='Title'
)
info = registry.getStepMetadata( 'docstring' )
self.assertEqual( info[ 'id' ], 'docstring' )
- self.assertEqual( info[ 'handler' ], FUNC_NAME )
+ self.assertEqual( info[ 'handler' ], DOC_FUNC_NAME )
self.assertEqual( info[ 'dependencies' ], () )
self.assertEqual( info[ 'title' ], 'Title' )
self.assertEqual( info[ 'description' ] , 'This is the second line.' )
@@ -171,7 +162,7 @@
registry = self._makeOne()
- registry.registerStep( id='one', version='1', handler=ONE_FUNC )
+ registry.registerStep( id='one', version='1', handler=ONE_FUNC_NAME )
self.assertRaises( KeyError
, registry.registerStep
@@ -180,7 +171,7 @@
, handler=ONE_FUNC
)
- registry.registerStep( id='one', version='1', handler=ONE_FUNC )
+ registry.registerStep( id='one', version='1', handler=ONE_FUNC_NAME )
info_list = registry.listStepMetadata()
self.assertEqual( len( info_list ), 1 )
@@ -632,7 +623,7 @@
def test_registerStep_simple( self ):
registry = self._makeOne()
- registry.registerStep( 'one', ONE_FUNC )
+ registry.registerStep( 'one', ONE_FUNC_NAME )
info = registry.getStepMetadata( 'one', {} )
self.assertEqual( info[ 'id' ], 'one' )
@@ -642,38 +633,24 @@
def test_registerStep_docstring( self ):
- def func_with_doc( site ):
- """This is the first line.
-
- This is the second line.
- """
- FUNC_NAME = '%s.%s' % ( __name__, func_with_doc.__name__ )
-
registry = self._makeOne()
- registry.registerStep( 'one', func_with_doc )
+ registry.registerStep( 'one', DOC_FUNC )
info = registry.getStepMetadata( 'one', {} )
self.assertEqual( info[ 'id' ], 'one' )
- self.assertEqual( info[ 'handler' ], FUNC_NAME )
+ self.assertEqual( info[ 'handler' ], DOC_FUNC_NAME )
self.assertEqual( info[ 'title' ], 'This is the first line.' )
self.assertEqual( info[ 'description' ] , 'This is the second line.' )
def test_registerStep_docstring_with_override( self ):
- def func_with_doc( site ):
- """This is the first line.
-
- This is the second line.
- """
- FUNC_NAME = '%s.%s' % ( __name__, func_with_doc.__name__ )
-
registry = self._makeOne()
- registry.registerStep( 'one', func_with_doc
+ registry.registerStep( 'one', DOC_FUNC
, description='Description' )
info = registry.getStepMetadata( 'one', {} )
self.assertEqual( info[ 'id' ], 'one' )
- self.assertEqual( info[ 'handler' ], FUNC_NAME )
+ self.assertEqual( info[ 'handler' ], DOC_FUNC_NAME )
self.assertEqual( info[ 'title' ], 'This is the first line.' )
self.assertEqual( info[ 'description' ], 'Description' )
Modified: GenericSetup/branches/1.3/tool.py
===================================================================
--- GenericSetup/branches/1.3/tool.py 2007-09-06 19:22:39 UTC (rev 79507)
+++ GenericSetup/branches/1.3/tool.py 2007-09-06 22:54:10 UTC (rev 79508)
@@ -50,6 +50,7 @@
from upgrade import listProfilesWithUpgrades
from upgrade import _upgrade_registry
+from utils import _getDottedName
from utils import _resolveDottedName
from utils import _wwwdir
@@ -162,7 +163,7 @@
self._import_registry = ImportStepRegistry()
self._export_registry = ExportStepRegistry()
self._export_registry.registerStep('step_registries',
- exportStepRegistries,
+ _getDottedName(exportStepRegistries),
'Export import / export steps.',
)
self._toolset_registry = ToolsetRegistry()
@@ -258,6 +259,7 @@
run_dependencies=True, purge_old=None):
""" See ISetupTool.
"""
+ old_context = self._import_context_id
context = self._getImportContext(profile_id, purge_old)
self.applyContext(context)
@@ -265,6 +267,7 @@
info = self._import_registry.getStepMetadata(step_id)
if info is None:
+ self._import_context_id = old_context
raise ValueError, 'No such import step: %s' % step_id
dependencies = info.get('dependencies', ())
@@ -285,6 +288,8 @@
messages[step_id] = '\n'.join(message_list)
steps.append(step_id)
+ self._import_context_id = old_context
+
return { 'steps' : steps, 'messages' : messages }
security.declareProtected(ManagePortal, 'runImportStep')
@@ -308,12 +313,16 @@
"""
__traceback_info__ = profile_id
+ old_context = self._import_context_id
context = self._getImportContext(profile_id, purge_old)
result = self._runImportStepsFromContext(context, purge_old=purge_old)
prefix = 'import-all-%s' % profile_id.replace(':', '_')
name = self._mangleTimestampName(prefix, 'log')
self._createReport(name, result['steps'], result['messages'])
+
+ self._import_context_id = old_context
+
return result
security.declareProtected(ManagePortal, 'runAllImportSteps')
@@ -356,7 +365,9 @@
handler = self._export_registry.getStep(step_id)
if handler is None:
- raise ValueError('Invalid export step: %s' % step_id)
+ logger = logging.getLogger('GenericSetup')
+ logger.error('Step %s has an invalid handler' % step_id)
+ continue
messages[step_id] = handler(context)
@@ -910,8 +921,7 @@
id = step_info['id']
version = step_info['version']
- handler = _resolveDottedName(step_info['handler'])
-
+ handler = step_info['handler']
dependencies = tuple(step_info.get('dependencies', ()))
title = step_info.get('title', id)
description = ''.join(step_info.get('description', []))
@@ -940,8 +950,7 @@
for step_info in info_list:
id = step_info['id']
- handler = _resolveDottedName(step_info['handler'])
-
+ handler = step_info['handler']
title = step_info.get('title', id)
description = ''.join(step_info.get('description', []))
@@ -957,12 +966,19 @@
""" Run a single import step, using a pre-built context.
"""
__traceback_info__ = step_id
+ marker = object()
handler = self._import_registry.getStep(step_id)
- if handler is None:
+ if handler is marker:
raise ValueError('Invalid import step: %s' % step_id)
+ if handler is None:
+ msg = 'Step %s has an invalid import handler' % step_id
+ logger = logging.getLogger('GenericSetup')
+ logger.error(msg)
+ return 'ERROR: ' + msg
+
return handler(context)
security.declarePrivate('_doRunExportSteps')
@@ -972,15 +988,22 @@
"""
context = TarballExportContext(self)
messages = {}
+ marker = object()
for step_id in steps:
- handler = self._export_registry.getStep(step_id)
+ handler = self._export_registry.getStep(step_id, marker)
- if handler is None:
+ if handler is marker:
raise ValueError('Invalid export step: %s' % step_id)
- messages[step_id] = handler(context)
+ if handler is None:
+ msg = 'Step %s has an invalid import handler' % step_id
+ logger = logging.getLogger('GenericSetup')
+ logger.error(msg)
+ messages[step_id] = msg
+ else:
+ messages[step_id] = handler(context)
return { 'steps' : steps
, 'messages' : messages
Modified: GenericSetup/branches/1.3/utils.py
===================================================================
--- GenericSetup/branches/1.3/utils.py 2007-09-06 19:22:39 UTC (rev 79507)
+++ GenericSetup/branches/1.3/utils.py 2007-09-06 22:54:10 UTC (rev 79508)
@@ -115,14 +115,17 @@
del parts_copy[ -1 ]
if not parts_copy:
- raise
+ return None
parts = parts[ 1: ] # Funky semantics of __import__'s return value
obj = module
for part in parts:
- obj = getattr( obj, part )
+ try:
+ obj = getattr( obj, part )
+ except AttributeError:
+ return None
return obj
Modified: GenericSetup/branches/1.3/www/sutImportSteps.zpt
===================================================================
--- GenericSetup/branches/1.3/www/sutImportSteps.zpt 2007-09-06 19:22:39 UTC (rev 79507)
+++ GenericSetup/branches/1.3/www/sutImportSteps.zpt 2007-09-06 22:54:10 UTC (rev 79508)
@@ -62,7 +62,8 @@
<tr valign="top"
tal:define="info python: registry.getStepMetadata( step_id );"
tal:attributes="class python:
- repeat[ 'step_id' ].odd and 'row-normal' or 'row-hilite'" >
+ repeat[ 'step_id' ].odd and 'row-normal' or 'row-hilite';
+ style python:info['invalid'] and 'background: red' or None" >
<td class="list-item" width="16">
<input type="checkbox" name="ids:list" value="STEP_ID"
tal:attributes="value step_id" />
More information about the Checkins
mailing list