From f1080df88b1dcdbfbea5cf76964464612810330a Mon Sep 17 00:00:00 2001 From: Helmut Merz Date: Sat, 28 Sep 2024 11:42:20 +0200 Subject: [PATCH] use zope-testrunner for running all relevant tests => more Python3 fixes --- cybertools/composer/layout/README.txt | 2 +- .../composer/layout/browser/liquid/default.py | 24 +------ cybertools/composer/layout/browser/view.py | 22 +----- cybertools/composer/message/README.txt | 10 ++- cybertools/composer/schema/README.txt | 68 +++++++++---------- cybertools/composer/schema/grid/field.py | 9 +-- cybertools/knowledge/survey/README.txt | 14 ++-- cybertools/knowledge/survey/questionnaire.py | 2 +- cybertools/plugin/testing/load.py | 6 ++ pyproject.toml | 8 +-- runtests.sh | 31 +++++++++ 11 files changed, 98 insertions(+), 98 deletions(-) create mode 100644 cybertools/plugin/testing/load.py create mode 100755 runtests.sh diff --git a/cybertools/composer/layout/README.txt b/cybertools/composer/layout/README.txt index 96e376c..a13843e 100644 --- a/cybertools/composer/layout/README.txt +++ b/cybertools/composer/layout/README.txt @@ -47,4 +47,4 @@ Browser Views >>> page = Page(Document(), TestRequest()) >>> page() - u'.........' + '.........' diff --git a/cybertools/composer/layout/browser/liquid/default.py b/cybertools/composer/layout/browser/liquid/default.py index dd1b7d4..040eb10 100644 --- a/cybertools/composer/layout/browser/liquid/default.py +++ b/cybertools/composer/layout/browser/liquid/default.py @@ -1,31 +1,11 @@ -# -# Copyright (c) 2008 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.composer.layout.browser.liquid.default -""" -Default layouts for the liquid skin. - -$Id$ +""" Default layouts for the liquid skin. """ from zope.app.pagetemplate import ViewPageTemplateFile from zope.cachedescriptors.property import Lazy from zope import component -from zope.interface import implements from cybertools.browser.liquid import Liquid from cybertools.browser.renderer import RendererFactory diff --git a/cybertools/composer/layout/browser/view.py b/cybertools/composer/layout/browser/view.py index 9f30da2..2862878 100644 --- a/cybertools/composer/layout/browser/view.py +++ b/cybertools/composer/layout/browser/view.py @@ -1,27 +1,9 @@ -# -# 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.composer.layout.browser.view -""" -Basic view classes for layout-based presentation. +""" Basic view classes for layout-based presentation. """ from zope import component -from zope.interface import Interface, implements from zope.cachedescriptors.property import Lazy from zope.app.pagetemplate import ViewPageTemplateFile from zope.app.security.interfaces import IUnauthenticatedPrincipal diff --git a/cybertools/composer/message/README.txt b/cybertools/composer/message/README.txt index 3af7478..37f006d 100644 --- a/cybertools/composer/message/README.txt +++ b/cybertools/composer/message/README.txt @@ -2,8 +2,6 @@ Message Management ================== - ($Id$) - >>> from zope import component >>> from cybertools.composer.message.base import MessageManager, Message @@ -25,11 +23,11 @@ Message interpolation >>> from cybertools.composer.message.instance import MessageTemplate >>> t = MessageTemplate(messageText) - >>> print t.safe_substitute({ + >>> print(t.safe_substitute({ ... 'person.firstname': 'John', 'person.lastname': 'Smith', ... '@@list_registrations_text': '0815: Python Introduction', ... 'services': 'events', - ... 'footer': 'Regards, $sender'}) + ... 'footer': 'Regards, $sender'})) Dear John Smith, You have been registered for the following events. 0815: Python Introduction @@ -42,11 +40,11 @@ Working with message instances >>> from cybertools.composer.message.instance import MessageInstance >>> mi = MessageInstance(None, manager.messages['feedback_text'], manager) >>> for key, value in mi.applyTemplate().items(): - ... print key + ':', value + ... print(key + ':', value) url: + subjectLine: text: Dear $person.firstname $person.lastname, You have been registered for the following events. $@@list_registrations_text Best regards, Jack - subjectLine: diff --git a/cybertools/composer/schema/README.txt b/cybertools/composer/schema/README.txt index 96b84cd..119efb7 100644 --- a/cybertools/composer/schema/README.txt +++ b/cybertools/composer/schema/README.txt @@ -12,11 +12,11 @@ Working with predefined schemas We start with setting up a schema with fields. >>> serviceSchema = Schema( - ... Field(u'title', renderFactory=None), - ... Field(u'description'), - ... Field(u'start'), - ... Field(u'end'), - ... Field(u'capacity'), + ... Field('title', renderFactory=None), + ... Field('description'), + ... Field('start'), + ... Field('end'), + ... Field('capacity'), ... ) For using a schema we need some class that we can use for creating @@ -42,7 +42,7 @@ correct conversion of input data to context attributes. <...FormState object ...> >>> srv.title, srv.description, srv.capacity - (u'Service', u'', u'30') + ('Service', '', '30') Field types ----------- @@ -62,7 +62,7 @@ Field types Dynamic default values ---------------------- - >>> idField = Field(u'id', default='user/title|string:???', defaultValueType='tales') + >>> idField = Field('id', default='user/title|string:???', defaultValueType='tales') >>> idField.getDefaultValue() '???' @@ -70,27 +70,27 @@ Dynamic default values Creating a schema from an interface =================================== - >>> from zope.interface import Interface, implements + >>> from zope.interface import Interface, implementer >>> import zope.schema >>> from cybertools.composer.schema.factory import SchemaFactory >>> component.provideAdapter(SchemaFactory) >>> class IPerson(Interface): - ... firstName = zope.schema.TextLine(title=u'First name') - ... lastName = zope.schema.TextLine(title=u'Last name') - ... age = zope.schema.Int(title=u'Age') + ... firstName = zope.schema.TextLine(title='First name') + ... lastName = zope.schema.TextLine(title='Last name') + ... age = zope.schema.Int(title='Age') >>> class Person(object): - ... implements(IPerson) - ... def __init__(self, firstName=u'', lastName=u'', age=None): + ... def __init__(self, firstName='', lastName='', age=None): ... self.firstName, self.lastName, self.age = firstName, lastName, age + >>> Person = implementer(IPerson)(Person) >>> from cybertools.composer.schema.interfaces import ISchemaFactory >>> factory = ISchemaFactory(Person()) >>> schema = factory(IPerson) >>> for f in schema.fields: - ... print f.name, f.title, f.fieldType + ... print(f.name, f.title, f.fieldType) firstName First name textline lastName Last name textline age Age number @@ -109,7 +109,7 @@ Using a more specialized schema factory >>> factory = ISchemaFactory(Person()) >>> schema = factory(IPerson) >>> for f in schema.fields: - ... print f.name, f.title, f.fieldType + ... print(f.name, f.title, f.fieldType) lastName Last name textline age Age number @@ -128,9 +128,9 @@ context object. >>> component.provideAdapter(NumberFieldInstance, name='number') >>> from cybertools.composer.schema.instance import Instance - >>> component.provideAdapter(Instance) + >>> component.provideAdapter(Instance, adapts=(IPerson,)) - >>> person = Person(u'John', u'Miller', 33) + >>> person = Person('John', 'Miller', 33) Note that the first name is not shown as we excluded it via the schema factory above. The age field is a number, but is shown here as a @@ -140,7 +140,7 @@ data suitable for showing on an HTML form. >>> form = Form(person, TestRequest()) >>> form.interface = IPerson >>> form.data - {'lastName': u'Miller', 'age': '33'} + {'lastName': 'Miller', 'age': '33'} For editing we have to provide another instance adapter. @@ -165,7 +165,7 @@ Create a new object using a schema-based form >>> from cybertools.composer.schema.browser.form import CreateForm >>> container = dict() - >>> input = dict(lastName=u'Smith', age='28', action='update') + >>> input = dict(lastName='Smith', age='28', action='update') >>> form = CreateForm(container, TestRequest(form=input)) >>> form.interface = IPerson >>> form.factory = Person @@ -174,23 +174,23 @@ Create a new object using a schema-based form >>> form.getName = lambda x: x.lastName.lower() >>> form.data - {'lastName': u'Smith', 'age': '28'} + {'lastName': 'Smith', 'age': '28'} >>> form.update() False >>> p2 = container['smith'] >>> p2.lastName, p2.age - (u'Smith', 28) + ('Smith', 28) Macros / renderers ------------------ >>> fieldRenderers = form.fieldRenderers >>> sorted(fieldRenderers.keys()) - [u'field', u'field_spacer', u'fields', u'form', u'input_checkbox', - u'input_date', u'input_dropdown', u'input_fileupload', u'input_html', - u'input_list', u'input_password', u'input_textarea', u'input_textline'] + ['field', 'field_spacer', 'fields', 'form', 'input_checkbox', + 'input_date', 'input_dropdown', 'input_fileupload', 'input_html', + 'input_list', 'input_password', 'input_textarea', 'input_textline'] Special Field Types @@ -202,15 +202,15 @@ Grids, Records, Key Tables >>> from cybertools.composer.schema.grid.field import KeyTableFieldInstance >>> ktfield = Field('data') - >>> ktfield.column_types = [zope.schema.Text(__name__='key', title=u'Key',), - ... zope.schema.Text(__name__='value', title=u'Value')] + >>> ktfield.column_types = [zope.schema.Text(__name__='key', title='Key',), + ... zope.schema.Text(__name__='value', title='Value')] >>> ktfi = KeyTableFieldInstance(ktfield) >>> ktfi.unmarshall([dict(key='0001', value='First row')]) - {u'0001': [u'First row']} + {'0001': ['First row']} - >>> ktfi.marshall({u'0001': [u'First row']}) - [{'value': u'First row', 'key': u'0001'}] + >>> ktfi.marshall({'0001': ['First row']}) + [{'key': '0001', 'value': 'First row'}] Now with some real stuff, using a field instance that takes the column types from the context object of the edit form. @@ -221,16 +221,16 @@ from the context object of the edit form. >>> component.provideAdapter(ContextBasedKeyTableFieldInstance, name='keytable') >>> class IDataTable(Interface): - ... title = zope.schema.TextLine(title=u'Title', required=False) - ... columnNames = zope.schema.List(title=u'Column Names', required=False) - ... data = KeyTable(title=u'Data', required=False) + ... title = zope.schema.TextLine(title='Title', required=False) + ... columnNames = zope.schema.List(title='Column Names', required=False) + ... data = KeyTable(title='Data', required=False) >>> IDataTable['columnNames'].nostore = True >>> class DataTable(object): - ... implements(IDataTable) ... def __init__(self, title, columnNames): ... self.title = title ... self.columnNames = columnNames + >>> DataTable = implementer(IDataTable)(DataTable) >>> dt = DataTable('Account Types', ['identifier', 'label', 'info']) @@ -245,4 +245,4 @@ from the context object of the edit form. False >>> dt.data - {u'0001': [u'Standard', u'']} + {'0001': ['Standard', '']} diff --git a/cybertools/composer/schema/grid/field.py b/cybertools/composer/schema/grid/field.py index 6d98529..1310e7e 100644 --- a/cybertools/composer/schema/grid/field.py +++ b/cybertools/composer/schema/grid/field.py @@ -66,13 +66,13 @@ class GridFieldInstance(ListFieldInstance): return result def marshall(self, value): - if isinstance(value, basestring): + if isinstance(value, str): return value v = value or [] for row in v: for fi in self.columnFieldInstances: vr = fi.marshall(row[fi.name]) - if isinstance(vr, basestring): + if isinstance(vr, str): row[fi.name] = vr.replace('\n', '\\n').replace('"', '\\"') empty = {} for fi in self.columnFieldInstances: @@ -136,9 +136,10 @@ class GridFieldInstance(ListFieldInstance): if idx is not None: fi.index = idx value = fi.unmarshall(row.get(fi.name) or u'') - if isinstance(value, basestring): + if isinstance(value, str): value = value.strip() - if idx < cardinality: + #if idx < cardinality: + if cardinality is not None and (idx is None or idx < cardinality): item[fi.name] = value else: if fi.default is not None: diff --git a/cybertools/knowledge/survey/README.txt b/cybertools/knowledge/survey/README.txt index 44da8f7..a7fd3c0 100644 --- a/cybertools/knowledge/survey/README.txt +++ b/cybertools/knowledge/survey/README.txt @@ -48,16 +48,16 @@ Now let's calculate the result for resp01. >>> res = resp01.getResult() >>> for fi, score in res: - ... print fi.text, score + ... print(fi.text, score) fi03 4.1 fi01 2.7 fi02 0.7 >>> res = resp02.getResult() >>> for fi, score in res: - ... print fi.text, score + ... print(fi.text, score) fi03 4.0 - fi01 2.4 + fi01 2.4... Grouped feedback items ---------------------- @@ -70,12 +70,12 @@ Grouped feedback items >>> res = resp01.getGroupedResult() >>> for r in res: - ... print r['feedback'].text, round(r['score'], 2), r['rank'] + ... print(r['feedback'].text, round(r['score'], 2), r['rank']) fi02 0.58 1 >>> res = resp02.getGroupedResult() >>> for r in res: - ... print r['feedback'].text, round(r['score'], 2), r['rank'] + ... print(r['feedback'].text, round(r['score'], 2), r['rank']) fi03 0.75 1 Team evaluation @@ -89,5 +89,7 @@ Team evaluation >>> teamData = resp01.getTeamResult([qugroup], [resp01, resp03]) >>> teamData - [{'average': 0.6666...}] + [{'group': ...}] + +[{'average': 0.6666...}] diff --git a/cybertools/knowledge/survey/questionnaire.py b/cybertools/knowledge/survey/questionnaire.py index 6e4b0d2..f6ea0bd 100644 --- a/cybertools/knowledge/survey/questionnaire.py +++ b/cybertools/knowledge/survey/questionnaire.py @@ -82,7 +82,7 @@ class Response(object): if qu.questionType not in (None, 'value_selection'): continue value = self.values.get(qu) - if value is None or isinstance(value, basestring): + if value is None or isinstance(value, str): continue answerRange = (qu.answerRange or self.questionnaire.defaultAnswerRange) diff --git a/cybertools/plugin/testing/load.py b/cybertools/plugin/testing/load.py new file mode 100644 index 0000000..81bba47 --- /dev/null +++ b/cybertools/plugin/testing/load.py @@ -0,0 +1,6 @@ + +from cybertools.plugin.manage import loadModules + +from cybertools.plugin.testing import mod1 +loadModules(mod1) + diff --git a/pyproject.toml b/pyproject.toml index 6db949f..4caab43 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -40,13 +40,13 @@ dependencies = [ ] [project.optional-dependencies] -test = ["pytest"] +test = ["zope.testrunner"] [tool.setuptools] packages = ["cybertools"] -[tool.pytest.ini_options] -addopts = "-vv" -python_files = "test_standard.py" # default: run only `standard` tests +#[tool.pytest.ini_options] +#addopts = "-vv" +#python_files = "test_standard.py" # default: run only `standard` tests # use .pytest.ini file with `python_files = test_*.py` to run all tests diff --git a/runtests.sh b/runtests.sh new file mode 100755 index 0000000..da7affd --- /dev/null +++ b/runtests.sh @@ -0,0 +1,31 @@ +# runtests.sh +# run all currently relevant unit / doc tests + +zope-testrunner --test-path=. \ + -s cybertools.brain \ + -s cybertools.browser \ + -s cybertools.catalog \ + -s cybertools.commerce \ + -s cybertools.composer \ + -s cybertools.container \ + -s cybertools.docgen \ + -s cybertools.external \ + -s cybertools.integrator -t \!bscw \ + -s cybertools.knowledge \ + -s cybertools.link \ + -s cybertools.media \ + -s cybertools.meta \ + -s cybertools.organize \ + -s cybertools.process \ + -s cybertools.relation \ + -s cybertools.reporter \ + -s cybertools.stateful \ + -s cybertools.storage -t \!pzope \ + -s cybertools.text \ + -s cybertools.tracking \ + -s cybertools.typology \ + -s cybertools.util \ + $* + +#-s cybertools.view \ +#-s cybertools.wiki \