integrator: Python3 fixes

This commit is contained in:
Helmut Merz 2024-09-26 19:59:51 +02:00
parent 5e5e9aedfc
commit bf1fda008c
11 changed files with 81 additions and 233 deletions

View file

@ -4,8 +4,6 @@ loops - Linked Objects for Organization and Processing Services
Integration of external sources.
($Id$)
Setting up a loops Site and Utilities
=====================================
@ -46,7 +44,7 @@ and methods of the external collect object.
>>> from loops.integrator.collection import ExternalCollectionAdapter
>>> tExternalCollection = concepts['extcollection']
>>> coll01 = addObject(concepts, Concept, 'coll01',
... title=u'Collection One', conceptType=tExternalCollection)
... title='Collection One', conceptType=tExternalCollection)
>>> aColl01 = ExternalCollectionAdapter(coll01)
An external collection carries a set of attributes that control the access
@ -58,7 +56,7 @@ to the external system:
>>> aColl01.baseAddress = dataDir
>>> aColl01.address = 'topics'
>>> aColl01.metaInfo = u'Photograph taken by...'
>>> aColl01.metaInfo = 'Photograph taken by...'
>>> aColl01.overwriteMetaInfo is None
True
@ -91,9 +89,9 @@ Let's now create the corresponding resource objects.
2
>>> xf1 = res[0]
>>> xf1.__name__
u'programming_beautifulprogram.pdf'
'programming_beautifulprogram.pdf'
>>> xf1.title
u'BeautifulProgram'
'BeautifulProgram'
>>> xf1.contentType
'application/pdf'
@ -115,8 +113,8 @@ Working with the External Collection
>>> len(res)
2
>>> sorted((r.__name__, r.title, r._storageName) for r in res)
[(u'programming_beautifulprogram.pdf', u'BeautifulProgram', 'fullpath'),
(u'programming_zope_zope3.txt', u'zope3', 'fullpath')]
[('programming_beautifulprogram.pdf', 'BeautifulProgram', 'fullpath'),
('programming_zope_zope3.txt', 'zope3', 'fullpath')]
We may update the collection after having changed the storage params.
This should also change the settings for existing objects if they still
@ -133,7 +131,7 @@ can be found.
('fullpath', {'subdirectory': '...programming'}, 'BeautifulProgram.pdf')
>>> aXf1.metaInfo
u'Photograph taken by...'
'Photograph taken by...'
But if one of the referenced objects is not found any more it will be deleted.
@ -153,14 +151,14 @@ Mail Collections
>>> tType = concepts['type']
>>> from loops.integrator.mail.interfaces import IMailCollection, IMailResource
>>> tMailCollection = addAndConfigureObject(concepts, Concept, 'mailcollection',
... title=u'Mail Collection', conceptType=tType,
... title='Mail Collection', conceptType=tType,
... typeInterface=IMailCollection)
>>> tMailResource = addAndConfigureObject(concepts, Concept, 'email',
... title=u'Mail Resource', conceptType=tType,
... title='Mail Resource', conceptType=tType,
... typeInterface=IMailResource)
>>> mailColl = addObject(concepts, Concept, 'mails.user1',
... title=u'My Mails (User1)', conceptType=tMailCollection)
... title='My Mails (User1)', conceptType=tMailCollection)
>>> from loops.integrator.mail.collection import MailCollectionAdapter
>>> aMailColl = MailCollectionAdapter(mailColl)
@ -168,10 +166,10 @@ Mail Collections
An external collection carries a set of attributes that control the access
to the external system:
>>> aMailColl.userName = u'jim'
>>> aMailColl.userName = 'jim'
>>> (aMailColl.providerName, aMailColl.baseAddress, aMailColl.address,
... aMailColl.pattern, aMailColl.userName)
(u'imap', None, None, None, u'jim')
('imap', None, None, None, 'jim')
>>> from loops.integrator.mail import testing
@ -187,9 +185,9 @@ to the external system:
>>> aMail.date, aMail.sender, aMail.receiver, aMail.title
(datetime.datetime(...), 'ceo@cy55.de', 'ceo@example.org', 'Blogging from Munich')
>>> aMail.data
u'<p><b>Blogging from ...</b><br />\n'
'<p><b>Blogging from ...</b><br />\n'
>>> aMail.externalAddress
u'imap://jim@.../20081208171745.e4ce2xm96cco80cg@cy55.de'
'imap://jim@.../20081208171745.e4ce2xm96cco80cg@cy55.de'
Uploading Resources with HTTP PUT Requests
@ -217,9 +215,9 @@ Uploading Resources with HTTP PUT Requests
*** resources.PUT .data local/user/filesystem/testing/data/file1.txt
>>> getName(resource)
u'local_user_filesystem_testing_data_file1.txt'
'local_user_filesystem_testing_data_file1.txt'
>>> resource.title
u'file1'
'file1'
Extracting Document Properties from MS Office Files
@ -234,7 +232,7 @@ Extracting Document Properties from MS Office Files
23561...
>>> officeFile = addAndConfigureObject(resources, Resource, 'test.docx',
... title=u'Example Word File', resourceType=tOfficeFile,
... title='Example Word File', resourceType=tOfficeFile,
... storageParams=dict(subdirectory=path))
>>> aOfficeFile = adapted(officeFile)
>>> aOfficeFile.externalAddress = 'example.docx'
@ -245,6 +243,7 @@ Extracting Document Properties from MS Office Files
Clean up:
>>> shutil.copy(fn + '.sav', fn)
'.../example.docx'
Fin de partie

View file

@ -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.integrator.collection
"""
Concept adapter(s) for external collections, e.g. a directory in the
""" Concept adapter(s) for external collections, e.g. a directory in the
file system.
"""
@ -26,15 +9,15 @@ from logging import getLogger
import os, re, stat
import transaction
from zope.app.container.interfaces import INameChooser
from zope.app.container.contained import ObjectRemovedEvent
from zope.container.interfaces import INameChooser
from zope.container.contained import ObjectRemovedEvent
from zope.cachedescriptors.property import Lazy
from zope import component
from zope.component import adapts
from zope.contenttype import guess_content_type
from zope.event import notify
from zope.lifecycleevent import ObjectModifiedEvent
from zope.interface import implements, Attribute
from zope.interface import implementer, Attribute
from zope.schema.interfaces import IField
from zope.traversing.api import getName, getParent
@ -56,12 +39,12 @@ TypeInterfaceSourceList.typeInterfaces += (IExternalCollection,)
logger = getLogger('loops.integrator.collection')
@implementer(IExternalCollection)
class ExternalCollectionAdapter(AdapterBase):
""" A concept adapter for accessing an external collection.
May delegate access to a named utility.
"""
implements(IExternalCollection)
adapts(IConcept)
_adapterAttributes = AdapterBase._adapterAttributes + (
@ -84,16 +67,16 @@ class ExternalCollectionAdapter(AdapterBase):
if self.useVersioning:
for obj in old.values():
for vaddr, vobj, vid in self.getVersions(obj):
print '###', vaddr, vobj, vid
print('###', vaddr, vobj, vid)
versions.add(vaddr)
new = []
oldFound = set([])
provider = component.getUtility(IExternalCollectionProvider,
name=self.providerName or '')
#print '*** old', old, versions, self.lastUpdated
#print('*** old', old, versions, self.lastUpdated)
changeCount = 0
for addr, mdate in provider.collect(self):
#print '***', addr, mdate
#print('***', addr, mdate)
if addr in versions:
continue
if addr in old:
@ -170,12 +153,11 @@ class ExternalCollectionAdapter(AdapterBase):
if IVersionable(v).parent is not None]
@implementer(IExternalCollectionProvider)
class DirectoryCollectionProvider(object):
""" A utility that provides access to files in a directory.
"""
implements(IExternalCollectionProvider)
extFileTypeMapping = {
'image/*': 'media_asset',
'*/*': 'extfile',
@ -256,7 +238,7 @@ class DirectoryCollectionProvider(object):
base, ext = title.rsplit('.', 1)
if ext.lower() in mimetypes.extensions.values():
title = base
if not isinstance(title, unicode):
if isinstance(title, bytes):
try:
title = title.decode('UTF-8')
except UnicodeDecodeError:

View file

@ -1,32 +1,13 @@
#
# Copyright (c) 2009 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.integrator.mail.collection
"""
Concept adapter(s) for external collections, e.g. a directory in the
""" Concept adapter(s) for external collections, e.g. a directory in the
file system.
$Id$
"""
from zope.cachedescriptors.property import Lazy
from zope import component
from zope.component import adapts
from zope.interface import implements
from zope.interface import implementer
from loops.integrator.collection import ExternalCollectionAdapter
from loops.integrator.mail.interfaces import IMailCollection
@ -36,13 +17,12 @@ from loops.type import TypeInterfaceSourceList
TypeInterfaceSourceList.typeInterfaces += (IMailCollection,)
@implementer(IMailCollection)
class MailCollectionAdapter(ExternalCollectionAdapter):
""" A concept adapter for accessing a mail collection.
May delegate access to a named utility.
"""
implements(IMailCollection)
_adapterAttributes = ExternalCollectionAdapter._adapterAttributes + (
'providerName', '_collectedObjects')
_contextAttributes = list(IMailCollection)

View file

@ -1,42 +1,23 @@
#
# Copyright (c) 2010 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.integrator.mail.imap
"""
Concept adapter(s) for external collections, e.g. a directory in the
""" Concept adapter(s) for external collections, e.g. a directory in the
file system.
$Id$
"""
from datetime import datetime
import email, email.Header
import email, email.header, email.utils
from logging import getLogger
import os
import time
from zope.app.container.interfaces import INameChooser
from zope.cachedescriptors.property import Lazy
from zope import component
from zope.component import adapts
from zope.container.interfaces import INameChooser
from zope.event import notify
from zope.lifecycleevent import ObjectCreatedEvent, ObjectModifiedEvent
from zope.event import notify
from zope.interface import implements
from zope.interface import implementer
from zope.traversing.api import getName, getParent
from loops.common import AdapterBase, adapted
@ -47,12 +28,11 @@ from loops.resource import Resource
from loops.setup import addAndConfigureObject
@implementer(IExternalCollectionProvider)
class IMAPCollectionProvider(object):
""" A utility that provides access to an IMAP folder.
"""
implements(IExternalCollectionProvider)
def collect(self, client):
client._collectedObjects = {}
hostName = client.baseAddress
@ -90,7 +70,7 @@ class IMAPCollectionProvider(object):
#raw_date = msg['Date'].rsplit(' ', 1)[0]
#fmt = '%a, %d %b %Y %H:%M:%S'
#date = datetime(*(time.strptime(raw_date, fmt)[0:6]))
date = datetime(*(email.Utils.parsedate(msg['Date'])[0:6]))
date = datetime(*(email.utils.parsedate(msg['Date'])[0:6]))
parts = getPayload(msg)
if 'html' in parts:
text = '<br /><br /><hr /><br /><br />'.join(parts['html'])
@ -117,7 +97,7 @@ class IMAPCollectionProvider(object):
def decodeHeader(h):
result = []
for v, dec in email.Header.decode_header(h):
for v, dec in email.header.decode_header(h):
if dec:
v = v.decode(dec)
result.append(v)

View file

@ -1,25 +1,6 @@
#
# Copyright (c) 2009 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.integrator.mail.interfaces
"""
Integrator interfaces for email representation.
$Id$
""" Integrator interfaces for email representation.
"""
from zope.interface import Interface, Attribute
@ -69,8 +50,8 @@ class IMailResource(ITextDocument):
title=_(u'External Address'),
description=_(u'The full address of the email in the external '
u'email system.'),
default='',
missing_value='',
default=b'',
missing_value=b'',
required=False)
sender = schema.TextLine(
title=_(u'Sender'),

View file

@ -1,31 +1,12 @@
#
# Copyright (c) 2009 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.integrator.mail.resouurce
"""
Adapter for mail resources.
$Id$
""" Adapter for mail resources.
"""
from zope.cachedescriptors.property import Lazy
from zope import component
from zope.component import adapts
from zope.interface import implements
from zope.interface import implementer
from loops.integrator.mail.interfaces import IMailResource
from loops.resource import TextDocumentAdapter
@ -35,11 +16,10 @@ from loops.type import TypeInterfaceSourceList
TypeInterfaceSourceList.typeInterfaces += (IMailResource,)
@implementer(IMailResource)
class MailResource(TextDocumentAdapter):
""" A concept adapter for accessing a mail collection.
May delegate access to a named utility.
"""
implements(IMailResource)
_contextAttributes = list(IMailResource)

View file

@ -1,23 +1,6 @@
#
# Copyright (c) 2014 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.integrator.office.base
"""
Resource adapter(s) for MS Office files.
""" Resource adapter(s) for MS Office files.
"""
from datetime import date, datetime, timedelta
@ -30,7 +13,7 @@ from zipfile import ZipFile, BadZipfile
from zope.cachedescriptors.property import Lazy
from zope import component
from zope.component import adapts
from zope.interface import implements
from zope.interface import implementer
from zope.traversing.api import getName, getParent
from cybertools.storage.interfaces import IExternalStorage
@ -45,13 +28,12 @@ from loops.versioning.interfaces import IVersionable
TypeInterfaceSourceList.typeInterfaces += (IOfficeFile,)
@implementer(IOfficeFile)
class OfficeFile(ExternalFileAdapter):
""" An external file that references a MS Office (2007/2010) file.
It provides access to the document content and properties.
"""
implements(IOfficeFile)
_adapterAttributes = (ExternalFileAdapter._adapterAttributes +
('documentPropertiesAccessible',))
@ -98,7 +80,7 @@ class OfficeFile(ExternalFileAdapter):
try:
zf = ZipFile(fn, 'r')
self.documentPropertiesAccessible = True
except (IOError, BadZipfile), e:
except (IOError, BadZipfile) as e:
from logging import getLogger
self.logger.warn(e)
self.documentPropertiesAccessible = False

View file

@ -1,37 +1,18 @@
#
# Copyright (c) 2007 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.integrator.put
"""
Traversal adapter for PUT requests, e.g. coming from loops.agent.
$Id$
""" Traversal adapter for PUT requests, e.g. coming from loops.agent.
"""
from zope import interface, component
from zope.interface import implements
from zope.component import adapts
from zope.app.catalog.interfaces import ICatalog
from zope.app.container.interfaces import INameChooser
from zope.app.container.traversal import ContainerTraverser, ItemTraverser
from zope.contenttype import guess_content_type
from zope.cachedescriptors.property import Lazy
from zope.catalog.interfaces import ICatalog
from zope.component import adapts
from zope.container.interfaces import INameChooser
from zope.container.traversal import ContainerTraverser, ItemTraverser
from zope.contenttype import guess_content_type
from zope.event import notify
from zope.filerepresentation.interfaces import IWriteFile
from zope.interface import implementer
from zope.lifecycleevent import ObjectCreatedEvent, ObjectModifiedEvent
from zope.publisher.interfaces import IPublishTraverse
@ -42,9 +23,9 @@ from loops.interfaces import IResourceManager
from loops.resource import Resource
@implementer(IPublishTraverse)
class ResourceManagerTraverser(ItemTraverser):
implements(IPublishTraverse)
adapts(IResourceManager)
def publishTraverse(self, request, name):
@ -61,8 +42,8 @@ class ResourceManagerTraverser(ItemTraverser):
for i in range(len(stack)):
# prevent further traversal
stack.pop()
#print '*** resources.PUT', name, path, machine, user, app
print '*** resources.PUT', name, path
#print('*** resources.PUT', name, path, machine, user, app)
print('*** resources.PUT', name, path)
resource = self.findResource(path)
if resource is None:
resource = self.createResource(path)
@ -118,9 +99,11 @@ class ResourceManagerTraverser(ItemTraverser):
base, ext = name.rsplit('.', 1)
if ext.lower() in mimetypes.extensions.values():
name = base
return name.decode('UTF-8')
return name
#return name.decode('UTF-8')
@implementer(IWriteFile)
class MetadataProxy(object):
""" Processes a metadata file for an associated resource.
"""
@ -128,19 +111,16 @@ class MetadataProxy(object):
def __init__(self, resource):
self.resource = resource
implements(IWriteFile)
def write(self, text):
# TODO: provide/change concept assignments based on metadata
print '*** metadata', repr(text)
print('*** metadata', repr(text))
@implementer(IWriteFile)
class DummyResource(object):
""" Just for testing
"""
implements(IWriteFile)
def write(self, text):
print '*** content', repr(text)
print('*** content', repr(text))

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.integrator.source
"""
Managing information form objects provided by external sources, e.g. loops.agent.
""" Managing information form objects provided by external sources, e.g. loops.agent.
"""
from persistent.mapping import PersistentMapping
from zope import interface, component
from zope.interface import implements
from zope.interface import implementer
from zope.component import adapts
from loops.common import adapted, AdapterBase
@ -33,9 +16,9 @@ from loops.integrator.interfaces import IExternalSourceInfo
sourceInfoAttrName = '__loops_integrator_sourceinfo__'
@implementer(IExternalSourceInfo)
class ExternalSourceInfo(object):
implements(IExternalSourceInfo)
adapts(ILoopsObject)
def __init__(self, context):

View file

@ -1,11 +1,12 @@
"""
Set up a loops site for testing.
# loops.integrator.testsetup
""" Set up a loops site for testing.
"""
import os
from zope import component
from zope.app.catalog.interfaces import ICatalog
from zope.app.catalog.field import FieldIndex
from zope.catalog.interfaces import ICatalog
from zope.catalog.field import FieldIndex
from cybertools.storage.interfaces import IExternalStorage
from cybertools.storage.filesystem import fullPathStorage

View file

@ -276,7 +276,7 @@ class Resource(Image, Contained):
if newAdapted is not None and newOptions.get('storage') != oldAdapted.storageName:
data = oldAdapted.data
#print 'data', data
oldAdapted.data = '' # clear old storage
oldAdapted.data = b'' # clear old storage
context._storageName = None # let's take storage from new type options
context._storageParams = None # "
if data: # do not write empty files