zopefoundation / zope.configuration

Extensible system for supporting various kinds of configurations
https://zopeconfiguration.readthedocs.io
Other
1 stars 6 forks source link

Annoying exception with zcml/require permission #2

Closed tseaver closed 5 years ago

tseaver commented 9 years ago

In https://bugs.launchpad.net/zope.configuration/+bug/98320, @agroszer reported:

I had a nicely working app with

# interfaces.py
class IVersion(IVersionable, INonVersionedData, IPhysicallyLocatable):
...
        orig_file_ref = Attribute(u"original file")
        pdf_file_ref = Attribute(u"PDF file")
<!-- configure.zcml -->
  <content class=".version.Version">
...
    <require permission="dkr.AddContent"
                         set_attributes="orig_file_ref pdf_file_ref"
             set_schema=".interfaces.IVersion" />
  </content>

I changed the intefaces.py into:

class IVersion(IVersionable, INonVersionedData, IPhysicallyLocatable):
...
        orig_file_ref = MyBytes(
                title=u"original file",
                description=u"original file",
                default='',
                missing_value='',
                required=False)
        pdf_file_ref = MyBytes(
                title=u"PDF file",
                description=u"PDF file",
                default='',
                missing_value='',
                required=False)

Of course I forgot to modify the zcml (remove the set_attributes=), so I got the following exception which is not quite useful:

Traceback (most recent call last):
  File "\bin\runzope", line 48, in ?
    run()
  File "\bin\runzope", line 44, in run
    main(["-C", CONFIG_FILE] + sys.argv[1:])
  File "Y:\zope\svn_zope3\src\zope\app\twisted\main.py", line 74, in main
    service = setup(load_options(args))
  File "Y:\zope\svn_zope3\src\zope\app\twisted\main.py", line 139, in setup
    zope.app.appsetup.config(options.site_definition, features=features)
  File "Y:\zope\svn_zope3\src\zope\app\appsetup\appsetup.py", line 110, in config
    context = xmlconfig.file(file, context=context, execute=execute)
  File "Y:\zope\svn_zope3\src\zope\configuration\xmlconfig.py", line 556, in file
    context.execute_actions()
  File "Y:\zope\svn_zope3\src\zope\configuration\config.py", line 606, in execute_actions
    for action in resolveConflicts(self.actions):
  File "Y:\zope\svn_zope3\src\zope\configuration\config.py", line 1511, in
resolveConflicts
    raise ConfigurationConflictError(conflicts)
zope.configuration.config.ConfigurationConflictError

@srichter followed up:

I think there was more to the traceback, for example the line and file where this happened. Also, the error raised is correct, though I agree it could be more descriptive. So yes, you could add it to the collector or just fix it yourself. But I think it is a hard bug/misfeature to fix.

As I remember the traceback is as it is above.

jamadden commented 5 years ago

Assuming the 'require' directive discussed above is (or uses) zope.security, it makes sense that the example would conflict: set_names and set_schema both use the same discriminator. The difference is that set_names must be given a list of attributes, but set_schema looks for all writable IField members of the schema (which happen to exactly match the set of names given).

We can recreate this example:

from zope.interface import Interface
from zope.schema import Text
from zope.configuration.xmlconfig import string

class IFoo(Interface):
    attr1 = Text(title=u'Text1')
    ttr2 = Text(title=u'Text2')

class Foo(object):
    pass

zcml = """
<configure xmlns='http://namespaces.zope.org/zope'>
  <include package="zope.security" file="meta.zcml" />
  <include package="zope.security" />
  <class class="__main__.Foo">
    <require permission="zope.Public"
        set_attributes="attr1 attr2"
        set_schema="__main__.IFoo" />
  </class>
</configure>
"""

if __name__ == '__main__':
    string(zcml)

Running it now produces an informative stack trace detailing the conflicts:

$ python /tmp/schema.py
Traceback (most recent call last):
  File "/tmp/schema.py", line 28, in <module>
    string(zcml)
  File "//zope.configuration/src/zope/configuration/xmlconfig.py", line 520, in string
    context.execute_actions()
  File "//zope.configuration/src/zope/configuration/config.py", line 370, in execute_actions
    for action in resolveConflicts(self.actions):
  File "//zope.configuration/src/zope/configuration/config.py", line 927, in resolveConflicts
    raise ConfigurationConflictError(conflicts)
zope.configuration.config.ConfigurationConflictError: Conflicting configuration actions
  For: ('protectSetAttribute', <class '__main__.Foo'>, 'attr1')
    File "<string>", line 5.2-9.2
      Could not read source.
    File "<string>", line 5.2-9.2
      Could not read source.
  For: ('protectSetAttribute', <class '__main__.Foo'>, 'attr2')
    File "<string>", line 5.2-9.2
      Could not read source.
    File "<string>", line 5.2-9.2
      Could not read source.

I think we can consider this resolved now.