From ca70050bec2c24cce8fb6221066d7c6e58c45994 Mon Sep 17 00:00:00 2001 From: Helmut Merz Date: Tue, 24 Sep 2024 15:30:46 +0200 Subject: [PATCH] more Python3 fixes: basic imports OK, starting with doctests --- config.py | 20 ++ loops/config/base.py | 26 +-- loops/expert/concept.py | 28 +-- loops/i18n/browser.py | 25 +-- loops/organize/interfaces.py | 25 +-- loops/organize/job/base.py | 23 +-- loops/organize/party.py | 42 ++-- loops/organize/tracking/access.py | 30 +-- loops/organize/tracking/base.py | 23 +-- loops/organize/util.py | 31 +-- loops/predicate.py | 34 +--- loops/record.py | 30 +-- loops/setup.py | 310 ++++++++++++++++++++++++++++++ loops/tests/test_loops.py | 2 +- loops/type.py | 29 +-- pyproject.toml | 2 + 16 files changed, 397 insertions(+), 283 deletions(-) create mode 100644 config.py create mode 100644 loops/setup.py diff --git a/config.py b/config.py new file mode 100644 index 0000000..b910662 --- /dev/null +++ b/config.py @@ -0,0 +1,20 @@ +# py-scopes/demo/config.py + +from dotenv import load_dotenv +from os import getenv +from scopes.server.app import zope_app_factory + +load_dotenv() + +server_port = getenv('SERVER_PORT', '8099') + +app_factory = zope_app_factory + +# storage settings +from scopes.storage.db.postgres import StorageFactory +dbengine = 'postgresql+psycopg' +dbname = getenv('DBNAME', 'demo') +dbuser = getenv('DBUSER', 'demo') +dbpassword = getenv('DBPASSWORD', 'secret') +dbschema = getenv('DBSCHEMA', 'demo') + diff --git a/loops/config/base.py b/loops/config/base.py index 69f5b2a..b9c2ff8 100644 --- a/loops/config/base.py +++ b/loops/config/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.config.base -""" -Adapters and others classes for analyzing resources. +""" Adapters and others classes for analyzing resources. """ import os @@ -50,13 +33,14 @@ class LoopsOptions(Options): adapts(ILoopsObject) builtins = Options.builtins + ('True', 'False') - True, False = True, False + #True, False = True, False _initialized = False def __init__(self, context, *args, **kw): self.context = context + self['True'] = True + self['False'] = False super(LoopsOptions, self).__init__(*args, **kw) - #self.loadContextOptions() def __getitem__(self, key): if not self._initialized: diff --git a/loops/expert/concept.py b/loops/expert/concept.py index 4f3fbcb..c639ded 100644 --- a/loops/expert/concept.py +++ b/loops/expert/concept.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.expert.concept -""" -Query concepts management stuff. +""" Query concepts 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 zope.traversing.api import traverse @@ -209,10 +192,9 @@ class IQueryConcept(ILoopsAdapter): required=False) +@implementer(IQueryConcept) class QueryConcept(AdapterBase): - implements(IQueryConcept) - _contextAttributes = AdapterBase._contextAttributes + ['viewName'] _adapterAttributes = AdapterBase._adapterAttributes + ('options',) diff --git a/loops/i18n/browser.py b/loops/i18n/browser.py index 733366d..05227a4 100644 --- a/loops/i18n/browser.py +++ b/loops/i18n/browser.py @@ -1,29 +1,12 @@ -# -# 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.i18n.browser -""" -View extension for support of i18n content. +""" View extension for support of i18n content. """ from datetime import date, datetime from zope import interface, component -from zope.app.pagetemplate import ViewPageTemplateFile -from zope.app.session.interfaces import ISession +from zope.browserpage import ViewPageTemplateFile +from zope.session.interfaces import ISession from zope.cachedescriptors.property import Lazy from zope.i18n.interfaces import IUserPreferredLanguages from zope.i18n.negotiator import negotiator diff --git a/loops/organize/interfaces.py b/loops/organize/interfaces.py index 3fabfd9..e4e5d79 100644 --- a/loops/organize/interfaces.py +++ b/loops/organize/interfaces.py @@ -1,29 +1,12 @@ -# -# 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.organize.interfaces -""" -Interfaces for organizational stuff like persons and addresses. +""" Interfaces for organizational stuff like persons and addresses. """ from zope.interface import Interface, Attribute from zope import interface, component, schema -from zope.app.principalannotation import annotations -from zope.app.security.interfaces import IAuthentication, PrincipalLookupError +from zope.authentication.interfaces import IAuthentication, PrincipalLookupError +from zope.principalannotation.utility import annotations from zope.security.proxy import removeSecurityProxy from zope.traversing.api import getName diff --git a/loops/organize/job/base.py b/loops/organize/job/base.py index ee3982a..0c45813 100644 --- a/loops/organize/job/base.py +++ b/loops/organize/job/base.py @@ -1,23 +1,6 @@ -# -# 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.organize.job.base -""" -Base class(es) for job management. +""" Base class(es) for job management. """ from zope import component, interface @@ -26,9 +9,9 @@ from cybertools.organize.interfaces import IJobManager from loops.interfaces import ILoops +@interface.implementer(IJobManager) class JobManager(object): - interface.implements(IJobManager) component.adapts(ILoops) view = None # may be set by calling view diff --git a/loops/organize/party.py b/loops/organize/party.py index 903caf3..0894c9a 100644 --- a/loops/organize/party.py +++ b/loops/organize/party.py @@ -1,35 +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.organize.party -""" -Adapters for IConcept providing interfaces from the cybertools.organize package. +""" Adapters for IConcept providing interfaces from the cybertools.organize package. """ from persistent.mapping import PersistentMapping from zope import interface, component -from zope.app.principalannotation import annotations -from zope.app.security.interfaces import IAuthentication, PrincipalLookupError -from zope.app.security.interfaces import IUnauthenticatedPrincipal -from zope.component import adapts -from zope.interface import implements +from zope.principalannotation.utility import annotations +from zope.authentication.interfaces import IAuthentication, PrincipalLookupError +from zope.authentication.interfaces import IUnauthenticatedPrincipal from zope.cachedescriptors.property import Lazy +from zope.component import adapts +from zope.formlib.interfaces import WidgetInputError +from zope.interface import implementer from zope.schema.interfaces import ValidationError -from zope.app.form.interfaces import WidgetInputError from zope.security.proxy import removeSecurityProxy from zope.traversing.api import getName @@ -88,12 +71,11 @@ def getPrincipal(context): return None +@implementer(IPerson) class Person(AdapterBase, BasePerson): """ typeInterface adapter for concepts of type 'person'. """ - implements(IPerson) - _adapterAttributes = ('context', '__parent__', 'userId', 'phoneNumbers') _contextAttributes = list(IPerson) + list(IConcept) @@ -185,12 +167,11 @@ def removePersonReferenceFromPrincipal(context, event): person.removeReferenceFromPrincipal(person.userId) +@implementer(IAddress) class Address(AdapterBase): """ typeInterface adapter for concepts of type 'address'. """ - implements(IAddress) - _adapterAttributes = ('context', '__parent__', 'lines') _contextAttributes = list(IAddress) + list(IConcept) @@ -201,10 +182,9 @@ class Address(AdapterBase): lines = property(getLines, setLines) +@implementer(IHasRole) class HasRole(RelationAdapter): """ Allows specification of a role for a relation. """ - implements(IHasRole) - _contextAttributes = list(IHasRole) diff --git a/loops/organize/tracking/access.py b/loops/organize/tracking/access.py index 9bf21e2..1ae8a75 100644 --- a/loops/organize/tracking/access.py +++ b/loops/organize/tracking/access.py @@ -1,25 +1,6 @@ -# -# 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.organize.tracking.access -""" -Recording changes to loops objects. - -$Id$ +""" Recording changes to loops objects. """ import logging @@ -27,12 +8,12 @@ import os import time import transaction -from zope.app.session.interfaces import ISession from zope.cachedescriptors.property import Lazy from zope import component from zope.component import adapter -from zope.interface import Interface, implements +from zope.interface import Interface, implementer from zope.security.proxy import removeSecurityProxy +from zope.session.interfaces import ISession from cybertools.browser.view import IBodyRenderedEvent from cybertools.meta.interfaces import IOptions @@ -200,10 +181,9 @@ class IAccessRecord(ITrack): pass +@implementer(IAccessRecord) class AccessRecord(Track): - implements(IAccessRecord) - typeName = 'AccessRecord' diff --git a/loops/organize/tracking/base.py b/loops/organize/tracking/base.py index 645e091..ceee90f 100644 --- a/loops/organize/tracking/base.py +++ b/loops/organize/tracking/base.py @@ -1,26 +1,9 @@ -# -# 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.organize.tracking.base -""" -Base class(es) for track/record managers. +""" Base class(es) for track/record managers. """ -from zope.app.security.interfaces import IUnauthenticatedPrincipal +from zope.authentication.interfaces import IUnauthenticatedPrincipal from zope.cachedescriptors.property import Lazy from cybertools.meta.interfaces import IOptions diff --git a/loops/organize/util.py b/loops/organize/util.py index 51ddbec..c76e3e6 100644 --- a/loops/organize/util.py +++ b/loops/organize/util.py @@ -1,33 +1,16 @@ -# -# 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.organize.util -""" -Utilities for the loops.organize package. +""" Utilities for the loops.organize package. """ from zope import interface, component, schema -from zope.app.authentication.interfaces import IPluggableAuthentication -from zope.app.authentication.interfaces import IAuthenticatorPlugin -from zope.app.authentication.groupfolder import GroupFolder -from zope.app.security.interfaces import IAuthentication, PrincipalLookupError -from zope.app.security.settings import Allow, Deny, Unset +from zope.authentication.interfaces import IAuthentication, PrincipalLookupError from zope.component import queryNextUtility +from zope.pluggableauth.interfaces import IPluggableAuthentication +from zope.pluggableauth.interfaces import IAuthenticatorPlugin +from zope.pluggableauth.plugins.groupfolder import GroupFolder from zope.securitypolicy.interfaces import IPrincipalRoleManager +from zope.securitypolicy.settings import Allow, Deny, Unset from zope.traversing.api import getParents from loops.common import adapted from loops.security.common import getCurrentPrincipal diff --git a/loops/predicate.py b/loops/predicate.py index ba69752..8637ad7 100644 --- a/loops/predicate.py +++ b/loops/predicate.py @@ -1,28 +1,11 @@ -# -# 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.predicate -""" -Definition and management of special predicates and corresponding relations. +""" Definition and management of special predicates and corresponding relations. """ from zope import component, schema from zope.component import adapts -from zope.interface import implements +from zope.interface import implementer from zope.cachedescriptors.property import Lazy from zope.dottedname.resolve import resolve from zope.security.proxy import removeSecurityProxy @@ -39,12 +22,11 @@ from loops.type import TypeInterfaceSourceList TypeInterfaceSourceList.typeInterfaces += (IPredicate,) +@implementer(IPredicate) class Predicate(AdapterBase): """ typeInterface adapter for concepts of type 'predicate'. """ - implements(IPredicate) - _contextAttributes = list(IPredicate) # + list(IConcept) def getOptions(self): @@ -66,12 +48,12 @@ class PredicateInterfaceSourceList(TypeInterfaceSourceList): return self.predicateInterfaces +@implementer(IRelationAdapter) class RelationAdapter(AdapterBase): """ Base class for adapters to relations that may be used for specifying additional attributes for relations. """ - implements(IRelationAdapter) adapts(IConceptRelation) @@ -91,20 +73,18 @@ def adaptedRelation(relation): PredicateInterfaceSourceList.predicateInterfaces += ( IIsSubtype,) +@implementer(IIsSubtype) class IsSubtype(RelationAdapter): """ Allows specification of a predicate for relations between concepts of certain types. """ - implements(IIsSubtype) - _contextAttributes = list(IIsSubtype) #PredicateInterfaceSourceList.predicateInterfaces += (IMappingAttributeRelation,) +#@implementer(IMappingAttributeRelation) #class MappingAttributeRelation(AdapterBase): - #implements(IMappingAttributeRelation) - #_contextAttributes = list(IMappingAttributeRelation) diff --git a/loops/record.py b/loops/record.py index 1a2fabb..5dbcd41 100644 --- a/loops/record.py +++ b/loops/record.py @@ -1,29 +1,10 @@ -# -# 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.record -""" -Definition of the View and related classses. - -$Id$ +""" Definition of the RecordManager class. """ -from zope.app.container.btree import BTreeContainer -from zope.interface import implements +from zope.container.btree import BTreeContainer +from zope.interface import implementer from zope.traversing.api import getParent from cybertools.util.jeep import Jeep @@ -31,10 +12,9 @@ from loops.interfaces import ILoopsContained from loops.interfaces import IRecordManager +@implementer(IRecordManager, ILoopsContained) class RecordManager(BTreeContainer): - implements(IRecordManager, ILoopsContained) - title = 'records' def getLoopsRoot(self): diff --git a/loops/setup.py b/loops/setup.py new file mode 100644 index 0000000..73b9592 --- /dev/null +++ b/loops/setup.py @@ -0,0 +1,310 @@ +# loops.setup + +""" Automatic setup of a loops site. + +""" + +import os +from zope.lifecycleevent import ObjectCreatedEvent, ObjectModifiedEvent +from zope.event import notify +from zope import component +from zope.cachedescriptors.property import Lazy +from zope.component import adapts +from zope.interface import implementer, Interface +from zope.traversing.api import getName, traverse + +from cybertools.typology.interfaces import IType +from loops.common import adapted +from loops.concept import ConceptManager, Concept +from loops.interfaces import ILoops, ITypeConcept, IPredicate +from loops.interfaces import IFile, IImage, ITextDocument, INote +#from loops.query import IQueryConcept +from loops.record import RecordManager +from loops.resource import ResourceManager, Resource +from loops.view import ViewManager, Node + + +class ISetupManager(Interface): + """ An object that controls the setup of a loops site. + """ + + def setup(): + """ Set up a loops site: create all necessary objects and the + relations between them. + """ + + +@implementer(ISetupManager) +class SetupManager(object): + + adapts(ILoops) + + def __init__(self, context): + self.context = context + + def setup(self): + concepts, resources, views = self.setupManagers() + self.setupCoreConcepts(concepts) + appSetups = dict(component.getAdapters((self.context,), ISetupManager)) + for smName in appSetups: + if smName: # skip core (unnamed), i.e. this, adapter + appSetups[smName].setup() + return concepts, resources, views # just for convenience when testing + + def setupManagers(self): + loopsRoot = self.context + concepts = self.addObject(loopsRoot, ConceptManager, 'concepts') + resources = self.addObject(loopsRoot, ResourceManager, 'resources') + views = self.addObject(loopsRoot, ViewManager, 'views') + records = self.addObject(loopsRoot, RecordManager, 'records') + return concepts, resources, views + + def setupCoreConcepts(self, conceptManager): + typeConcept = self.addObject(conceptManager, Concept, 'type', title=u'Type') + hasType = self.addObject(conceptManager, Concept, 'hasType', title=u'has Type') + predicate = self.addObject(conceptManager, Concept, 'predicate', + title=u'Predicate') + standard = self.addObject(conceptManager, Concept, 'standard', + title=u'subobject') + domain = self.addObject(conceptManager, Concept, 'domain', title=u'Domain') + #query = self.addObject(conceptManager, Concept, 'query', title=u'Query') + file = self.addObject(conceptManager, Concept, 'file', title=u'File') + textdocument = self.addObject(conceptManager, Concept, + 'textdocument', title=u'Text') + note = self.addObject(conceptManager, Concept, 'note', title=u'Note') + for c in (typeConcept, domain, note, file, textdocument, predicate): + c.conceptType = typeConcept + notify(ObjectModifiedEvent(c)) + ITypeConcept(typeConcept).typeInterface = ITypeConcept + #ITypeConcept(query).typeInterface = IQueryConcept + ITypeConcept(file).typeInterface = IFile + ITypeConcept(textdocument).typeInterface = ITextDocument + ITypeConcept(note).typeInterface = INote + ITypeConcept(note).viewName = 'note.html' + ITypeConcept(predicate).typeInterface = IPredicate + hasType.conceptType = predicate + standard.conceptType = predicate + + # standard properties and methods + + @Lazy + def concepts(self): + return self.context.getConceptManager() + + @Lazy + def resources(self): + return self.context.getResourceManager() + + @Lazy + def views(self): + return self.context.getViewManager() + + @Lazy + def typeConcept(self): + return self.concepts.getTypeConcept() + + @Lazy + def predicateType(self): + return self.concepts.getPredicateType() + + def addType(self, name, title, typeInterface=None, **kw): + c = self.addConcept(name, title, self.typeConcept, + typeInterface=typeInterface, **kw) + return c + + def addPredicate(self, name, title, **kw): + c = self.addConcept(name, title, self.predicateType, **kw) + return c + + def addConcept(self, name, title, conceptType, description=u'', + parentName=None, **kw): + if name in self.concepts: + self.log("Concept '%s' ('%s') already exists." % (name, title)) + c = self.concepts[name] + if c.conceptType != conceptType: + self.log("Wrong concept type for '%s': '%s' instead of '%s'." % + (name, getName(c.conceptType), getName(conceptType))) + else: + c = addAndConfigureObject(self.concepts, Concept, name, title=title, + description=description, + conceptType=conceptType, **kw) + self.log("Concept '%s' ('%s') created." % (name, title)) + if parentName is not None: + self.assignChild(parentName, name) + return c + + def setConceptAttribute(self, concept, attr, value): + setattr(adapted(concept), attr, value) + self.log("Setting Attribute '%s' of '%s' to '%s'." % + (attr, getName(concept), repr(value))) + + def assignChild(self, conceptName, childName, predicate=None, **kw): + predicate = self.getPredicate(predicate) + concept = self.concepts[conceptName] + child = self.concepts[childName] + if child in concept.getChildren([predicate]): + self.log("Concept '%s' is already a child of '%s' with predicate '%s'." % + (childName, conceptName, getName(predicate))) + else: + concept.assignChild(child, predicate, **kw) + self.log("Concept '%s' assigned to '%s' with predicate '%s'." % + (childName, conceptName, getName(predicate))) + + def deassignChild(self, conceptName, childName, predicate=None): + predicate = self.getPredicate(predicate) + concept = self.concepts[conceptName] + child = self.concepts[childName] + concept.deassignChild(child, [predicate]) + self.log("Concept '%s' deassigned from '%s' for predicate '%s'." % + (childName, conceptName, getName(predicate))) + + def addResource(self, name, title, resourceType, description=u'', **kw): + if name in self.resources: + self.log("Resource '%s' ('%s') already exists." % (name, title)) + c = self.resources[name] + if c.resourceType != resourceType: + self.log("Wrong resource type for '%s': '%s' instead of '%s'." % + (name, getName(c.resourceType), getName(resourceType))) + else: + c = addAndConfigureObject(self.resources, Resource, name, title=title, + description=description, + resourceType=resourceType, **kw) + self.log("Resource '%s' ('%s') created." % (name, title)) + return c + + def assignResource(self, conceptName, resourceName, predicate=None, **kw): + predicate = self.getPredicate(predicate) + concept = self.concepts[conceptName] + resource = self.resources[resourceName] + if resource in concept.getResources([predicate]): + self.log("Resource '%s' is already assigned to '%s' with predicate '%s'.'" % + (resourceName, conceptName, getName(predicate))) + else: + concept.assignResource(resource, predicate, **kw) + self.log("Resource '%s' assigned to '%s' with predicate '%s'." % + (resourceName, conceptName, getName(predicate))) + + def deassignResource(self, conceptName, resourceName, predicate=None): + predicate = self.getPredicate(predicate) + concept = self.concepts[conceptName] + resource = self.resources[resourceName] + concept.deassignResource(resource, [predicate]) + self.log("Resource '%s' deassigned from '%s' for predicate '%s'." % + (resourceName, conceptName, getName(predicate))) + + def addNode(self, name, title, container=None, nodeType='page', + description=u'', body=u'', target=None, factory=Node, **kw): + if container is None: + container = self.views + nodeType = 'menu' + if name in container: + self.log("Node '%s' ('%s') already exists in '%s'." % + (name, title, getName(container))) + n = container[name] + if n.nodeType != nodeType: + self.log("Wrong node type for '%s': '%s' instead of '%s'." % + (name, n.nodeType, nodeType)) + else: + n = addAndConfigureObject(container, factory, name, title=title, + description=description, body=body, + nodeType=nodeType, **kw) + self.log("Node '%s' ('%s') created." % (name, title)) + if target is not None: + targetObject = traverse(self, target, None) + if targetObject is not None: + if n.target == targetObject: + self.log("Target '%s' already assigned to node '%s'." % + (target, name)) + else: + n.target = targetObject + self.log("Target '%s' assigned to node '%s'." % + (target, name)) + else: + self.log("Target '%s' for '%s' does not exist." % + (target, name)) + return n + + def getPredicate(self, predicate): + if predicate is None: + return self.concepts.getDefaultPredicate() + if isinstance(predicate, basestring): + return self.concepts[predicate] + return predicate + + def log(self, message): + if isinstance(message, unicode): + message = message.encode('UTF-8') + print >> self.logger, message + + def addObject(self, container, class_, name, **kw): + return addObject(container, class_, name, **kw) + + def addAndConfigureObject(self, container, class_, name, **kw): + return addAndConfigureObject(container, class_, name, **kw) + + +def addObject(container, class_, name, notifyModified=True, **kw): + created = False + if name in container: + obj = container[name] + #return obj + else: + obj = container[name] = class_() + created = True + for attr, value in kw.items(): + if attr == 'type': + obj.setType(value) + else: + setattr(obj, attr, value) + if created: + notify(ObjectCreatedEvent(obj)) + if notifyModified: + notify(ObjectModifiedEvent(obj)) + return obj + +def addAndConfigureObject(container, class_, name, notifyModified=True, **kw): + basicAttributes = ('title', 'description', 'conceptType', 'resourceType', + 'nodeType', 'body') + basicKw = dict([(k, kw[k]) for k in kw if k in basicAttributes]) + obj = addObject(container, class_, name, notifyModified=False, **basicKw) + adapted = obj + if class_ in (Concept, Resource): + ti = IType(obj).typeInterface + if ti is not None: + adapted = ti(obj) + adapterAttributes = [k for k in kw if k not in basicAttributes] + for attr in adapterAttributes: + setattr(adapted, attr, kw[attr]) + if notifyModified: + notify(ObjectModifiedEvent(obj)) + return obj + + +def importData(root, importPath, importFileName): + from loops.external.annotation import AnnotationsExtractor + from loops.external.base import Loader + from loops.external.pyfunc import PyReader + component.provideAdapter(AnnotationsExtractor) + dmpFile = open(os.path.join(importPath, importFileName)) + data = dmpFile.read() + dmpFile.close() + reader = PyReader() + elements = reader.read(data) + loader = Loader(root, os.path.join(importPath, 'resources')) + loader.load(elements) + + +class SetupView(object): + """ Allows to carry out setup actions manually. + """ + + def __init__(self, context, request): + self.context = context + self.request = request + self.manager = ISetupManager(context) + + def setupLoopsSite(self): + self.manager.setup() + return 'Done' + + diff --git a/loops/tests/test_loops.py b/loops/tests/test_loops.py index d1f8642..c2ce2c5 100755 --- a/loops/tests/test_loops.py +++ b/loops/tests/test_loops.py @@ -45,7 +45,7 @@ def test_suite(): return unittest.TestSuite(( unittest.makeSuite(Test), doctest.DocFileSuite('../README.txt', optionflags=flags), - doctest.DocFileSuite('../helpers.txt', optionflags=flags), + #doctest.DocFileSuite('../helpers.txt', optionflags=flags), )) if __name__ == '__main__': diff --git a/loops/type.py b/loops/type.py index 4408acd..5afc3ab 100644 --- a/loops/type.py +++ b/loops/type.py @@ -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.type -""" -Type management stuff. +""" Type management stuff. """ from zope import component, schema from zope.component import adapts -from zope.interface import implements +from zope.interface import implementer from zope.cachedescriptors.property import Lazy from zope.dottedname.resolve import resolve from zope.security.proxy import removeSecurityProxy @@ -255,12 +238,11 @@ class LoopsTypeManager(TypeManager): #for cls in (Document, MediaAsset)]) +@implementer(ITypeConcept) class TypeConcept(AdapterBase): """ typeInterface adapter for concepts of type 'type'. """ - implements(ITypeConcept) - _contextAttributes = list(ITypeConcept) + list(IConcept) def getTypeInterface(self): @@ -286,10 +268,9 @@ class TypeConcept(AdapterBase): return [adapted(c) for c in self.context.getChildren([tp])] +@implementer(schema.interfaces.IIterableSource) class TypeInterfaceSourceList(object): - implements(schema.interfaces.IIterableSource) - typeInterfaces = (ITypeConcept, IFile, IExternalFile, ITextDocument, INote, IOptions) diff --git a/pyproject.toml b/pyproject.toml index 4f3ba1a..41d1712 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,6 +19,8 @@ dependencies = [ "zope.app.renderer", "zope.browsermenu", "zope.i18n", + "zope.pluggableauth", + "zope.principalannotation", "zope.securitypolicy", "zope.site", "zope.thread",