plone / plone.testing

Provides tools for writing unit and integration tests in a Zope and Plone environment. It is not tied to Plone, and it does not depend on Zope 2 (although it has some optional Zope 2-only features)
https://pypi.org/project/plone.testing/
3 stars 9 forks source link

Importing plone.app.testing forces Zope (partly) into production mode due to regression in plone.testing #64

Closed datakurre closed 5 years ago

datakurre commented 5 years ago

I was wondering, why my pip installed Plone was showing "production mode" even when it was started in foreground mode (fg). This was within add-on development setup where the environment also had test packages (so this should never happen in production unless you accidentally include test packages).

I traced the issue to this change in plone.testing by @thet where an inline import from Testing.ZopeTestCase.ZopeLite import _patched as ZOPETESTCASEALERT was moved with the other imports in file:

https://github.com/plone/plone.testing/commit/499e369d55b86b36c5d4bb07082178918afe9108

Because of that change, importing plone.app.testing has side effect of injecting ZopeLite test configuration into global Zope configuration.

As we see below, plone.app.testing gets imported by z3c.autoinclude when it is looking for includable plugins:

env/lib/python3.7/site-packages/Zope2/App/startup.py(142)startup()
-> load_zcml()
env/lib/python3.7/site-packages/Zope2/App/startup.py(57)load_zcml()
-> load_site()
env/lib/python3.7/site-packages/Zope2/App/zcml.py(43)load_site()
-> _context = xmlconfig.file(site_zcml)
env/lib/python3.7/site-packages/zope/configuration/xmlconfig.py(657)file()
-> include(context, name, package)
env/lib/python3.7/site-packages/zope/configuration/xmlconfig.py(557)include()
-> processxmlfile(f, context)
env/lib/python3.7/site-packages/zope/configuration/xmlconfig.py(407)processxmlfile()
-> parser.parse(src)
env/lib/python3.7/xml/sax/expatreader.py(111)parse()
-> xmlreader.IncrementalParser.parse(self, source)
env/lib/python3.7/xml/sax/xmlreader.py(125)parse()
-> self.feed(buffer)
env/lib/python3.7/xml/sax/expatreader.py(217)feed()
-> self._parser.Parse(data, isFinal)
env/lib/python3.7/xml/sax/expatreader.py(381)end_element_ns()
-> self._cont_handler.endElementNS(pair, None)
env/lib/python3.7/site-packages/zope/configuration/xmlconfig.py(391)endElementNS()
-> self.context.end()
env/lib/python3.7/site-packages/zope/configuration/config.py(703)end()
-> self.stack.pop().finish()
env/lib/python3.7/site-packages/zope/configuration/config.py(868)finish()
-> actions = self.handler(context, **args)
env/lib/python3.7/site-packages/OFS/metaconfigure.py(47)loadProducts()
-> xmlconfig.include(_context, zcml, package=product)
env/lib/python3.7/site-packages/zope/configuration/xmlconfig.py(557)include()
-> processxmlfile(f, context)
env/lib/python3.7/site-packages/zope/configuration/xmlconfig.py(407)processxmlfile()
-> parser.parse(src)
env/lib/python3.7/xml/sax/expatreader.py(111)parse()
-> xmlreader.IncrementalParser.parse(self, source)
env/lib/python3.7/xml/sax/xmlreader.py(125)parse()
-> self.feed(buffer)
env/lib/python3.7/xml/sax/expatreader.py(217)feed()
-> self._parser.Parse(data, isFinal)
env/lib/python3.7/xml/sax/expatreader.py(381)end_element_ns()
-> self._cont_handler.endElementNS(pair, None)
env/lib/python3.7/site-packages/zope/configuration/xmlconfig.py(391)endElementNS()
-> self.context.end()
env/lib/python3.7/site-packages/zope/configuration/config.py(703)end()
-> self.stack.pop().finish()
env/lib/python3.7/site-packages/zope/configuration/config.py(868)finish()
-> actions = self.handler(context, **args)
env/lib/python3.7/site-packages/z3c/autoinclude/zcml.py(101)includePluginsDirective()
-> info = PluginFinder(dotted_name).includableInfo(zcml_to_look_for)
env/lib/python3.7/site-packages/z3c/autoinclude/plugin.py(18)includableInfo()
-> groups = zcml_to_include(plugin_dottedname, zcml_to_look_for)
env/lib/python3.7/site-packages/z3c/autoinclude/plugin.py(36)zcml_to_include()
-> filename = resource_filename(dotted_name, zcmlgroup)
env/lib/python3.7/site-packages/setuptools-40.8.0-py3.7.egg/pkg_resources/__init__.py(1144)resource_filename()
-> return get_provider(package_or_requirement).get_resource_filename(
env/lib/python3.7/site-packages/setuptools-40.8.0-py3.7.egg/pkg_resources/__init__.py(361)get_provider()
-> __import__(moduleOrReq)
env/lib/python3.7/site-packages/plone/app/robotframework/__init__.py(4)<module>()
-> from plone.app.robotframework.server import Zope2Server
env/lib/python3.7/site-packages/plone/app/robotframework/server.py(3)<module>()
-> from plone.app.robotframework.remote import RemoteLibrary
env/lib/python3.7/site-packages/plone/app/robotframework/remote.py(3)<module>()
-> from plone.app.testing import (
env/lib/python3.7/site-packages/plone/app/testing/__init__.py(4)<module>()
-> from plone.app.testing.helpers import applyProfile
env/lib/python3.7/site-packages/plone/app/testing/helpers.py(5)<module>()
-> from plone.app.testing import layers
env/lib/python3.7/site-packages/plone/app/testing/layers.py(19)<module>()
-> from plone.testing import zope
env/lib/python3.7/site-packages/plone/testing/zope.py(10)<module>()
-> from Testing.ZopeTestCase.ZopeLite import _patched as ZOPETESTCASEALERT
env/lib/python3.7/site-packages/Testing/ZopeTestCase/__init__.py(22)<module>()
-> from Testing.ZopeTestCase import ZopeLite as Zope2
env/lib/python3.7/site-packages/Testing/ZopeTestCase/ZopeLite.py(98)<module>()
-> _configure_debug_mode()
env/lib/python3.7/site-packages/Testing/ZopeTestCase/ZopeLite.py(87)_configure_debug_mode()
thet commented 5 years ago

oh. then the move of the import statement should be reverted with a comment to leave it there. what do you think @datakurre ?

datakurre commented 5 years ago

@thet Yes, I also assume that is the easiest solution.

thet commented 5 years ago

https://github.com/plone/plone.testing/pull/65

thet commented 5 years ago

@datakurre this is an interesting side effect and makes me rethink doing any import restructures in tests. It should be fixed now. Closing this issue.