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
7
Merge Requests
7
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Jobs
Commits
Open sidebar
Jérome Perrin
erp5
Commits
158eaf85
Commit
158eaf85
authored
Jan 29, 2024
by
Jérome Perrin
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
wip py3 sort categories
parent
97eb88eb
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
104 additions
and
37 deletions
+104
-37
product/CMFCategory/Category.py
product/CMFCategory/Category.py
+40
-29
product/CMFCategory/Renderer.py
product/CMFCategory/Renderer.py
+15
-3
product/CMFCategory/tests/testCMFCategory.py
product/CMFCategory/tests/testCMFCategory.py
+40
-4
product/ERP5Type/Utils.py
product/ERP5Type/Utils.py
+9
-1
No files found.
product/CMFCategory/Category.py
View file @
158eaf85
...
@@ -28,6 +28,7 @@
...
@@ -28,6 +28,7 @@
from
past.builtins
import
cmp
from
past.builtins
import
cmp
import
string
import
string
import
warnings
from
Products.ERP5Type.Globals
import
InitializeClass
,
DTMLFile
from
Products.ERP5Type.Globals
import
InitializeClass
,
DTMLFile
from
AccessControl
import
ClassSecurityInfo
from
AccessControl
import
ClassSecurityInfo
...
@@ -282,6 +283,7 @@ class Category(Folder):
...
@@ -282,6 +283,7 @@ class Category(Folder):
def
getCategoryChildValueList
(
self
,
recursive
=
1
,
include_if_child
=
1
,
def
getCategoryChildValueList
(
self
,
recursive
=
1
,
include_if_child
=
1
,
is_self_excluded
=
1
,
sort_on
=
None
,
is_self_excluded
=
1
,
sort_on
=
None
,
sort_order
=
None
,
local_sort_method
=
None
,
sort_order
=
None
,
local_sort_method
=
None
,
local_sort_key
=
None
,
local_sort_id
=
None
,
checked_permission
=
None
,
local_sort_id
=
None
,
checked_permission
=
None
,
**
kw
):
**
kw
):
"""
"""
...
@@ -305,8 +307,13 @@ class Category(Folder):
...
@@ -305,8 +307,13 @@ class Category(Folder):
WARNING: using these parameters can slow down
WARNING: using these parameters can slow down
significantly, because this is written in Python
significantly, because this is written in Python
local_sort_key - When using the default preorder traversal, use
this function as sort key for objects of the same
depth.
local_sort_method - When using the default preorder traversal, use
local_sort_method - When using the default preorder traversal, use
this function to sort objects of the same depth.
this function to sort objects of the same depth.
DEPRECATED, use local_sort_key
local_sort_id - When using the default preorder traversal, sort
local_sort_id - When using the default preorder traversal, sort
objects of the same depth by comparing their
objects of the same depth by comparing their
...
@@ -325,24 +332,23 @@ class Category(Folder):
...
@@ -325,24 +332,23 @@ class Category(Folder):
child_value_list
=
self
.
objectValues
(
self
.
allowed_types
)
child_value_list
=
self
.
objectValues
(
self
.
allowed_types
)
if
local_sort_id
:
if
local_sort_id
:
if
isinstance
(
local_sort_id
,
(
tuple
,
list
)):
if
not
isinstance
(
local_sort_id
,
(
tuple
,
list
)):
def
sort_method
(
a
,
b
):
local_sort_id
=
(
local_sort_id
,
)
for
sort_id
in
local_sort_id
:
def
sort_key
(
c
):
diff
=
cmp
(
a
.
getProperty
(
sort_id
,
0
),
b
.
getProperty
(
sort_id
,
0
))
return
[
c
.
getProperty
(
sort_id
,
0
)
for
sort_id
in
local_sort_id
]
if
diff
!=
0
:
local_sort_key
=
sort_key
return
diff
return
0
local_sort_method
=
sort_method
else
:
local_sort_method
=
lambda
a
,
b
:
cmp
(
a
.
getProperty
(
local_sort_id
,
0
),
b
.
getProperty
(
local_sort_id
,
0
))
if
local_sort_method
:
if
local_sort_method
:
# sort objects at the current level
warnings
.
warn
(
"`local_sort_method` argument is deprecated, use `local_sort_key` instead"
,
DeprecationWarning
)
child_value_list
=
list
(
child_value_list
)
child_value_list
=
list
(
child_value_list
)
if
six
.
PY2
:
if
six
.
PY2
:
child_value_list
.
sort
(
local_sort_method
)
child_value_list
.
sort
(
local_sort_method
)
else
:
else
:
child_value_list
.
sort
(
key
=
cmp_to_key
(
local_sort_method
))
local_sort_key
=
cmp_to_key
(
local_sort_method
)
if
local_sort_key
:
child_value_list
=
sorted
(
child_value_list
,
key
=
local_sort_key
)
if
recursive
:
if
recursive
:
for
c
in
child_value_list
:
for
c
in
child_value_list
:
# Do not pass sort_on / sort_order parameters intentionally, because
# Do not pass sort_on / sort_order parameters intentionally, because
...
@@ -351,6 +357,7 @@ class Category(Folder):
...
@@ -351,6 +357,7 @@ class Category(Folder):
is_self_excluded
=
0
,
is_self_excluded
=
0
,
include_if_child
=
include_if_child
,
include_if_child
=
include_if_child
,
local_sort_method
=
local_sort_method
,
local_sort_method
=
local_sort_method
,
local_sort_key
=
local_sort_key
,
local_sort_id
=
local_sort_id
))
local_sort_id
=
local_sort_id
))
else
:
else
:
for
c
in
child_value_list
:
for
c
in
child_value_list
:
...
@@ -838,7 +845,7 @@ class BaseCategory(Category):
...
@@ -838,7 +845,7 @@ class BaseCategory(Category):
'getCategoryChildValueList'
)
'getCategoryChildValueList'
)
def
getCategoryChildValueList
(
self
,
is_self_excluded
=
1
,
recursive
=
1
,
def
getCategoryChildValueList
(
self
,
is_self_excluded
=
1
,
recursive
=
1
,
include_if_child
=
1
,
sort_on
=
None
,
sort_order
=
None
,
include_if_child
=
1
,
sort_on
=
None
,
sort_order
=
None
,
local_sort_method
=
None
,
local_sort_id
=
None
,
local_sort_method
=
None
,
local_sort_
key
=
None
,
local_sort_
id
=
None
,
checked_permission
=
None
,
**
kw
):
checked_permission
=
None
,
**
kw
):
"""
"""
List the child objects of this category and all its subcategories.
List the child objects of this category and all its subcategories.
...
@@ -860,8 +867,13 @@ class BaseCategory(Category):
...
@@ -860,8 +867,13 @@ class BaseCategory(Category):
the 'sort_on' attribute. The default is to do a preorder tree
the 'sort_on' attribute. The default is to do a preorder tree
traversal on all subobjects.
traversal on all subobjects.
local_sort_key - When using the default preorder traversal, use
this function as sort key for objects of the same
depth.
local_sort_method - When using the default preorder traversal, use
local_sort_method - When using the default preorder traversal, use
this function to sort objects of the same depth.
this function to sort objects of the same depth.
DEPRECATED, use local_sort_key
local_sort_id - When using the default preorder traversal, sort
local_sort_id - When using the default preorder traversal, sort
objects of the same depth by comparing their
objects of the same depth by comparing their
...
@@ -879,32 +891,31 @@ class BaseCategory(Category):
...
@@ -879,32 +891,31 @@ class BaseCategory(Category):
child_value_list
=
self
.
objectValues
(
self
.
allowed_types
)
child_value_list
=
self
.
objectValues
(
self
.
allowed_types
)
if
local_sort_id
:
if
local_sort_id
:
if
isinstance
(
local_sort_id
,
(
tuple
,
list
)):
if
not
isinstance
(
local_sort_id
,
(
tuple
,
list
)):
def
sort_method
(
a
,
b
):
local_sort_id
=
(
local_sort_id
,
)
for
sort_id
in
local_sort_id
:
def
sort_key
(
c
):
diff
=
cmp
(
a
.
getProperty
(
sort_id
,
0
),
b
.
getProperty
(
sort_id
,
0
))
return
[
c
.
getProperty
(
sort_id
,
0
)
for
sort_id
in
local_sort_id
]
if
diff
!=
0
:
local_sort_key
=
sort_key
return
diff
return
0
local_sort_method
=
sort_method
else
:
local_sort_method
=
lambda
a
,
b
:
cmp
(
a
.
getProperty
(
local_sort_id
,
0
),
b
.
getProperty
(
local_sort_id
,
0
))
if
local_sort_method
:
if
local_sort_method
:
# sort objects at the current level
warnings
.
warn
(
"`local_sort_method` argument is deprecated, use `local_sort_key` instead"
,
DeprecationWarning
)
child_value_list
=
list
(
child_value_list
)
child_value_list
=
list
(
child_value_list
)
if
six
.
PY2
:
if
six
.
PY2
:
child_value_list
.
sort
(
local_sort_method
)
child_value_list
.
sort
(
local_sort_method
)
else
:
else
:
child_value_list
.
sort
(
key
=
cmp_to_key
(
local_sort_method
))
local_sort_key
=
cmp_to_key
(
local_sort_method
)
if
local_sort_key
:
child_value_list
=
sorted
(
child_value_list
,
key
=
local_sort_key
)
if
recursive
:
if
recursive
:
for
c
in
child_value_list
:
for
c
in
child_value_list
:
value_list
.
extend
(
c
.
getCategoryChildValueList
(
recursive
=
1
,
value_list
.
extend
(
c
.
getCategoryChildValueList
(
recursive
=
1
,
is_self_excluded
=
0
,
is_self_excluded
=
0
,
include_if_child
=
include_if_child
,
include_if_child
=
include_if_child
,
local_sort_id
=
local_sort_id
,
local_sort_method
=
local_sort_method
,
local_sort_method
=
local_sort_method
))
local_sort_key
=
local_sort_key
,
local_sort_id
=
local_sort_id
))
else
:
else
:
for
c
in
child_value_list
:
for
c
in
child_value_list
:
if
include_if_child
:
if
include_if_child
:
...
...
product/CMFCategory/Renderer.py
View file @
158eaf85
...
@@ -30,6 +30,9 @@
...
@@ -30,6 +30,9 @@
from
Products.CMFCategory.Filter
import
Filter
from
Products.CMFCategory.Filter
import
Filter
from
ZODB.POSException
import
ConflictError
from
ZODB.POSException
import
ConflictError
from
zLOG
import
LOG
,
PROBLEM
from
zLOG
import
LOG
,
PROBLEM
import
six
if
six
.
PY3
:
from
functools
import
cmp_to_key
class
Renderer
(
Filter
):
class
Renderer
(
Filter
):
"""
"""
...
@@ -42,7 +45,7 @@ class Renderer(Filter):
...
@@ -42,7 +45,7 @@ class Renderer(Filter):
def
__init__
(
self
,
spec
=
None
,
filter
=
None
,
portal_type
=
None
,
def
__init__
(
self
,
spec
=
None
,
filter
=
None
,
portal_type
=
None
,
display_id
=
None
,
sort_id
=
None
,
display_id
=
None
,
sort_id
=
None
,
display_method
=
None
,
sort_method
=
None
,
filter_method
=
None
,
display_method
=
None
,
sort_
key
=
None
,
sort_
method
=
None
,
filter_method
=
None
,
filter_node
=
0
,
disable_node
=
0
,
filter_node
=
0
,
disable_node
=
0
,
filter_leave
=
0
,
disable_leave
=
0
,
filter_leave
=
0
,
disable_leave
=
0
,
is_right_display
=
0
,
translate_display
=
0
,
is_right_display
=
0
,
translate_display
=
0
,
...
@@ -74,7 +77,10 @@ class Renderer(Filter):
...
@@ -74,7 +77,10 @@ class Renderer(Filter):
foo2 5
foo2 5
display order will be (foo1, foo, foo2)
display order will be (foo1, foo, foo2)
- *sort_method*: a callable method which provides a sort function (?la cmp)
- *sort_key*: a callable method used to sort the values, as in sort(key=sort_key)
- *sort_method*: a callable method used to sort the values, as in python2 cmp.
DEPRECATED, use sort_key.
- *is_right_display*: use the right value in the couple as the display value.
- *is_right_display*: use the right value in the couple as the display value.
...
@@ -109,6 +115,7 @@ class Renderer(Filter):
...
@@ -109,6 +115,7 @@ class Renderer(Filter):
self
.
display_id
=
display_id
self
.
display_id
=
display_id
self
.
sort_id
=
sort_id
self
.
sort_id
=
sort_id
self
.
display_method
=
display_method
self
.
display_method
=
display_method
self
.
sort_key
=
sort_key
self
.
sort_method
=
sort_method
self
.
sort_method
=
sort_method
self
.
is_right_display
=
is_right_display
self
.
is_right_display
=
is_right_display
self
.
translate_display
=
translate_display
self
.
translate_display
=
translate_display
...
@@ -135,7 +142,12 @@ class Renderer(Filter):
...
@@ -135,7 +142,12 @@ class Renderer(Filter):
value_list
=
self
.
getObjectList
(
value_list
)
value_list
=
self
.
getObjectList
(
value_list
)
value_list
=
self
.
filter
(
value_list
)
value_list
=
self
.
filter
(
value_list
)
if
self
.
sort_method
is
not
None
:
if
self
.
sort_method
is
not
None
:
value_list
.
sort
(
self
.
sort_method
)
if
six
.
PY2
:
value_list
.
sort
(
self
.
sort_method
)
else
:
value_list
.
sort
(
key
=
cmp_to_key
(
self
.
sort_method
))
elif
self
.
sort_key
is
not
None
:
value_list
.
sort
(
key
=
self
.
sort_key
)
elif
self
.
sort_id
is
not
None
:
elif
self
.
sort_id
is
not
None
:
value_list
.
sort
(
key
=
lambda
x
:
x
.
getProperty
(
self
.
sort_id
))
value_list
.
sort
(
key
=
lambda
x
:
x
.
getProperty
(
self
.
sort_id
))
...
...
product/CMFCategory/tests/testCMFCategory.py
View file @
158eaf85
...
@@ -30,6 +30,7 @@
...
@@ -30,6 +30,7 @@
import
mock
import
mock
from
collections
import
deque
from
collections
import
deque
import
unittest
import
unittest
import
warnings
from
Acquisition
import
aq_base
from
Acquisition
import
aq_base
from
Products.ERP5Type.tests.ERP5TypeTestCase
import
ERP5TypeTestCase
from
Products.ERP5Type.tests.ERP5TypeTestCase
import
ERP5TypeTestCase
...
@@ -952,8 +953,8 @@ class TestCMFCategory(ERP5TypeTestCase):
...
@@ -952,8 +953,8 @@ class TestCMFCategory(ERP5TypeTestCase):
self
.
assertSameSet
(
c1
.
getCategoryChildValueList
(
is_self_excluded
=
0
),
self
.
assertSameSet
(
c1
.
getCategoryChildValueList
(
is_self_excluded
=
0
),
(
c1
,
c11
,
c111
))
(
c1
,
c11
,
c111
))
def
test_24_getCategoryChildValueListLocalSort
Method
(
self
):
def
test_24_getCategoryChildValueListLocalSort
(
self
):
'''Test getCategoryChildValueList local sort
method
'''
'''Test getCategoryChildValueList local sort'''
pc
=
self
.
getCategoriesTool
()
pc
=
self
.
getCategoriesTool
()
bc
=
pc
.
newContent
(
portal_type
=
'Base Category'
,
id
=
'child_test'
)
bc
=
pc
.
newContent
(
portal_type
=
'Base Category'
,
id
=
'child_test'
)
c1
=
bc
.
newContent
(
portal_type
=
'Category'
,
id
=
'1'
,
int_index
=
10
,
title
=
'C'
)
c1
=
bc
.
newContent
(
portal_type
=
'Category'
,
id
=
'1'
,
int_index
=
10
,
title
=
'C'
)
...
@@ -974,17 +975,52 @@ class TestCMFCategory(ERP5TypeTestCase):
...
@@ -974,17 +975,52 @@ class TestCMFCategory(ERP5TypeTestCase):
# sort_order which sort the whole list regardless of the original
# sort_order which sort the whole list regardless of the original
# structure).
# structure).
# This can be done either with a function (like cmp argument to python
sort_key_calls
=
[]
# list sort)
def
sort_key
(
c
):
sort_key_calls
.
append
(
c
)
return
c
.
getTitle
()
# here c1, c2, c3 are sorted by their titles
self
.
assertEqual
(
list
(
bc
.
getCategoryChildValueList
(
local_sort_key
=
sort_key
)),
[
c3
,
c2
,
c1
,
c11
,
c111
,
c12
])
self
.
assertTrue
(
sort_key_calls
)
# here c11 & c12 are sorted by their titles
self
.
assertEqual
(
list
(
c1
.
getCategoryChildValueList
(
local_sort_key
=
sort_key
)),
[
c11
,
c111
,
c12
])
self
.
assertTrue
(
sort_key_calls
)
# This can be done with a function, using `local_sort_key` or
# `local_sort_method` (with is like cmp argument to python2 list sort)
sort_func_calls
=
[]
def
sort_func
(
a
,
b
):
def
sort_func
(
a
,
b
):
sort_func_calls
.
append
((
a
,
b
))
return
cmp
(
a
.
getTitle
(),
b
.
getTitle
())
return
cmp
(
a
.
getTitle
(),
b
.
getTitle
())
# `local_sort_method` is deprecated, so using it cause a warning to be
# emitted. Because the method exists on both category and base category
# there can be two warnings.
with
warnings
.
catch_warnings
(
record
=
True
)
as
warning_list
:
c1
.
getCategoryChildValueList
(
local_sort_method
=
sort_func
)
self
.
assertEqual
(
[
str
(
w
.
message
)
for
w
in
warning_list
],
[
'`local_sort_method` argument is deprecated, use `local_sort_key` instead'
])
with
warnings
.
catch_warnings
(
record
=
True
)
as
warning_list
:
bc
.
getCategoryChildValueList
(
local_sort_method
=
sort_func
)
self
.
assertEqual
(
[
str
(
w
.
message
)
for
w
in
warning_list
],
[
'`local_sort_method` argument is deprecated, use `local_sort_key` instead'
]
*
2
)
sort_func_calls
.
clear
()
# here c1, c2, c3 are sorted by their titles
# here c1, c2, c3 are sorted by their titles
self
.
assertEqual
(
list
(
bc
.
getCategoryChildValueList
(
self
.
assertEqual
(
list
(
bc
.
getCategoryChildValueList
(
local_sort_method
=
sort_func
)),
local_sort_method
=
sort_func
)),
[
c3
,
c2
,
c1
,
c11
,
c111
,
c12
])
[
c3
,
c2
,
c1
,
c11
,
c111
,
c12
])
self
.
assertTrue
(
sort_func_calls
)
sort_func_calls
.
clear
()
# here c11 & c12 are sorted by their titles
# here c11 & c12 are sorted by their titles
self
.
assertEqual
(
list
(
c1
.
getCategoryChildValueList
(
self
.
assertEqual
(
list
(
c1
.
getCategoryChildValueList
(
local_sort_method
=
sort_func
)),
[
c11
,
c111
,
c12
])
local_sort_method
=
sort_func
)),
[
c11
,
c111
,
c12
])
self
.
assertTrue
(
sort_func_calls
)
# This can also be done with a local_sort_id, then objects are sorted by
# This can also be done with a local_sort_id, then objects are sorted by
# comparing this 'sort_id' property (using getProperty())
# comparing this 'sort_id' property (using getProperty())
...
...
product/ERP5Type/Utils.py
View file @
158eaf85
...
@@ -33,7 +33,7 @@ from six import string_types as basestring
...
@@ -33,7 +33,7 @@ from six import string_types as basestring
from
six.moves
import
xrange
from
six.moves
import
xrange
import
six
import
six
if
six
.
PY3
:
if
six
.
PY3
:
from
functools
import
cmp_to_key
from
functools
import
cmp_to_key
,
total_ordering
import
os
import
os
import
re
import
re
import
string
import
string
...
@@ -146,13 +146,21 @@ else:
...
@@ -146,13 +146,21 @@ else:
if
six
.
PY2
:
if
six
.
PY2
:
OrderableKey
=
lambda
x
:
x
OrderableKey
=
lambda
x
:
x
else
:
else
:
@
total_ordering
class
OrderableKey
(
object
):
class
OrderableKey
(
object
):
def
__init__
(
self
,
value
):
def
__init__
(
self
,
value
):
self
.
value
=
value
self
.
value
=
value
def
__lt__
(
self
,
other
):
def
__lt__
(
self
,
other
):
if
not
isinstance
(
other
,
OrderableKey
):
raise
TypeError
return
cmp
(
self
.
value
,
other
.
value
)
!=
1
return
cmp
(
self
.
value
,
other
.
value
)
!=
1
def
__eq__
(
self
,
other
):
if
not
isinstance
(
other
,
OrderableKey
):
raise
TypeError
return
self
.
value
==
other
.
value
def
__repr__
(
self
):
def
__repr__
(
self
):
return
'OrderableKey(%r)'
%
self
.
value
return
'OrderableKey(%r)'
%
self
.
value
...
...
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