From 53be77b5b9becb7b8f2fb3977acb7de98fea9200 Mon Sep 17 00:00:00 2001 From: Helmut Merz Date: Tue, 24 Sep 2024 19:23:54 +0200 Subject: [PATCH] work in progress: Python3 fixes --- loops/README.txt | 20 +++++++++--------- loops/browser/form.py | 31 +++++++--------------------- loops/browser/resource.py | 36 +++++++++------------------------ loops/common.py | 16 +++++++-------- loops/psu.py | 32 ++++++++++++++--------------- loops/query.py | 31 ++++++---------------------- loops/repair/base.py | 31 +++++++--------------------- loops/security/browser/admin.py | 36 +++++++++------------------------ loops/util.py | 2 +- pyproject.toml | 1 + 10 files changed, 74 insertions(+), 162 deletions(-) diff --git a/loops/README.txt b/loops/README.txt index 3dc888c..f47ed36 100755 --- a/loops/README.txt +++ b/loops/README.txt @@ -444,13 +444,13 @@ Node Views >>> page = view.page >>> items = page.textItems >>> for item in items: - ... print item.url, item.editable + ... print(item.url, item.editable) http://127.0.0.1/loops/views/m1/m11/m112 False >>> menu = view.menu >>> items = menu.menuItems >>> for item in items: - ... print item.url, view.selected(item) + ... print(item.url, view.selected(item)) http://127.0.0.1/loops/views/m1/m11 True A NodeView provides an itemNum attribute that may be used to count elements @@ -796,7 +796,7 @@ that in turns calls formlibs ``setUpWidgets()``. The new technique uses the ``fields`` and ``data`` attributes... >>> for f in view.fields: - ... print f.name, f.fieldType, f.required, f.vocabulary + ... print(f.name, f.fieldType, f.required, f.vocabulary) title textline True None data textarea False None contentType dropdown True <...SimpleVocabulary object...> @@ -804,8 +804,8 @@ The new technique uses the ``fields`` and ``data`` attributes... linkText textline False None >>> view.data - {'linkUrl': 'http://', 'contentType': 'text/restructured', 'data': '', - 'linkText': '', 'title': 'Test Note'} + {'title': 'Test Note', 'data': '', 'contentType': 'text/restructured', + 'linkUrl': 'http://', 'linkText': ''} The object is changed via a FormController adapter created for a NodeView. @@ -883,13 +883,13 @@ informations about all parents of an object. >>> parents = m113.getAllParents() >>> for p in parents: - ... print p.object.title + ... print(p.object.title) Zope Menu >>> parents = resources['test_note'].getAllParents() >>> for p in parents: - ... print p.object.title, len(p.relations) + ... print(p.object.title, len(p.relations)) Note 1 Type 2 @@ -916,10 +916,10 @@ relates ISO country codes with the full name of the country. [('at', ['Austria']), ('de', ['Germany'])] >>> countries.dataAsRecords() - [{'value': 'Austria', 'key': 'at'}, {'value': 'Germany', 'key': 'de'}] + [{'key': 'at', 'value': 'Austria'}, {'key': 'de', 'value': 'Germany'}] >>> countries.getRowsByValue('value', 'Germany') - [{'value': 'Germany', 'key': 'de'}] + [{'key': 'de', 'value': 'Germany'}] The ``recordstable`` type is a variation of this datable type that contains a simple list of records - without a key column. A record in this type is a @@ -939,7 +939,7 @@ We just reuse the existing ``countries`` table and convert it to a records table >>> countries = adapted(concepts['countries']) >>> countries.data - [{'value': 'Austria', 'key': 'at'}, {'value': 'Germany', 'key': 'de'}] + [{'key': 'at', 'value': 'Austria'}, {'key': 'de', 'value': 'Germany'}] Caching diff --git a/loops/browser/form.py b/loops/browser/form.py index da608b0..eacc61d 100755 --- a/loops/browser/form.py +++ b/loops/browser/form.py @@ -1,35 +1,18 @@ -# -# Copyright (c) 2017 Helmut Merz helmutm@cy55.de -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -# +# loops.browser.form -""" -Classes for form presentation and processing. +""" Classes for form presentation and processing. """ -from urllib import urlencode, unquote_plus -from zope.app.container.contained import ObjectRemovedEvent +from urllib.parse import urlencode, unquote_plus from zope import component, interface, schema from zope.component import adapts +from zope.container.contained import ObjectRemovedEvent from zope.event import notify from zope.interface import Interface from zope.lifecycleevent import ObjectCreatedEvent, ObjectModifiedEvent -from zope.app.container.interfaces import INameChooser -from zope.app.container.contained import ObjectAddedEvent -from zope.app.pagetemplate import ViewPageTemplateFile +from zope.container.interfaces import INameChooser +from zope.lifecycleevent import ObjectAddedEvent +from zope.browserpage import ViewPageTemplateFile from zope.cachedescriptors.property import Lazy from zope.contenttype import guess_content_type from zope.publisher.browser import FileUpload diff --git a/loops/browser/resource.py b/loops/browser/resource.py index 323d92b..9802312 100644 --- a/loops/browser/resource.py +++ b/loops/browser/resource.py @@ -1,36 +1,18 @@ -# -# Copyright (c) 2015 Helmut Merz helmutm@cy55.de -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -# +# loops.browser.resource -""" -View class for resource objects. +""" View class for resource objects. """ import os.path -import urllib +from zope.authentication.interfaces import IUnauthenticatedPrincipal +from zope.browserpagge import ViewPageTemplateFile from zope.cachedescriptors.property import Lazy from zope import component -from zope.app.catalog.interfaces import ICatalog -from zope.app.container.interfaces import INameChooser -from zope.app.form.browser.textwidgets import FileWidget -from zope.app.pagetemplate import ViewPageTemplateFile -from zope.app.security.interfaces import IUnauthenticatedPrincipal +from zope.catalog.interfaces import ICatalog +from zope.container.interfaces import INameChooser from zope.formlib.form import FormFields from zope.formlib.interfaces import DISPLAY_UNWRITEABLE +from zope.formlib.textwidgets import FileWidget from zope.proxy import removeAllProxies from zope.schema.interfaces import IBytes from zope.security import canAccess, canWrite @@ -272,7 +254,7 @@ class ResourceView(BaseView): #wp = wiki.createPage(getName(self.context)) wp = wiki.addPage(LoopsWikiPage(self.context)) wp.text = text - #print wp.wiki.getManager() + #print(wp.wiki.getManager()) #return util.toUnicode(wp.render(self.request)) return super(ResourceView, self).renderText(text, contentType) @@ -467,7 +449,7 @@ class ExternalEditorView(ExternalEditorView, BaseView): r.append('meta_type:' + '.'.join((context.__module__, context.__class__.__name__))) auth = self.request.get('_auth') if auth: - print 'ExternalEditorView: auth = ', auth + print('ExternalEditorView: auth = ', auth) if auth.endswith('\n'): auth = auth[:-1] r.append('auth:' + auth) diff --git a/loops/common.py b/loops/common.py index a1dbbe0..8841b72 100644 --- a/loops/common.py +++ b/loops/common.py @@ -233,12 +233,12 @@ def generateNameFromTitle(title): def normalizeName(baseName): specialCharacters = { - '\xc4': 'Ae', '\xe4': 'ae', '\xd6': 'Oe', '\xf6': 'oe', - '\xdc': 'Ue', '\xfc': 'ue', '\xdf': 'ss'} + b'\xc4': 'Ae', b'\xe4': 'ae', b'\xd6': 'Oe', b'\xf6': 'oe', + b'\xdc': 'Ue', b'\xfc': 'ue', b'\xdf': 'ss'} result = [] for c in baseName: try: - c = c.encode('ISO8859-15') + x = c.encode('ISO8859-15') except UnicodeEncodeError: # replace all characters not representable in ISO encoding result.append('_') @@ -250,13 +250,13 @@ def normalizeName(baseName): # separator and special characters to keep result.append(c) continue - if c in specialCharacters: + if x in specialCharacters: # transform umlauts and other special characters - result.append(specialCharacters[c].lower()) + result.append(specialCharacters[x].lower()) continue - if ord(c) > 127: + if ord(x) > 127: # map to ASCII characters - c = chr(ord(c) & 127) + c = chr(ord(x) & 127).decode('ISO8859-15') if c in ':,/\\ ': # replace separator characters with _ result.append('_') @@ -265,7 +265,7 @@ def normalizeName(baseName): continue else: result.append(c.lower()) - name = unicode(''.join(result)) + name = ''.join(result) return name diff --git a/loops/psu.py b/loops/psu.py index d983010..62552a0 100644 --- a/loops/psu.py +++ b/loops/psu.py @@ -13,17 +13,17 @@ import os from transaction import commit, abort -from zope.app.authentication.principalfolder import Principal -from zope.app.component.hooks import setSite -from zope.app.container.contained import ObjectAddedEvent, ObjectRemovedEvent from zope.cachedescriptors.property import Lazy from zope.catalog.interfaces import ICatalog -from zope.copypastemove.interfaces import IContainerItemRenamer from zope import component +from zope.component.hooks import setSite +from zope.container.contained import ObjectAddedEvent, ObjectRemovedEvent +from zope.copypastemove.interfaces import IContainerItemRenamer from zope.event import notify from zope.exceptions.interfaces import DuplicationError from zope.lifecycleevent import ObjectCreatedEvent, ObjectModifiedEvent from zope.publisher.browser import TestRequest as BaseTestRequest +from zope.pluggableauth.factories import Principal from zope.security.management import getInteraction, newInteraction, endInteraction from zope.interface import Interface @@ -83,7 +83,7 @@ def notifyRemoved(obj): def delete(container, name, docommit=True): obj = container.get(name) if obj is None: - print '*** Object', name, 'not found!' + print('*** Object', name, 'not found!') return notifyRemoved(obj) del container[name] @@ -93,14 +93,14 @@ def delete(container, name, docommit=True): def rename(container, old, new, docommit=True): obj = container.get(old) if obj is None: - print '*** Object', old, 'not found!' + print('*** Object', old, 'not found!') return renamer = IContainerItemRenamer(container) if new != old: try: renamer.renameItem(old, new) except DuplicationError: - print '*** Object', new, 'already exists!' + print('*** Object', new, 'already exists!') # container[new] = obj # notifyAdded(obj) notifyModification(obj) @@ -110,7 +110,7 @@ def rename(container, old, new, docommit=True): def move(source, target, name): obj = source.get(name) if obj is None: - print '*** Object', name, 'not found!' + print('*** Object', name, 'not found!') return #notifyRemoved(obj) #del source[name] @@ -124,14 +124,14 @@ def get(container, obj): name = obj obj = container.get(name) if obj is None: - print '*** Object', name, 'not found!' + print('*** Object', name, 'not found!') return None return adapted(obj) # startup, loop, finish... def startup(msg, **kw): - print '***', msg + print('***', msg) step = kw.pop('step', 10) return Jeep(count=0, step=step, message=msg, **kw) @@ -148,20 +148,20 @@ def update(fct, obj, info): objInfo = obj.context.__name__ except: objInfo = obj - print '*** Processing object # %i: %s' % (info.count, objInfo) + print('*** Processing object # %i: %s' % (info.count, objInfo)) if info.get('updated'): - print '*** updated: %i.' % info.updated + print('*** updated: %i.' % info.updated) if info.get('errors'): - print '*** errors: %i.' % info.error + print('*** errors: %i.' % info.error) commit() return fct(obj, info) def finish(info): - print '*** count: %i.' % info.count + print('*** count: %i.' % info.count) if info.get('updated'): - print '*** updated: %i.' % info.updated + print('*** updated: %i.' % info.updated) if info.get('errors'): - print '*** errors: %i.' % info.error + print('*** errors: %i.' % info.error) commit() def stop_condition(info): diff --git a/loops/query.py b/loops/query.py index 486eb7d..92750d4 100644 --- a/loops/query.py +++ b/loops/query.py @@ -1,31 +1,14 @@ -# -# Copyright (c) 2013 Helmut Merz helmutm@cy55.de -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -# +# loops.query -""" -Query management stuff. +""" Query management stuff. """ from BTrees.IOBTree import IOBTree from BTrees.IFBTree import weightedIntersection, weightedUnion, IFBucket from zope import schema, component -from zope.interface import Interface, Attribute, implements -from zope.app.catalog.interfaces import ICatalog +from zope.interface import Interface, Attribute, implementer from zope.cachedescriptors.property import Lazy +from zope.catalog.interfaces import ICatalog from zope.intid.interfaces import IIntIds from cybertools.typology.interfaces import IType @@ -58,10 +41,9 @@ class IQuery(Interface): """ +@implementer(IQuery) class BaseQuery(object): - implements(IQuery) - def __init__(self, context): self.context = context @@ -194,10 +176,9 @@ class IQueryConcept(IConceptSchema, ILoopsAdapter, IOptions): required=False) +@implementer(IQueryConcept) class QueryConcept(AdapterBase): - implements(IQueryConcept) - _contextAttributes = AdapterBase._contextAttributes + ['viewName'] _adapterAttributes = AdapterBase._adapterAttributes + ('options',) diff --git a/loops/repair/base.py b/loops/repair/base.py index 9988e21..94456ad 100644 --- a/loops/repair/base.py +++ b/loops/repair/base.py @@ -1,23 +1,6 @@ -# -# Copyright (c) 2016 Helmut Merz helmutm@cy55.de -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -# +# loops.repair.base -""" -Basic stuff for database fixes. +""" Basic stuff for database fixes. """ import os @@ -33,7 +16,7 @@ os.environ['NLS_LANG'] = 'German_Germany.UTF8' # start, loop, finish... def startup(msg, **kw): - print '***', msg + print('***', msg) step = kw.pop('step', 10) return Jeep(count=0, step=step, message=msg, **kw) @@ -50,16 +33,16 @@ def update(fct, obj, info): objInfo = obj.context.__name__ except: objInfo = obj - print '*** Processing object # %i: %s.' % (info.count, objInfo) + print( '*** Processing object # %i: %s.' % (info.count, objInfo)) if info.get('updated'): - print '*** updated: %i.' % info.updated + print('*** updated: %i.' % info.updated) psu.commit() return fct(obj, info) def finish(info): - print '*** count: %i.' % info.count + print('*** count: %i.' % info.count) if info.get('updated'): - print '*** updated: %i.' % info.updated + print('*** updated: %i.' % info.updated) psu.commit() def stop_condition(info): diff --git a/loops/security/browser/admin.py b/loops/security/browser/admin.py index d4e020c..56a307e 100644 --- a/loops/security/browser/admin.py +++ b/loops/security/browser/admin.py @@ -1,37 +1,19 @@ -# -# Copyright (c) 2013 Helmut Merz helmutm@cy55.de -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -# +# loops.security.browser.admin -""" -Security-related views. +""" Security-related views. """ -from zope.app.authentication.groupfolder import GroupInformation -from zope.app.pagetemplate import ViewPageTemplateFile -from zope.app.security.interfaces import IPermission -from zope.app.security.settings import Allow, Deny, Unset -from zope.app.securitypolicy.browser import granting -from zope.app.securitypolicy.browser.rolepermissionview import RolePermissionView +from zope.app.authentication.browser import granting +from zope.app.authentication.browser.rolepermissionview import RolePermissionView +from zope.browserpage import ViewPageTemplateFile +from zope.cachedescriptors.property import Lazy from zope import component from zope.event import notify -from zope.interface import implements -from zope.cachedescriptors.property import Lazy from zope.lifecycleevent import ObjectCreatedEvent, ObjectModifiedEvent +from zope.pluggableauth.plugins.groupfolder import GroupInformation +from zope.security.interfaces import IPermission from zope.security.proxy import removeSecurityProxy +from zope.securitypolicy.settings import Allow, Deny, Unset from zope.securitypolicy.interfaces import IPrincipalRoleManager, \ IRolePermissionMap from zope.securitypolicy.interfaces import IPrincipalPermissionManager, \ diff --git a/loops/util.py b/loops/util.py index 449a485..11e08ef 100644 --- a/loops/util.py +++ b/loops/util.py @@ -175,7 +175,7 @@ def getMigratedItem(uid, storage): def getObjectForUid(uid, intIds=None): if uid == '*': # wild card return '*' - if isinstance(uid, basestring) and not uid.isdigit(): # not a valid uid + if isinstance(uid, str) and not uid.isdigit(): # not a valid uid return None if intIds is None: intIds = component.getUtility(IIntIds) diff --git a/pyproject.toml b/pyproject.toml index b37610d..379d977 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,6 +17,7 @@ dependencies = [ "markdown", "python-dotenv", "zope.app.renderer", + "zope.app.authentication", "zope.browsermenu", "zope.i18n", "zope.pluggableauth",