Skip to content

Commit

Permalink
Merge 6c10da8 into 792fe5b
Browse files Browse the repository at this point in the history
  • Loading branch information
koenedaele committed Oct 3, 2019
2 parents 792fe5b + 6c10da8 commit 1df856e
Show file tree
Hide file tree
Showing 5 changed files with 245 additions and 28 deletions.
85 changes: 82 additions & 3 deletions docs/install.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,91 @@ To install `pyramid_skosprovider`, use pip
pip install pyramid_skosprovider
To activate `pyramid_skosprovider`, just include it.
To activate `pyramid_skosprovider`, you need to include it and configure your
:class:`skosprovider.registry.Registry`. Older versions, before `0.9.0`,
attached the `registry` to the Pyramid application registry. Starting with
`0.9.0` it's possible and recommended to attach the skos registry to a request.
The old way is still allowed for backward compatibility, but should only be
used with local provider that store all their data in memory, such as a
:class:`skosprovider.providers.DictionaryProvider`. Future versions will remove
this way of working.

Since `0.9.0`, two new settings were added:

*skosprovider.skosregistry_location* deteremines where your registry lives in
the application. Currently two options are supported: `registry` or `request`.
The first attaches the :class:`skosprovider.registry.Registry` to the Pyramid
application registry as the Pyramid application is started. The second option
attaches the skos registry to the Pyramid request. This ensures every reqeust
has it's own registry.

*skosprovider.skosregistry_factory* allows you to specify a factory function
for instantiating the :class:`skosprovider.registry.Registry`. This function
will receive the Pyramid request as a first argument if you are using a
registry attached to a request. If you do specify a factory, an empty skos
registry will be created and used.

Please be aware that attaching a registry to the Pyramid application registry
was the only option before `0.9.0`. It is still supported because it makes
sense for a registry that only contains providers that load all their data in
memory on initialisation. Providers that require a database connection should
always be attached to a request.

Supposing you want to attach your registry to requests, you would configure
your application. A possible configuration for a `myskos` application would be:

.. code-block:: yaml
skosprovider.skosregistry_location: request
skosprovider.skosregistry_factory: myskos.skos.build_registry
To actually use `pyramid_skosprovider`, you still need to include it in your
pyramid application and write the factory function. In your Pyramid startup
function:

.. code-block:: python
config = Configurator()
config.include('pyramid_skosprovider')
This will create a :class:`skosprovider.registry.Registry` and add it to
the pyramid application registry.
This will instantiate the :class:`skosprovider.registry.Registry` using the
configuration you have provided and make it available to your application.

Your `myskos.skos` python module should then contain a `build_registry`
function that receives a Pyramid request, creates the skos registry and
returns it:

.. code-block:: python
from skosprovider.registry import Registry
from skosprovider.providers import DictionaryProvider
def build_registry(request):
r = Registry(
instance_scope='threaded_thread'
)
dictprovider = DictionaryProvider(
{
'id': 'TREES',
'default_language': 'nl',
'subject': ['biology'],
'dataset': {
'uri': 'http://id.trees.org/dataset'
}
},
[],
uri_generator=UriPatternGenerator('http://id.trees.org/types/%s'),
concept_scheme=ConceptScheme('http://id.trees.org')
)
r.register_provider(dictprovider)
return r
This is a very simple example. A typical real-life application would have
several providers. Some of them might be DictionaryProviders, others might
reaf from rdf files and still others might read from a SQL Databases. If you're
using the `skosprovider_sqlalchemy` provider, you would attach your database
session maker to the request and then pass it on to the SQLAlchemy provider in
your factory function.
90 changes: 81 additions & 9 deletions pyramid_skosprovider/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,44 +9,116 @@
jsonld_renderer
)

from pyramid.path import (
DottedNameResolver
)


class ISkosRegistry(Interface):
pass


def _build_skos_registry(registry):
skos_registry = registry.queryUtility(ISkosRegistry)
if skos_registry is not None:
return skos_registry
def _parse_settings(settings):
defaults = {
'skosregistry_location': 'registry',
}
args = defaults.copy()

# string setting
for short_key_name in ('skosregistry_location', 'skosregistry_factory'):
key_name = "skosprovider.%s" % short_key_name
if key_name in settings:
args[short_key_name] = settings.get(key_name)

return args


def _register_global_skos_registry(registry):
'''
Build a :class:`skosprovider.registry.Registry` and attach it to the
Pyramid registry.
:param registry: The Pyramid registry
:rtype: :class:`skosprovider.registry.Registry`
'''
settings = _parse_settings(registry.settings)

skos_registry = Registry()
if 'skosregistry_factory' in settings:
r = DottedNameResolver()
skos_registry = r.resolve(settings['skosregistry_factory'])()
else:
skos_registry = Registry(instance_scope='threaded_global')

registry.registerUtility(skos_registry, ISkosRegistry)
return registry.queryUtility(ISkosRegistry)


def _register_request_skos_registry(request):
'''
Get the :class:`skosprovider.registry.Registry` attached to this request.
:param request: The Pyramid request
:rtype: :class:`skosprovider.registry.Registry`
'''
settings = _parse_settings(request.registry.settings)

if 'skosregistry_factory' in settings:
r = DottedNameResolver()
skos_registry = r.resolve(settings['skosregistry_factory'])(request)
else:
skos_registry = Registry(instance_scope='threaded_thread')

return skos_registry


def get_skos_registry(registry):
'''
Get the :class:`skosprovider.registry.Registry` attached to this pyramid
application.
:param registry: A Pyramid registry, request or config.
:rtype: :class:`skosprovider.registry.Registry`
'''
# Argument might be a config or request
# Argument might be a registry or have it as an attribute
regis = getattr(registry, 'registry', None)
if regis is None:
regis = registry
return regis.queryUtility(ISkosRegistry)
settings = _parse_settings(regis.settings)

print(settings)

if settings['skosregistry_location'] == 'registry':
return regis.queryUtility(ISkosRegistry)
else:
raise RuntimeError('This is an older method that \
is maintained for Backward Compatibility. It should \
only be called for a global registry.')


def includeme(config):
_build_skos_registry(config.registry)
settings = _parse_settings(config.registry.settings)

if settings['skosregistry_location'] == 'registry':
_register_global_skos_registry(config.registry)
config.add_request_method(
get_skos_registry,
'skos_registry',
reify=True
)
else:
config.add_request_method(
_register_request_skos_registry,
'skos_registry',
reify=True
)

config.add_renderer('skosjson', json_renderer)
config.add_renderer('skosjsonld', jsonld_renderer)

config.add_directive('get_skos_registry', get_skos_registry)
config.add_request_method(get_skos_registry, 'skos_registry', reify=True)

config.add_route(
'skosprovider.context',
Expand Down
4 changes: 3 additions & 1 deletion tests/test_functional.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ def skosmain(global_config, **settings):
class FunctionalTests(unittest.TestCase):

def setUp(self):
settings = {}
settings = {
'skosprovider.skosregistry_location': 'registry'
}
app = skosmain({}, **settings)
self.testapp = TestApp(app)

Expand Down
88 changes: 75 additions & 13 deletions tests/test_varia.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@

from pyramid_skosprovider import (
ISkosRegistry,
_build_skos_registry,
get_skos_registry,
#get_request_skos_registry,
_register_global_skos_registry,
_register_request_skos_registry,
includeme
)

Expand All @@ -16,6 +18,7 @@
)

import unittest
import pytest


class TestRegistry(object):
Expand All @@ -25,7 +28,7 @@ def __init__(self, settings=None):
if settings is None:
self.settings = {}
else: # pragma NO COVER
self.settings = settings
self.settings = settings

self.skos_registry = None

Expand All @@ -36,26 +39,77 @@ def registerUtility(self, skos_registry, iface):
self.skos_registry = skos_registry


def _skosregis_factory_global():
return Registry(
instance_scope='threaded_global'
)


def _skosregis_factory_request(request):
return Registry(
instance_scope='threaded_thread'
)


class TestGetAndBuild(unittest.TestCase):

def test_get_skos_registry(self):
r = TestRegistry()
SR = Registry()
settings={
'skosprovider.skosregistry_location': 'registry',
}
r = TestRegistry(settings=settings)
SR = Registry(
instance_scope='threaded_global'
)
r.registerUtility(SR, ISkosRegistry)
SR2 = get_skos_registry(r)
self.assertEqual(SR, SR2)

def test_build_skos_registry_already_exists(self):
assert SR == SR2

def test_get_skos_registry_not_working_for_requests(self):
settings={
'skosprovider.skosregistry_location': 'request',
}
r = TestRegistry(settings=settings)
with pytest.raises(RuntimeError):
assert isinstance(get_skos_registry(r), Registry)

def test_register_global_skos_registry_custom_factory(self):
settings={
'skosprovider.skosregistry_location': 'registry',
'skosprovider.skosregistry_factory': 'tests.test_varia._skosregis_factory_global'
}
r = TestRegistry(settings=settings)
SR = _register_global_skos_registry(r)
assert isinstance(SR, Registry)

def test_register_global_skos_registry_already_exists(self):
r = TestRegistry()
SR = Registry()
SR = Registry(
instance_scope='threaded_global'
)
r.registerUtility(SR, ISkosRegistry)
SR2 = _build_skos_registry(r)
self.assertEqual(SR, SR2)
SR2 = _register_global_skos_registry(r)
assert isinstance(SR, Registry)

def test_build_skos_registry_default_settings(self):
def test_register_global_skos_registry_default_settings(self):
r = TestRegistry()
SR = _build_skos_registry(r)
self.assertIsInstance(SR, Registry)
SR = _register_global_skos_registry(r)
assert isinstance(SR, Registry)

def test_get_request_skos_registry(self):
request = testing.DummyRequest()
request.registry.settings = {'skosprovider.skosregistry_location': 'request'}
SR = _register_request_skos_registry(request)
assert isinstance(SR, Registry)

def test_get_request_skos_registry_custom_factory(self):
request = testing.DummyRequest()
request.registry.settings = {
'skosprovider.skosregistry_location': 'request',
'skosprovider.skosregistry_factory': 'tests.test_varia._skosregis_factory_request'
}
SR = _register_request_skos_registry(request)
assert isinstance(SR, Registry)


class TestIncludeMe(unittest.TestCase):
Expand All @@ -75,3 +129,11 @@ def test_directive_was_added(self):
includeme(self.config)
SR = self.config.get_skos_registry()
self.assertIsInstance(SR, Registry)

def test_includeme_request(self):
settings = {
'skosprovider.skosregistry_location': 'request',
'skosprovider.skosregistry_factory': 'tests.test_varia._skosregis_factory_request'
}
self.config = testing.setUp(settings=settings);
includeme(self.config)
6 changes: 4 additions & 2 deletions tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,14 @@
Label
)

from skosprovider.registry import Registry

class StaticViewTests(unittest.TestCase):

def setUp(self):
self.config = testing.setUp()
self.config.include('pyramid_skosprovider')
self.regis = self.config.get_skos_registry()
self.regis = Registry()

def tearDown(self):
testing.tearDown()
Expand Down Expand Up @@ -53,7 +55,7 @@ class ProviderViewTests(unittest.TestCase):
def setUp(self):
self.config = testing.setUp()
self.config.include('pyramid_skosprovider')
self.regis = self.config.get_skos_registry()
self.regis = Registry()
self.regis.register_provider(trees)

def tearDown(self):
Expand Down

0 comments on commit 1df856e

Please sign in to comment.