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
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Laurent S
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
Hide 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'
)
component_file
.
write
(
self
.
getTextContent
())
component_file
.
close
()
importLocalDocument
(
self
.
getReference
(),
path
=
path
)
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
())
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