Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
erp5
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Labels
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Commits
Open sidebar
Romain Courteaud
erp5
Commits
c89c6533
Commit
c89c6533
authored
Jan 18, 2012
by
Arnaud Fontaine
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add erp5.component.extension as a dynamic module where extensions are lazily loaded.
parent
610b2abe
Changes
4
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
109 additions
and
81 deletions
+109
-81
product/ERP5Type/Core/DocumentComponent.py
product/ERP5Type/Core/DocumentComponent.py
+21
-11
product/ERP5Type/Tool/ComponentTool.py
product/ERP5Type/Tool/ComponentTool.py
+1
-70
product/ERP5Type/dynamic/component_class.py
product/ERP5Type/dynamic/component_class.py
+80
-0
product/ERP5Type/dynamic/dynamic_module.py
product/ERP5Type/dynamic/dynamic_module.py
+7
-0
No files found.
product/ERP5Type/Core/DocumentComponent.py
View file @
c89c6533
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (c) 2010 Nexedi SA and Contributors. All Rights Reserved.
# Copyright (c) 2012 Nexedi SA and Contributors. All Rights Reserved.
# Arnaud Fontaine <arnaud.fontaine@nexedi.com>
# Jean-Paul Smets <jp@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility of assessing all potential
...
...
@@ -26,6 +28,9 @@
#
##############################################################################
import
imp
import
os
from
AccessControl
import
ClassSecurityInfo
from
Products.ERP5Type
import
Permissions
from
Products.ERP5Type.Base
import
Base
...
...
@@ -53,15 +58,20 @@ class DocumentComponent(Base):
'Reference'
,
'TextDocument'
)
def
loadComponent
(
self
):
"""
"""
from
Products.ERP5Type.Utils
import
importLocalDocument
def
load
(
self
):
# XXX-arnau: There should be a load_source() taking a string rather than
# creating a temporary file
from
App.config
import
getConfiguration
instance_home
=
getConfiguration
().
instancehome
path
=
'%s/component/document'
%
instance_home
component_path
=
'%s/%s.py'
%
(
path
,
self
.
getReference
())
# using ID would be better... with some extensions in importLocalDocument
component_file
=
open
(
component_path
,
'w'
)
path
=
'%s/Component'
%
instance_home
if
not
os
.
path
.
isdir
(
path
):
os
.
mkdir
(
path
)
component_path
=
'%s/%s.py'
%
(
path
,
self
.
getId
())
with
open
(
component_path
,
'w'
)
as
component_file
:
component_file
.
write
(
self
.
getTextContent
())
component_file
.
close
()
importLocalDocument
(
self
.
getReference
(),
path
=
path
)
try
:
return
imp
.
load_source
(
self
.
getReference
(),
component_path
)
finally
:
os
.
remove
(
component_path
)
product/ERP5Type/Tool/ComponentTool.py
View file @
c89c6533
...
...
@@ -27,88 +27,19 @@
#
##############################################################################
""" Component Tool module for ERP5 """
from
AccessControl
import
ClassSecurityInfo
from
Products.ERP5Type.Tool.BaseTool
import
BaseTool
from
Products.ERP5Type
import
Permissions
class
ComponentLoader
:
"""
A callable class which delegates component load to ComponentTool
and which contains attributes which can either be called or
implement default component access for different types of components
"""
def
__init__
(
self
):
self
.
component
=
self
# This could be automated by introspecting
# portal_types and listing all component types
self
.
document
=
TypedComponentLoader
(
'Document Component'
)
self
.
interface
=
TypedComponentLoader
(
'Interface Component'
)
self
.
mixin
=
TypedComponentLoader
(
'Mixin Component'
)
self
.
accessor
=
TypedComponentLoader
(
'Accessor Component'
)
self
.
test
=
TypedComponentLoader
(
'Test Component'
)
self
.
extension
=
TypedComponentLoader
(
'Extension Component'
)
def
__call__
(
self
,
portal_type
,
reference
,
version
=
None
):
site
=
getSite
()
return
site
.
portal_components
.
loadComponent
(
portal_type
,
reference
,
version
=
version
)
def
TypedComponentLoader
(
ComponentLoader
):
"""
A callable class which delegates component load to
ComponentLoader and provides default component access through
attributes.
"""
def
__init__
(
self
,
portal_type
):
self
.
_portal_type
=
portal_type
def
__call__
(
self
,
reference
,
version
=
None
):
return
ComponentLoader
.
__call__
(
self
.
_portal_type
,
reference
,
version
=
version
)
def
__getattr__
(
self
,
key
):
if
key
.
startswith
(
'_'
):
return
self
.
__dict__
[
key
]
return
self
(
key
)
component
=
ComponentLoader
()
component_revision
=
None
component_dict
=
None
class
ComponentTool
(
BaseTool
):
"""
This tool provides methods to load the the different types
of components of the ERP5 framework: Document classes, interfaces,
mixin classes, fields, accessors, etc.
"""
id
=
"portal_components"
meta_type
=
"ERP5 Component Tool"
portal_type
=
"Component Tool"
security
=
ClassSecurityInfo
()
manage_options
=
BaseTool
.
manage_options
def
loadComponent
(
self
,
portal_type
,
reference
,
version
=
None
):
"""
This first version compiles all components once. A lazy
version could be more efficient.
"""
global
component_dict
# Reset cache if modified
#if component_revision is None:
# component_dict = None
if
component_dict
is
None
:
component_dict
=
{}
for
document
in
contentValues
():
portal_type
=
document
.
getPortalType
()
version
=
document
.
getVersion
()
reference
=
document
.
getReference
()
component
=
document
.
loadComponent
()
typed_component_dict
=
component_dict
.
setdefault
(
portal_type
,
{})
component_version_dict
=
typed_component_dict
.
setdefault
(
reference
,
{})
# How to handle default ?
component_version_dict
[
version
]
=
component
component_version_dict
[
None
]
=
component
return
component_dict
[
portal_type
][
reference
][
version
]
security
.
declareObjectProtected
(
Permissions
.
AccessContentsInformation
)
product/ERP5Type/dynamic/component_class.py
0 → 100644
View file @
c89c6533
##############################################################################
#
# Copyright (c) 2012 Nexedi SARL and Contributors. All Rights Reserved.
# Arnaud Fontaine <arnaud.fontaine@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# guarantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
##############################################################################
from
zLOG
import
LOG
,
INFO
class
ComponentProxyClass
(
object
):
"""
XXX-arnau: should maybe use Ghost class?
"""
def
__init__
(
self
,
component
,
module
):
self
.
_component
=
component
self
.
_module
=
module
self
.
__isghost__
=
False
# XXX-arnau: metaclass!
self
.
__class__
.
__name__
=
component
.
getReference
()
self
.
__class__
.
__module__
=
component
.
getId
().
rsplit
(
'.'
,
1
)[
0
]
description
=
component
.
getDescription
()
if
description
:
self
.
__doc__
=
description
def
restoreGhostState
(
self
):
self
.
__isghost__
=
True
def
__getattr__
(
self
,
name
):
if
self
.
__isghost__
:
self
.
_module
=
self
.
_component
.
load
()
self
.
__isghost__
=
False
LOG
(
"ERP5Type.dynamic"
,
INFO
,
"Reloaded %s"
%
self
.
_component
.
getId
())
return
getattr
(
self
.
_module
,
name
)
def
generateComponentClassWrapper
(
namespace
):
def
generateComponentClass
(
component_name
):
from
Products.ERP5.ERP5Site
import
getSite
site
=
getSite
()
component_name
=
'%s.%s'
%
(
namespace
,
component_name
)
try
:
component
=
getattr
(
site
.
portal_components
,
component_name
)
except
AttributeError
:
LOG
(
"ERP5Type.dynamic"
,
INFO
,
"Could not find %s, perhaps it has not been migrated yet?"
%
component_name
)
raise
else
:
if
component
.
getValidationState
()
==
'validated'
:
klass
=
ComponentProxyClass
(
component
,
component
.
load
())
LOG
(
"ERP5Type.dynamic"
,
INFO
,
"Loaded successfully %s"
%
component_name
)
return
klass
else
:
raise
AttributeError
(
"Component %s not validated"
%
component_name
)
return
generateComponentClass
product/ERP5Type/dynamic/dynamic_module.py
View file @
c89c6533
...
...
@@ -87,6 +87,8 @@ def initializeDynamicModules():
holds accessors holders of Portal Types
erp5.component:
holds component modules
erp5.component.extension:
holds extension classes previously found in bt5 in instancehome/Extensions
"""
erp5
=
ModuleType
(
"erp5"
)
sys
.
modules
[
"erp5"
]
=
erp5
...
...
@@ -122,3 +124,8 @@ def initializeDynamicModules():
# Components
erp5
.
component
=
ModuleType
(
"erp5.component"
)
sys
.
modules
[
"erp5.component"
]
=
erp5
.
component
from
component_class
import
generateComponentClassWrapper
erp5
.
component
.
extension
=
registerDynamicModule
(
'erp5.component.extension'
,
generateComponentClassWrapper
(
'erp5.component.extension'
))
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment