Commit 5cc9f702 authored by Arnaud Fontaine's avatar Arnaud Fontaine

ZODB Components: Fix clearing of pylint/astroid AST cache.

When a Component was not imported but only used during pylint checking,
its Module AST was never removed from the cache.

This fixes testDynamicClassGeneration failures since the migration of
IMovement (e8e5f273).
parent 4341268c
...@@ -528,6 +528,18 @@ class ERP5Site(ResponseHeaderGenerator, FolderMixIn, CMFSite, CacheCookieMixin): ...@@ -528,6 +528,18 @@ class ERP5Site(ResponseHeaderGenerator, FolderMixIn, CMFSite, CacheCookieMixin):
XXX-arnau: must be written through an interaction workflow when ERP5Site XXX-arnau: must be written through an interaction workflow when ERP5Site
will become a real ERP5 object... will become a real ERP5 object...
""" """
# Clear completely astroid cache: could be more efficient to clear only
# the deleted versions and all their associated ZODB Components packages,
# but it's probably enough as this is not done often after all...
try:
from astroid.builder import MANAGER
except ImportError:
pass
else:
for k in MANAGER.astroid_cache.keys():
if k.startswith('erp5.component.'):
del MANAGER.astroid_cache[k]
if not isinstance(version_priority_tuple, tuple): if not isinstance(version_priority_tuple, tuple):
version_priority_tuple = tuple(version_priority_tuple) version_priority_tuple = tuple(version_priority_tuple)
......
state_change['object'].reset()
state_change['object'].getPortalObject().portal_components.resetOnceAtTransactionBoundary() state_change['object'].getPortalObject().portal_components.resetOnceAtTransactionBoundary()
...@@ -429,14 +429,6 @@ class ComponentDynamicPackage(ModuleType): ...@@ -429,14 +429,6 @@ class ComponentDynamicPackage(ModuleType):
delattr(package, name) delattr(package, name)
# Clear pylint cache
try:
from astroid.builder import MANAGER
except ImportError:
pass
else:
MANAGER.astroid_cache.pop(module_name, None)
class ToolComponentDynamicPackage(ComponentDynamicPackage): class ToolComponentDynamicPackage(ComponentDynamicPackage):
def reset(self, *args, **kw): def reset(self, *args, **kw):
""" """
......
...@@ -311,6 +311,30 @@ class ComponentMixin(PropertyRecordableMixin, Base): ...@@ -311,6 +311,30 @@ class ComponentMixin(PropertyRecordableMixin, Base):
""" """
return checkPythonSourceCode(self.getTextContent(), self.getPortalType()) return checkPythonSourceCode(self.getTextContent(), self.getPortalType())
security.declareProtected(Permissions.ResetDynamicClasses, 'reset')
def reset(self):
"""
Called on validate/invalidate
"""
# Clear pylint cache
try:
from astroid.builder import MANAGER
except ImportError:
pass
else:
namespace = self._getDynamicModuleNamespace()
reference = self.getReference()
# Clear the main module (erp5.component.document.foo_version.Bar)
version_module_name = '%s.%s_version.%s' % (namespace,
self.getVersion(),
reference)
module_name = '%s.%s' % (namespace, reference)
version_astroid_module = MANAGER.astroid_cache.pop(version_module_name, None)
# And its alias (erp5.component.document.Bar)
if (version_astroid_module is not None and
MANAGER.astroid_cache.get(module_name) is version_astroid_module):
del MANAGER.astroid_cache[module_name]
security.declareProtected(Permissions.ModifyPortalContent, 'PUT') security.declareProtected(Permissions.ModifyPortalContent, 'PUT')
def PUT(self, REQUEST, RESPONSE): def PUT(self, REQUEST, RESPONSE):
""" """
......
...@@ -2206,8 +2206,7 @@ def hoge(): ...@@ -2206,8 +2206,7 @@ def hoge():
imported_module2_with_version = self._getComponentFullModuleName( imported_module2_with_version = self._getComponentFullModuleName(
imported_reference2, version='erp5') imported_reference2, version='erp5')
component.setTextContent( component_text_content = ("""# -*- coding: utf-8 -*-
"""# -*- coding: utf-8 -*-
# Source code with non-ASCII character should not fail: éàホゲ # Source code with non-ASCII character should not fail: éàホゲ
from %(namespace)s import %(reference1)s from %(namespace)s import %(reference1)s
from %(namespace)s.erp5_version import %(reference1)s from %(namespace)s.erp5_version import %(reference1)s
...@@ -2242,6 +2241,7 @@ from Shared.DC.ZRDB.Results import Results # pylint: disable=unused-import ...@@ -2242,6 +2241,7 @@ from Shared.DC.ZRDB.Results import Results # pylint: disable=unused-import
module2=imported_module2, module2=imported_module2,
module2_with_version=imported_module2_with_version)) + module2_with_version=imported_module2_with_version)) +
component.getTextContent()) component.getTextContent())
component.setTextContent(component_text_content)
self.tic() self.tic()
self._assertAstroidCacheContent( self._assertAstroidCacheContent(
must_be_in_cache_set={'%s' % namespace, must_be_in_cache_set={'%s' % namespace,
...@@ -2324,6 +2324,101 @@ undefined() ...@@ -2324,6 +2324,101 @@ undefined()
imported_module2_with_version]) imported_module2_with_version])
self.assertEqual(component.getTextContentWarningMessageList(), []) self.assertEqual(component.getTextContentWarningMessageList(), [])
# Check that astroid cache is properly cleaned up when a Component is modified
component.setTextContent(component_text_content)
self.tic()
self.assertEqual(component.getValidationState(), 'validated')
self.assertEqual(component.getTextContentErrorMessageList(), [])
self.assertEqual(component.getTextContentWarningMessageList(), [])
imported_component2.setTextContent(imported_component2.getTextContent() + '\n')
self.tic()
self.assertEqual(imported_component2.getValidationState(), 'validated')
self.assertEqual(imported_component2.getTextContentErrorMessageList(), [])
self.assertEqual(imported_component2.getTextContentWarningMessageList(), [])
self._assertAstroidCacheContent(
must_be_in_cache_set={'%s' % namespace,
'%s.erp5_version' % namespace,
imported_module1,
imported_module1_with_version},
must_not_be_in_cache_set={imported_module2,
imported_module2_with_version})
imported_component2.invalidate()
self.tic()
self.assertEqual(imported_component2.getValidationState(), 'invalidated')
self._assertAstroidCacheContent(
must_be_in_cache_set={'%s' % namespace,
'%s.erp5_version' % namespace,
imported_module1,
imported_module1_with_version},
must_not_be_in_cache_set={imported_module2,
imported_module2_with_version})
imported_component2.validate()
self.tic()
self.assertEqual(imported_component2.getValidationState(), 'validated')
self.assertEqual(imported_component2.getTextContentErrorMessageList(), [])
self.assertEqual(imported_component2.getTextContentWarningMessageList(), [])
# And when version_priority is changed
priority_tuple = self.portal.getVersionPriorityList()
imported_module2_with_bar_version = self._getComponentFullModuleName(
imported_reference2, version='bar')
try:
self.portal.setVersionPriorityList(('bar | 42.0',) + priority_tuple)
self.tic()
self._assertAstroidCacheContent(
must_be_in_cache_set=set(),
must_not_be_in_cache_set={'%s' % namespace,
'%s.erp5_version' % namespace,
'%s.bar_version' % namespace,
imported_module1,
imported_module1_with_version,
imported_module2,
imported_module2_with_version,
imported_module2_with_bar_version,
'%s.bar_version' % namespace})
imported_component2.setId(imported_component2.getId().replace('erp5', 'bar'))
imported_component2.setVersion('bar')
self.tic()
self.assertEqual(imported_component2.getValidationState(), 'validated')
self.assertEqual(imported_component2.getTextContentErrorMessageList(), [])
self.assertEqual(imported_component2.getTextContentWarningMessageList(), [])
component.setTextContent(component.getTextContent().replace(
imported_module2_with_version, imported_module2_with_bar_version))
self.tic()
self.assertEqual(imported_component2.getValidationState(), 'validated')
self.assertEqual(imported_component2.getTextContentErrorMessageList(), [])
self.assertEqual(imported_component2.getTextContentWarningMessageList(), [])
self._assertAstroidCacheContent(
must_be_in_cache_set={'%s' % namespace,
'%s.erp5_version' % namespace,
'%s.bar_version' % namespace,
imported_module1,
imported_module1_with_version,
imported_module2,
imported_module2_with_bar_version,
'%s.bar_version' % namespace},
must_not_be_in_cache_set={imported_module2_with_version})
finally:
self.portal.setVersionPriorityList(priority_tuple)
self.tic()
self._assertAstroidCacheContent(
must_be_in_cache_set=set(),
must_not_be_in_cache_set={'%s' % namespace,
'%s.erp5_version' % namespace,
'%s.bar_version' % namespace,
imported_module1,
imported_module1_with_version,
imported_module2,
imported_module2_with_version,
imported_module2_with_bar_version,
'%s.bar_version' % namespace})
def testPylintAstroidModuleGeneratedOnce(self): def testPylintAstroidModuleGeneratedOnce(self):
imported_reference = self._generateReference('TestPylintAstroidModuleGeneratedOnceImported') imported_reference = self._generateReference('TestPylintAstroidModuleGeneratedOnceImported')
imported_component = self._newComponent(imported_reference) imported_component = self._newComponent(imported_reference)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment