work in progress: loops.classifier - some refactorings

git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@2073 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
helmutm 2007-09-28 13:06:42 +00:00
parent 1e0b976929
commit dd809a07af
8 changed files with 68 additions and 92 deletions

View file

@ -27,7 +27,7 @@ configuration):
>>> concepts, resources, views = t.setup() >>> concepts, resources, views = t.setup()
>>> len(concepts), len(resources) >>> len(concepts), len(resources)
(20, 0) (21, 0)
Let's now add an external collection that reads in a set of resources Let's now add an external collection that reads in a set of resources
from external files so we have something to work with. from external files so we have something to work with.
@ -84,8 +84,8 @@ and follow the classifier step by step.
>>> infoSet >>> infoSet
{'filename': 'cust_im_contract_webbg_20071015.txt'} {'filename': 'cust_im_contract_webbg_20071015.txt'}
>>> analyzer = component.getUtility(IAnalyzer, name=classifier.analyzer) >>> analyzer = component.getAdapter(classifier, name=classifier.analyzer)
>>> statements = analyzer.extractStatements(infoSet, classifier) >>> statements = analyzer.extractStatements(infoSet)
>>> statements >>> statements
[] []
@ -120,11 +120,10 @@ that may be identified as being candidates for classification.
>>> from zope.app.catalog.interfaces import ICatalog >>> from zope.app.catalog.interfaces import ICatalog
>>> cat = component.getUtility(ICatalog) >>> cat = component.getUtility(ICatalog)
>>> #list(cat.searchResults(loops_text='webbg'))
>>> statements = analyzer.extractStatements(infoSet, classifier) >>> statements = analyzer.extractStatements(infoSet)
>>> len(statements) >>> len(statements)
2 3
So we are now ready to have the whole stuff run in one call. So we are now ready to have the whole stuff run in one call.

View file

@ -55,8 +55,8 @@ class Classifier(AdapterBase):
for name in self.extractors.split(): for name in self.extractors.split():
extractor = component.getAdapter(adapted(resource), IExtractor, name=name) extractor = component.getAdapter(adapted(resource), IExtractor, name=name)
infoSet.update(extractor.extractInformationSet()) infoSet.update(extractor.extractInformationSet())
analyzer = component.getUtility(IAnalyzer, name=self.analyzer) analyzer = component.getAdapter(self, name=self.analyzer)
statements = analyzer.extractStatements(infoSet, self) statements = analyzer.extractStatements(infoSet)
for statement in statements: for statement in statements:
self.assignConcept(statement) self.assignConcept(statement)
@ -79,8 +79,12 @@ class Extractor(object):
class Analyzer(object): class Analyzer(object):
implements(IAnalyzer) implements(IAnalyzer)
adapts(IClassifier)
def extractStatements(self, informationSet, classifier=None): def __init__(self, context):
self.context = context
def extractStatements(self, informationSet):
return [] return []
@ -93,7 +97,7 @@ class Statement(object):
implements(IStatement) implements(IStatement)
def __init__(self, subject=None, predicate=None, object=None, relevance=100): def __init__(self, object=None, predicate=None, subject=None, relevance=100):
self.subject = subject self.subject = subject
self.predicate = predicate self.predicate = predicate
self.object = object self.object = object

View file

@ -41,8 +41,8 @@ class IClassifier(Interface):
analyzer = schema.TextLine( analyzer = schema.TextLine(
title=_(u'Analyzer'), title=_(u'Analyzer'),
description=_(u'Name of a utility that is able to analyze ' description=_(u'Name of an adapter (or a utility?) that is able to '
'the resources assigned to this classifier.'), 'analyze the resources assigned to this classifier.'),
default=u'', default=u'',
required=False) required=False)
@ -74,17 +74,13 @@ class IExtractor(Interface):
class IAnalyzer(Interface): class IAnalyzer(Interface):
""" Utility that is able to analyze an information set and """ Adapter (or utility?) that is able to analyze an information set and
provide a collection of statements about it. provide a collection of statements about it.
""" """
def extractStatements(informationSet, classifier=None): def extractStatements(informationSet):
""" Return a collection of statements derived from the """ Return a collection of statements derived from the
information set given. information set given.
The ``classifier`` argument may be given in order to
check the environment of the classifier, e.g. available
concepts that may be used as attributes for statements.
""" """

View file

@ -24,6 +24,7 @@ $Id$
from zope import component from zope import component
from zope.app.catalog.interfaces import ICatalog from zope.app.catalog.interfaces import ICatalog
from zope.cachedescriptors.property import Lazy
from zope.component import adapts from zope.component import adapts
from cybertools.organize.interfaces import IPerson from cybertools.organize.interfaces import IPerson
@ -45,48 +46,34 @@ class SampleAnalyzer(Analyzer):
resource. resource.
""" """
def handleCustomer(self, name, classifier): def handleCustomer(self, name):
result = [] custTypes = self.getTypes(('institution', 'customer',))
candidates = self.findConcepts(name) for c in self.findConcepts(name):
cm = self.getConceptManager(classifier) if IType(c).typeProvider in custTypes:
custTypes = [c for c in (cm.get('institution'), cm.get('customer'),) yield Statement(c)
if c is not None]
for c in candidates:
ctype = IType(c)
if ctype.typeProvider in custTypes:
result.append(Statement(c))
return result
def handleEmployee(self, name, classifier): def handleEmployee(self, name):
result = [] for c in self.findConcepts(name):
candidates = self.findConcepts(name)
cm = self.getConceptManager(classifier)
for c in candidates:
ctype = IType(c)
if ctype.typeInterface == IPerson:
result.append(Statement(c))
return result
def handleOwner(self, name, classifier):
result = []
candidates = self.findConcepts(name)
cm = self.getConceptManager(classifier)
for c in candidates:
if IPerson.providedBy(adapted(c)): if IPerson.providedBy(adapted(c)):
result.append(Statement(c)) yield Statement(c)
return result
def handleDoctype(self, name, classifier): def handleOwner(self, name):
result = [] cm = self.conceptManager
#print 'doctype', name ownedby = cm.get('ownedby')
return result for c in self.findConcepts(name):
if IPerson.providedBy(adapted(c)):
yield Statement(c, ownedby)
def handleDoctype(self, name):
docTypes = self.getTypes(('doctype',))
for c in self.findConcepts(name):
if IType(c).typeProvider in docTypes:
yield Statement(c)
handlers = dict(cust=handleCustomer, emp=handleEmployee) handlers = dict(cust=handleCustomer, emp=handleEmployee)
def extractStatements(self, informationSet, classifier=None): def extractStatements(self, informationSet):
result = [] result = []
if classifier is None:
return result # classifier is needed for getting access to concepts
fn = informationSet.get('filename') fn = informationSet.get('filename')
if fn is None: if fn is None:
return result return result
@ -95,17 +82,21 @@ class SampleAnalyzer(Analyzer):
ctype = parts.pop(0) ctype = parts.pop(0)
if ctype in self.handlers: if ctype in self.handlers:
name = parts.pop(0) name = parts.pop(0)
result.extend(self.handlers[ctype](self, name, classifier)) result.extend(self.handlers[ctype](self, name))
if len(parts) > 1: if len(parts) > 1:
result.extend(self.handleDoctype(parts.pop(0), classifier)) result.extend(self.handleDoctype(parts.pop(0)))
if len(parts) > 1: if len(parts) > 1:
result.extend(self.handleOwner(parts.pop(0), classifier)) result.extend(self.handleOwner(parts.pop(0)))
return result return result
def findConcepts(self, name): def findConcepts(self, name):
cat = component.getUtility(ICatalog) cat = component.getUtility(ICatalog)
return cat.searchResults(loops_text=name) return cat.searchResults(loops_text=name)
def getConceptManager(self, obj): @Lazy
return obj.context.getLoopsRoot().getConceptManager() def conceptManager(self):
return self.context.context.getConceptManager()
def getTypes(self, typeNames):
cm = self.conceptManager
return [c for c in [cm.get(name) for name in typeNames] if c is not None]

View file

@ -23,6 +23,7 @@ from loops.interfaces import IConcept, IIndexAttributes, IExternalFile
from loops.integrator.collection import DirectoryCollectionProvider from loops.integrator.collection import DirectoryCollectionProvider
from loops.integrator.collection import ExternalCollectionAdapter from loops.integrator.collection import ExternalCollectionAdapter
from loops.integrator.interfaces import IExternalCollection, IExternalCollectionProvider from loops.integrator.interfaces import IExternalCollection, IExternalCollectionProvider
from loops.organize.setup import SetupManager as OrganizeSetupManager
from loops.knowledge.setup import SetupManager as KnowledgeSetupManager from loops.knowledge.setup import SetupManager as KnowledgeSetupManager
from loops.knowledge.knowledge import Person from loops.knowledge.knowledge import Person
from loops.knowledge.interfaces import IPerson from loops.knowledge.interfaces import IPerson
@ -39,6 +40,7 @@ class TestSite(BaseTestSite):
def setup(self): def setup(self):
component.provideAdapter(KnowledgeSetupManager, name='knowledge') component.provideAdapter(KnowledgeSetupManager, name='knowledge')
component.provideAdapter(OrganizeSetupManager, name='organize')
concepts, resources, views = self.baseSetup() concepts, resources, views = self.baseSetup()
#catalog = component.getUtility(ICatalog) #catalog = component.getUtility(ICatalog)
@ -56,7 +58,7 @@ class TestSite(BaseTestSite):
sampleClassifier.extractors = 'filename' sampleClassifier.extractors = 'filename'
sampleClassifier.analyzer = 'sample' sampleClassifier.analyzer = 'sample'
component.provideAdapter(FilenameExtractor, name='filename') component.provideAdapter(FilenameExtractor, name='filename')
component.provideUtility(SampleAnalyzer(), IAnalyzer, name='sample') component.provideAdapter(SampleAnalyzer, name='sample')
# external file stuff for providing test files # external file stuff for providing test files
component.provideAdapter(ExternalFileAdapter, provides=IExternalFile) component.provideAdapter(ExternalFileAdapter, provides=IExternalFile)

View file

@ -240,26 +240,6 @@ class ConceptManager(BTreeContainer):
# adapters and similar components # adapters and similar components
class xxxConceptSourceList(object):
# seems to be obsolete
implements(schema.interfaces.IIterableSource)
def __init__(self, context):
self.context = context
#self.context = removeSecurityProxy(context)
root = self.context.getLoopsRoot()
self.concepts = root.getConceptManager()
def __iter__(self):
for obj in self.concepts.values():
yield obj
def __len__(self):
return len(self.concepts)
class ConceptTypeSourceList(object): class ConceptTypeSourceList(object):
implements(schema.interfaces.IIterableSource) implements(schema.interfaces.IIterableSource)

View file

@ -36,9 +36,13 @@ class SetupManager(BaseSetupManager):
def setup(self): def setup(self):
concepts = self.context.getConceptManager() concepts = self.context.getConceptManager()
type = concepts.getTypeConcept() type = concepts.getTypeConcept()
predicate = concepts['predicate']
person = self.addObject(concepts, Concept, 'person', title=u'Person', person = self.addObject(concepts, Concept, 'person', title=u'Person',
conceptType=type) conceptType=type)
personTypeAdapter = ITypeConcept(person) aPerson = ITypeConcept(person)
if not personTypeAdapter.typeInterface: # only set if not set yet if not aPerson.typeInterface: # allow overriding by other packages
personTypeAdapter.typeInterface = IPerson aPerson.typeInterface = IPerson
owner = self.addObject(concepts, Concept, 'ownedby', title=u'owned by',
conceptType=predicate)

View file

@ -43,22 +43,22 @@ ZCML setup):
Let's look what setup has provided us with: Let's look what setup has provided us with:
>>> sorted(concepts) >>> sorted(concepts)
[u'domain', u'file', u'hasType', u'note', u'person', u'predicate', u'query', [u'domain', u'file', u'hasType', u'note', u'ownedby', u'person',
u'standard', u'textdocument', u'type'] u'predicate', u'query', u'standard', u'textdocument', u'type']
Now let's add a few more concepts: Now let's add a few more concepts:
>>> topic = concepts[u'topic'] = Concept(u'Topic') >>> topic = concepts[u'topic'] = Concept(u'Topic')
>>> intIds.register(topic) >>> intIds.register(topic)
10 11
>>> zope = concepts[u'zope'] = Concept(u'Zope') >>> zope = concepts[u'zope'] = Concept(u'Zope')
>>> zope.conceptType = topic >>> zope.conceptType = topic
>>> intIds.register(zope) >>> intIds.register(zope)
11 12
>>> zope3 = concepts[u'zope3'] = Concept(u'Zope 3') >>> zope3 = concepts[u'zope3'] = Concept(u'Zope 3')
>>> zope3.conceptType = topic >>> zope3.conceptType = topic
>>> intIds.register(zope3) >>> intIds.register(zope3)
12 13
Navigation typically starts at a start object, which by default ist the Navigation typically starts at a start object, which by default ist the
domain concept (if present, otherwise the top-level type concept): domain concept (if present, otherwise the top-level type concept):
@ -86,13 +86,13 @@ There are a few standard objects we can retrieve directly:
In addition we can get a list of all types and all predicates available; In addition we can get a list of all types and all predicates available;
note that the 'hasType' predicate is not shown as it should not be note that the 'hasType' predicate is not shown as it should not be
applied in a direct assignment. applied in an explicit assignment.
>>> sorted(t['name'] for t in xrf.getConceptTypes()) >>> sorted(t['name'] for t in xrf.getConceptTypes())
[u'domain', u'file', u'note', u'person', u'predicate', u'query', [u'domain', u'file', u'note', u'person', u'predicate', u'query',
u'textdocument', u'type'] u'textdocument', u'type']
>>> sorted(t['name'] for t in xrf.getPredicates()) >>> sorted(t['name'] for t in xrf.getPredicates())
[u'standard'] [u'ownedby', u'standard']
We can also retrieve a certain object by its id or its name: We can also retrieve a certain object by its id or its name:
@ -184,14 +184,14 @@ Updating the concept map
>>> topicId = xrf.getObjectByName('topic')['id'] >>> topicId = xrf.getObjectByName('topic')['id']
>>> xrf.createConcept(topicId, u'zope2', u'Zope 2') >>> xrf.createConcept(topicId, u'zope2', u'Zope 2')
{'description': u'', 'title': u'Zope 2', 'type': '10', 'id': '16', {'description': u'', 'title': u'Zope 2', 'type': '11', 'id': '17',
'name': u'zope2'} 'name': u'zope2'}
The name of the concept is checked by a name chooser; if the corresponding The name of the concept is checked by a name chooser; if the corresponding
parameter is empty, the name will be generated from the title. parameter is empty, the name will be generated from the title.
>>> xrf.createConcept(topicId, u'', u'Python') >>> xrf.createConcept(topicId, u'', u'Python')
{'description': u'', 'title': u'Python', 'type': '10', 'id': '17', {'description': u'', 'title': u'Python', 'type': '11', 'id': '18',
'name': u'python'} 'name': u'python'}
Changing the attributes of a concept Changing the attributes of a concept