more Python3 fixes: compound, knowledge, versioning

This commit is contained in:
Helmut Merz 2024-09-27 09:37:54 +02:00
parent 010106406d
commit 1da71c72a9
12 changed files with 99 additions and 244 deletions

View file

@ -1,26 +1,9 @@
#
# Copyright (c) 2012 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.lobo.standard
"""
View classes for lobo (blueprint-based) layouts.
""" View classes for lobo (blueprint-based) layouts.
"""
from cgi import parse_qs
from urllib.parse import parse_qs
from zope import interface, component
from zope.app.pagetemplate import ViewPageTemplateFile
from zope.cachedescriptors.property import Lazy

View file

@ -33,13 +33,13 @@ We first create the compound type and one instance of the newly created
type. We also need an ``ispartof`` predicate.
>>> tCompound = addAndConfigureObject(concepts, Concept, 'compound',
... title=u'Compound',
... title='Compound',
... conceptType=tType, typeInterface=ICompound)
>>> c01 = addAndConfigureObject(concepts, Concept, 'c01',
... title=u'Compound #01', conceptType=tCompound)
... title='Compound #01', conceptType=tCompound)
>>> tPredicate = concepts.getPredicateType()
>>> isPartof = addAndConfigureObject(concepts, Concept, 'ispartof',
... title=u'is Part of', conceptType=tPredicate)
... title='is Part of', conceptType=tPredicate)
In order to access the compound concept's attributes we have to adapt
it.
@ -49,31 +49,31 @@ it.
Now we are able to add resources to it.
>>> aC01.add(resources[u'd003.txt'])
>>> aC01.add(resources[u'd001.txt'])
>>> aC01.add(resources['d003.txt'])
>>> aC01.add(resources['d001.txt'])
>>> [getName(p) for p in aC01.getParts()]
[u'd003.txt', u'd001.txt']
['d003.txt', 'd001.txt']
>>> aC01.add(resources[u'd001.txt'], 0)
>>> aC01.add(resources['d001.txt'], 0)
>>> [getName(p) for p in aC01.getParts()]
[u'd001.txt', u'd003.txt', u'd001.txt']
['d001.txt', 'd003.txt', 'd001.txt']
>>> aC01.add(resources[u'd002.txt'], -1)
>>> aC01.add(resources['d002.txt'], -1)
>>> [getName(p) for p in aC01.getParts()]
[u'd001.txt', u'd003.txt', u'd002.txt', u'd001.txt']
['d001.txt', 'd003.txt', 'd002.txt', 'd001.txt']
We can reorder the parts of a compound.
>>> aC01.reorder([resources[u'd002.txt'], resources[u'd001.txt'], ])
>>> aC01.reorder([resources['d002.txt'], resources['d001.txt'], ])
>>> [getName(p) for p in aC01.getParts()]
[u'd002.txt', u'd001.txt', u'd003.txt', u'd001.txt']
['d002.txt', 'd001.txt', 'd003.txt', 'd001.txt']
And remove a part from the compound.
>>> aC01.remove(resources[u'd001.txt'], 1)
>>> aC01.remove(resources['d001.txt'], 1)
>>> [getName(p) for p in aC01.getParts()]
[u'd002.txt', u'd003.txt', u'd001.txt']
['d002.txt', 'd003.txt', 'd001.txt']
Blogs
@ -83,23 +83,23 @@ Blogs
>>> from loops.compound.blog.interfaces import IBlogPost
>>> component.provideAdapter(BlogPost, provides=IBlogPost)
>>> tBlog = addAndConfigureObject(concepts, Concept, 'blog', title=u'Blog',
>>> tBlog = addAndConfigureObject(concepts, Concept, 'blog', title='Blog',
... conceptType=tType)
>>> tBlogPost = addAndConfigureObject(concepts, Concept, 'blogpost',
... title=u'Blog Post', conceptType=tType,
... title='Blog Post', conceptType=tType,
... typeInterface=IBlogPost)
>>> myBlog = addAndConfigureObject(concepts, Concept, 'myblog', title=u'My Blog',
>>> myBlog = addAndConfigureObject(concepts, Concept, 'myblog', title='My Blog',
... conceptType=tBlog)
>>> firstPost = addAndConfigureObject(concepts, Concept, 'firstpost',
... title=u'My first post', conceptType=tBlogPost)
... title='My first post', conceptType=tBlogPost)
>>> aFirstPost = adapted(firstPost)
>>> aFirstPost.date
>>> aFirstPost.text = u'My first blog post.'
>>> aFirstPost.text = 'My first blog post.'
>>> aFirstPost.text
u'My first blog post.'
'My first blog post.'
>>> aFirstPost.creator
Blog and BlogPost views
@ -114,7 +114,7 @@ a new post.
>>> view = BlogView(myBlog, TestRequest())
>>> for act in view.getActions('portlet'):
... print act.name
... print(act.name)
createBlogPost
>>> view = BlogPostView(firstPost, TestRequest())
@ -143,13 +143,13 @@ and a corresponding person.
>>> auth = setupData.auth
>>> tPerson = concepts['person']
>>> userJohn = auth.definePrincipal('users.john', u'John', login='john')
>>> userJohn = auth.definePrincipal('users.john', 'John', login='john')
>>> persJohn = addAndConfigureObject(concepts, Concept, 'person.john',
... title=u'John Smith', conceptType=tPerson,
... title='John Smith', conceptType=tPerson,
... userId='users.john')
>>> blogJohn = addAndConfigureObject(concepts, Concept, 'blog.john',
... title=u'John\'s Blog', conceptType=tBlog)
... title='John\'s Blog', conceptType=tBlog)
>>> persJohn.assignChild(blogJohn)
Let's now login as the newly defined user.
@ -178,9 +178,9 @@ used for creating the blog post.
>>> home.target = myBlog
>>> from loops.compound.blog.browser import CreateBlogPostForm, CreateBlogPost
>>> input = {'title': u'John\'s first post', 'text': u'Text of John\'s post',
>>> input = {'title': 'John\'s first post', 'text': 'Text of John\'s post',
... 'date': '2008-02-02T15:54:11',
... 'privateComment': u'John\'s private comment',
... 'privateComment': 'John\'s private comment',
... 'form.type': '.loops/concepts/blogpost'}
>>> cbpForm = CreateBlogPostForm(home, TestRequest(form=input))
>>> cbpController = CreateBlogPost(cbpForm, cbpForm.request)
@ -192,11 +192,11 @@ used for creating the blog post.
1
>>> postJohn0 = posts[0]
>>> postJohn0.title
u"John's first post"
"John's first post"
>>> postJohn0Text = adapted(postJohn0.getResources()[0])
>>> postJohn0Text.data
u"Text of John's post"
"Text of John's post"
Security
@ -269,7 +269,7 @@ So let's now switch to another user. On a global level, Martha also has
the ContentManager role, i.e. she is allowed to edit content objects.
Nevertheless she is not allowed to change John's blog post.
>>> userMartha = auth.definePrincipal('users.martha', u'Martha', login='martha')
>>> userMartha = auth.definePrincipal('users.martha', 'Martha', login='martha')
>>> assignRole('zope.Member', 'users.martha')
>>> assignRole('zope.ContentManager', 'users.martha')
@ -322,29 +322,29 @@ Micro Articles
>>> component.provideAdapter(MicroArt, provides=IMicroArt)
>>> tMicroArt = addAndConfigureObject(concepts, Concept, 'microart',
... title=u'MicroArt', conceptType=tType,
... title='MicroArt', conceptType=tType,
... typeInterface=IMicroArt)
>>> ma01 = addAndConfigureObject(concepts, Concept, 'ma01',
... conceptType=tMicroArt,
... title=u'Organizational Knowledge',
... story=u'Systemic KM talks about organizational knowledge.',
... insight=u'Organizational knowledge is not visible.',
... consequences=u'Use examples. Look for strucure and rules. '
... u'Knowledge shows itself in actions.',
... followUps=u'What about collective intelligence? '
... u'How does an organization express itself?')
... title='Organizational Knowledge',
... story='Systemic KM talks about organizational knowledge.',
... insight='Organizational knowledge is not visible.',
... consequences='Use examples. Look for strucure and rules. '
... 'Knowledge shows itself in actions.',
... followUps='What about collective intelligence? '
... 'How does an organization express itself?')
>>> ma01._insight
u'Organizational knowledge is not visible.'
'Organizational knowledge is not visible.'
>>> list(resources)
[..., u'ma01_story']
[..., 'ma01_story']
>>> adMa01 = adapted(ma01)
>>> adMa01.insight
u'Organizational knowledge is not visible.'
'Organizational knowledge is not visible.'
>>> adMa01.story
u'Systemic KM talks about organizational knowledge.'
'Systemic KM talks about organizational knowledge.'
Books, Sections, and Pages

View file

@ -1,37 +1,19 @@
#
# Copyright (c) 2012 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.compound.base
"""
Compound objects like articles, blog posts, storyboard items, ...
""" Compound objects like articles, blog posts, storyboard items, ...
"""
from zope.cachedescriptors.property import Lazy
from zope.interface import implements
from zope.interface import implementer
from zope.traversing.api import getName
from loops.common import AdapterBase
from loops.compound.interfaces import ICompound, compoundPredicateNames
@implementer(ICompound)
class Compound(AdapterBase):
implements(ICompound)
compoundPredicateNames = compoundPredicateNames
@Lazy

View file

@ -1,28 +1,11 @@
#
# 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.compound.blog.post
"""
Blogs and blog posts.
""" Blogs and blog posts.
"""
from zope.cachedescriptors.property import Lazy
from zope.dublincore.interfaces import IZopeDublinCore
from zope.interface import implements
from zope.interface import implementer
from zope.event import notify
from zope.lifecycleevent import ObjectCreatedEvent, ObjectModifiedEvent
from zope import schema
@ -40,10 +23,9 @@ from loops.type import TypeInterfaceSourceList
TypeInterfaceSourceList.typeInterfaces += (ISimpleBlogPost, IBlogPost,)
@implementer(ISimpleBlogPost)
class SimpleBlogPost(Compound):
implements(ISimpleBlogPost)
textContentType = 'text/html'
_adapterAttributes = Compound._adapterAttributes + ('creator',)
@ -57,10 +39,9 @@ class SimpleBlogPost(Compound):
return cr and cr[0] or None
@implementer(IBlogPost)
class BlogPost(Compound):
implements(IBlogPost)
_adapterAttributes = Compound._adapterAttributes + ('text', 'private', 'creator',)
_contextAttributes = Compound._contextAttributes + ['date', 'privateComment']
_noexportAttributes = ('creator', 'text', 'private')

View file

@ -1,28 +1,10 @@
#
# 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.compound.blog.security
"""
Security settings for blogs and blog posts.
""" Security settings for blogs and blog posts.
"""
from zope.cachedescriptors.property import Lazy
from zope.component import adapts
from zope.interface import implements
from zope.traversing.api import getName
from loops.compound.blog.interfaces import IBlogPost

View file

@ -1,28 +1,11 @@
#
# 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.compound.book.browser
"""
View class(es) book/section/page structures.
""" View class(es) book/section/page structures.
"""
from cgi import parse_qs
from urllib.parse import parse_qs
from zope import interface, component
from zope.app.pagetemplate import ViewPageTemplateFile
from zope.browserpage import ViewPageTemplateFile
from zope.cachedescriptors.property import Lazy
from zope.traversing.api import getName

View file

@ -1,28 +1,11 @@
#
# Copyright (c) 2011 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.compound.microart.base
"""
Micro articles (MicroArt).
""" Micro articles (MicroArt).
"""
from zope.cachedescriptors.property import Lazy
from zope.dublincore.interfaces import IZopeDublinCore
from zope.interface import implements
from zope.interface import implementer
from zope.event import notify
from zope.lifecycleevent import ObjectCreatedEvent, ObjectModifiedEvent
from zope import schema
@ -39,10 +22,9 @@ from loops.type import TypeInterfaceSourceList
TypeInterfaceSourceList.typeInterfaces += (IMicroArt,)
@implementer(IMicroArt)
class MicroArt(Compound):
implements(IMicroArt)
_contextAttributes = list(IMicroArt)
_adapterAttributes = Compound._adapterAttributes + ('story',)
_noexportAttributes = ('story',)

View file

@ -54,12 +54,12 @@ from their typeInterface adapters we here append a 'C' to the name of
the variables:
>>> from loops.concept import Concept
>>> progLangC = concepts['progLang'] = Concept(u'Programming Language')
>>> ooProgC = concepts['ooProg'] = Concept(u'Object-oriented Programming')
>>> pythonC = concepts['python'] = Concept(u'Python')
>>> pyBasicsC = concepts['pyBasics'] = Concept(u'Python Basics')
>>> pyOoC = concepts['pyOo'] = Concept(u'OO Programming with Python')
>>> pySpecialsC = concepts['pySpecials'] = Concept(u'Python Specials')
>>> progLangC = concepts['progLang'] = Concept('Programming Language')
>>> ooProgC = concepts['ooProg'] = Concept('Object-oriented Programming')
>>> pythonC = concepts['python'] = Concept('Python')
>>> pyBasicsC = concepts['pyBasics'] = Concept('Python Basics')
>>> pyOoC = concepts['pyOo'] = Concept('OO Programming with Python')
>>> pySpecialsC = concepts['pySpecials'] = Concept('Python Specials')
>>> topicConcepts = (progLangC, ooProgC, pythonC, pyBasicsC, pyOoC, pySpecialsC)
@ -78,13 +78,13 @@ the variables:
We now create a person and assign some knowledge to it:
>>> johnC = concepts['john'] = Concept(u'John')
>>> johnC = concepts['john'] = Concept('John')
>>> johnC.conceptType = person
>>> john = IPerson(johnC)
>>> john.knows(pyBasics)
>>> list(john.getKnowledge())[0].title
u'Python Basics'
'Python Basics'
Now let's get to tasks - a task is used as a requirement profile, i.e.
it requires a certain set of knowledge elements:
@ -100,7 +100,7 @@ a position with the requirement profile:
>>> missing = john.getMissingKnowledge(task01)
>>> [m.title for m in missing]
[u'Object-oriented Programming', u'OO Programming with Python']
['Object-oriented Programming', 'OO Programming with Python']
Luckily there are a few elearning content objects out there that
provide some of the knowledge needed:
@ -155,7 +155,7 @@ For testing, we first have to provide the needed utilities and settings
>>> principalAnnotations = PrincipalAnnotationUtility()
>>> component.provideUtility(principalAnnotations, IPrincipalAnnotationUtility)
>>> principal = auth.definePrincipal('users.john', u'John', login='john')
>>> principal = auth.definePrincipal('users.john', 'John', login='john')
>>> john.userId = 'users.john'
>>> from zope.publisher.browser import TestRequest

View file

@ -1,30 +1,13 @@
#
# 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.knowledge.survey.browser
"""
Definition of view classes and other browser related stuff for
""" Definition of view classes and other browser related stuff for
surveys and self-assessments.
"""
import csv
from cStringIO import StringIO
from io import StringIO
import math
from zope.app.pagetemplate import ViewPageTemplateFile
from zope.browserpage import ViewPageTemplateFile
from zope.cachedescriptors.property import Lazy
from zope.i18n import translate

View file

@ -1,27 +1,10 @@
#
# 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.knowledge.survey.response
"""
Handling survey responses.
""" Handling survey responses.
"""
from zope.component import adapts
from zope.interface import implements
from zope.interface import implementer
from cybertools.tracking.btree import Track
from cybertools.tracking.interfaces import ITrackingStorage
@ -29,10 +12,9 @@ from loops.knowledge.survey.interfaces import IResponse, IResponses
from loops.organize.tracking.base import BaseRecordManager
@implementer(IResponses)
class Responses(BaseRecordManager):
implements(IResponses)
storageName = 'survey_responses'
personId = None
institutionId = None
@ -84,9 +66,8 @@ class Responses(BaseRecordManager):
return self.storage.query(taskId=self.uid)
@implementer(IResponse)
class Response(Track):
implements(IResponse)
typeName = 'Response'

View file

@ -4,8 +4,6 @@ loops - Linked Objects for Organization and Processing Services
Managing versions of resources.
($Id$)
Setting up a loops Site and Utilities
=====================================
@ -45,7 +43,7 @@ adapter on the object.
>>> d001 = resources['d001.txt']
>>> d001.title
u'Doc 001'
'Doc 001'
>>> vD001 = IVersionable(d001)
>>> vD001.versionLevels
['major', 'minor']
@ -68,9 +66,9 @@ Now we can create a new version for our document:
>>> d001v1_2 = vD001.createVersion()
>>> getName(d001v1_2)
u'd001_1.2.txt'
'd001_1.2.txt'
>>> d001v1_2.title
u'Doc 001'
'Doc 001'
>>> vD001v1_2 = IVersionable(d001v1_2)
>>> vD001v1_2.versionId
@ -91,14 +89,14 @@ a major version change, the lower levels are reset to 1:
>>> d001v2_1 = vD001.createVersion(0)
>>> getName(d001v2_1)
u'd001_2.1.txt'
'd001_2.1.txt'
The name of the new version is always derived from the name of the master
even if we create a new version from another one:
>>> d001v2_2 = IVersionable(d001v1_2).createVersion()
>>> getName(d001v2_2)
u'd001_2.2.txt'
'd001_2.2.txt'
Providing the Correct Version
@ -151,7 +149,7 @@ derived from it are deleted as well.
>>> del resources['d001.txt']
>>> sorted(resources)
[u'd002.txt', u'd003.txt']
['d002.txt', 'd003.txt']
Fin de partie

View file

@ -1,22 +1,22 @@
"""
Set up a loops site for testing.
# loops.versioning.testsetup
$Id$
""" Set up a loops site for testing.
"""
from zope import component
from zope.annotation.attribute import AttributeAnnotations
from zope.annotation.interfaces import IAnnotatable
from zope.app.catalog.catalog import Catalog
from zope.app.catalog.interfaces import ICatalog
from zope.app.catalog.field import FieldIndex
from zope.app.catalog.text import TextIndex
from zope.app.container.interfaces import IObjectRemovedEvent
from zope.app.security.interfaces import IAuthentication
from zope.app.security.principalregistry import principalRegistry
from zope.authentication.interfaces import IAuthentication
from zope.catalog.catalog import Catalog
from zope.catalog.interfaces import ICatalog
from zope.catalog.field import FieldIndex
from zope.catalog.text import TextIndex
from zope.container.interfaces import IObjectRemovedEvent
from zope.dublincore.annotatableadapter import ZDCAnnotatableAdapter
from zope.dublincore.interfaces import IZopeDublinCore
from zope.principalregistry.principalregistry import principalRegistry
from cybertools.meta.interfaces import IOptions
from cybertools.relation.tests import IntIdsStub
from cybertools.relation.registry import RelationRegistry
from cybertools.relation.interfaces import IRelationRegistry
@ -56,7 +56,7 @@ class TestSite(object):
component.provideAdapter(ZDCAnnotatableAdapter, (ILoopsObject,), IZopeDublinCore)
component.provideAdapter(AttributeAnnotations, (ILoopsObject,))
component.provideAdapter(LoopsDCAdapter, (IConcept,), IZopeDublinCore)
component.provideAdapter(LoopsOptions)
component.provideAdapter(LoopsOptions, provides=IOptions)
component.provideAdapter(ConceptType)
component.provideAdapter(ResourceType)