Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
erp5-Boxiang
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
Hamza
erp5-Boxiang
Commits
603c8600
Commit
603c8600
authored
Dec 10, 2014
by
wenjie.zheng
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
ERP5Workflow Method Generation for live test.
parent
425949fe
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
158 additions
and
63 deletions
+158
-63
product/ERP5Type/Base.py
product/ERP5Type/Base.py
+133
-58
product/ERP5Type/ERP5Type.py
product/ERP5Type/ERP5Type.py
+5
-4
product/ERP5Type/dynamic/lazy_class.py
product/ERP5Type/dynamic/lazy_class.py
+20
-1
No files found.
product/ERP5Type/Base.py
View file @
603c8600
...
...
@@ -165,100 +165,135 @@ class WorkflowMethod(Method):
# already better than what we had. I (JPS) would prefer to use
# critical sections in this part of the code and a
# thread variable which tells in which semantic context the code
# should
n
e executed. - XXX
# should
b
e executed. - XXX
return
self
.
_m
(
instance
,
*
args
,
**
kw
)
#=============== Workflow5 Project, Wenjie, Dec 2014 =====================
# Get Workflow5 which is an ERP5 default module.
# Available workflow5 bt should be initially installed.
# Only check Base Type obejct:
wf5_module
=
instance
.
getPortalObject
().
getDefaultModule
(
portal_type
=
"Workflow"
)
valid_list5
=
[]
valid_transition_item_list5
=
[]
#if instance.portal_type == "Object Type":
#raise NotImplementedError (instance.getTypeInfo())# Base Type at Object Type
if
hasattr
(
instance
.
getTypeInfo
(),
"workflow_list"
):
WorkflowList
=
instance
.
getTypeInfo
().
getTypeWorkflowList
()
#raise NotImplementedError (WorkflowList)# new_workflow
for
wf_id
in
WorkflowList
:
wf5
=
wf5_module
.
_getOb
(
wf_id
)
for
transition
in
wf5
.
objectValues
(
portal_type
=
'Transition'
):
valid_list5
.
append
(
transition
.
getId
())
#raise NotImplementedError (valid_list5) # ['transition1', 'transition2']
if
valid_list5
:
valid_transition_item_list5
.
append
((
wf_id
,
valid_list5
))
# execute method
for
wf_id
,
transition_list
in
valid_transition_item_list5
:
# ??? see original <245, 256>
for
tr
in
transition_list
:
method5
=
wf5_module
.
_getOb
(
wf_id
).
_getOb
(
tr
)
method5
.
execute
(
instance
)
# also execute before & after script
#return method5._changeState(instance) # only change state
#raise NotImplementedError (instance.getId()) # new_object
#raise NotImplementedError (method5) # Transition at transition1
#raise NotImplementedError (instance.getCategoryStateTitle()) # None
#=================================== wf5 =================================
# New implementation does not use any longer wrapWorkflowMethod
# but directly calls the workflow methods
try
:
wf
=
getattr
(
instance
.
getPortalObject
(),
'portal_workflow'
)
wf
=
getattr
(
instance
.
getPortalObject
(),
'portal_workflow'
)
# portal_workflow is a list!
except
AttributeError
:
# XXX instance is unwrapped(no acquisition)
# XXX I must think that what is a correct behavior.(Yusei)
return
self
.
_m
(
instance
,
*
args
,
**
kw
)
try
:
# Build a list of transitions which may need to be invoked
instance_path
=
instance
.
getPhysicalPath
()
portal_type
=
instance
.
portal_type
transactional_variable
=
getTransactionalVariable
()
invoke_once_dict
=
self
.
_invoke_once
.
get
(
portal_type
,
{})
valid_invoke_once_item_list
=
[]
instance_path
=
instance
.
getPhysicalPath
()
portal_type
=
instance
.
portal_type
transactional_variable
=
getTransactionalVariable
()
invoke_once_dict
=
self
.
_invoke_once
.
get
(
portal_type
,
{})
valid_invoke_once_item_list
=
[]
# Only keep those transitions which were never invoked
once_transition_dict
=
{}
for
wf_id
,
transition_list
in
invoke_once_dict
.
iteritems
():
valid_transition_list
=
[]
for
transition_id
in
transition_list
:
once_transition_key
=
(
'Products.ERP5Type.Base.WorkflowMethod.__call__'
,
wf_id
,
transition_id
,
instance_path
)
once_transition_dict
[(
wf_id
,
transition_id
)]
=
once_transition_key
if
once_transition_key
not
in
transactional_variable
:
valid_transition_list
.
append
(
transition_id
)
if
valid_transition_list
:
valid_invoke_once_item_list
.
append
((
wf_id
,
valid_transition_list
))
candidate_transition_item_list
=
valid_invoke_once_item_list
+
\
once_transition_dict
=
{}
for
wf_id
,
transition_list
in
invoke_once_dict
.
iteritems
():
valid_transition_list
=
[]
for
transition_id
in
transition_list
:
once_transition_key
=
(
'Products.ERP5Type.Base.WorkflowMethod.__call__'
,
wf_id
,
transition_id
,
instance_path
)
once_transition_dict
[(
wf_id
,
transition_id
)]
=
once_transition_key
if
once_transition_key
not
in
transactional_variable
:
valid_transition_list
.
append
(
transition_id
)
if
valid_transition_list
:
valid_invoke_once_item_list
.
append
((
wf_id
,
valid_transition_list
))
candidate_transition_item_list
=
valid_invoke_once_item_list
+
\
self
.
_invoke_always
.
get
(
portal_type
,
{}).
items
()
#LOG('candidate_transition_item_list %s' % self.__name__, 0, str(candidate_transition_item_list))
# Try to return immediately if there are no transition to invoke
if
not
candidate_transition_item_list
:
return
apply
(
self
.
__dict__
[
'_m'
],
(
instance
,)
+
args
,
kw
)
if
not
candidate_transition_item_list
:
return
apply
(
self
.
__dict__
[
'_m'
],
(
instance
,)
+
args
,
kw
)
# Prepare a list of transitions which should be invoked.
# This list is based on the results of isWorkflowMethodSupported.
# An interaction is ignored if the guard prevents execution.
# Otherwise, an exception is raised if the workflow transition does not
# exist from the current state, or if the guard rejects it.
valid_transition_item_list
=
[]
for
wf_id
,
transition_list
in
candidate_transition_item_list
:
candidate_workflow
=
wf
[
wf_id
]
valid_list
=
[]
for
transition_id
in
transition_list
:
if
candidate_workflow
.
isWorkflowMethodSupported
(
instance
,
transition_id
):
valid_list
.
append
(
transition_id
)
once_transition_key
=
once_transition_dict
.
get
((
wf_id
,
transition_id
))
if
once_transition_key
:
# a run-once transition, prevent it from running again in
# the same transaction
transactional_variable
[
once_transition_key
]
=
1
elif
candidate_workflow
.
__class__
.
__name__
==
'DCWorkflowDefinition'
:
raise
UnsupportedWorkflowMethod
(
instance
,
wf_id
,
transition_id
)
valid_transition_item_list
=
[]
for
wf_id
,
transition_list
in
candidate_transition_item_list
:
candidate_workflow
=
wf
[
wf_id
]
valid_list
=
[]
for
transition_id
in
transition_list
:
if
candidate_workflow
.
isWorkflowMethodSupported
(
instance
,
transition_id
):
valid_list
.
append
(
transition_id
)
once_transition_key
=
once_transition_dict
.
get
((
wf_id
,
transition_id
))
if
once_transition_key
:
# a run-once transition, prevent it from running again in
# the same transaction
transactional_variable
[
once_transition_key
]
=
1
elif
candidate_workflow
.
__class__
.
__name__
==
'DCWorkflowDefinition'
:
raise
UnsupportedWorkflowMethod
(
instance
,
wf_id
,
transition_id
)
# XXX Keep the log for projects that needs to comment out
# the previous line.
LOG
(
"WorkflowMethod.__call__"
,
ERROR
,
LOG
(
"WorkflowMethod.__call__"
,
ERROR
,
"Transition %s/%s on %r is ignored. Current state is %r."
%
(
wf_id
,
transition_id
,
instance
,
candidate_workflow
.
_getWorkflowStateOf
(
instance
,
id_only
=
1
)))
if
valid_list
:
valid_transition_item_list
.
append
((
wf_id
,
valid_list
))
if
valid_list
:
valid_transition_item_list
.
append
((
wf_id
,
valid_list
))
#LOG('valid_transition_item_list %s' % self.__name__, 0, str(valid_transition_item_list))
# Call whatever must be called before changing states
for
wf_id
,
transition_list
in
valid_transition_item_list
:
wf
[
wf_id
].
notifyBefore
(
instance
,
transition_list
,
args
=
args
,
kw
=
kw
)
# Call whatever must be called before changing states
for
wf_id
,
transition_list
in
valid_transition_item_list
:
wf
[
wf_id
].
notifyBefore
(
instance
,
transition_list
,
args
=
args
,
kw
=
kw
)
# Compute expected result
result
=
apply
(
self
.
__dict__
[
'_m'
],
(
instance
,)
+
args
,
kw
)
# Compute expected result
result
=
apply
(
self
.
__dict__
[
'_m'
],
(
instance
,)
+
args
,
kw
)
# Change the state of statefull workflows
for
wf_id
,
transition_list
in
valid_transition_item_list
:
try
:
wf
[
wf_id
].
notifyWorkflowMethod
(
instance
,
transition_list
,
args
=
args
,
kw
=
kw
)
except
ObjectDeleted
:
# Re-raise with a different result.
raise
ObjectDeleted
(
result
)
except
ObjectMoved
,
ex
:
# Re-raise with a different result.
raise
ObjectMoved
(
ex
.
getNewObject
(),
result
)
# Change the state of statefull workflows
for
wf_id
,
transition_list
in
valid_transition_item_list
:
try
:
wf
[
wf_id
].
notifyWorkflowMethod
(
instance
,
transition_list
,
args
=
args
,
kw
=
kw
)
except
ObjectDeleted
:
# Re-raise with a different result.
raise
ObjectDeleted
(
result
)
except
ObjectMoved
,
ex
:
# Re-raise with a different result.
raise
ObjectMoved
(
ex
.
getNewObject
(),
result
)
# Call whatever must be called after changing states
for
wf_id
,
transition_list
in
valid_transition_item_list
:
wf
[
wf_id
].
notifySuccess
(
instance
,
transition_list
,
result
,
args
=
args
,
kw
=
kw
)
# Return result finally
return
result
for
wf_id
,
transition_list
in
valid_transition_item_list
:
# /product/ERP5/InteractionWorkflow.py, update value, provide info
wf
[
wf_id
].
notifySuccess
(
instance
,
transition_list
,
result
,
args
=
args
,
kw
=
kw
)
# Return result finally
return
result
except
:
pass
# Interactions should not be disabled during normal operation. Only in very
# rare and specific cases like data migration. That's why it is implemented
# with temporary monkey-patching, instead of slowing down __call__ with yet
...
...
@@ -492,6 +527,43 @@ def getClassPropertyList(klass):
if
p
not
in
ps_list
])
return
ps_list
# =================== Workflow5 Project, Wenjie, Dec 2014 ======================
### this function will be used in /product/ERP5Type/dynamic/lazy_class.py
### in generatePortalTypeAccessors()
def
intializePortalTypeERP5WorkflowMethod
(
ptype_klass
,
portal_workflow5
):
### portal_workflow5 is the entire ERP5Workflow module, need to access the
### workflow_list from instance's portal type. So only the related erp5 workflow will be used.
wf5_module
=
aq_inner
(
portal_workflow5
)
portal_type
=
portal_workflow5
.
getPortalObject
().
getDefaultModule
(
portal_type
=
"portal_types"
)
pt
=
portal_type
.
_getOb
(
ptype_klass
.
__name__
)
#raise NotImplementedError (portal_type)
#raise NotImplementedError (wf5_module)#<Workflow Module at workflow_module>
for
workflow5
in
pt
.
workflow_list
:
for
tr
in
wf5_module
.
_getOb
(
workflow5
).
objectValues
(
portal_type
=
"Transition"
):
tr_id
=
tr
.
id
method_id
=
tr_id
wf_id
=
workflow5
ptype_klass
.
security
.
declareProtected
(
Permissions
.
AccessContentsInformation
,
method_id
)
ptype_klass
.
registerWorkflowMethod
(
method_id
,
wf_id
,
tr_id
)
method
=
getattr
(
ptype_klass
,
method_id
)
# Wrap method
if
not
callable
(
method
):
LOG
(
'initializePortalTypeERP5WorkflowMethods'
,
100
,
'WARNING! Can not initialize %s on %s'
%
\
(
method_id
,
portal_type
))
continue
if
not
isinstance
(
method
,
WorkflowMethod
):
method
=
WorkflowMethod
(
method
)
setattr
(
ptype_klass
,
method_id
,
method
)
method
.
registerTransitionAlways
(
portal_type
,
wf_id
,
tr_id
)
# =================== WF5 ======================================================
def
initializePortalTypeDynamicWorkflowMethods
(
ptype_klass
,
portal_workflow
):
"""We should now make sure workflow methods are defined
and also make sure simulation state is defined."""
...
...
@@ -505,6 +577,8 @@ def initializePortalTypeDynamicWorkflowMethods(ptype_klass, portal_workflow):
dc_workflow_dict
=
dict
()
interaction_workflow_dict
=
dict
()
# DCworkflow
for
wf
in
portal_workflow
.
getWorkflowsFor
(
portal_type
):
wf_id
=
wf
.
id
wf_type
=
wf
.
__class__
.
__name__
...
...
@@ -545,6 +619,7 @@ def initializePortalTypeDynamicWorkflowMethods(ptype_klass, portal_workflow):
storage
[
wf_id
]
=
(
transition_id_set
,
trigger_dict
)
# Generate Workflow method:
for
wf_id
,
v
in
dc_workflow_dict
.
iteritems
():
transition_id_set
,
trigger_dict
=
v
for
tr_id
,
tdef
in
trigger_dict
.
iteritems
():
...
...
product/ERP5Type/ERP5Type.py
View file @
603c8600
...
...
@@ -46,6 +46,7 @@ from TranslationProviderBase import TranslationProviderBase
from
sys
import
exc_info
from
zLOG
import
LOG
,
ERROR
from
Products.CMFCore.exceptions
import
zExceptions_Unauthorized
from
types
import
NoneType
def
getCurrentUserIdOrAnonymousToken
():
"""Return connected user_id or simple token for
...
...
@@ -421,10 +422,9 @@ class ERP5TypeInformation(XMLObject,
for
workflow5
in
self
.
getTypeWorkflowList
():
workflow_module
=
portal
.
getDefaultModule
(
portal_type
=
"Workflow"
)
if
workflow_module
is
not
None
:
workflow5
=
workflow_module
.
_getOb
(
workflow5
)
workflow5
.
initializeDocument
(
ob
)
workflow5
=
workflow_module
.
_getOb
(
workflow5
)
workflow5
.
initializeDocument
(
ob
)
if
not
temp_object
:
init_script
=
self
.
getTypeInitScriptId
()
...
...
@@ -531,6 +531,7 @@ class ERP5TypeInformation(XMLObject,
"""
Return all the properties of the Portal Type
"""
### cls's class is PortalTypeMetaClass defined in ERP5Type/dynamic/lazy_class.py
cls
=
self
.
getPortalObject
().
portal_types
.
getPortalTypeClass
(
self
.
getId
())
return_set
=
set
()
for
property_dict
in
cls
.
getAccessorHolderPropertyList
(
content
=
True
):
...
...
product/ERP5Type/dynamic/lazy_class.py
View file @
603c8600
...
...
@@ -7,7 +7,7 @@ from Products.ERP5Type.Accessor.Constant import Getter as ConstantGetter
from
Products.ERP5Type.Globals
import
InitializeClass
from
Products.ERP5Type.Base
import
Base
as
ERP5Base
from
.
import
aq_method_lock
from
Products.ERP5Type.Base
import
PropertyHolder
,
initializePortalTypeDynamicWorkflowMethods
from
Products.ERP5Type.Base
import
PropertyHolder
,
initializePortalTypeDynamicWorkflowMethods
,
intializePortalTypeERP5WorkflowMethod
from
Products.ERP5Type.Utils
import
UpperCase
from
Products.ERP5Type.Core.CategoryProperty
import
CategoryProperty
from
ExtensionClass
import
ExtensionClass
,
pmc_init_of
...
...
@@ -266,6 +266,25 @@ class PortalTypeMetaClass(GhostBaseMetaClass, PropertyHolder):
else
:
initializePortalTypeDynamicWorkflowMethods
(
cls
,
portal_workflow
)
# ================== Workflow5 Project, Wenjie, Dec 2014 =======================
#raise NotImplementedError (cls.__name__) # Category Property
### the ERP5Workflow list is defined in ERP5Type, only try to get erp5workflow
### when it's an erp5workflow related type.
if
cls
.
__name__
==
"Object Type"
:
portal_workflow5
=
site
.
getDefaultModule
(
portal_type
=
"Workflow"
)
#raise NotImplementedError (portal_workflow5) #<Workflow Module at workflow_module>
#raise NotImplementedError (cls.__module__) #<class 'erp5.portal_type.Category Property'>
if
portal_workflow5
is
None
:
LOG
(
"ERP5Type.Dynamic"
,
WARNING
,
"no workflow5 methods for %s"
%
cls
.
__name__
)
else
:
intializePortalTypeERP5WorkflowMethod
(
cls
,
portal_workflow5
)
# ================== WF5 =======================================================
# portal type group methods, isNodeType, isResourceType...
from
Products.ERP5Type.ERP5Type
import
ERP5TypeInformation
# XXX possible optimization:
...
...
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