[Zope3-checkins] CVS: Zope3/src/zope/app/services -
globalmodule.py:1.1.2.1 module.py:1.21.2.1
module.zcml:1.4.18.1 registration.py:1.20.4.1
service.py:1.36.4.1 servicenames.py:1.13.2.1
Fred L. Drake, Jr.
fred at zope.com
Thu Jan 15 15:50:52 EST 2004
Update of /cvs-repository/Zope3/src/zope/app/services
In directory cvs.zope.org:/tmp/cvs-serv1563/src/zope/app/services
Modified Files:
Tag: zope3-fdrake-globalized-modules-branch
module.py module.zcml registration.py service.py
servicenames.py
Added Files:
Tag: zope3-fdrake-globalized-modules-branch
globalmodule.py
Log Message:
Checkpointing the current state of the module globalization work on a branch
so it does not get lost. See http://dev.zope.org/Zope3/ModulesAreGlobal.
=== Added File Zope3/src/zope/app/services/globalmodule.py ===
##############################################################################
#
# Copyright (c) 2003 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Global module service.
$Id: globalmodule.py,v 1.1.2.1 2004/01/15 20:50:21 fdrake Exp $
"""
import os
from persistence import Persistent
from persistence.dict import PersistentDict
from zodb.code import module
from zope.interface import implements
from zope.app import zapi
from zope.app.container.contained import Contained
from zope.app.interfaces.annotation import IAttributeAnnotatable
from zope.app.interfaces.services import registration as interfaces
from zope.app.interfaces.services.module import IModuleManager
from zope.app.interfaces.services.module import IModuleRegistration
from zope.app.interfaces.services.module import IModuleService
from zope.app.interfaces.services.service import ILocalService
from zope.app.services.registration import NameComponentRegistry
from zope.app.services.registration import NamedComponentRegistration
from zope.app.services.registration import RegistrationStatusProperty
from zope.app.services.servicenames import Modules
class ModuleService(NameComponentRegistry, Persistent, Contained):
implements(IModuleService, ILocalService, IAttributeAnnotatable)
def createRegistrations(self, name):
"""See INameRegistry"""
# This must be redefined since we have to create a special
# type of registration stack.
try:
stack = self._bindings[name]
except KeyError:
parts = name.split(".")
for x in range(len(parts), 0, -1):
n = _dotjoin(parts[:x])
stack = self._bindings.get(n)
if stack is None:
stack = GlobalRegistrationStack(self, n)
self._bindings[n] = stack
self._p_changed = 1
else:
break
stack = self._bindings[name]
return stack
def queryActiveComponent(self, name, default=None):
stack = self._bindings.get(name)
if stack is None:
return default
registration = stack.active()
if registration is None:
return default
if IModuleRegistration.isImplementedBy(registration):
return stack.module
else:
return registration.getComponent()
def findModule(self, name):
stack = self._bindings.get(name)
if stack is None:
return None
mod = stack.module
if mod is not None:
keys = mod.__dict__.keys()
keys.sort()
if "__builtins__" in keys:
keys.remove("__builtins__")
if keys == ["__doc__", "__name__"]:
# this is an empty virtual package; don't allow the import
mod = None
return mod
def resolve(self, name):
l = name.rfind('.')
mod = self.findModule(name[:l])
return getattr(mod, name[l+1:])
# GlobalRegistrationStack calls back to these to allow the set of
# modules to be properly maintained.
def activateRegistration(self, stack, registration):
if IModuleRegistration.isImplementedBy(registration):
component = stack.module
else:
component = registration.getComponent()
pkgname, attrname = _split_name(registration.name)
while pkgname:
pkg = self._bindings[pkgname].getModule()
d = pkg.__dict__
if attrname in d:
# XXX something is here that we don't expect; scream
assert d[attrname] is component
break
if "__file__" in d:
raise ValueError(
"cannot nest modules in the global package structure;"
" %s is a module, not a package" % pkgname)
setattr(pkg, attrname, component)
component = pkg
pkgname, attrname = _split_name(pkgname)
def deactivateRegistration(self, stack, registration):
pkgname, attrname = _split_name(registration.name)
while pkgname:
pkg = self._bindings[pkgname].module
delattr(pkg, attrname)
pkgname, attrname = _split_name(pkgname)
_dotjoin = ".".join
def _split_name(name):
# split a dotted name into a module.attr pair
x = name.rfind(".")
if x < 0:
return None, name
else:
return name[:x], name[x+1:]
class GlobalModuleStatusProperty(RegistrationStatusProperty):
"""Descriptor for a property that affects a global registration."""
def _get_service(self, registration):
"""Return the Module service. There can be only one."""
return zapi.getService(registration, Modules)
class GlobalModuleRegistration(NamedComponentRegistration):
"""Registration object that modifies the global module service
instead of a local service."""
implements(IModuleRegistration)
label = "modules"
serviceType = Modules
status = GlobalModuleStatusProperty()
def getInterface(self):
return IModuleManager
class GlobalRegistrationStack(Persistent, Contained):
"""Registration registry implementation with module semantics.
The invariants for _data are as follows:
1. None occurs exactly once
2. No value occurs more than once
3. Each value except None is an object implementing IRegistration
for a persistent module or a persistent schema.
"""
implements(interfaces.IRegistrationStack)
def __init__(self, container, name):
# This part is like a "normal" registration stack:
self.__parent__ = container
self.__name__ = name
self._data = None,
self.module = None
def register(self, registration):
# add inactive registration
if registration not in self._data:
if not interfaces.INamedComponentRegistration.isImplementedBy(
registration):
raise TypeError("global registrations must implement"
" INamedComponentRegistration")
self._data += (registration, )
def unregister(self, registration):
data = self._data
if data[0] is registration:
self._deactivate(registration)
data = data[1:]
self._activate(data[0])
else:
# Remove it from our data
data = tuple([item for item in data if item is not registration])
# Write data back
self._data = data
def registered(self, registration):
return registration in self._data
def activate(self, registration):
data = self._data
if data[0] is registration:
return # already in the state we want
if registration in data:
# registered, but not active
self._deactivate(data[0])
# Insert it in front, removing it from back
data = [item for item in data if item is not registration]
data.insert(0, registration)
# Write data back
self._data = tuple(data)
self._activate(registration)
else:
raise ValueError(
"Registration to be activated is not registered",
registration)
def deactivate(self, registration):
data = self._data
if registration not in data:
raise ValueError(
"Registration to be deactivated is not registered",
registration)
if data[0] is not registration:
return # already inactive
self._deactivate(registration)
# Move it to the end
data = data[1:] + data[:1]
self._activate(data[0])
# Write data back
self._data = data
def active(self):
return self._data[0]
def __nonzero__(self):
return len(self._data) > 1
def info(self, keep_dummy=False):
result = [{'id': registration and registration.componentPath or "",
'active': False,
'registration': registration,
}
for registration in self._data
]
result[0]['active'] = True
if not keep_dummy:
# Throw away dummy:
result = [x for x in result if x['registration'] is not None]
return result
def getModule(self):
if self.module is None:
self.module = module.PersistentModule(self.__name__)
self.module.__doc__ = None
return self.module
# Helpers to make sure everything needed to activate or deactivate
# a registration is handled consistently, regardless of why the
# activation or deactivation occurred.
def _activate(self, registration):
if registration is None:
return
# activate a registration, updating the stored module if the
# registration if for a module
registration.activated()
if IModuleRegistration.isImplementedBy(registration):
localmod = registration.getComponent()
mod = self.getModule()
mod.__file__ = registration.componentPath
module.compileModule(mod, self.__parent__, localmod.source)
self.__parent__.activateRegistration(self, registration)
def _deactivate(self, registration):
if registration is None:
return
registration.deactivated()
if IModuleRegistration.isImplementedBy(registration):
mod = self.module
builtins = mod.__dict__.get("__builtins__")
mod.__dict__.clear()
if builtins is not None:
mod.__builtins__ = builtins
mod.__doc__ = None
mod.__name__ = self.__name__
self.__parent__.deactivateRegistration(self, registration)
=== Zope3/src/zope/app/services/module.py 1.21 => 1.21.2.1 ===
--- Zope3/src/zope/app/services/module.py:1.21 Thu Jan 15 11:08:05 2004
+++ Zope3/src/zope/app/services/module.py Thu Jan 15 15:50:21 2004
@@ -16,27 +16,43 @@
$Id$
"""
+import re
+
+from keyword import iskeyword
+
from persistence import Persistent
from zodb.code.module import PersistentModule, compileModule
-from zope.app.event import function
-from zope.app.interfaces.annotation import IAttributeAnnotatable
-from zope.app.interfaces.file import IFileFactory
-from zope.app.interfaces.services.module import IModuleManager
-from zope.fssync.server.entryadapter import ObjectEntryAdapter, AttrMapping
+
+from zope.fssync.server.entryadapter import ObjectEntryAdapter
from zope.fssync.server.interfaces import IObjectFile
from zope.interface import implements
from zope.security.proxy import trustedRemoveSecurityProxy
+
+from zope.app import zapi
from zope.app.container.contained import Contained
+from zope.app.event import function
+from zope.app.interfaces.annotation import IAttributeAnnotatable
+from zope.app.interfaces.file import IFileFactory
+from zope.app.interfaces.services.module import IModuleManager
+from zope.app.interfaces.services.registration import ActiveStatus
+from zope.app.services.servicenames import Modules
+
class Manager(Persistent, Contained):
implements(IModuleManager, IAttributeAnnotatable)
- def __init__(self, name, source):
- self.name = name
+ def __init__(self, source):
self._source = None
self.source = source
+ def name(self):
+ name = self.__name__
+ if name.endswith(".py"):
+ name = name[:-3]
+ return name
+ name = property(name)
+
def __setstate__(self, state):
manager = state.get('_manager')
if manager is None:
@@ -44,7 +60,6 @@
# We need to convert an old-style manager
self._module = manager._module
- self.name = manager.name
self._source = manager.source
self._recompile = False
@@ -53,7 +68,9 @@
mod = self._module
except AttributeError:
mod = self._module = PersistentModule(self.name)
-
+ else:
+ if mod.__name__ != self.name:
+ mod.__name__ = self.name
folder = self.__parent__
@@ -64,8 +81,21 @@
# When we do support untrusted code, we're going to have to do
# something different.
folder = trustedRemoveSecurityProxy(folder)
+ regmgr = folder.getRegistrationManager()
+ modules = zapi.getService(self, Modules)
+ mypath = zapi.getPath(self)
compileModule(mod, folder, self.source)
+ non_local = None
+ for registration in regmgr.values():
+ if (registration.componentPath == mypath
+ and registration.status == ActiveStatus):
+ # Get the global module that needs to be updated and
+ # re-execute the source there as well:
+ mod = modules.findModule(registration.name)
+ if non_local is None:
+ non_local = NonLocalImportRegistry(folder)
+ compileModule(mod, non_local, self.source)
self._recompile = False
def getModule(self):
@@ -82,11 +112,72 @@
self._recompile = True
source = property(_get_source, _set_source)
+ def getSize(self):
+ return len(self._source)
+
+ def __name__(self):
+ return self.__dict__.get("__name__")
+ def _set__name__(self, name):
+ # check
+ if "." in name:
+ base, ext = name.split(".", 1)
+ if not isident(base):
+ raise ValueError("invalid module name: %r"
+ " (first part must be a Python identifier)"
+ % name)
+ if ext != "py":
+ raise ValueError("invalid module name: %r"
+ " (extension must be '.py')"
+ % name)
+ elif not isident(name):
+ raise ValueError("invalid module name: %r" % name)
+ oldname = self.__name__
+ if oldname is None:
+ # too early to re-execute, so just return (we don't have
+ # source yet!)
+ self.__dict__["__name__"] = name
+ self._p_changed = 1
+ self._recompile = True
+ return
+ oldpath = zapi.getPath(self)
+ self.__dict__["__name__"] = name
+ self._p_changed = 1
+ newpath = zapi.getPath(self)
+ mod = getattr(self, "_module", None)
+ recompile = mod is not None and not self._recompile
+ # update componentPath for registrations of this module
+ regmgr = self.__parent__.getRegistrationManager()
+ for registration in regmgr.values():
+ if registration.componentPath == oldpath:
+ registration.componentPath = newpath
+ recompile = True
+ if recompile:
+ self.execute()
+ __name__ = property(__name__, _set__name__)
+
# Hack to allow unpickling of old Managers to get far enough for __setstate__
# to do it's magic:
Registry = Manager
+
+_ident_rx = re.compile("[a-zA-Z_][a-zA-Z_0-9]*$")
+
+def isident(name):
+ """Return true iff name is a valid Python identifier."""
+ return _ident_rx.match(name) is not None and not iskeyword(name)
+
+
+class NonLocalImportRegistry:
+ def __init__(self, context):
+ self.context = context
+
+ def findModule(self, name):
+ if name == "__folder__" or name.startswith("__folder__."):
+ return None
+ return self.context._find_non_folder_module(name)
+
+
class ModuleAdapter(ObjectEntryAdapter):
implements(IObjectFile)
@@ -95,10 +186,8 @@
return self.context.source
def setBody(self, source):
- self.context.update(source)
-
- def extra(self):
- return AttrMapping(self.context, ("name",))
+ self.context.source = source
+ self.context.execute()
class ModuleFactory(object):
@@ -110,8 +199,8 @@
def __call__(self, name, content_type, data):
assert name.endswith(".py")
- name = name[:-3]
- m = Manager(name, data)
+ m = Manager(data)
+ m.__name__ = name
m.__parent__ = self.context
m.execute()
return m
=== Zope3/src/zope/app/services/module.zcml 1.4 => 1.4.18.1 ===
--- Zope3/src/zope/app/services/module.zcml:1.4 Fri Aug 22 16:02:20 2003
+++ Zope3/src/zope/app/services/module.zcml Thu Jan 15 15:50:21 2004
@@ -25,10 +25,50 @@
permission="zope.ManageContent"
/>
+<adapter
+ for="zope.app.interfaces.services.module.IModuleManager"
+ provides="zope.app.interfaces.size.ISized"
+ factory="zope.app.size.DefaultSized"
+ permission="zope.Public"
+ />
+
+<!-- Global module support -->
+<serviceType
+ id="Modules"
+ interface="zope.app.interfaces.services.module.IModuleService"
+ />
+
+<content class="zope.app.services.globalmodule.ModuleService">
+ <require
+ permission="zope.ManageServices"
+ interface=
+ "zope.app.interfaces.services.registration.INameComponentRegistry"
+ />
+</content>
+
+<content class="zope.app.services.globalmodule.GlobalModuleRegistration">
+ <require
+ permission="zope.ManageServices"
+ interface=
+ "zope.app.interfaces.services.module.IModuleRegistration"
+ set_schema=
+ "zope.app.interfaces.services.module.IModuleRegistration"
+ />
+</content>
+
+<content class="zope.app.services.globalmodule.GlobalRegistrationStack">
+ <require
+ permission="zope.ManageServices"
+ interface=
+ "zope.app.interfaces.services.registration.IRegistrationStack"
+ />
+</content>
+
+
<!-- Enable import of persistent modules -->
<event:subscribe
- subscriber=".module.installPersistentModuleImporter"
- event_types="zope.app.interfaces.event.IProcessStartingEvent"
- />
+ subscriber=".module.installPersistentModuleImporter"
+ event_types="zope.app.interfaces.event.IProcessStartingEvent"
+ />
</configure>
=== Zope3/src/zope/app/services/registration.py 1.20 => 1.20.4.1 ===
--- Zope3/src/zope/app/services/registration.py:1.20 Tue Jan 13 14:32:23 2004
+++ Zope3/src/zope/app/services/registration.py Thu Jan 15 15:50:21 2004
@@ -17,25 +17,27 @@
"""
__metaclass__ = type
-from zope.app import zapi
+import sys
from persistence import Persistent
-from zope.interface import implements
-from zope.fssync.server.interfaces import IObjectFile
+from zope.exceptions import DuplicationError
from zope.fssync.server.entryadapter import ObjectEntryAdapter
-from zope.proxy import removeAllProxies, getProxiedObject
+from zope.fssync.server.interfaces import IObjectFile
+from zope.interface import implements
+from zope.proxy import removeAllProxies
from zope.security.checker import InterfaceChecker, CheckerPublic
from zope.security.proxy import Proxy, trustedRemoveSecurityProxy
-from zope.exceptions import DuplicationError
from zope.xmlpickle import dumps, loads
+from zope.app import zapi
from zope.app.container.contained import Contained
-from zope.app.container.contained import setitem, contained, uncontained
+from zope.app.container.contained import setitem, uncontained
from zope.app.interfaces.annotation import IAttributeAnnotatable
from zope.app.interfaces.container import IAddNotifiable, IRemoveNotifiable
from zope.app.interfaces.dependable import IDependable, DependencyError
from zope.app.interfaces.services import registration as interfaces
from zope.app.interfaces.services.module import IModuleManager
+from zope.app.services.servicenames import Modules
class RegistrationStatusProperty(object):
@@ -722,39 +724,60 @@
def findModule(self, name):
# Used by the persistent modules import hook
+ if name.startswith("__folder__."):
+ return self._find_folder_module(name.split(".", 1)[1])
+ elif name == "__folder__":
+ return FolderPackage(self._find_folder_module)
+ else:
+ return self._find_non_folder_module(name)
+
+ def _find_folder_module(self, name):
+ if "." in name:
+ return None
# Look for a .py file first:
- manager = self.get(name+'.py')
+ manager = self.get(name + '.py')
if manager is not None:
- # found an item with that name, make sure it's a module(manager):
+ # found item with that name, make sure it's a module(manager):
if IModuleManager.isImplementedBy(manager):
return manager.getModule()
- # Look for the module in this folder:
+ # Now look for a module with the .py:
manager = self.get(name)
if manager is not None:
- # found an item with that name, make sure it's a module(manager):
+ # found item with that name, make sure it's a module(manager):
if IModuleManager.isImplementedBy(manager):
return manager.getModule()
-
- # See if out container is a RegistrationManagerContainer:
- c = self.__parent__
- if interfaces.IRegistrationManagerContainer.isImplementedBy(c):
- return c.findModule(name)
-
- # Use sys.modules in lieu of module service:
- module = sys.modules.get(name)
- if module is not None:
- return module
-
- raise ImportError(name)
-
+ def _find_non_folder_module(self, name):
+ # Not a __folder__ import; get the module service and ask
+ # that in case there's a global module
+ module = zapi.getService(self, Modules).findModule(name)
+
+ # look in sys.modules if we still haven't found it
+ if module is None:
+ module = sys.modules.get(name)
+ return module
def resolve(self, name):
l = name.rfind('.')
mod = self.findModule(name[:l])
return getattr(mod, name[l+1:])
+
+
+class FolderPackage(type(sys)):
+ """Package that loads modules from the database on attribute access."""
+
+ def __init__(self, loader):
+ super(FolderPackage, self).__init__("__folder__")
+ self.__path__ = []
+ self.__loader = loader
+
+ def __getattr__(self, name):
+ m = self.__loader(name)
+ if m is None:
+ raise AttributeError, name
+ return m
class ComponentRegistrationAdapter(ObjectEntryAdapter):
=== Zope3/src/zope/app/services/service.py 1.36 => 1.36.4.1 ===
--- Zope3/src/zope/app/services/service.py:1.36 Tue Jan 13 14:32:23 2004
+++ Zope3/src/zope/app/services/service.py Thu Jan 15 15:50:21 2004
@@ -241,22 +241,22 @@
return local
- def findModule(wrapped_self, name):
- # override to pass call up to next service manager
- mod = super(ServiceManager,
- removeAllProxies(wrapped_self)).findModule(name)
- if mod is not None:
- return mod
+## def findModule(wrapped_self, name):
+## # override to pass call up to next service manager
+## mod = super(ServiceManager,
+## removeAllProxies(wrapped_self)).findModule(name)
+## if mod is not None:
+## return mod
- sm = getNextServiceManager(wrapped_self)
- try:
- findModule = sm.findModule
- except AttributeError:
- # The only service manager that doesn't implement this
- # interface is the global service manager. There is no
- # direct way to ask if sm is the global service manager.
- return None
- return findModule(name)
+## sm = getNextServiceManager(wrapped_self)
+## try:
+## findModule = sm.findModule
+## except AttributeError:
+## # The only service manager that doesn't implement this
+## # interface is the global service manager. There is no
+## # direct way to ask if sm is the global service manager.
+## return None
+## return findModule(name)
def __import(wrapped_self, module_name):
=== Zope3/src/zope/app/services/servicenames.py 1.13 => 1.13.2.1 ===
--- Zope3/src/zope/app/services/servicenames.py:1.13 Wed Jan 14 17:55:28 2004
+++ Zope3/src/zope/app/services/servicenames.py Thu Jan 15 15:50:21 2004
@@ -27,6 +27,7 @@
EventSubscription = 'Subscription'
ErrorLogging = 'ErrorLogging'
HubIds = 'HubIds'
+Modules = 'Modules'
Permissions = 'Permissions'
PrincipalAnnotation = 'PrincipalAnnotation'
Translation = 'Translation'
More information about the Zope3-Checkins
mailing list