Commit d692ad4d authored by Jérome Perrin's avatar Jérome Perrin

stack/erp5,software/erp5: support python3

This brings updates of many dependencies on python3, while mostly
keeping the same versions for python2.

This enables a new `erp5-py3` test in software/slapos-sr-testing, which
should pass already, but with NEO and WCFS being marked as expected
failure or skipped for now.

This also brings pylint support on python3, which we will be able to
reuse in software/slapos-testing.
Co-authored-by: Kazuhiko Shiozaki's avatarKazuhiko SHIOZAKI <kazuhiko@nexedi.com>
Co-authored-by: Arnaud Fontaine's avatarArnaud Fontaine <arnaud.fontaine@nexedi.com>
Co-authored-by: Bryton Lacquement's avatarBryton Lacquement <bryton.lacquement@nexedi.com>
parent 03dbf635
Pipeline #34630 failed with stage
in 0 seconds
......@@ -57,6 +57,12 @@ egg-versions =
[ZODB5]
<= _ZODB
egg-versions =
ZODB = 5.8.1
transaction = 4.0.0
[ZODB5:python2]
<= _ZODB
egg-versions =
ZODB = 5.8.1
transaction = 3.0.1
......@@ -94,11 +100,17 @@ setup-eggs = ${python-cffi:egg}
# eggs that are common to ZODB4 and ZODB5.
[versions]
BTrees = 4.11.3
persistent = 4.9.3
zodbpickle = 2.6.0
BTrees = 5.1.0
persistent = 5.1.0
zodbpickle = 3.1.0
# Provide ZODB3 for those eggs that still care about ZODB3 compatibility -
# for example wendelin.core. ZODB3 3.11 is just a dependency egg on _latest_
# ZODB, persistent, BTrees and ZEO.
ZODB3 = 3.11.0
[versions:python2]
BTrees = 4.11.3
persistent = 4.9.3
zodbpickle = 2.6.0
From 3666a7afd46ea6d069606450c520b8b7e2b5fddf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=A9rome=20Perrin?= <jerome@nexedi.com>
Date: Thu, 22 Feb 2024 23:33:41 +0900
Subject: [PATCH] Make dict views behave like their unrestricted versions
unlike the restricted versions, the unrestricted versions:
- are not iterators, they are views
- have a len
- are false when the mapping is empty, true otherwise
- are instances of collections.abc.MappingView
During this refactoring, also change `.items()` to validate
ach keys and values, like `.keys()` and `.values()` do.
---
CHANGES.rst | 7 ++++
src/AccessControl/ZopeGuards.py | 50 ++++++++++++++++++-----
src/AccessControl/tests/actual_python.py | 33 +++++++++++++++
src/AccessControl/tests/testZopeGuards.py | 34 +++++++++++----
4 files changed, 104 insertions(+), 20 deletions(-)
diff --git a/CHANGES.rst b/CHANGES.rst
index f35a8d2..073b791 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -8,6 +8,13 @@ For changes before version 3.0, see ``HISTORY.rst``.
- Nothing changed yet.
+- Make dict views (`.keys()`, `.items()` and `.values()`) behave like their
+ unrestricted versions.
+ (`#147 <https://github.com/zopefoundation/AccessControl/pull/147>`_)
+
+- Make `.items()` validate each keys and values, like `.keys()` and
+ `.values()` do.
+
6.3 (2023-11-20)
----------------
diff --git a/src/AccessControl/ZopeGuards.py b/src/AccessControl/ZopeGuards.py
index 84c2e9e..bc24941 100644
--- a/src/AccessControl/ZopeGuards.py
+++ b/src/AccessControl/ZopeGuards.py
@@ -12,6 +12,7 @@
##############################################################################
+import collections.abc
import math
import random
import string
@@ -127,13 +128,18 @@ def guarded_pop(key, default=_marker):
return guarded_pop
-def get_iter(c, name):
- iter = getattr(c, name)
+def get_mapping_view(c, name):
- def guarded_iter():
- return SafeIter(iter(), c)
+ view_class = {
+ 'keys': SafeKeysView,
+ 'items': SafeItemsView,
+ 'values': SafeValuesView,
+ }
- return guarded_iter
+ def guarded_mapping_view():
+ return view_class[name](c)
+
+ return guarded_mapping_view
def get_list_pop(lst, name):
@@ -153,18 +159,15 @@ def guarded_pop(index=-1):
'copy': 1,
'fromkeys': 1,
'get': get_dict_get,
- 'items': 1,
+ 'items': get_mapping_view,
+ 'keys': get_mapping_view,
'pop': get_dict_pop,
'popitem': 1,
'setdefault': 1,
'update': 1,
+ 'values': get_mapping_view,
}
-_dict_white_list.update({
- 'keys': get_iter,
- 'values': get_iter,
-})
-
def _check_dict_access(name, value):
# Check whether value is a dict method
@@ -262,6 +265,31 @@ def __next__(self):
next = __next__
+class _SafeMappingView:
+ __allow_access_to_unprotected_subobjects__ = 1
+
+ def __iter__(self):
+ for e in super().__iter__():
+ guard(self._mapping, e)
+ yield e
+
+
+class SafeKeysView(_SafeMappingView, collections.abc.KeysView):
+ pass
+
+
+class SafeValuesView(_SafeMappingView, collections.abc.ValuesView):
+ pass
+
+
+class SafeItemsView(_SafeMappingView, collections.abc.ItemsView):
+ def __iter__(self):
+ for k, v in super().__iter__():
+ guard(self._mapping, k)
+ guard(self._mapping, v)
+ yield k, v
+
+
class NullIter(SafeIter):
def __init__(self, ob):
self._iter = ob
diff --git a/src/AccessControl/tests/actual_python.py b/src/AccessControl/tests/actual_python.py
index 3405b8e..866a480 100644
--- a/src/AccessControl/tests/actual_python.py
+++ b/src/AccessControl/tests/actual_python.py
@@ -123,6 +123,39 @@ def f7():
access = getattr(d, meth)
result = sorted(access())
assert result == expected[kind], (meth, kind, result, expected[kind])
+ assert len(access()) == len(expected[kind]), (meth, kind, "len")
+ iter_ = access() # iterate twice on the same view
+ assert list(iter_) == list(iter_)
+
+ assert sorted([k for k in getattr(d, meth)()]) == expected[kind]
+ assert sorted(k for k in getattr(d, meth)()) == expected[kind]
+ assert {k: v for k, v in d.items()} == d
+
+ assert 1 in d
+ assert 1 in d.keys()
+ assert 2 in d.values()
+ assert (1, 2) in d.items()
+
+ assert d
+ assert d.keys()
+ assert d.values()
+ assert d.items()
+
+ empty_d = {}
+ assert not empty_d
+ assert not empty_d.keys()
+ assert not empty_d.values()
+ assert not empty_d.items()
+
+ smaller_d = {1: 2}
+ for m, _ in methods:
+ assert getattr(d, m)() != getattr(smaller_d, m)()
+ assert not getattr(d, m)() == getattr(smaller_d, m)()
+ if m != 'values':
+ assert getattr(d, m)() > getattr(smaller_d, m)()
+ assert getattr(d, m)() >= getattr(smaller_d, m)()
+ assert getattr(smaller_d, m)() < getattr(d, m)()
+ assert getattr(smaller_d, m)() <= getattr(d, m)()
f7()
diff --git a/src/AccessControl/tests/testZopeGuards.py b/src/AccessControl/tests/testZopeGuards.py
index 533bfa2..50eeca9 100644
--- a/src/AccessControl/tests/testZopeGuards.py
+++ b/src/AccessControl/tests/testZopeGuards.py
@@ -258,23 +258,40 @@ def test_pop_validates(self):
self.assertTrue(sm.calls)
def test_keys_empty(self):
- from AccessControl.ZopeGuards import get_iter
- keys = get_iter({}, 'keys')
+ from AccessControl.ZopeGuards import get_mapping_view
+ keys = get_mapping_view({}, 'keys')
self.assertEqual(list(keys()), [])
+ def test_kvi_len(self):
+ from AccessControl.ZopeGuards import get_mapping_view
+ for attr in ("keys", "values", "items"):
+ with self.subTest(attr):
+ view = get_mapping_view({'a': 1}, attr)
+ self.assertEqual(len(view()), 1)
+
def test_keys_validates(self):
sm = SecurityManager()
old = self.setSecurityManager(sm)
keys = guarded_getattr({GuardTestCase: 1}, 'keys')
try:
- next(keys())
+ next(iter(keys()))
finally:
self.setSecurityManager(old)
self.assertTrue(sm.calls)
+ def test_items_validates(self):
+ sm = SecurityManager()
+ old = self.setSecurityManager(sm)
+ items = guarded_getattr({GuardTestCase: GuardTestCase}, 'items')
+ try:
+ next(iter(items()))
+ finally:
+ self.setSecurityManager(old)
+ self.assertEqual(len(sm.calls), 2)
+
def test_values_empty(self):
- from AccessControl.ZopeGuards import get_iter
- values = get_iter({}, 'values')
+ from AccessControl.ZopeGuards import get_mapping_view
+ values = get_mapping_view({}, 'values')
self.assertEqual(list(values()), [])
def test_values_validates(self):
@@ -282,18 +299,17 @@ def test_values_validates(self):
old = self.setSecurityManager(sm)
values = guarded_getattr({GuardTestCase: 1}, 'values')
try:
- next(values())
+ next(iter(values()))
finally:
self.setSecurityManager(old)
self.assertTrue(sm.calls)
def test_kvi_iteration(self):
- from AccessControl.ZopeGuards import SafeIter
d = dict(a=1, b=2)
for attr in ("keys", "values", "items"):
v = getattr(d, attr)()
- si = SafeIter(v)
- self.assertEqual(next(si), next(iter(v)))
+ si = guarded_getattr(d, attr)()
+ self.assertEqual(next(iter(si)), next(iter(v)))
class TestListGuards(GuardTestCase):
From 77f86b50f097dcf364e0d140e45593bf001d46bc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=A9rome=20Perrin?= <jerome@nexedi.com>
Date: Fri, 1 Mar 2024 09:49:17 +0900
Subject: [PATCH] set metadata in setup.py for compatibility with old slapos
buildout
---
setup.py | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/setup.py b/setup.py
index 1bf0bcff5..a93fe7b22 100755
--- a/setup.py
+++ b/setup.py
@@ -987,6 +987,11 @@ ext_modules = [
try:
setup(
+ name='pillow',
+ version='10.2.0',
+ packages=["PIL"],
+ include_package_data=True,
+ package_dir={"": "src"},
cmdclass={"build_ext": pil_build_ext},
ext_modules=ext_modules,
zip_safe=not (debug_build() or PLATFORM_MINGW),
--
2.42.0
From 3c6b815bbb2a9300984a7b50cb5ec5375bf4588e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=A9rome=20Perrin?= <jerome@nexedi.com>
Date: Tue, 2 Apr 2024 21:54:07 +0900
Subject: [PATCH] Revive TRIGGER_WORKFLOW_METHOD support, ERP5 uses it
---
src/Products/DCWorkflow/DCWorkflow.py | 47 +++++++++++++++++++
src/Products/DCWorkflow/Transitions.py | 1 +
.../dtml/transition_properties.dtml | 10 ++++
src/Products/DCWorkflow/dtml/transitions.dtml | 3 +-
src/Products/DCWorkflow/exportimport.py | 2 +-
5 files changed, 61 insertions(+), 2 deletions(-)
diff --git a/src/Products/DCWorkflow/DCWorkflow.py b/src/Products/DCWorkflow/DCWorkflow.py
index 9adf05c..d0306dc 100644
--- a/src/Products/DCWorkflow/DCWorkflow.py
+++ b/src/Products/DCWorkflow/DCWorkflow.py
@@ -38,6 +38,7 @@ from .Expression import createExprContext
from .interfaces import IDCWorkflowDefinition
from .Transitions import TRIGGER_AUTOMATIC
from .Transitions import TRIGGER_USER_ACTION
+from .Transitions import TRIGGER_WORKFLOW_METHOD
from .utils import Message as _
from .utils import modifyRolesForGroup
from .utils import modifyRolesForPermission
@@ -278,6 +279,52 @@ class DCWorkflowDefinition(WorkflowUIMixin, Folder):
raise Unauthorized(action)
self._changeStateOf(ob, tdef, kw)
+ @security.private
+ def isWorkflowMethodSupported(self, ob, method_id):
+ '''
+ Returns a true value if the given workflow method
+ is supported in the current state.
+ '''
+ sdef = self._getWorkflowStateOf(ob)
+ if sdef is None:
+ return 0
+ if method_id in sdef.transitions:
+ tdef = self.transitions.get(method_id, None)
+ if (tdef is not None and
+ tdef.trigger_type == TRIGGER_WORKFLOW_METHOD and
+ self._checkTransitionGuard(tdef, ob)):
+ return 1
+ return 0
+
+ @security.private
+ def wrapWorkflowMethod(self, ob, method_id, func, args, kw):
+ '''
+ Allows the user to request a workflow action. This method
+ must perform its own security checks.
+ '''
+ sdef = self._getWorkflowStateOf(ob)
+ if sdef is None:
+ raise WorkflowException('Object is in an undefined state')
+ if method_id not in sdef.transitions:
+ raise Unauthorized(method_id)
+ tdef = self.transitions.get(method_id, None)
+ if tdef is None or tdef.trigger_type != TRIGGER_WORKFLOW_METHOD:
+ raise WorkflowException(
+ 'Transition %s is not triggered by a workflow method'
+ % method_id)
+ if not self._checkTransitionGuard(tdef, ob):
+ raise Unauthorized(method_id)
+ res = func(*args, **kw)
+ try:
+ self._changeStateOf(ob, tdef)
+ except ObjectDeleted:
+ # Re-raise with a different result.
+ raise ObjectDeleted(res)
+ except ObjectMoved as ex:
+ # Re-raise with a different result.
+ raise ObjectMoved(ex.getNewObject(), res)
+ return res
+
@security.private
def isInfoSupported(self, ob, name):
'''
diff --git a/src/Products/DCWorkflow/Transitions.py b/src/Products/DCWorkflow/Transitions.py
index a6e1e6f..b4e012c 100644
--- a/src/Products/DCWorkflow/Transitions.py
+++ b/src/Products/DCWorkflow/Transitions.py
@@ -31,6 +31,7 @@ from .utils import _dtmldir
TRIGGER_AUTOMATIC = 0
TRIGGER_USER_ACTION = 1
+TRIGGER_WORKFLOW_METHOD = 2
class TransitionDefinition(SimpleItem):
diff --git a/src/Products/DCWorkflow/dtml/transition_properties.dtml b/src/Products/DCWorkflow/dtml/transition_properties.dtml
index d6b8a74..6a0803e 100644
--- a/src/Products/DCWorkflow/dtml/transition_properties.dtml
+++ b/src/Products/DCWorkflow/dtml/transition_properties.dtml
@@ -55,6 +55,16 @@ Initiated by user action
</td>
</tr>
+<tr>
+<th></th>
+<td>
+<dtml-let checked="trigger_type==2 and 'checked' or ' '">
+<input type="radio" name="trigger_type" value="2" &dtml-checked; />
+Initiated by WorkflowMethod
+</dtml-let>
+</td>
+</tr>
+
<tr>
<th align="left">Script (before)</th>
<td>
diff --git a/src/Products/DCWorkflow/dtml/transitions.dtml b/src/Products/DCWorkflow/dtml/transitions.dtml
index 4cdd3d3..37e949c 100644
--- a/src/Products/DCWorkflow/dtml/transitions.dtml
+++ b/src/Products/DCWorkflow/dtml/transitions.dtml
@@ -17,7 +17,8 @@
<td>
Destination state: <code><dtml-if new_state_id>&dtml-new_state_id;<dtml-else>(Remain in state)</dtml-if></code> <br />
Trigger: <dtml-var expr="(trigger_type == 0 and 'Automatic') or
- (trigger_type == 1 and 'User action')">
+ (trigger_type == 1 and 'User action') or
+ (trigger_type == 2 and 'WorkflowMethod')">
<br />
<dtml-if script_name>
Script (before): &dtml-script_name;
diff --git a/src/Products/DCWorkflow/exportimport.py b/src/Products/DCWorkflow/exportimport.py
index f17264d..2374b6e 100644
--- a/src/Products/DCWorkflow/exportimport.py
+++ b/src/Products/DCWorkflow/exportimport.py
@@ -37,7 +37,7 @@ from .interfaces import IDCWorkflowDefinition
from .utils import _xmldir
-TRIGGER_TYPES = ('AUTOMATIC', 'USER')
+TRIGGER_TYPES = ('AUTOMATIC', 'USER', 'METHOD' )
_FILENAME = 'workflows.xml'
--
2.42.0
From 21a91db138cca3ada0e4dff475b061066362410c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=A9rome=20Perrin?= <jerome@nexedi.com>
Date: Sat, 17 Feb 2024 23:25:43 +0900
Subject: [PATCH] backport changes from 0.52.29
We can not use 0.52.29 directly because it does not have a setup.py
and our buildout / setuptools tooling is too old.
---
src/SOAPpy/Client.py | 3 ++-
src/SOAPpy/Types.py | 2 ++
2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/src/SOAPpy/Client.py b/src/SOAPpy/Client.py
index e86c5ec..d2bbefb 100644
--- a/src/SOAPpy/Client.py
+++ b/src/SOAPpy/Client.py
@@ -45,6 +45,7 @@
ident = '$Id: Client.py 1496 2010-03-04 23:46:17Z pooryorick $'
from .version import __version__
+from io import StringIO
#import xml.sax
import urllib.request, urllib.parse, urllib.error
@@ -152,7 +153,7 @@ class HTTP:
return -1, e.line, None
self.headers = response.msg
- self.file = response.fp
+ self.file = StringIO(response.fp.read().decode('utf-8'))
return response.status, response.reason, response.msg
def close(self):
diff --git a/src/SOAPpy/Types.py b/src/SOAPpy/Types.py
index de9dcac..cf08d17 100644
--- a/src/SOAPpy/Types.py
+++ b/src/SOAPpy/Types.py
@@ -1451,6 +1451,8 @@ class arrayType(collections.UserList, compoundType):
def __getitem__(self, item):
try:
return self.data[int(item)]
+ except TypeError:
+ return self.data[item]
except ValueError:
return getattr(self, item)
--
2.42.0
From c8c52a14d481403f1db252631d3cc4b8e86e1798 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=A9rome=20Perrin?= <perrinjerome@gmail.com>
Date: Sat, 17 Feb 2024 05:32:46 +0000
Subject: [PATCH] Fix authentication error viewing ZMI with a user defined
outside of zope root.
Fixes https://github.com/zopefoundation/Zope/issues/1195
5.9 (2023-11-24)
----------------
diff --git a/src/App/dtml/manage_page_header.dtml b/src/App/dtml/manage_page_header.dtml
index 2dcb047552..e8b8659e10 100644
--- a/src/App/dtml/manage_page_header.dtml
+++ b/src/App/dtml/manage_page_header.dtml
@@ -10,24 +10,27 @@
</dtml-let>
<title><dtml-if title_or_id><dtml-var title_or_id><dtml-else>Zope</dtml-if></title>
+<dtml-let basepath="'/'.join([''] + [p for p in (REQUEST['BASEPATH1'], REQUEST.get('AUTHENTICATION_PATH')) if p])">
+
<dtml-in css_urls>
- <link rel="stylesheet" type="text/css" href="&dtml-BASEPATH1;&dtml-sequence-item;" />
+ <link rel="stylesheet" type="text/css" href="&dtml-basepath;&dtml-sequence-item;" />
</dtml-in>
<dtml-in js_urls>
- <script src="&dtml-BASEPATH1;&dtml-sequence-item;"></script>
+ <script src="&dtml-basepath;&dtml-sequence-item;"></script>
</dtml-in>
-<link rel="shortcut icon" type="image/x-icon" href="&dtml-BASEPATH1;/++resource++zmi/logo/favicon/favicon.ico" />
-<link rel="apple-touch-icon" sizes="180x180" href="&dtml-BASEPATH1;/++resource++zmi/logo/favicon/apple-touch-icon.png" />
-<link rel="icon" type="image/png" sizes="32x32" href="&dtml-BASEPATH1;/++resource++zmi/logo/favicon/favicon-32x32.png" />
-<link rel="icon" type="image/png" sizes="16x16" href="&dtml-BASEPATH1;/++resource++zmi/logo/favicon/favicon-16x16.png" />
-<link rel="manifest" href="&dtml-BASEPATH1;/++resource++zmi/logo/favicon/site.webmanifest" />
-<link rel="mask-icon" href="&dtml-BASEPATH1;/++resource++zmi/logo/favicon/safari-pinned-tab.svg" color="#5bbad5" />
-<meta name="msapplication-config" content="&dtml-BASEPATH1;/++resource++zmi/logo/favicon/browserconfig.xml"/>
+<link rel="shortcut icon" type="image/x-icon" href="&dtml-basepath;/++resource++zmi/logo/favicon/favicon.ico" />
+<link rel="apple-touch-icon" sizes="180x180" href="&dtml-basepath;/++resource++zmi/logo/favicon/apple-touch-icon.png" />
+<link rel="icon" type="image/png" sizes="32x32" href="&dtml-basepath;/++resource++zmi/logo/favicon/favicon-32x32.png" />
+<link rel="icon" type="image/png" sizes="16x16" href="&dtml-basepath;/++resource++zmi/logo/favicon/favicon-16x16.png" />
+<link rel="manifest" href="&dtml-basepath;/++resource++zmi/logo/favicon/site.webmanifest" />
+<link rel="mask-icon" href="&dtml-basepath;/++resource++zmi/logo/favicon/safari-pinned-tab.svg" color="#5bbad5" />
+<meta name="msapplication-config" content="&dtml-basepath;/++resource++zmi/logo/favicon/browserconfig.xml"/>
<meta name="msapplication-TileColor" content="#2d89ef" />
<meta name="theme-color" content="#ffffff" />
</head>
+</dtml-let>
<!-- REFACT what is a better way to get the last part of the current URL? -->
<body id="nodeid-<dtml-var "getId()">" class="zmi zmi-<dtml-var "this().meta_type.replace(' ', '-').replace('(', '').replace(')', '')"> zmi-<dtml-var "URL0[_.len(URL1)+1:]">">
</dtml-unless>
diff --git a/src/zmi/styles/tests.py b/src/zmi/styles/tests.py
index 256edfa74b..36c7b65bec 100644
--- a/src/zmi/styles/tests.py
+++ b/src/zmi/styles/tests.py
@@ -21,6 +21,8 @@ def setupZCML():
class SubscriberTests(Testing.ZopeTestCase.FunctionalTestCase):
"""Testing .subscriber.*"""
+ base_path = f'/{Testing.ZopeTestCase.folder_name}'
+
def call_manage_main(self):
"""Call /folder/manage_main and return the HTML text."""
def _call_manage_main(self):
@@ -29,7 +31,7 @@ def _call_manage_main(self):
# which the WSGI publisher does not expect.
endInteraction()
response = self.publish(
- f'/{Testing.ZopeTestCase.folder_name}/manage_main',
+ f'{self.base_path}/manage_main',
basic=basic_auth)
return str(response)
return temporaryPlacelessSetUp(
@@ -40,11 +42,11 @@ def test_subscriber__css_paths__1(self):
from .subscriber import css_paths
body = self.call_manage_main()
for path in css_paths(None):
- self.assertIn(path, body)
+ self.assertIn(f'href="{self.base_path}{path}"', body)
def test_subscriber__js_paths__1(self):
"""The paths it returns are rendered in the ZMI."""
from .subscriber import js_paths
body = self.call_manage_main()
for path in js_paths(None):
- self.assertIn(path, body)
+ self.assertIn(f'src="{self.base_path}{path}"', body)
From 7f4c61c0d7fe0751be93e80683659271fa0c65a3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=A9rome=20Perrin?= <perrinjerome@gmail.com>
Date: Sat, 17 Feb 2024 13:06:28 +0000
Subject: [PATCH] Fix Content-Disposition heeader for clients without rfc6266
support.
Since https://github.com/zopefoundation/Zope/pull/893 the
Content-Disposition header supports non-ascii filenames, by containing
the filename in ascii and the filename in UTF-8, but the ascii version
was produced by applying `str` on a `bytes` instance, so it looks like
`b'file.txt'` instead of `file.txt`.
---
CHANGES.rst | 3 +++
src/ZPublisher/HTTPResponse.py | 3 ++-
src/ZPublisher/tests/testHTTPResponse.py | 4 ++--
3 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/CHANGES.rst b/CHANGES.rst
index e8dedc6a66..30061e2093 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -18,6 +18,9 @@ https://github.com/zopefoundation/Zope/blob/4.x/CHANGES.rst
- Fix redirections to URLs with host given as IP-literal with brackets.
Fixes `#1191 <https://github.com/zopefoundation/Zope/issues/1191>`_.
+- Fix ``Content-Disposition`` filename for clients without rfc6266 support.
+ (`#1198 <https://github.com/zopefoundation/Zope/pull/1198>`_)
+
5.9 (2023-11-24)
----------------
diff --git a/src/ZPublisher/HTTPResponse.py b/src/ZPublisher/HTTPResponse.py
index ed6bc00a89..264a488a03 100644
--- a/src/ZPublisher/HTTPResponse.py
+++ b/src/ZPublisher/HTTPResponse.py
@@ -142,7 +142,8 @@ def make_content_disposition(disposition, file_name):
#
# a special header has to be crafted
# also see https://tools.ietf.org/html/rfc6266#appendix-D
- encoded_file_name = file_name.encode('us-ascii', errors='ignore')
+ encoded_file_name = file_name.encode(
+ 'us-ascii', errors='ignore').decode()
header += f'; filename="{encoded_file_name}"'
quoted_file_name = quote(file_name)
header += f'; filename*=UTF-8\'\'{quoted_file_name}'
diff --git a/src/ZPublisher/tests/testHTTPResponse.py b/src/ZPublisher/tests/testHTTPResponse.py
index 1613b0ea59..5d64b5b3dd 100644
--- a/src/ZPublisher/tests/testHTTPResponse.py
+++ b/src/ZPublisher/tests/testHTTPResponse.py
@@ -1433,7 +1433,7 @@ def test_ascii(self):
def test_latin_one(self):
self.assertEqual(
make_content_disposition('inline', 'Dänemark.png'),
- 'inline; filename="b\'Dnemark.png\'"; filename*=UTF-8\'\'D%C3%A4nemark.png' # noqa: E501
+ 'inline; filename="Dnemark.png"; filename*=UTF-8\'\'D%C3%A4nemark.png' # noqa: E501
)
def test_unicode(self):
@@ -1445,7 +1445,7 @@ def test_unicode(self):
"""
self.assertEqual(
make_content_disposition('inline', 'ıq.png'),
- 'inline; filename="b\'q.png\'"; filename*=UTF-8\'\'%C4%B1q.png'
+ 'inline; filename="q.png"; filename*=UTF-8\'\'%C4%B1q.png'
)
From c56146829ab065183c709229a9daa682cc445212 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=A9rome=20Perrin?= <jerome@nexedi.com>
Date: Fri, 26 Apr 2024 15:09:39 +0900
Subject: [PATCH] fix loading font for ean13
use same technique as for code128
---
hubarcode/ean13/renderer.py | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/hubarcode/ean13/renderer.py b/hubarcode/ean13/renderer.py
index 654501e..ff5f518 100644
--- a/hubarcode/ean13/renderer.py
+++ b/hubarcode/ean13/renderer.py
@@ -78,8 +78,10 @@ class EAN13Renderer:
# Draw the text
font_size = font_sizes.get(bar_width, 24)
- # Use relative name, PIL will do searching for us
- fontfile = os.path.join("fonts", "courR%02d.pil" % font_size)
+ # Locate and load the font file relative to the module
+ ean13dir, _ = os.path.split(__file__)
+ rootdir, _ = os.path.split(ean13dir)
+ fontfile = os.path.join(rootdir, "fonts", "courR%02d.pil" % font_size)
font = ImageFont.load_path(fontfile)
draw = ImageDraw.Draw(img)
--
2.42.0
From 42fab4bbede61a384046646dbc2573bb79957a89 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=A9rome=20Perrin?= <jerome@nexedi.com>
Date: Sat, 17 Feb 2024 16:07:18 +0900
Subject: [PATCH] python3 support
---
interval.py | 366 ++++++++++++++++++++++++++++------------------------
1 file changed, 194 insertions(+), 172 deletions(-)
diff --git a/interval.py b/interval.py
index fe9e595..8a4b2be 100644
--- a/interval.py
+++ b/interval.py
@@ -36,15 +36,18 @@ False
>>> "15:30" in myHours
True
>>> inOffice = officeHours & myHours
->>> print inOffice
+>>> print(inOffice)
['08:30'..'11:30'),('12:30'..'17:00']
>>> overtime = myHours - officeHours
->>> print overtime
+>>> print(overtime)
('17:00'..'19:30']
"""
import copy
+import functools
+
+@functools.total_ordering
class Smallest:
"""Represents the smallest value
@@ -70,11 +73,17 @@ class Smallest:
The opposite of negative infinity is infinity, the largest value.
- >>> print -Smallest()
+ >>> print(-Smallest())
~
"""
return Largest()
+ def __eq__(self, other):
+ return isinstance(other, self.__class__)
+
+ def __gt__(self, other):
+ return False
+
def __cmp__(self, other):
"""Compares this with another object
@@ -103,7 +112,7 @@ class Smallest:
The string for the smallest number is -~, which means negative infinity.
- >>> print Smallest()
+ >>> print(Smallest())
-~
"""
return "-~"
@@ -124,6 +133,7 @@ class Smallest:
return 0x55555555
+@functools.total_ordering
class Largest:
"""Class representing the universal largest value
@@ -149,11 +159,17 @@ class Largest:
The opposite of infinity is negative infinity, the smallest value.
- >>> print -Largest()
+ >>> print(-Largest())
-~
"""
return Smallest()
+ def __eq__(self, other):
+ return isinstance(other, self.__class__)
+
+ def __ge__(self, other):
+ return True
+
def __cmp__(self, other):
"""Compares object with another object
@@ -182,7 +198,7 @@ class Largest:
The largest number is displayed as ~ (it sort of looks like infinity...)
- >>> print Largest()
+ >>> print(Largest())
~
"""
return "~"
@@ -203,6 +219,8 @@ class Largest:
Inf = Largest()
# Use -Inf for the smallest value
+
+@functools.total_ordering
class Interval:
"""Represents a continuous range of values
@@ -255,7 +273,7 @@ class Interval:
Intervals that are not normalized, i.e. that have a lower bound
exceeding an upper bound, are silently normalized.
- >>> print Interval(5, 2, lower_closed=False)
+ >>> print(Interval(5, 2, lower_closed=False))
[2..5)
Intervals can represent an empty set.
@@ -343,27 +361,27 @@ class Interval:
consisting of only a single value are shown as that value. Empty
intervals are shown as the string <Empty>
- >>> print Interval.all()
+ >>> print(Interval.all())
(...)
- >>> print Interval.less_than(100)
+ >>> print(Interval.less_than(100))
(...100)
- >>> print Interval.less_than_or_equal_to(2593)
+ >>> print(Interval.less_than_or_equal_to(2593))
(...2593]
- >>> print Interval.greater_than(2378)
+ >>> print(Interval.greater_than(2378))
(2378...)
- >>> print Interval.between(26, 8234, False)
+ >>> print(Interval.between(26, 8234, False))
(26..8234)
- >>> print Interval(237, 2348, lower_closed=False)
+ >>> print(Interval(237, 2348, lower_closed=False))
(237..2348]
- >>> print Interval.greater_than_or_equal_to(347)
+ >>> print(Interval.greater_than_or_equal_to(347))
[347...)
- >>> print Interval(237, 278, upper_closed=False)
+ >>> print(Interval(237, 278, upper_closed=False))
[237..278)
- >>> print Interval.between(723, 2378)
+ >>> print(Interval.between(723, 2378))
[723..2378]
- >>> print Interval.equal_to(5)
+ >>> print(Interval.equal_to(5))
5
- >>> print Interval.none()
+ >>> print(Interval.none())
<Empty>
"""
if self.lower_bound == self.upper_bound:
@@ -399,20 +417,22 @@ class Interval:
retval = "".join([lbchar, lstr, between, ustr, ubchar])
return retval
- def __nonzero__(self):
+ def __bool__(self):
"""Tells whether the interval is empty
-
>>> if Interval(12, 12, closed=False):
- ... print "Non-empty"
+ ... print("Non-empty")
>>> if Interval(12, 12, upper_closed=False):
- ... print "Non-empty"
+ ... print("Non-empty")
>>> if Interval(12, 12):
- ... print "Non-empty"
+ ... print("Non-empty")
Non-empty
"""
return self.lower_bound != self.upper_bound \
or (self.upper_closed and self.lower_closed)
+ def __lt__(self, other):
+ return self.comes_before(other)
+
def __cmp__(self, other):
"""Compares two intervals for ordering purposes
@@ -442,15 +462,15 @@ class Interval:
def __and__(self, other):
"""Returns the intersection of two intervals
- >>> print Interval.greater_than(3) & Interval.greater_than(5)
+ >>> print(Interval.greater_than(3) & Interval.greater_than(5))
(5...)
- >>> print Interval.greater_than(3) & Interval.equal_to(3)
+ >>> print(Interval.greater_than(3) & Interval.equal_to(3))
<Empty>
- >>> print Interval.greater_than_or_equal_to(3) & Interval.equal_to(3)
+ >>> print(Interval.greater_than_or_equal_to(3) & Interval.equal_to(3))
3
- >>> print Interval.all() & Interval.all()
+ >>> print(Interval.all() & Interval.all())
(...)
- >>> print Interval.greater_than(3) & Interval.less_than(10)
+ >>> print(Interval.greater_than(3) & Interval.less_than(10))
(3..10)
"""
if self == other:
@@ -494,7 +514,7 @@ class Interval:
def none(cls):
"""Returns an empty interval
- >>> print Interval.none()
+ >>> print(Interval.none())
<Empty>
"""
return cls(0, 0, closed=False)
@@ -503,7 +523,7 @@ class Interval:
def all(cls):
"""Returns an interval encompassing all values
- >>> print Interval.all()
+ >>> print(Interval.all())
(...)
"""
return cls()
@@ -516,9 +536,9 @@ class Interval:
then the endpoints are included. Otherwise, the endpoints are
excluded.
- >>> print Interval.between(2, 4)
+ >>> print(Interval.between(2, 4))
[2..4]
- >>> print Interval.between(2, 4, False)
+ >>> print(Interval.between(2, 4, False))
(2..4)
"""
return cls(a, b, closed=closed)
@@ -529,7 +549,7 @@ class Interval:
Returns an interval containing only a.
- >>> print Interval.equal_to(32)
+ >>> print(Interval.equal_to(32))
32
"""
return cls(a, a)
@@ -541,7 +561,7 @@ class Interval:
Returns an interval containing all values less than a. If closed
is True, then all values less than or equal to a are returned.
- >>> print Interval.less_than(32)
+ >>> print(Interval.less_than(32))
(...32)
"""
return cls(upper_bound=a, upper_closed=False)
@@ -550,7 +570,7 @@ class Interval:
def less_than_or_equal_to(cls, a):
"""Returns an interval containing the given values and everything less
- >>> print Interval.less_than_or_equal_to(32)
+ >>> print(Interval.less_than_or_equal_to(32))
(...32]
"""
return cls(upper_bound=a, upper_closed=True)
@@ -559,7 +579,7 @@ class Interval:
def greater_than(cls, a):
"""Returns interval of all values greater than the given value
- >>> print Interval.greater_than(32)
+ >>> print(Interval.greater_than(32))
(32...)
"""
return cls(lower_bound=a, lower_closed=False)
@@ -568,7 +588,7 @@ class Interval:
def greater_than_or_equal_to(cls, a):
"""Returns interval of all values greater than or equal to the given value
- >>> print Interval.greater_than_or_equal_to(32)
+ >>> print(Interval.greater_than_or_equal_to(32))
[32...)
"""
return cls(lower_bound=a, lower_closed=True)
@@ -637,29 +657,29 @@ class Interval:
>>> r13 = Interval.greater_than(100)
>>> r14 = Interval.equal_to(100)
>>> r15 = Interval.greater_than_or_equal_to(100)
- >>> print r13.join(r15)
+ >>> print(r13.join(r15))
[100...)
- >>> print r7.join(r6)
+ >>> print(r7.join(r6))
(-100..100]
- >>> print r11.join(r2)
+ >>> print(r11.join(r2))
(...100]
- >>> print r4.join(r15)
+ >>> print(r4.join(r15))
(...)
- >>> print r8.join(r8)
+ >>> print(r8.join(r8))
(-100...)
- >>> print r3.join(r7)
+ >>> print(r3.join(r7))
(...100]
- >>> print r5.join(r10)
+ >>> print(r5.join(r10))
(...)
- >>> print r9.join(r1)
+ >>> print(r9.join(r1))
(...-100]
- >>> print r12.join(r5)
+ >>> print(r12.join(r5))
(...)
- >>> print r13.join(r1)
+ >>> print(r13.join(r1))
Traceback (most recent call last):
...
ArithmeticError: The Intervals are disjoint.
- >>> print r14.join(r2)
+ >>> print(r14.join(r2))
Traceback (most recent call last):
...
ArithmeticError: The Intervals are disjoint.
@@ -894,27 +914,27 @@ class BaseIntervalSet(object):
If no parameters are provided, then an empty IntervalSet is
constructed.
- >>> print IntervalSet() # An empty set
+ >>> print(IntervalSet()) # An empty set
<Empty>
Interval objects arguments are added directly to the IntervalSet.
- >>> print IntervalSet([Interval(4, 6, lower_closed=False)])
+ >>> print(IntervalSet([Interval(4, 6, lower_closed=False)]))
(4..6]
- >>> print IntervalSet([Interval.less_than_or_equal_to(2)])
+ >>> print(IntervalSet([Interval.less_than_or_equal_to(2)]))
(...2]
Each non-Interval value of an iterator is added as a discrete
value.
- >>> print IntervalSet(set([3, 7, 2, 1]))
+ >>> print(IntervalSet(set([3, 7, 2, 1])))
1,2,3,7
- >>> print IntervalSet(["Bob", "Fred", "Mary"])
+ >>> print(IntervalSet(["Bob", "Fred", "Mary"]))
'Bob','Fred','Mary'
- >>> print IntervalSet(range(10))
+ >>> print(IntervalSet(range(10)))
0,1,2,3,4,5,6,7,8,9
- >>> print IntervalSet(
- ... Interval.between(l, u) for l, u in [(10, 20), (30, 40)])
+ >>> print(IntervalSet(
+ ... Interval.between(l, u) for l, u in [(10, 20), (30, 40)]))
[10..20],[30..40]
"""
self.intervals = []
@@ -935,9 +955,9 @@ class BaseIntervalSet(object):
1
>>> nonempty = IntervalSet([3])
>>> if IntervalSet.empty():
- ... print "Non-empty"
+ ... print("Non-empty")
>>> if nonempty:
- ... print "Non-empty"
+ ... print("Non-empty")
Non-empty
"""
return len(self.intervals)
@@ -948,17 +968,17 @@ class BaseIntervalSet(object):
This function shows a string representation of an IntervalSet.
The string is shown sorted, with all intervals normalized.
- >>> print IntervalSet()
+ >>> print(IntervalSet())
<Empty>
- >>> print IntervalSet([62])
+ >>> print(IntervalSet([62]))
62
- >>> print IntervalSet([62, 56])
+ >>> print(IntervalSet([62, 56]))
56,62
- >>> print IntervalSet([23, Interval(26, 32, upper_closed=False)])
+ >>> print(IntervalSet([23, Interval(26, 32, upper_closed=False)]))
23,[26..32)
- >>> print IntervalSet.less_than(3) + IntervalSet.greater_than(3)
+ >>> print(IntervalSet.less_than(3) + IntervalSet.greater_than(3))
(...3),(3...)
- >>> print IntervalSet([Interval.less_than_or_equal_to(6)])
+ >>> print(IntervalSet([Interval.less_than_or_equal_to(6)]))
(...6]
"""
if len(self.intervals) == 0:
@@ -987,20 +1007,20 @@ class BaseIntervalSet(object):
...
IndexError: Index is out of range
>>> interval = IntervalSet.greater_than(5)
- >>> print interval[0]
+ >>> print(interval[0])
(5...)
- >>> print interval[1]
+ >>> print(interval[1])
Traceback (most recent call last):
...
IndexError: Index is out of range
- >>> print interval[-1]
+ >>> print(interval[-1])
(5...)
>>> interval = IntervalSet([3, 6])
- >>> print interval[1]
+ >>> print(interval[1])
6
- >>> print interval[0]
+ >>> print(interval[0])
3
- >>> print interval[2]
+ >>> print(interval[2])
Traceback (most recent call last):
...
IndexError: Index is out of range
@@ -1018,14 +1038,14 @@ class BaseIntervalSet(object):
that with the left-most lower bound to that with the right-most.
>>> for i in IntervalSet():
- ... print i
+ ... print(i)
...
>>> for i in IntervalSet.between(3, 5):
- ... print i
+ ... print(i)
...
[3..5]
>>> for i in IntervalSet([2, 5, 3]):
- ... print i
+ ... print(i)
...
2
3
@@ -1104,11 +1124,11 @@ class BaseIntervalSet(object):
def bounds(self):
"""Returns an interval that encompasses the entire BaseIntervalSet
- >>> print IntervalSet([Interval.between(4, 6), 2, 12]).bounds()
+ >>> print(IntervalSet([Interval.between(4, 6), 2, 12]).bounds())
[2..12]
- >>> print IntervalSet().bounds()
+ >>> print(IntervalSet().bounds())
<Empty>
- >>> print IntervalSet.all().bounds()
+ >>> print(IntervalSet.all().bounds())
(...)
"""
if len(self.intervals) == 0:
@@ -1240,7 +1260,7 @@ class BaseIntervalSet(object):
>>> for i in s:
... l.add(str(i))
...
- >>> print len(l)
+ >>> print(len(l))
6
>>> "2" in l
True
@@ -1284,15 +1304,15 @@ class BaseIntervalSet(object):
>>> zero = IntervalSet([0])
>>> nonzero = IntervalSet.not_equal_to(0)
>>> empty = IntervalSet.empty()
- >>> print evens + positives
+ >>> print(evens + positives)
-8,-6,-4,-2,[0...)
- >>> print negatives + zero
+ >>> print(negatives + zero)
(...0]
- >>> print empty + negatives
+ >>> print(empty + negatives)
(...0)
- >>> print empty + naturals
+ >>> print(empty + naturals)
[0...)
- >>> print nonzero + evens
+ >>> print(nonzero + evens)
(...)
"""
return self.__or__(other)
@@ -1309,17 +1329,17 @@ class BaseIntervalSet(object):
>>> nonzero = IntervalSet.not_equal_to(0)
>>> empty = IntervalSet.empty()
>>> all = IntervalSet.all()
- >>> print evens - nonzero
+ >>> print(evens - nonzero)
0
- >>> print empty - naturals
+ >>> print(empty - naturals)
<Empty>
- >>> print zero - naturals
+ >>> print(zero - naturals)
<Empty>
- >>> print positives - zero
+ >>> print(positives - zero)
(0...)
- >>> print naturals - negatives
+ >>> print(naturals - negatives)
[0...)
- >>> print all - zero
+ >>> print(all - zero)
(...0),(0...)
>>> all - zero == nonzero
True
@@ -1380,17 +1400,17 @@ class BaseIntervalSet(object):
>>> nonzero = IntervalSet.not_equal_to(0)
>>> empty = IntervalSet.empty()
>>> all = IntervalSet.all()
- >>> print evens.difference(nonzero)
+ >>> print(evens.difference(nonzero))
0
- >>> print empty.difference(naturals)
+ >>> print(empty.difference(naturals))
<Empty>
- >>> print zero.difference(naturals)
+ >>> print(zero.difference(naturals))
<Empty>
- >>> print positives.difference(zero)
+ >>> print(positives.difference(zero))
(0...)
- >>> print naturals.difference(negatives)
+ >>> print(naturals.difference(negatives))
[0...)
- >>> print all.difference(zero)
+ >>> print(all.difference(zero))
(...0),(0...)
>>> all.difference(zero) == nonzero
True
@@ -1413,15 +1433,15 @@ class BaseIntervalSet(object):
>>> zero = IntervalSet([0])
>>> nonzero = IntervalSet.not_equal_to(0)
>>> empty = IntervalSet.empty()
- >>> print naturals and naturals
+ >>> print(naturals and naturals)
[0...)
- >>> print evens & zero
+ >>> print(evens & zero)
0
- >>> print negatives & zero
+ >>> print(negatives & zero)
<Empty>
- >>> print nonzero & positives
+ >>> print(nonzero & positives)
(0...)
- >>> print empty & zero
+ >>> print(empty & zero)
<Empty>
>>> positives & [0]
Traceback (most recent call last):
@@ -1469,15 +1489,15 @@ class BaseIntervalSet(object):
>>> zero = IntervalSet([0])
>>> nonzero = IntervalSet.not_equal_to(0)
>>> empty = IntervalSet.empty()
- >>> print naturals.intersection(naturals)
+ >>> print(naturals.intersection(naturals))
[0...)
- >>> print evens.intersection(zero)
+ >>> print(evens.intersection(zero))
0
- >>> print negatives.intersection(zero)
+ >>> print(negatives.intersection(zero))
<Empty>
- >>> print nonzero.intersection(positives)
+ >>> print(nonzero.intersection(positives))
(0...)
- >>> print empty.intersection(zero)
+ >>> print(empty.intersection(zero))
<Empty>
"""
if isinstance(other, BaseIntervalSet):
@@ -1497,17 +1517,17 @@ class BaseIntervalSet(object):
>>> nonzero = IntervalSet.not_equal_to(0)
>>> empty = IntervalSet.empty()
>>> all = IntervalSet.all()
- >>> print evens | positives
+ >>> print(evens | positives)
-8,-6,-4,-2,[0...)
- >>> print negatives | zero
+ >>> print(negatives | zero)
(...0]
- >>> print empty | negatives
+ >>> print(empty | negatives)
(...0)
- >>> print empty | naturals
+ >>> print(empty | naturals)
[0...)
- >>> print nonzero | evens
+ >>> print(nonzero | evens)
(...)
- >>> print negatives | range(5)
+ >>> print(negatives | range(5))
Traceback (most recent call last):
...
TypeError: unsupported operand type(s) for |: expected BaseIntervalSet
@@ -1537,17 +1557,17 @@ class BaseIntervalSet(object):
>>> nonzero = IntervalSet.not_equal_to(0)
>>> empty = IntervalSet.empty()
>>> all = IntervalSet.all()
- >>> print evens.union(positives)
+ >>> print(evens.union(positives))
-8,-6,-4,-2,[0...)
- >>> print negatives.union(zero)
+ >>> print(negatives.union(zero))
(...0]
- >>> print empty.union(negatives)
+ >>> print(empty.union(negatives))
(...0)
- >>> print empty.union(naturals)
+ >>> print(empty.union(naturals))
[0...)
- >>> print nonzero.union(evens)
+ >>> print(nonzero.union(evens))
(...)
- >>> print negatives.union(range(5))
+ >>> print(negatives.union(range(5)))
(...0],1,2,3,4
"""
if isinstance(other, BaseIntervalSet):
@@ -1566,13 +1586,13 @@ class BaseIntervalSet(object):
>>> zero = IntervalSet([0])
>>> nonzero = IntervalSet.not_equal_to(0)
>>> empty = IntervalSet.empty()
- >>> print nonzero ^ naturals
+ >>> print(nonzero ^ naturals)
(...0]
- >>> print zero ^ negatives
+ >>> print(zero ^ negatives)
(...0]
- >>> print positives ^ empty
+ >>> print(positives ^ empty)
(0...)
- >>> print evens ^ zero
+ >>> print(evens ^ zero)
-8,-6,-4,-2,2,4,6,8
>>> negatives ^ [0]
Traceback (most recent call last):
@@ -1599,15 +1619,15 @@ class BaseIntervalSet(object):
>>> zero = IntervalSet([0])
>>> nonzero = IntervalSet.not_equal_to(0)
>>> empty = IntervalSet.empty()
- >>> print nonzero.symmetric_difference(naturals)
+ >>> print(nonzero.symmetric_difference(naturals))
(...0]
- >>> print zero.symmetric_difference(negatives)
+ >>> print(zero.symmetric_difference(negatives))
(...0]
- >>> print positives.symmetric_difference(empty)
+ >>> print(positives.symmetric_difference(empty))
(0...)
- >>> print evens.symmetric_difference(zero)
+ >>> print(evens.symmetric_difference(zero))
-8,-6,-4,-2,2,4,6,8
- >>> print evens.symmetric_difference(range(0, 9, 2))
+ >>> print(evens.symmetric_difference(range(0, 9, 2)))
-8,-6,-4,-2
"""
if isinstance(other, BaseIntervalSet):
@@ -1625,15 +1645,15 @@ class BaseIntervalSet(object):
>>> evens = IntervalSet([-8, -6, -4, -2, 0, 2, 4, 6, 8])
>>> zero = IntervalSet([0])
>>> nonzero = IntervalSet.not_equal_to(0)
- >>> print ~(IntervalSet.empty())
+ >>> print(~(IntervalSet.empty()))
(...)
>>> ~negatives == naturals
True
- >>> print ~positives
+ >>> print(~positives)
(...0]
>>> ~naturals == negatives
True
- >>> print ~evens
+ >>> print(~evens)
(...-8),(-8..-6),(-6..-4),(-4..-2),(-2..0),(0..2),(2..4),(4..6),(6..8),(8...)
>>> ~zero == nonzero
True
@@ -1954,9 +1974,9 @@ class BaseIntervalSet(object):
def less_than(cls, n):
"""Returns an IntervalSet containing values less than the given value
- >>> print IntervalSet.less_than(0)
+ >>> print(IntervalSet.less_than(0))
(...0)
- >>> print IntervalSet.less_than(-23)
+ >>> print(IntervalSet.less_than(-23))
(...-23)
"""
return cls([Interval.less_than(n)])
@@ -1966,9 +1986,9 @@ class BaseIntervalSet(object):
"""Returns an IntervalSet containing values less than or equal to the
given value
- >>> print IntervalSet.less_than_or_equal_to(0)
+ >>> print(IntervalSet.less_than_or_equal_to(0))
(...0]
- >>> print IntervalSet.less_than_or_equal_to(-23)
+ >>> print(IntervalSet.less_than_or_equal_to(-23))
(...-23]
"""
return cls([Interval.less_than_or_equal_to(n)])
@@ -1977,9 +1997,9 @@ class BaseIntervalSet(object):
def greater_than(cls, n):
"""Returns an IntervalSet containing values greater than the given value
- >>> print IntervalSet.greater_than(0)
+ >>> print(IntervalSet.greater_than(0))
(0...)
- >>> print IntervalSet.greater_than(-23)
+ >>> print(IntervalSet.greater_than(-23))
(-23...)
"""
return cls([Interval.greater_than(n)])
@@ -1989,9 +2009,9 @@ class BaseIntervalSet(object):
"""Returns an IntervalSet containing values greater than or equal to
the given value
- >>> print IntervalSet.greater_than_or_equal_to(0)
+ >>> print(IntervalSet.greater_than_or_equal_to(0))
[0...)
- >>> print IntervalSet.greater_than_or_equal_to(-23)
+ >>> print(IntervalSet.greater_than_or_equal_to(-23))
[-23...)
"""
return cls([Interval.greater_than_or_equal_to(n)])
@@ -2000,9 +2020,9 @@ class BaseIntervalSet(object):
def not_equal_to(cls, n):
"""Returns an IntervalSet of all values not equal to n
- >>> print IntervalSet.not_equal_to(0)
+ >>> print(IntervalSet.not_equal_to(0))
(...0),(0...)
- >>> print IntervalSet.not_equal_to(-23)
+ >>> print(IntervalSet.not_equal_to(-23))
(...-23),(-23...)
"""
return cls([Interval.less_than(n), Interval.greater_than(n)])
@@ -2014,9 +2034,9 @@ class BaseIntervalSet(object):
If closed is True, then the endpoints are included; otherwise, they
aren't.
- >>> print IntervalSet.between(0, 100)
+ >>> print(IntervalSet.between(0, 100))
[0..100]
- >>> print IntervalSet.between(-1, 1)
+ >>> print(IntervalSet.between(-1, 1))
[-1..1]
"""
return cls([Interval.between(a, b, closed)])
@@ -2025,7 +2045,7 @@ class BaseIntervalSet(object):
def all(cls):
"""Returns an interval set containing all values
- >>> print IntervalSet.all()
+ >>> print(IntervalSet.all())
(...)
"""
return cls([Interval.all()])
@@ -2034,7 +2054,7 @@ class BaseIntervalSet(object):
def empty(cls):
"""Returns an interval set containing no values.
- >>> print IntervalSet.empty()
+ >>> print(IntervalSet.empty())
<Empty>
"""
return cls()
@@ -2101,7 +2121,7 @@ class IntervalSet(BaseIntervalSet):
>>> del interval[1]
>>> len(interval)
2
- >>> print interval
+ >>> print(interval)
-2,7
"""
try:
@@ -2114,13 +2134,13 @@ class IntervalSet(BaseIntervalSet):
>>> r = IntervalSet()
>>> r.add(4)
- >>> print r
+ >>> print(r)
4
>>> r.add(Interval(23, 39, lower_closed=False))
- >>> print r
+ >>> print(r)
4,(23..39]
>>> r.add(Interval.less_than(25))
- >>> print r
+ >>> print(r)
(...39]
"""
BaseIntervalSet._add(self, obj)
@@ -2134,10 +2154,10 @@ class IntervalSet(BaseIntervalSet):
>>> r = IntervalSet.all()
>>> r.remove(4)
- >>> print r
+ >>> print(r)
(...4),(4...)
>>> r.remove(Interval(23, 39, lower_closed=False))
- >>> print r
+ >>> print(r)
(...4),(4..23],(39...)
>>> r.remove(Interval.less_than(25))
Traceback (most recent call last):
@@ -2157,13 +2177,13 @@ class IntervalSet(BaseIntervalSet):
>>> r = IntervalSet.all()
>>> r.discard(4)
- >>> print r
+ >>> print(r)
(...4),(4...)
>>> r.discard(Interval(23, 39, lower_closed=False))
- >>> print r
+ >>> print(r)
(...4),(4..23],(39...)
>>> r.discard(Interval.less_than(25))
- >>> print r
+ >>> print(r)
(39...)
"""
diff = self - IntervalSet([obj])
@@ -2177,18 +2197,18 @@ class IntervalSet(BaseIntervalSet):
>>> r = IntervalSet.all()
>>> r.difference_update([4])
- >>> print r
+ >>> print(r)
(...4),(4...)
>>> r.difference_update(
... IntervalSet([Interval(23, 39, lower_closed=False)]))
- >>> print r
+ >>> print(r)
(...4),(4..23],(39...)
>>> r.difference_update(IntervalSet.less_than(25))
- >>> print r
+ >>> print(r)
(39...)
>>> r2 = IntervalSet.all()
>>> r.difference_update(r2)
- >>> print r
+ >>> print(r)
<Empty>
"""
diff = self.difference(other)
@@ -2198,10 +2218,10 @@ class IntervalSet(BaseIntervalSet):
"""Removes all Intervals from the object
>>> s = IntervalSet([2, 7, Interval.greater_than(8), 2, 6, 34])
- >>> print s
+ >>> print(s)
2,6,7,(8...)
>>> s.clear()
- >>> print s
+ >>> print(s)
<Empty>
"""
self.intervals = []
@@ -2214,17 +2234,17 @@ class IntervalSet(BaseIntervalSet):
>>> r = IntervalSet()
>>> r.update([4])
- >>> print r
+ >>> print(r)
4
>>> r.update(IntervalSet([Interval(23, 39, lower_closed=False)]))
- >>> print r
+ >>> print(r)
4,(23..39]
>>> r.update(IntervalSet.less_than(25))
- >>> print r
+ >>> print(r)
(...39]
>>> r2 = IntervalSet.all()
>>> r.update(r2)
- >>> print r
+ >>> print(r)
(...)
"""
union = self.union(other)
@@ -2238,19 +2258,19 @@ class IntervalSet(BaseIntervalSet):
>>> r = IntervalSet.all()
>>> r.intersection_update([4])
- >>> print r
+ >>> print(r)
4
>>> r = IntervalSet.all()
>>> r.intersection_update(
... IntervalSet([Interval(23, 39, lower_closed=False)]))
- >>> print r
+ >>> print(r)
(23..39]
>>> r.intersection_update(IntervalSet.less_than(25))
- >>> print r
+ >>> print(r)
(23..25)
>>> r2 = IntervalSet.all()
>>> r.intersection_update(r2)
- >>> print r
+ >>> print(r)
(23..25)
"""
intersection = self.intersection(other)
@@ -2264,18 +2284,18 @@ class IntervalSet(BaseIntervalSet):
>>> r = IntervalSet.empty()
>>> r.symmetric_difference_update([4])
- >>> print r
+ >>> print(r)
4
>>> r.symmetric_difference_update(
... IntervalSet([Interval(23, 39, lower_closed=False)]))
- >>> print r
+ >>> print(r)
4,(23..39]
>>> r.symmetric_difference_update(IntervalSet.less_than(25))
- >>> print r
+ >>> print(r)
(...4),(4..23],[25..39]
>>> r2 = IntervalSet.all()
>>> r.symmetric_difference_update(r2)
- >>> print r
+ >>> print(r)
4,(23..25),(39...)
"""
xor = self.symmetric_difference(other)
@@ -2294,7 +2314,7 @@ class IntervalSet(BaseIntervalSet):
True
>>> "7" in l
True
- >>> print s
+ >>> print(s)
<Empty>
>>> i = s.pop()
Traceback (most recent call last):
@@ -2341,7 +2361,7 @@ class FrozenIntervalSet(BaseIntervalSet):
... FrozenIntervalSet.less_than(3) : 3}
"""
- def __new__(cls, items=[]):
+ def __new__(cls, items=None):
"""Constructs a new FrozenInteralSet
Object creation is just like with a regular IntervalSet, except for
@@ -2354,11 +2374,13 @@ class FrozenIntervalSet(BaseIntervalSet):
>>> id(fs1) == id(fs2)
True
"""
+ if items is None:
+ items = []
if (cls == FrozenIntervalSet) and isinstance(items, FrozenIntervalSet):
result = items
else:
s = IntervalSet(items)
- result = super(FrozenIntervalSet, cls).__new__(cls, items)
+ result = super(FrozenIntervalSet, cls).__new__(cls)
result.intervals = s.intervals
return result
--
2.42.0
......@@ -34,3 +34,8 @@ rpath =
${libjpeg:location}/lib
${libtiff:location}/lib
${zlib:location}/lib
Pillow-patches = ${:_profile_base_location_}/../../component/egg-patch/Pillow/0001-set-metadata-in-setup.py-for-compatibility-with-old-.patch#0a06cc5a94d3db24688938731e4b15e2
Pillow-patch-options = -p1
[pillow-python:python2]
Pillow-patches =
......@@ -8,10 +8,34 @@ extends =
[astroid]
recipe = zc.recipe.egg:custom
egg = astroid
setup-eggs = ${lazy-object-proxy:egg}
[astroid:python2]
patches =
${:_profile_base_location_}/astroid-six_moves_import_error.patch#377beb0c50f52b9608bb6be7bf93096e
${:_profile_base_location_}/fix-import-six.moves.urllib.request-on-astroid-1.3.8.patch#266139a893d0eba377ac510fb0fa75f1
patch-options = -p1
patch-binary = ${patch:location}/bin/patch
setup-eggs =
[lazy-object-proxy]
recipe = zc.recipe.egg:custom
egg = lazy-object-proxy
setup-eggs =
${setuptools-scm:egg}
typing-extensions
tomli
[setuptools-scm]
recipe = zc.recipe.egg:custom
egg = setuptools-scm
setup-eggs = packaging
[mccabe]
recipe = zc.recipe.egg:custom
egg = mccabe
setup-eggs = pytest-runner
[pylint]
recipe = zc.recipe.egg:custom
......@@ -21,3 +45,14 @@ patches =
${:_profile_base_location_}/pylint-redefining-builtins-modules.patch#043defc6e9002ac48b40e078797d4d17
patch-options = -p1
patch-binary = ${patch:location}/bin/patch
[pylint:python3]
recipe = zc.recipe.egg
patches =
[mccabe:python3]
recipe = zc.recipe.egg
setup-eggs =
[astroid:python3]
recipe = zc.recipe.egg
From 67abf302360eab857fb02d1e83a97aff86f31aa5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=A9rome=20Perrin?= <jerome@nexedi.com>
Date: Tue, 9 Apr 2024 11:04:38 +0900
Subject: [PATCH] fix "import six.moves.urllib.request" on astroid 1.3.8
---
astroid/brain/pysix_moves.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/astroid/brain/pysix_moves.py b/astroid/brain/pysix_moves.py
index 4a82b499..9bf31146 100644
--- a/astroid/brain/pysix_moves.py
+++ b/astroid/brain/pysix_moves.py
@@ -164,6 +164,7 @@ if sys.version_info[0] == 2:
urllib_parse = UrllibParse()
urllib_error = UrllibError()
+ urllib_request = UrllibRequest()
urllib = DummyModule()
urllib.request = UrllibRequest()
urllib.parse = UrllibParse()
--
2.42.0
[buildout]
parts =
python-ldap
python-ldap-python
extends =
../cyrus-sasl/buildout.cfg
../openldap/buildout.cfg
......@@ -10,19 +10,25 @@ extends =
[python-ldap-python]
recipe = zc.recipe.egg:custom
egg = python-ldap
patches =
${:_profile_base_location_}/python-ldap-no_default_dirs.patch#959115f13f1de5c63654c69b8dfacd69
patch-options = -p1
patch-binary = ${patch:location}/bin/patch
rpath =
${openldap:location}/lib
${cyrus-sasl:location}/lib
${openssl:location}/lib
include-dirs =
${openldap:location}/include
${cyrus-sasl:location}/include/sasl
${cyrus-sasl:location}/include
${openssl:location}/include
library-dirs =
${openldap:location}/lib
${cyrus-sasl:location}/lib
${openssl:location}/lib
[python-ldap-python:python2]
patches =
${:_profile_base_location_}/python-ldap-no_default_dirs.patch#959115f13f1de5c63654c69b8dfacd69
patch-options = -p1
patch-binary = ${patch:location}/bin/patch
include-dirs =
${openldap:location}/include
${cyrus-sasl:location}/include/sasl
${openssl:location}/include
......@@ -16,3 +16,5 @@ egg = pyzmq
environment = python-pyzmq-env
rpath =
${libzmq:location}/lib
setup-eggs =
packaging
......@@ -21,9 +21,19 @@ setup-eggs =
pkgconfig
pathlib2
setuptools-scm
toml
tomli
environment = python-xmlsec-env
[python-xmlsec:python2]
setup-eggs =
${lxml-python:egg}
pkgconfig
pathlib2
setuptools-scm
toml
[python-xmlsec-env]
PKG_CONFIG=${pkgconfig:location}/bin/pkg-config
PKG_CONFIG_PATH=${libxml2:location}/lib/pkgconfig:${libxslt:location}/lib/pkgconfig:${xmlsec:location}/lib/pkgconfig
......
[buildout]
extends =
../../stack/erp5/buildout.cfg
[python]
part = python3
[erp5]
repository = https://lab.nexedi.com/nexedi/erp5.git
branch = zope4py3
develop = true
[neoppod-repository]
# Pinned to a revision before 6ffafcbd (Fix egg dependencies, 2024-05-17) which
# is incompatible with our versions:
# The requirement ('msgpack<1,>=0.5.6') is not allowed by your [versions] constraint (1.0.5)
revision = c4443632e3541c064f5b43096099f4a8b74cbf58
[template-zope]
link-binary +=
${python3:location}/bin/2to3
software.cfg.json
\ No newline at end of file
[buildout]
extends =
../../stack/erp5/buildout.cfg
[template-zope]
link-binary +=
${python2.7:location}/bin/2to3
......@@ -46,10 +46,14 @@ from cryptography.x509.oid import NameOID
from slapos.testing.testcase import ManagedResource, makeModuleSetUpAndTestCaseClass
from slapos.testing.utils import findFreeTCPPort
ERP5PY3 = os.environ['SLAPOS_SR_TEST_NAME'] == 'erp5-py3'
_setUpModule, SlapOSInstanceTestCase = makeModuleSetUpAndTestCaseClass(
os.path.abspath(
os.path.join(os.path.dirname(__file__), '..', '..', 'software.cfg')))
os.path.join(os.path.dirname(__file__), '..', '..', 'software%s.cfg' % (
'-py3' if ERP5PY3 else ''))),
software_id=os.environ['SLAPOS_SR_TEST_NAME'],
)
setup_module_executed = False
......@@ -191,7 +195,10 @@ def neo(instance_parameter_dict):
class ERP5InstanceTestCase(SlapOSInstanceTestCase, metaclass=ERP5InstanceTestMeta):
"""ERP5 base test case
"""
__test_matrix__ = matrix((zeo, neo)) # switch between NEO and ZEO mode
if ERP5PY3:
__test_matrix__ = matrix((zeo, )) # TODO: NEO is not yet enabled for py3
else:
__test_matrix__ = matrix((zeo, neo)) # switch between NEO and ZEO mode
@classmethod
def isNEO(cls):
......
......@@ -51,7 +51,7 @@ import urllib3
from slapos.testing.utils import CrontabMixin
import zc.buildout.configparser
from . import CaucaseService, ERP5InstanceTestCase, default, matrix, neo, setUpModule
from . import CaucaseService, ERP5InstanceTestCase, default, matrix, neo, setUpModule, ERP5PY3
setUpModule # pyflakes
......@@ -1302,60 +1302,80 @@ class TestNEO(ZopeSkinsMixin, CrontabMixin, ERP5InstanceTestCase):
__partition_reference__ = 'n'
__test_matrix__ = matrix((neo,))
def _getCrontabCommand(self, crontab_name: str) -> str:
"""Read a crontab and return the command that is executed.
overloaded to use crontab from neo partition
"""
with open(
os.path.join(
if ERP5PY3:
# NEO is not ready for python3 at this time, this test is here to become
# an unexpected success once it starts working, so that we remember to
# remove this and enable neo in ERP5InstanceTestCase.__test_matrix__
setup_failed_exception = None
@classmethod
def setUpClass(cls):
try:
super().setUpClass()
except BaseException as e:
cls.setup_failed_exception = e
cls.setUp = lambda self: None
cls.tearDownClass = classmethod(lambda cls: None)
@unittest.expectedFailure
def test_neo_py3(self):
self.assertIsNone(self.setup_failed_exception)
else:
def _getCrontabCommand(self, crontab_name: str) -> str:
"""Read a crontab and return the command that is executed.
overloaded to use crontab from neo partition
"""
with open(
os.path.join(
self.getComputerPartitionPath('neo-0'),
'etc',
'cron.d',
crontab_name,
)) as f:
crontab_spec, = f.readlines()
self.assertNotEqual(crontab_spec[0], '@', crontab_spec)
return crontab_spec.split(None, 5)[-1]
def test_log_rotation(self):
# first run to create state files
self._executeCrontabAtDate('logrotate', '2000-01-01')
def check_sqlite_log(path):
with self.subTest(path), contextlib.closing(sqlite3.connect(path)) as con:
con.execute('select * from log')
logfiles = ('neoadmin.log', 'neomaster.log', 'neostorage-0.log')
for f in logfiles:
check_sqlite_log(
os.path.join(
self.getComputerPartitionPath('neo-0'),
'etc',
'cron.d',
crontab_name,
)) as f:
crontab_spec, = f.readlines()
self.assertNotEqual(crontab_spec[0], '@', crontab_spec)
return crontab_spec.split(None, 5)[-1]
def test_log_rotation(self):
# first run to create state files
self._executeCrontabAtDate('logrotate', '2000-01-01')
def check_sqlite_log(path):
with self.subTest(path), contextlib.closing(sqlite3.connect(path)) as con:
con.execute('select * from log')
'var',
'log',
f))
logfiles = ('neoadmin.log', 'neomaster.log', 'neostorage-0.log')
for f in logfiles:
check_sqlite_log(
os.path.join(
self.getComputerPartitionPath('neo-0'),
'var',
'log',
f))
self._executeCrontabAtDate('logrotate', '2050-01-01')
self._executeCrontabAtDate('logrotate', '2050-01-01')
for f in logfiles:
check_sqlite_log(
os.path.join(
self.getComputerPartitionPath('neo-0'),
'srv',
'backup',
'logrotate',
f'{f}-20500101'))
for f in logfiles:
check_sqlite_log(
os.path.join(
self.getComputerPartitionPath('neo-0'),
'srv',
'backup',
'logrotate',
f'{f}-20500101'))
self._executeCrontabAtDate('logrotate', '2050-01-02')
requests.get(self._getAuthenticatedZopeUrl('/'), verify=False).raise_for_status()
self._executeCrontabAtDate('logrotate', '2050-01-02')
requests.get(self._getAuthenticatedZopeUrl('/'), verify=False).raise_for_status()
for f in logfiles:
check_sqlite_log(
os.path.join(
self.getComputerPartitionPath('neo-0'),
'var',
'log',
f))
for f in logfiles:
check_sqlite_log(
os.path.join(
self.getComputerPartitionPath('neo-0'),
'var',
'log',
f))
class TestPassword(ERP5InstanceTestCase, TestPublishedURLIsReachableMixin):
__partition_reference__ = 'p'
......
......@@ -23,7 +23,7 @@ import unittest
from slapos.grid.utils import md5digest
from . import ERP5InstanceTestCase
from . import setUpModule as _setUpModule
from . import setUpModule as _setUpModule, ERP5PY3
from .test_erp5 import TestPublishedURLIsReachableMixin
......@@ -38,6 +38,8 @@ def setUpModule():
md5digest(cls.getSoftwareURL()),
'bin', 'wcfs')):
raise unittest.SkipTest("built with wendelin.core 1")
if ERP5PY3:
raise unittest.SkipTest("wendelin.core does not support python3 yet")
class TestWCFS(ERP5InstanceTestCase, TestPublishedURLIsReachableMixin):
......
......@@ -22,7 +22,7 @@ md5sum = 102a7f1c1bc46a9b3fa5bd9b9a628e1d
[instance-neo-admin]
filename = instance-neo-admin.cfg.in
md5sum = b6e1ccb1d90160110202e5111eec2afa
md5sum = a0ec1dce4c7a237fbeef3f8aee62e55a
[instance-neo-master]
filename = instance-neo-master.cfg.in
......@@ -34,7 +34,7 @@ md5sum = bc647a29f9d6ece2e4117ce8f04d27c5
[template-neo-my-cnf]
filename = my.cnf.in
md5sum = 56ea8f452d9e1526157ab9d03e631e1a
md5sum = 3ae93702f3890a504cc8a93eb5ad52bc
[template-neo]
filename = instance.cfg.in
......
......@@ -45,7 +45,7 @@ ssl = {{ dumps(bool(slapparameter_dict['ssl'])) }}
cluster = {{ dumps(slapparameter_dict['cluster']) }}
masters = {{ dumps(slapparameter_dict['masters']) }}
extra-options =
{%- for k, v in monitor_dict.iteritems() %}
{%- for k, v in six.iteritems(monitor_dict) %}
{%- if k == 'backup' %}
{%- set k = 'monitor-backup' %}
{%- endif %}
......
......@@ -45,7 +45,7 @@ innodb_locks_unsafe_for_binlog = 1
{{x}}sync_frm = 0
# Extra parameters.
{%- for k, v in extra_dict.iteritems() %}
{%- for k, v in six.iteritems(extra_dict) %}
{%- do assert('-' not in k) %}
{{ k }} = {{ v }}
{%- endfor %}
......
......@@ -138,10 +138,14 @@ inline =
exec "$basedir/bin/mysqld" --defaults-file='{{defaults_file}}' "$@"
[versions]
coverage = 5.5
coverage = 7.5.1
ecdsa = 0.13
mysqlclient = 1.3.12
mysqlclient = 2.0.1
PyMySQL = 0.10.1
pycrypto = 2.6.1
cython-zstd = 0.2
funcsigs = 1.0.2
[versions:python2]
coverage = 5.5
mysqlclient = 1.3.12
......@@ -15,4 +15,4 @@
[template]
filename = instance.cfg
md5sum = f10fbca22d1d30dd7a4f36e1cd521b97
md5sum = 59a5b559b22ad0590e691226cea45055
......@@ -67,6 +67,7 @@ inline =
command,
cwd={{ repr(folder) }},
summaryf=UnitTest.summary,
envadj={ 'SLAPOS_SR_TEST_NAME': {{ repr(name) }} },
)
{%- endif %}
{%- endfor %}
......
......@@ -440,6 +440,7 @@ tests =
dream ${slapos.test.dream-setup:setup}
dufs ${slapos.test.dufs-setup:setup}
erp5 ${slapos.test.erp5-setup:setup}
erp5-py3 ${slapos.test.erp5-setup:setup}
erp5testnode ${slapos.test.erp5testnode-setup:setup}
fluentd ${slapos.test.fluentd-setup:setup}
galene ${slapos.test.galene-setup:setup}
......@@ -487,7 +488,7 @@ recurls =
slapos.core =
# Various needed versions
Pillow = 9.2.0
Pillow = 10.2.0+SlapOSPatched001
forcediphttpsadapter = 1.0.1
image = 1.5.25
plantuml = 0.3.0:whl
......@@ -495,7 +496,6 @@ pysftp = 0.2.9
requests-toolbelt = 0.8.0
testfixtures = 6.11.0
mysqlclient = 2.1.1
pexpect = 4.8.0
ptyprocess = 0.6.0
paho-mqtt = 1.5.0
pcpp = 1.30
......
......@@ -737,7 +737,7 @@ PyPDF2 = 1.26.0+SlapOSPatched001
## https://lab.nexedi.com/nexedi/slapos/merge_requests/648
pylint = 1.4.4+SlapOSPatched002
# astroid 1.4.1 breaks testDynamicClassGeneration
astroid = 1.3.8+SlapOSPatched001
astroid = 1.3.8+SlapOSPatched002
# use newer version than specified in ZTK
PasteDeploy = 1.5.2
......
......@@ -2,7 +2,7 @@
extends =
# versions pins from zope, vendored with:
# curl https://zopefoundation.github.io/Zope/releases/4.8.9/versions-prod.cfg > zope-versions.cfg
# curl https://zopefoundation.github.io/Zope/releases/5.9/versions-prod.cfg > zope-versions.cfg
# When updating, keep in mind that some versions are defined in other places,
# for example component/ZEO , component/ZODB and stack/slapos
zope-versions.cfg
......@@ -63,6 +63,7 @@ extends =
../../component/pygolang/buildout.cfg
../../component/bcrypt/buildout.cfg
../../component/python-pynacl/buildout.cfg
../../component/python-pyzmq/buildout.cfg
../../component/python-xmlsec/buildout.cfg
../../component/selenium/buildout.cfg
../../stack/caucase/buildout.cfg
......@@ -269,7 +270,6 @@ link-binary =
${poppler:location}/bin/pdfinfo
${poppler:location}/bin/pdftohtml
${poppler:location}/bin/pdftotext
${python2.7:location}/bin/2to3
${sed:location}/bin/sed
${tesseract:location}/bin/tesseract
${w3m:location}/bin/w3m
......@@ -476,7 +476,6 @@ eggs +=
ipython_genutils
ipykernel
ipywidgets
requests
[egg-with-zope-proxy]
......@@ -493,13 +492,14 @@ setup-eggs +=
[eggs]
<= neoppod
eggs = ${neoppod:eggs}
eggs =
${erp5-eggs-python-version-dependent:eggs}
${neoppod:eggs}
${caucase-eggs:eggs}
${wendelin.core:egg}
${numpy:egg}
${matplotlib:egg}
${lxml-python:egg}
${ocropy:egg}
${pandas:egg}
${pillow-python:egg}
${python-ldap-python:egg}
......@@ -521,14 +521,12 @@ eggs = ${neoppod:eggs}
astor
APacheDEX
Pympler
SOAPpy
chardet
collective.recipe.template
erp5diff
interval
ipdb
Jinja2
jsonschema
mechanize
oauthlib
objgraph
......@@ -540,39 +538,30 @@ eggs = ${neoppod:eggs}
PyPDF2
python-magic
python-memcached
pytz
requests
responses
uritemplate
urlnorm
uuid
xml_marshaller
xupdate_processor
feedparser
validictory
erp5.util
z3c.etestbrowser
huBarcode
qrcode
spyne
httplib2
suds
pprofile
pycountry
xfw
jsonschema
${selenium:egg}
pytesseract
decorator
networkx
# Needed for checking ZODB Components source code
${astroid:egg}
${pylint:egg}
jedi
yapf
typing
# Used for Python 2 only
${pytracemalloc:egg}
xlrd
pydot
# Zope
......@@ -585,25 +574,16 @@ eggs = ${neoppod:eggs}
# for runzeo
${ZEO:egg}
# Other Zope 2 packages
Products.PluggableAuthService
Products.DCWorkflow
# Other products
Products.PluggableAuthService
Products.MimetypesRegistry
Products.TIDStorage
# Currently forked in our repository
# Products.PortalTransforms
# Dependency for our fork of PortalTransforms
StructuredText
# Needed for parsing .po files from our Localizer subset
polib
# Needed for Google OAuth
google-api-python-client
# Need for Facebook OAuth
facebook-sdk
......@@ -629,11 +609,9 @@ eggs = ${neoppod:eggs}
docutils
zLOG
Products.ZSQLMethods
ZServer
Products.ExternalMethod
Products.SiteErrorLog
tempstorage
Products.DCWorkflow
Products.Sessions
Products.ZODBMountPoint
Record
......@@ -659,28 +637,48 @@ extra-paths =
patch-binary = ${patch:location}/bin/patch
Acquisition-patches = ${:_profile_base_location_}/../../component/egg-patch/Acquisition/aq_dynamic-4.7.patch#85b0090e216cead0fc86c5c274450d96
Acquisition-patch-options = -p1
DateTime-patches =
${:_profile_base_location_}/../../component/egg-patch/DateTime/0001-Cast-int-to-float-in-compare-methods.patch#9898a58ce90dd31c884a7183aeec4361
${:_profile_base_location_}/../../component/egg-patch/DateTime/0002-Fix-compare-methods-between-DateTime-0-and-None-fix-.patch#733903a564c8b14df65c45c4f2eec262
${:_profile_base_location_}/../../component/egg-patch/DateTime/0003-Make-it-possible-to-pickle-datetimes-returned-by-asd.patch#e94a71ef40de130720e621e296537000
${:_profile_base_location_}/../../component/egg-patch/DateTime/0004-Repair-equality-comparison-between-DateTime-instance.patch#ea146c00dfbc31c7d96af8abc6f0b301
DateTime-patch-options = -p1
Products.BTreeFolder2-patches = ${:_profile_base_location_}/../../component/egg-patch/Products.BTreeFolder2/0001-Add-a-confirmation-prompt-on-Delete-All-Objects-butt.patch#44de3abf382e287b8766c2f29ec1cf74
Products.BTreeFolder2-patch-options = -p1
Products.CMFCore-patches = ${:_profile_base_location_}/../../component/egg-patch/Products.CMFCore/portal_skins_ZMI_find.patch#19ec05c0477c50927ee1df6eb75d1e7f
Products.CMFCore-patch-options = -p1
Products.DCWorkflow-patches = ${:_profile_base_location_}/../../component/egg-patch/Products.DCWorkflow/workflow_method-2.4.1.patch#ec7bb56a9f1d37fcbf960cd1e96e6e6d
Products.DCWorkflow-patch-options = -p1
PyPDF2-patches =
${:_profile_base_location_}/../../component/egg-patch/PyPDF2/0001-Custom-implementation-of-warnings.formatwarning-remo.patch#d25bb0f5dde7f3337a0a50c2f986f5c8
${:_profile_base_location_}/../../component/egg-patch/PyPDF2/0002-fix-pdf-reader-getting-stuck-when-trying-to-read-lar.patch#c06a29b6b6a5df612ae36731b938fb95
PyPDF2-patch-options = -p1
python-magic-patches = ${:_profile_base_location_}/../../component/egg-patch/python_magic/magic.patch#de0839bffac17801e39b60873a6c2068
python-magic-patch-options = -p1
RestrictedPython-patches = ${:_profile_base_location_}/../../component/egg-patch/RestrictedPython/0001-compile-implicitly-enable-__future__.print_function-.patch#f746dccbf3b462e67386490b898512e4
RestrictedPython-patch-options = -p1
urlnorm-patches = ${:_profile_base_location_}/../../component/egg-patch/urlnorm/urlnorm-1.1.4-py3.patch#5ef268fb44cbc005b62140099c33b641
urlnorm-patch-options = -p1
SOAPpy-py3-patches = ${:_profile_base_location_}/../../component/egg-patch/SOAPpy-py3/0001-backport-changes-from-0.52.29.patch#28a08e587bf2e287ec3491c5ae7e8f1a
SOAPpy-py3-patch-options = -p1
Zope-patches =
${:_profile_base_location_}/../../component/egg-patch/Zope/0001-Fix-redirections-to-URLS-with-host-given-as-IP-litte.patch#093ad5755094d537c6a4deadc959ade0
${:_profile_base_location_}/../../component/egg-patch/Zope/1196.patch#1a1c32984cf4b2cb8558a3fdce4c4fb3
${:_profile_base_location_}/../../component/egg-patch/Zope/1198.patch#b108c121bc2de37460f330eb93ae5825
Zope-patch-options = -p1
[eggs:python3]
AccessControl-patches = ${:_profile_base_location_}/../../component/egg-patch/AccessControl/147.patch#5eb2b07dc79bef05dbc0c60d046d2847
AccessControl-patch-options = -p1
interval-patches = ${:_profile_base_location_}/../../component/egg-patch/interval/0001-python3-support.patch#66ac345f0a6d73e0bd29e394b7646311
interval-patch-options = -p1
Products.DCWorkflow-patches = ${:_profile_base_location_}/../../component/egg-patch/Products.DCWorkflow/workflow_method-3.0.0.patch#4cc8607213b1ef08331366d9873becaa
Products.DCWorkflow-patch-options = -p1
[eggs:python2]
DateTime-patches =
${:_profile_base_location_}/../../component/egg-patch/DateTime/0001-Cast-int-to-float-in-compare-methods.patch#9898a58ce90dd31c884a7183aeec4361
${:_profile_base_location_}/../../component/egg-patch/DateTime/0002-Fix-compare-methods-between-DateTime-0-and-None-fix-.patch#733903a564c8b14df65c45c4f2eec262
${:_profile_base_location_}/../../component/egg-patch/DateTime/0003-Make-it-possible-to-pickle-datetimes-returned-by-asd.patch#e94a71ef40de130720e621e296537000
${:_profile_base_location_}/../../component/egg-patch/DateTime/0004-Repair-equality-comparison-between-DateTime-instance.patch#ea146c00dfbc31c7d96af8abc6f0b301
DateTime-patch-options = -p1
huBarcode-patches =
${:_profile_base_location_}/../../component/egg-patch/huBarcode/fix-loading-font-for-ean13.patch#77879186092d0b55ee009c6ef3c3e2e4
huBarcode-patch-options = -p1
Products.DCWorkflow-patches = ${:_profile_base_location_}/../../component/egg-patch/Products.DCWorkflow/workflow_method-2.4.1.patch#ec7bb56a9f1d37fcbf960cd1e96e6e6d
Products.DCWorkflow-patch-options = -p1
RestrictedPython-patches = ${:_profile_base_location_}/../../component/egg-patch/RestrictedPython/0001-compile-implicitly-enable-__future__.print_function-.patch#f746dccbf3b462e67386490b898512e4
RestrictedPython-patch-options = -p1
# backported security patches for waitress-1.4.4 from Debian 1.4.4-1.1+deb11u1 package.
waitress-patches =
${:_profile_base_location_}/../../component/egg-patch/waitress/CVE-2022-24761-1.patch#a0508880f24662e48a20ce3bcbf440c2
......@@ -695,6 +693,27 @@ Zope-patches =
${:_profile_base_location_}/../../component/egg-patch/Zope/0001-Fix-redirections-to-URLS-with-host-given-as-IP-litte.patch#093ad5755094d537c6a4deadc959ade0
Zope-patch-options = -p1
# python version dependent eggs
[erp5-eggs-python-version-dependent:python2]
eggs =
huBarcode
${ocropy:egg}
${pytracemalloc:egg}
Products.TIDStorage
SOAPpy
suds
typing
uuid
xlrd
ZServer
[erp5-eggs-python-version-dependent:python3]
eggs =
${python-pyzmq:egg}
python-barcode
SOAPpy-py3
suds-py3
# neoppod installs bin/coverage so we inject erp5 plugin here so that coverage script can use it in report
[neoppod]
eggs +=
......@@ -725,123 +744,128 @@ depends =
# neoppod, mysqlclient, slapos.recipe.template
# patched eggs
Acquisition = 4.7+SlapOSPatched001
DateTime = 4.9+SlapOSPatched004
Products.DCWorkflow = 2.4.1+SlapOSPatched001
ocropy = 1.0+SlapOSPatched001
AccessControl = 6.3+SlapOSPatched001
Acquisition = 5.2+SlapOSPatched001
PyPDF2 = 1.26.0+SlapOSPatched002
pysvn = 1.9.15+SlapOSPatched001
python-ldap = 2.4.32+SlapOSPatched001
python-magic = 0.4.12+SlapOSPatched001
RestrictedPython = 5.4+SlapOSPatched001
waitress = 1.4.4+SlapOSPatched006
Zope = 4.8.9+SlapOSPatched002
## https://lab.nexedi.com/nexedi/slapos/merge_requests/648
pylint = 1.4.4+SlapOSPatched002
# astroid 1.4.1 breaks testDynamicClassGeneration
astroid = 1.3.8+SlapOSPatched001
# modified version that works fine for buildout installation
SOAPpy = 0.12.0nxd001
Zope = 5.9+SlapOSPatched003
# Pinned versions
alabaster = 0.7.12
APacheDEX = 1.8
APacheDEX = 2.0
astroid = 3.2.0:whl
Beaker = 1.11.0
cloudpickle = 0.5.3
cookies = 2.2.1
dask = 0.18.1
deepdiff = 3.3.0
deepdiff = 6.7.1
dill = 0.3.8:whl
docutils = 0.17.1
erp5-coverage-plugin = 0.0.1
erp5diff = 0.8.1.9
facebook-sdk = 2.0.0
five.formlib = 1.0.4
five.localsitemanager = 4.0
fpconst = 0.7.2
future = 0.18.2
google-api-python-client = 1.6.1
google-api-core = 2.17.1
google-api-python-client = 2.118.0
google-auth = 2.28.1
google-auth-httplib2 = 0.2.0
googleapis-common-protos = 1.62.0
graphviz = 0.5.2
haufe.requestmonitoring = 0.6.0
html5lib = 1.1
huBarcode = 1.0.0
interval = 1.0.0
huBarcode = 1.0.0+SlapOSPatched001
imageio = 2.34.0
interval = 1.0.0+SlapOSPatched001
ipdb = 0.10.2
isort = 5.13.2
jdcal = 1.3
jedi = 0.15.1
jsonpickle = 0.9.6
jsonpointer = 2.2
lazy-object-proxy = 1.10.0
logilab-common = 1.3.0
Mako = 1.1.4
mccabe = 0.7.0:whl
mechanize = 0.4.8
Missing = 5.0.0
mock = 4.0.3
mpmath = 0.19
munnel = 0.3
networkx = 2.1
networkx = 3.1
nt-svcutils = 2.13.0
numpy = 1.13.1
oauth2client = 4.0.0
oauthlib = 3.1.0
objgraph = 3.1.0
oic = 0.15.1
oic = 1.6.1
olefile = 0.44
openpyxl = 2.4.8
parso = 0.5.1
Pillow = 6.2.2
polib = 1.0.8
ordered-set = 4.1.0
Pillow = 10.2.0+SlapOSPatched001
polib = 1.2.0
pprofile = 2.0.4
Products.BTreeFolder2 = 4.4+SlapOSPatched001
Products.CMFCore = 2.7.0+SlapOSPatched001
Products.ExternalMethod = 4.7
Products.GenericSetup = 2.3.0
Products.MailHost = 4.13
Products.MimetypesRegistry = 2.1.8
Products.PluggableAuthService = 2.8.1
Products.PluginRegistry = 1.11
Products.PythonScripts = 4.15
Products.Sessions = 4.15
Products.SiteErrorLog = 5.7
Products.StandardCacheManagers = 4.2
Products.TIDStorage = 5.5.0
Products.ZODBMountPoint = 1.3
Products.ZSQLMethods = 3.16
pyasn1-modules = 0.0.8
Products.DCWorkflow = 3.0.0+SlapOSPatched001
Products.ExternalMethod = 5.0
Products.GenericSetup = 3.0.2
Products.MailHost = 5.2
Products.MimetypesRegistry = 3.0.1
Products.PluggableAuthService = 3.0
Products.PluginRegistry = 2.0
Products.PythonScripts = 5.0
Products.Sessions = 5.0
Products.SiteErrorLog = 6.0
Products.StandardCacheManagers = 5.0
Products.ZCatalog = 7.0
Products.ZODBMountPoint = 2.0
Products.ZSQLMethods = 4.1
protobuf = 4.25.3
pyasn1-modules = 0.3
pycountry = 17.1.8
pycrypto = 2.6.1
pycryptodomex = 3.10.1
pydantic-settings = 2.2.1:whl
pydot = 1.4.2
pyflakes = 1.5.0
pyjwkest = 1.4.2
Pympler = 0.4.3
pylint = 3.2.0:whl
Pympler = 1.0.1
pyPdf = 1.13
PyStemmer = 2.2.0.1
pytesseract = 0.2.2
python-barcode = 0.15.1:whl
python-dotenv = 1.0.1
python-gettext = 4.1
python-ldap = 3.4.4
python-libmilter = 1.0.3
python-memcached = 1.58
pytracemalloc = 1.2
PyWavelets = 0.5.2
pythran = 0.15.0:whl
PyWavelets = 1.4.0
qrcode = 5.3
Record = 4.1.0
responses = 0.10.6
rfc3987 = 1.3.8
rsa = 3.4.2
scikit-image = 0.14.0
scipy = 0.19.0
spyne = 2.12.14
scikit-image = 0.19.3
SOAPpy-py3 = 0.52.26+SlapOSPatched001
spyne = 2.14.0
strict-rfc3339 = 0.7
StructuredText = 2.11.1
suds = 0.4
suds-py3 = 1.4.5.0
tifffile = 2024.2.12
tomlkit = 0.12.4:whl
toolz = 0.9.0
typed-ast = 1.5.5
typing = 3.10.0.0
unidiff = 0.5.5
urlnorm = 1.1.4+SlapOSPatched001
uuid = 1.30
validictory = 1.1.0
webcolors = 1.10
webencodings = 0.5.1
WebOb = 1.8.5
WebTest = 2.0.33
wrapt = 1.16.0
WSGIProxy2 = 0.4.6
WSGIUtils = 0.7
wstools-py3 = 0.54.4
xfw = 0.10
xupdate-processor = 0.5
yapf = 0.28.0
......@@ -858,8 +882,127 @@ zope.authentication = 5.0
zope.error = 4.6
zope.minmax = 2.3
zope.password = 4.4
zope.sendmail = 6.1
zope.session = 4.5
zope.testbrowser = 5.5.1
[versions:python2]
AccessControl = 4.4
Acquisition = 4.13+SlapOSPatched001
APacheDEX = 1.8
astroid = 1.3.8+SlapOSPatched002
AuthEncoding = 4.3
Chameleon = 3.9.1
DateTime = 4.9+SlapOSPatched004
deepdiff = 3.3.0
DocumentTemplate = 3.4
ExtensionClass = 4.9
five.globalrequest = 99.1
five.localsitemanager = 3.4
interval = 1.0.0
ipython = 5.3.0
jedi = 0.15.1
Missing = 4.2
mock = 3.0.5
MultiMapping = 4.1
multipart = 0.1.1
networkx = 2.1
numpy = 1.13.1
ocropy = 1.0+SlapOSPatched001
oic = 0.15.1
openpyxl = 2.4.8
parso = 0.5.1
Paste = 3.5.2
PasteDeploy = 2.1.1
pbr = 5.11.0
Persistence = 3.6
Pillow = 6.2.2
Products.BTreeFolder2 = 4.4
Products.DCWorkflow = 2.4.1+SlapOSPatched001
Products.ExternalMethod = 4.7
Products.GenericSetup = 2.3.0
Products.MailHost = 4.13
Products.MimetypesRegistry = 2.1.8
Products.PluggableAuthService = 2.8.1
Products.PluginRegistry = 1.11
Products.PythonScripts = 4.15
Products.Sessions = 4.15
Products.SiteErrorLog = 5.7
Products.StandardCacheManagers = 4.2
Products.TIDStorage = 5.5.0
Products.ZCatalog = 5.4
Products.ZODBMountPoint = 1.3
Products.ZSQLMethods = 3.16
prompt-toolkit = 1.0.13
pyasn1-modules = 0.0.8
pylint = 1.4.4+SlapOSPatched002
Pympler = 0.4.3
PyStemmer = 1.3.0
python-ldap = 2.4.32+SlapOSPatched001
pytracemalloc = 1.2
pytz = 2022.7
PyWavelets = 0.5.2
Record = 3.6
RestrictedPython = 5.4+SlapOSPatched001
roman = 3.3
scikit-image = 0.14.0
scipy = 0.19.0
shutilwhich = 1.1.0
SOAPpy = 0.12.0nxd001
transaction = 3.0.1
waitress = 1.4.4+SlapOSPatched006
webcolors = 1.10
WebOb = 1.8.7
WebTest = 2.0.35
WSGIProxy2 = 0.4.6
z3c.pt = 3.3.1
zc.lockfile = 2.0
zdaemon = 4.4
zExceptions = 4.3
Zope = 4.8.9+SlapOSPatched002
zope.annotation = 4.8
zope.browser = 2.4
zope.browsermenu = 4.4
zope.browserpage = 4.4.0
zope.browserresource = 4.4
zope.cachedescriptors = 4.4
zope.component = 5.0.1
zope.componentvocabulary = 2.3.0
zope.configuration = 4.4.1
zope.container = 4.10
zope.contentprovider = 4.2.1
zope.contenttype = 4.6
zope.datetime = 4.3.0
zope.deferredimport = 4.4
zope.deprecation = 4.4.0
zope.dottedname = 4.3
zope.event = 4.6
zope.exceptions = 4.6
zope.filerepresentation = 5.0.0
zope.formlib = 5.0.1
zope.globalrequest = 1.6
zope.hookable = 5.4
zope.i18n = 4.9.0
zope.i18nmessageid = 5.1.1
zope.lifecycleevent = 4.4
zope.location = 4.3
zope.pagetemplate = 4.6.0
zope.processlifetime = 2.4
zope.proxy = 4.6.1
zope.ptresource = 4.3.0
zope.publisher = 6.1.0
zope.ramcache = 2.4
zope.schema = 6.2.1
zope.security = 5.8
zope.sendmail = 5.3
zope.sequencesort = 4.2
zope.site = 4.6.1
zope.size = 4.4
zope.structuredtext = 4.4
zope.tal = 4.5
zope.tales = 5.2
zope.testbrowser = 5.6.1
zope.traversing = 4.4.1
zope.viewlet = 4.3
ZServer = 4.0.2
......@@ -74,7 +74,7 @@ md5sum = ca0cb83950dd9079cc289891cce08e76
[template-erp5]
filename = instance-erp5.cfg.in
md5sum = edce1c63c13f0d8ec477711ea646444f
md5sum = d6f7d2fa1bde019892897c767f93e089
[template-zeo]
filename = instance-zeo.cfg.in
......@@ -86,11 +86,11 @@ md5sum = 0ac4b74436f554cd677f19275d18d880
[template-zope]
filename = instance-zope.cfg.in
md5sum = e94599e02c987ed5dfc26263a54ccc15
md5sum = 9547bacad0635b0f64cac48f15c4e9ae
[template-balancer]
filename = instance-balancer.cfg.in
md5sum = 727c6f045da382fe50916e6ea5ae6405
md5sum = 48b8b8b4b87973beaa1fd6299244ebd6
[template-haproxy-cfg]
filename = haproxy.cfg.in
......
......@@ -472,10 +472,9 @@ command = generate-apachedex-report
recipe = slapos.recipe.template
output = ${directory:etc}/${:_buildout_section_name_}
inline =
{% for line in slapparameter_dict['apachedex-configuration'] %}
{% for line in slapparameter_dict['apachedex-configuration'] -%}
{# apachedex config files use shlex.split, so we need to quote the arguments. #}
{# BBB: in python 3 we can use shlex.quote instead. #}
{{ repr(line.encode('utf-8')) }}
{{ six.moves.shlex_quote(line) }}
{% endfor %}
[apachedex-parameters]
......
......@@ -200,7 +200,7 @@ config-zodb-dict = {{ dumps(zodb_dict) }}
{% for server_type, server_dict in six.iteritems(storage_dict) -%}
{% if server_type == 'neo' -%}
config-neo-cluster = ${publish-early:neo-cluster}
config-neo-name = {{ server_dict.keys()[0] }}
config-neo-name = {{ list(server_dict.keys())[0] }}
config-neo-masters = ${publish-early:neo-masters}
{% else -%}
config-zodb-zeo = ${request-zodb:connection-storage-dict}
......
......@@ -80,6 +80,8 @@ environment +=
TZ={{ slapparameter_dict['timezone'] }}
MATPLOTLIBRC={{ parameter_dict['matplotlibrc'] }}
PYTHONUNBUFFERED=1
OFS_IMAGE_USE_DENYLIST=1
DISALLOWED_INLINE_MIMETYPES=
INSTANCE_HOME=${:instance-home}
FONTCONFIG_FILE=${fontconfig-conf:output}
JUPYTER_PATH=${directory:jupyter-dir}
......@@ -402,8 +404,8 @@ config-port = {{ '${' ~ zope_tunnel_section_name ~ ':ipv6-port}' }}
promise = check_error_on_zope_longrequest_log
name = {{'check-' ~ name ~ '-longrequest-error-log.py'}}
config-log-file = {{ '${' ~ conf_parameter_name ~ ':longrequest-logger-file}' }}
config-error-threshold = {{ slapparameter_dict["zope-longrequest-logger-error-threshold"] }}
config-maximum-delay = {{ slapparameter_dict["zope-longrequest-logger-maximum-delay"] }}
config-error-threshold = {{ dumps(slapparameter_dict["zope-longrequest-logger-error-threshold"]) }}
config-maximum-delay = {{ dumps(slapparameter_dict["zope-longrequest-logger-maximum-delay"]) }}
{% endif -%}
[{{ section('logrotate-entry-' ~ name) }}]
......
......@@ -2,150 +2,95 @@
# Version pins for required and commonly used dependencies.
[versions]
Zope = 4.8.9
Zope = 5.9
Zope2 = 4.0
# AccessControl 5+ no longer supports Zope 4.
AccessControl = 4.4
Acquisition = 4.13
AuthEncoding = 4.3
BTrees = 4.11.3
Chameleon = 3.10.2
DateTime = 4.9
DocumentTemplate = 4.1
ExtensionClass = 4.9
Missing = 4.2
MultiMapping = 4.1
Paste = 3.5.2
PasteDeploy = 3.0.1
Persistence = 3.6
Products.BTreeFolder2 = 4.4
# ZCatalog 6+ no longer supports Zope 4.
Products.ZCatalog = 5.4
Record = 3.6
# RestrictedPython >= 6 no longer supports Zope 4
RestrictedPython = 5.4
AccessControl = 6.3
Acquisition = 5.1
AuthEncoding = 5.0
BTrees = 5.1
Chameleon = 4.2.0
; DateTime = 5.3
DateTime = 5.5
DocumentTemplate = 4.6
ExtensionClass = 5.1
MultiMapping = 5.0
Paste = 3.7.1
PasteDeploy = 3.1.0
Persistence = 4.1
RestrictedPython = 7.0
WebTest = 3.0.0
WSGIProxy2 = 0.5.1
WebOb = 1.8.7
WebTest = 3.0.0
ZConfig = 3.6.1
ZEO = 5.3.0
ZODB = 5.8.0
five.globalrequest = 99.1
five.localsitemanager = 3.4
funcsigs = 1.0.2
future = 0.18.2
ipaddress = 1.0.23
mock = 4.0.3
ZConfig = 4.0
ZODB = 5.8.1
beautifulsoup4 = 4.12.2
cffi = 1.16.0
multipart = 0.2.4
pbr = 5.11.0
persistent = 4.9.3
pytz = 2022.7
roman = 3.3
shutilwhich = 1.1.0
persistent = 5.1
pycparser = 2.21
python-gettext = 5.0
pytz = 2023.3.post1
six = 1.16.0
transaction = 3.0.1
roman = 4.1
soupsieve = 2.5
transaction = 4.0
waitress = 2.1.2
z3c.pt = 3.3.1
zExceptions = 4.3
zc.lockfile = 2.0
zdaemon = 4.4
zodbpickle = 2.6
zope.annotation = 4.8
zope.browser = 2.4
zope.browsermenu = 4.4
zope.browserpage = 4.4.0
zope.browserresource = 4.4
zope.cachedescriptors = 4.4
zope.component = 5.0.1
zope.componentvocabulary = 2.3.0
zope.configuration = 4.4.1
zope.container = 5.1
zope.contentprovider = 4.2.1
zope.contenttype = 4.6
zope.datetime = 4.3.0
zope.deferredimport = 4.4
zope.deprecation = 4.4.0
zope.dottedname = 5.0
zope.event = 4.6
zope.exceptions = 4.6
zope.filerepresentation = 5.0.0
zope.formlib = 5.0.1
zope.globalrequest = 1.6
zope.hookable = 5.4
zope.i18n = 4.9.0
zope.i18nmessageid = 5.1.1
zope.interface = 5.5.2
zope.lifecycleevent = 4.4
zope.location = 4.3
zope.pagetemplate = 4.6.0
zope.processlifetime = 2.4
zope.proxy = 4.6.1
zope.ptresource = 4.3.0
zope.publisher = 6.1.0
zope.ramcache = 2.4
zope.schema = 6.2.1
zope.security = 5.8
zope.sendmail = 5.3
zope.sequencesort = 4.2
zope.site = 4.6.1
zope.size = 4.4
zope.structuredtext = 4.4
zope.tal = 4.5
zope.tales = 5.2
zope.testbrowser = 5.6.1
zope.testing = 4.10
zope.testrunner = 5.6
zope.traversing = 4.4.1
zope.viewlet = 4.3
[versions:python27]
# Chameleon 3.10 doesn't work on Python 2.7
Chameleon = 3.9.1
# DocumentTemplate 4+ requires Python 3.5 or higher
DocumentTemplate = 3.4
# PasteDeploy >3 requires Python 3.7
PasteDeploy = 2.1.1
# WSGIProxy 0.5 and up requires Python 3.7 and up
WSGIProxy2 = 0.4.6
# WebTest 3.0 and up requires Python 3.6 and up
WebTest = 2.0.35
# ZServer is only available for Python 2
ZServer = 4.0.2
# mock 4.0 and up requires Python 3.6 or higher
mock = 3.0.5
# multipart 0.2 and up requires Python 3
multipart = 0.1.1
# waitress 2 requires Python 3.6 or higher
waitress = 1.4.4
# zope.dottedname >= 5 requires Python 3.6 or higher
zope.dottedname = 4.3
# zope.container 5.x requires Python 3.7 or higher
zope.container = 4.10
z3c.pt = 4.0
zExceptions = 5.0
zc.lockfile = 3.0.post1
zc.recipe.egg = 2.0.7
zodbpickle = 3.1
zope.annotation = 5.0
zope.browser = 3.0
zope.browsermenu = 5.0
zope.browserpage = 5.0
zope.browserresource = 5.1
zope.cachedescriptors = 5.0
zope.component = 6.0
zope.configuration = 5.0
zope.container = 5.2
zope.contentprovider = 5.0
zope.contenttype = 5.1
zope.datetime = 5.0.0
zope.deferredimport = 5.0
zope.deprecation = 5.0
zope.dottedname = 6.0
zope.event = 5.0
zope.exceptions = 5.0.1
zope.filerepresentation = 6.0
zope.globalrequest = 2.0
zope.hookable = 6.0
zope.i18n = 5.1
zope.i18nmessageid = 6.1.0
zope.interface = 6.1
zope.lifecycleevent = 5.0
zope.location = 5.0
zope.pagetemplate = 5.0
zope.processlifetime = 3.0
zope.proxy = 5.1
zope.ptresource = 5.0
zope.publisher = 7.0
zope.schema = 7.0.1
zope.security = 6.2
zope.sequencesort = 5.0
zope.site = 5.0
zope.size = 5.0
zope.structuredtext = 5.0
zope.tal = 5.0.1
zope.tales = 6.0
zope.testbrowser = 6.0
zope.testing = 5.0.1
zope.traversing = 5.0
zope.viewlet = 5.0
[versions:python35]
# DocumentTemplate 4+ cannot be installed on Zope 4 for Python 3.5
DocumentTemplate = 3.4
# PasteDeploy >3 requires Python 3.7
PasteDeploy = 2.1.1
# WSGIProxy 0.5 and up requires Python 3.7 and up
WSGIProxy2 = 0.4.6
# WebTest 3.0 and up requires Python 3.6 and up
WebTest = 2.0.35
# mock 4.0 and up requires Python 3.6 or higher
mock = 3.0.5
# waitress 2 requires Python 3.6 or higher
waitress = 1.4.4
# zope.dottedname >= 5 requires Python 3.6 or higher
zope.dottedname = 4.3
# zope.container 5.x requires Python 3.7 or higher
zope.container = 4.10
[versions:python36]
# PasteDeploy >3 requires Python 3.7
PasteDeploy = 2.1.1
# WSGIProxy 0.5 and up requires Python 3.7 and up
WSGIProxy2 = 0.4.6
# waitress 2.1 requires Python 3.7 or higher
waitress = 2.0.0
# zope.container 5.x requires Python 3.7 or higher
zope.container = 4.10
# XXX this is commented out because slapos.buildout is based on a too old buildout
# which does not understands :python37 yet. We target a more recent python version
# so we don't use these versions.
# [versions:python37]
# # PasteDeploy 3.x works on Python 3.7 but pulls tons of dependencies
# PasteDeploy = 2.1.1
# # SoupSieve 2.5 and up requires Python 3.8
# soupsieve = 2.4.1
# # cffi 1.16.0 requires Python 3.8
# cffi = 1.15.1
......@@ -393,9 +393,9 @@ zipp = 3.12.0:whl
zodburi = 2.5.0
zope.event = 4.6.0
zope.exceptions = 4.6
zope.interface = 5.4.0
zope.testing = 4.7
zope.testrunner = 5.2
zope.interface = 5.5.2
zope.testing = 4.10
zope.testrunner = 5.6
[versions:sys.version_info < (3,10)]
# keep old statsmodels by default until slapos.toolbox is updated
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment