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:
parent
1e0b976929
commit
dd809a07af
8 changed files with 68 additions and 92 deletions
|
@ -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.
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
"""
|
||||
|
||||
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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)
|
||||
|
|
20
concept.py
20
concept.py
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue