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()
>>> len(concepts), len(resources)
(20, 0)
(21, 0)
Let's now add an external collection that reads in a set of resources
from external files so we have something to work with.
@ -84,8 +84,8 @@ and follow the classifier step by step.
>>> infoSet
{'filename': 'cust_im_contract_webbg_20071015.txt'}
>>> analyzer = component.getUtility(IAnalyzer, name=classifier.analyzer)
>>> statements = analyzer.extractStatements(infoSet, classifier)
>>> analyzer = component.getAdapter(classifier, name=classifier.analyzer)
>>> statements = analyzer.extractStatements(infoSet)
>>> statements
[]
@ -120,11 +120,10 @@ that may be identified as being candidates for classification.
>>> from zope.app.catalog.interfaces import ICatalog
>>> cat = component.getUtility(ICatalog)
>>> #list(cat.searchResults(loops_text='webbg'))
>>> statements = analyzer.extractStatements(infoSet, classifier)
>>> statements = analyzer.extractStatements(infoSet)
>>> len(statements)
2
3
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():
extractor = component.getAdapter(adapted(resource), IExtractor, name=name)
infoSet.update(extractor.extractInformationSet())
analyzer = component.getUtility(IAnalyzer, name=self.analyzer)
statements = analyzer.extractStatements(infoSet, self)
analyzer = component.getAdapter(self, name=self.analyzer)
statements = analyzer.extractStatements(infoSet)
for statement in statements:
self.assignConcept(statement)
@ -79,8 +79,12 @@ class Extractor(object):
class Analyzer(object):
implements(IAnalyzer)
adapts(IClassifier)
def extractStatements(self, informationSet, classifier=None):
def __init__(self, context):
self.context = context
def extractStatements(self, informationSet):
return []
@ -93,7 +97,7 @@ class Statement(object):
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.predicate = predicate
self.object = object

View file

@ -41,8 +41,8 @@ class IClassifier(Interface):
analyzer = schema.TextLine(
title=_(u'Analyzer'),
description=_(u'Name of a utility that is able to analyze '
'the resources assigned to this classifier.'),
description=_(u'Name of an adapter (or a utility?) that is able to '
'analyze the resources assigned to this classifier.'),
default=u'',
required=False)
@ -74,17 +74,13 @@ class IExtractor(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.
"""
def extractStatements(informationSet, classifier=None):
def extractStatements(informationSet):
""" Return a collection of statements derived from the
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.app.catalog.interfaces import ICatalog
from zope.cachedescriptors.property import Lazy
from zope.component import adapts
from cybertools.organize.interfaces import IPerson
@ -45,48 +46,34 @@ class SampleAnalyzer(Analyzer):
resource.
"""
def handleCustomer(self, name, classifier):
result = []
candidates = self.findConcepts(name)
cm = self.getConceptManager(classifier)
custTypes = [c for c in (cm.get('institution'), cm.get('customer'),)
if c is not None]
for c in candidates:
ctype = IType(c)
if ctype.typeProvider in custTypes:
result.append(Statement(c))
return result
def handleCustomer(self, name):
custTypes = self.getTypes(('institution', 'customer',))
for c in self.findConcepts(name):
if IType(c).typeProvider in custTypes:
yield Statement(c)
def handleEmployee(self, name, classifier):
result = []
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:
def handleEmployee(self, name):
for c in self.findConcepts(name):
if IPerson.providedBy(adapted(c)):
result.append(Statement(c))
return result
yield Statement(c)
def handleDoctype(self, name, classifier):
result = []
#print 'doctype', name
return result
def handleOwner(self, name):
cm = self.conceptManager
ownedby = cm.get('ownedby')
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)
def extractStatements(self, informationSet, classifier=None):
def extractStatements(self, informationSet):
result = []
if classifier is None:
return result # classifier is needed for getting access to concepts
fn = informationSet.get('filename')
if fn is None:
return result
@ -95,17 +82,21 @@ class SampleAnalyzer(Analyzer):
ctype = parts.pop(0)
if ctype in self.handlers:
name = parts.pop(0)
result.extend(self.handlers[ctype](self, name, classifier))
result.extend(self.handlers[ctype](self, name))
if len(parts) > 1:
result.extend(self.handleDoctype(parts.pop(0), classifier))
result.extend(self.handleDoctype(parts.pop(0)))
if len(parts) > 1:
result.extend(self.handleOwner(parts.pop(0), classifier))
result.extend(self.handleOwner(parts.pop(0)))
return result
def findConcepts(self, name):
cat = component.getUtility(ICatalog)
return cat.searchResults(loops_text=name)
def getConceptManager(self, obj):
return obj.context.getLoopsRoot().getConceptManager()
@Lazy
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 ExternalCollectionAdapter
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.knowledge import Person
from loops.knowledge.interfaces import IPerson
@ -39,6 +40,7 @@ class TestSite(BaseTestSite):
def setup(self):
component.provideAdapter(KnowledgeSetupManager, name='knowledge')
component.provideAdapter(OrganizeSetupManager, name='organize')
concepts, resources, views = self.baseSetup()
#catalog = component.getUtility(ICatalog)
@ -56,7 +58,7 @@ class TestSite(BaseTestSite):
sampleClassifier.extractors = 'filename'
sampleClassifier.analyzer = 'sample'
component.provideAdapter(FilenameExtractor, name='filename')
component.provideUtility(SampleAnalyzer(), IAnalyzer, name='sample')
component.provideAdapter(SampleAnalyzer, name='sample')
# external file stuff for providing test files
component.provideAdapter(ExternalFileAdapter, provides=IExternalFile)

View file

@ -240,26 +240,6 @@ class ConceptManager(BTreeContainer):
# 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):
implements(schema.interfaces.IIterableSource)

View file

@ -36,9 +36,13 @@ class SetupManager(BaseSetupManager):
def setup(self):
concepts = self.context.getConceptManager()
type = concepts.getTypeConcept()
predicate = concepts['predicate']
person = self.addObject(concepts, Concept, 'person', title=u'Person',
conceptType=type)
personTypeAdapter = ITypeConcept(person)
if not personTypeAdapter.typeInterface: # only set if not set yet
personTypeAdapter.typeInterface = IPerson
aPerson = ITypeConcept(person)
if not aPerson.typeInterface: # allow overriding by other packages
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:
>>> sorted(concepts)
[u'domain', u'file', u'hasType', u'note', u'person', u'predicate', u'query',
u'standard', u'textdocument', u'type']
[u'domain', u'file', u'hasType', u'note', u'ownedby', u'person',
u'predicate', u'query', u'standard', u'textdocument', u'type']
Now let's add a few more concepts:
>>> topic = concepts[u'topic'] = Concept(u'Topic')
>>> intIds.register(topic)
10
11
>>> zope = concepts[u'zope'] = Concept(u'Zope')
>>> zope.conceptType = topic
>>> intIds.register(zope)
11
12
>>> zope3 = concepts[u'zope3'] = Concept(u'Zope 3')
>>> zope3.conceptType = topic
>>> intIds.register(zope3)
12
13
Navigation typically starts at a start object, which by default ist the
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;
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())
[u'domain', u'file', u'note', u'person', u'predicate', u'query',
u'textdocument', u'type']
>>> 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:
@ -184,14 +184,14 @@ Updating the concept map
>>> topicId = xrf.getObjectByName('topic')['id']
>>> 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'}
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.
>>> 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'}
Changing the attributes of a concept