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
141
Merge Requests
141
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
Jobs
Commits
Open sidebar
nexedi
erp5
Commits
d6c35741
Commit
d6c35741
authored
Jan 29, 2024
by
Jérome Perrin
Committed by
Arnaud Fontaine
Jul 05, 2024
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
wip py3 sort categories
parent
19f1be4a
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 @
d6c35741
...
...
@@ -28,6 +28,7 @@
from
past.builtins
import
cmp
import
string
import
warnings
from
Products.ERP5Type.Globals
import
InitializeClass
,
DTMLFile
from
AccessControl
import
ClassSecurityInfo
...
...
@@ -282,6 +283,7 @@ class Category(Folder):
def
getCategoryChildValueList
(
self
,
recursive
=
1
,
include_if_child
=
1
,
is_self_excluded
=
1
,
sort_on
=
None
,
sort_order
=
None
,
local_sort_method
=
None
,
local_sort_key
=
None
,
local_sort_id
=
None
,
checked_permission
=
None
,
**
kw
):
"""
...
...
@@ -305,8 +307,13 @@ class Category(Folder):
WARNING: using these parameters can slow down
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
this function to sort objects of the same depth.
DEPRECATED, use local_sort_key
local_sort_id - When using the default preorder traversal, sort
objects of the same depth by comparing their
...
...
@@ -325,24 +332,23 @@ class Category(Folder):
child_value_list
=
self
.
objectValues
(
self
.
allowed_types
)
if
local_sort_id
:
if
isinstance
(
local_sort_id
,
(
tuple
,
list
)):
def
sort_method
(
a
,
b
):
for
sort_id
in
local_sort_id
:
diff
=
cmp
(
a
.
getProperty
(
sort_id
,
0
),
b
.
getProperty
(
sort_id
,
0
))
if
diff
!=
0
:
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
not
isinstance
(
local_sort_id
,
(
tuple
,
list
)):
local_sort_id
=
(
local_sort_id
,
)
def
sort_key
(
c
):
return
[
c
.
getProperty
(
sort_id
,
0
)
for
sort_id
in
local_sort_id
]
local_sort_key
=
sort_key
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
)
if
six
.
PY2
:
child_value_list
.
sort
(
local_sort_method
)
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
:
for
c
in
child_value_list
:
# Do not pass sort_on / sort_order parameters intentionally, because
...
...
@@ -351,6 +357,7 @@ class Category(Folder):
is_self_excluded
=
0
,
include_if_child
=
include_if_child
,
local_sort_method
=
local_sort_method
,
local_sort_key
=
local_sort_key
,
local_sort_id
=
local_sort_id
))
else
:
for
c
in
child_value_list
:
...
...
@@ -838,7 +845,7 @@ class BaseCategory(Category):
'getCategoryChildValueList'
)
def
getCategoryChildValueList
(
self
,
is_self_excluded
=
1
,
recursive
=
1
,
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
):
"""
List the child objects of this category and all its subcategories.
...
...
@@ -860,8 +867,13 @@ class BaseCategory(Category):
the 'sort_on' attribute. The default is to do a preorder tree
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
this function to sort objects of the same depth.
DEPRECATED, use local_sort_key
local_sort_id - When using the default preorder traversal, sort
objects of the same depth by comparing their
...
...
@@ -879,32 +891,31 @@ class BaseCategory(Category):
child_value_list
=
self
.
objectValues
(
self
.
allowed_types
)
if
local_sort_id
:
if
isinstance
(
local_sort_id
,
(
tuple
,
list
)):
def
sort_method
(
a
,
b
):
for
sort_id
in
local_sort_id
:
diff
=
cmp
(
a
.
getProperty
(
sort_id
,
0
),
b
.
getProperty
(
sort_id
,
0
))
if
diff
!=
0
:
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
not
isinstance
(
local_sort_id
,
(
tuple
,
list
)):
local_sort_id
=
(
local_sort_id
,
)
def
sort_key
(
c
):
return
[
c
.
getProperty
(
sort_id
,
0
)
for
sort_id
in
local_sort_id
]
local_sort_key
=
sort_key
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
)
if
six
.
PY2
:
child_value_list
.
sort
(
local_sort_method
)
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
:
for
c
in
child_value_list
:
value_list
.
extend
(
c
.
getCategoryChildValueList
(
recursive
=
1
,
is_self_excluded
=
0
,
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
:
for
c
in
child_value_list
:
if
include_if_child
:
...
...
product/CMFCategory/Renderer.py
View file @
d6c35741
...
...
@@ -30,6 +30,9 @@
from
Products.CMFCategory.Filter
import
Filter
from
ZODB.POSException
import
ConflictError
from
zLOG
import
LOG
,
PROBLEM
import
six
if
six
.
PY3
:
from
functools
import
cmp_to_key
class
Renderer
(
Filter
):
"""
...
...
@@ -42,7 +45,7 @@ class Renderer(Filter):
def
__init__
(
self
,
spec
=
None
,
filter
=
None
,
portal_type
=
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_leave
=
0
,
disable_leave
=
0
,
is_right_display
=
0
,
translate_display
=
0
,
...
...
@@ -74,7 +77,10 @@ class Renderer(Filter):
foo2 5
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.
...
...
@@ -109,6 +115,7 @@ class Renderer(Filter):
self
.
display_id
=
display_id
self
.
sort_id
=
sort_id
self
.
display_method
=
display_method
self
.
sort_key
=
sort_key
self
.
sort_method
=
sort_method
self
.
is_right_display
=
is_right_display
self
.
translate_display
=
translate_display
...
...
@@ -135,7 +142,12 @@ class Renderer(Filter):
value_list
=
self
.
getObjectList
(
value_list
)
value_list
=
self
.
filter
(
value_list
)
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
:
value_list
.
sort
(
key
=
lambda
x
:
x
.
getProperty
(
self
.
sort_id
))
...
...
product/CMFCategory/tests/testCMFCategory.py
View file @
d6c35741
...
...
@@ -30,6 +30,7 @@
import
mock
from
collections
import
deque
import
unittest
import
warnings
from
Acquisition
import
aq_base
from
Products.ERP5Type.tests.ERP5TypeTestCase
import
ERP5TypeTestCase
...
...
@@ -952,8 +953,8 @@ class TestCMFCategory(ERP5TypeTestCase):
self
.
assertSameSet
(
c1
.
getCategoryChildValueList
(
is_self_excluded
=
0
),
(
c1
,
c11
,
c111
))
def
test_24_getCategoryChildValueListLocalSort
Method
(
self
):
'''Test getCategoryChildValueList local sort
method
'''
def
test_24_getCategoryChildValueListLocalSort
(
self
):
'''Test getCategoryChildValueList local sort'''
pc
=
self
.
getCategoriesTool
()
bc
=
pc
.
newContent
(
portal_type
=
'Base Category'
,
id
=
'child_test'
)
c1
=
bc
.
newContent
(
portal_type
=
'Category'
,
id
=
'1'
,
int_index
=
10
,
title
=
'C'
)
...
...
@@ -974,17 +975,52 @@ class TestCMFCategory(ERP5TypeTestCase):
# sort_order which sort the whole list regardless of the original
# structure).
# This can be done either with a function (like cmp argument to python
# list sort)
sort_key_calls
=
[]
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
):
sort_func_calls
.
append
((
a
,
b
))
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
self
.
assertEqual
(
list
(
bc
.
getCategoryChildValueList
(
local_sort_method
=
sort_func
)),
[
c3
,
c2
,
c1
,
c11
,
c111
,
c12
])
self
.
assertTrue
(
sort_func_calls
)
sort_func_calls
.
clear
()
# here c11 & c12 are sorted by their titles
self
.
assertEqual
(
list
(
c1
.
getCategoryChildValueList
(
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
# comparing this 'sort_id' property (using getProperty())
...
...
product/ERP5Type/Utils.py
View file @
d6c35741
...
...
@@ -33,7 +33,7 @@ from six import string_types as basestring
from
six.moves
import
xrange
import
six
if
six
.
PY3
:
from
functools
import
cmp_to_key
from
functools
import
cmp_to_key
,
total_ordering
import
os
import
re
import
string
...
...
@@ -146,13 +146,21 @@ else:
if
six
.
PY2
:
OrderableKey
=
lambda
x
:
x
else
:
@
total_ordering
class
OrderableKey
(
object
):
def
__init__
(
self
,
value
):
self
.
value
=
value
def
__lt__
(
self
,
other
):
if
not
isinstance
(
other
,
OrderableKey
):
raise
TypeError
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
):
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