from .models import Concept, Type
from conceptpower import Conceptpower
from urlparse import urlparse
from django.conf import settings
import logging
logging.basicConfig()
logger = logging.getLogger(__name__)
logger.setLevel('DEBUG')
[docs]class AuthorityManager(object):
pass
[docs]class ConceptpowerAuthority(AuthorityManager, Conceptpower):
__name__ = 'ConceptpowerAuthority'
endpoint = settings.CONCEPTPOWER_ENDPOINT
namespace = settings.CONCEPTPOWER_NAMESPACE
#
# class VogonAuthority(AuthorityManager):
# __name__ = "VogonAuthority"
#
# def search(self, query, pos='noun'):
# return Concept.objects.filter(label__contains=query).filter(pos=pos)
#
# def get(self, uri):
# return Concept.object.get(uri=uri)
#
# def get_type(self, uri):
# return Type.objects.get(uri=uri)
#
# namespace = '{http://vogon.asu.edu/}'
# Register AuthorityManagers here.
authority_managers = (
ConceptpowerAuthority,
# VogonAuthority,
)
[docs]def search(query, pos='noun'):
results = [r for manager in authority_managers
for r in manager().search(query, pos=pos)]
concepts = []
for r in results:
r['label'] = r['lemma']
instance, created = Concept.objects.get_or_create(
uri=r['id'],
authority=manager.__name__)
if created:
instance = update_instance(Concept, instance, r, manager.__name__)
concepts.append(instance)
return concepts
[docs]def update_instance(sender, instance, concept_data, authority):
# Update description, label, (and typed).
instance.description = concept_data['description']
instance.label = concept_data['label']
if 'pos' in concept_data:
instance.pos = concept_data['pos']
else:
instance.pos = 'unknown'
# For Types, this will create a cascade of post_save
# signals resulting in a crawl up the Type ontology
# based on the ``supertype`` property.
if sender is Concept:
if 'type_uri' in concept_data:
type_uri = concept_data['type_uri']
else:
type_uri = None
elif sender is Type:
if 'supertype_uri' in concept_data:
type_uri = concept_data['supertype_uri']
else:
type_uri = None
if type_uri is not None:
type_instance = Type.objects.get_or_create(uri=type_uri, authority=authority)[0]
instance.typed = type_instance
logger.debug(
'Added Type {0} to Concept {1}.'.format(
type_instance.uri, instance.uri))
instance.save()
return instance
[docs]def resolve(sender, instance):
"""
Resolve :class:`.Concept`\s and :class:`.Type`\s using the registered
:class:`.AuthorityManager`\s.
Parameters
----------
sender : class
instance : :class:`.Type` or :class:`.Concept`
"""
logger.debug(
'Received post_save signal for Concept {0}.'.format(instance.id))
if instance is not None:
# Configure based on sender model class.
try:
instance_cast = instance.cast()
except:
return
if type(instance_cast) is Concept:
get_method = 'get'
label_field = 'lemma'
elif type(instance_cast) is Type:
get_method = 'get_type'
label_field = 'type'
# Skip any instance that has already been resolved, or that lacks a URI.
if not instance.resolved and instance.uri is not None:
logger.debug('Instance {0} not yet resolved.'.format(instance.id))
# Get AuthorityManager classes by namespace.
managers = get_by_namespace(get_namespace(instance.uri))
logger.debug(
'Found {0} managers for {1}'.format(len(managers),instance.uri))
# Try each AuthorityManager...
for manager_class in managers:
if instance.resolved: break # ...until success.
manager = manager_class()
method = getattr(manager, get_method)
concept_data = method(instance.uri)
concept_data['label'] = concept_data.get(label_field, 'No label')
instance.authority = manager.__name__
logger.debug(
'Trying AuthorityManager {0}.'.format(manager.__name__))
instance.resolved = True
instance.concept_state = Concept.RESOLVED
update_instance(sender, instance, concept_data, manager.__name__)
[docs]def get_namespace(uri):
"""
Extract namespace from URI.
"""
o = urlparse(uri)
namespace = o.scheme + "://" + o.netloc + "/"
if o.scheme == '' or o.netloc == '':
raise ValueError("Could not determine namespace for {0}.".format(uri))
return "{" + namespace + "}"
[docs]def get_by_namespace(namespace):
"""
Retrieve a registered :class:`AuthorityManager` by its namespace.
"""
return [ manager for manager in authority_managers
if manager.namespace == namespace ]
[docs]def add(instance):
"""
Add the approved concept to Conceptpower
Parameters
-----------
instance : :class:'.Concept'
Returns
-------
response : dict
Examples
-------
.. code-block:: python
>>> add(concept)
{
u'word': u'Askania-Nova',
u'description': u'A biosphere reserve located in Kherson Oblast, Ukraine',
u'conceptlist': u'VogonWeb Concepts',
u'type': u'http://www.digitalhps.org/types/TYPE_dfc95f97-f128-42ae-b54c-ee40333eae8c',
u'equals': [],
u'pos': u'noun',
u'synonymids': [],
u'similar': [],
u'id': u'CONf3a936bd-f9fe-415c-8e9e-e463de7d4bbf'
}
"""
concept_list = 'VogonWeb Concepts'
conceptpower = ConceptpowerAuthority()
response = conceptpower.create(settings.CONCEPTPOWER_USERID,
settings.CONCEPTPOWER_PASSWORD,
instance.label,
instance.pos,
concept_list,
instance.description,
instance.typed.uri)
# This is kind of hacky, but the current version of Conceptpower does not
# return the full URI of the new Concept -- just its ID. We can remove this
# when the new version of Conceptpower is released.
if 'uri' not in response:
response['uri'] = u'http://www.digitalhps.org/concepts/%s' % response['id']
return response