Source code for fantastico.roa.resources_registry

'''
Copyright 2013 Cosnita Radu Viorel

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

.. codeauthor:: Radu Viorel Cosnita <radu.cosnita@gmail.com>
.. py:module:: fantastico.roa.resources_registry
'''
from fantastico.roa.roa_exceptions import FantasticoRoaDuplicateError
from fantastico.utils.singleton import Singleton

@Singleton()
[docs]class ResourcesRegistry(object): '''This class provide the methods for registering resources into Fantastico framework and locating them by url or name and version. As a Developer you will not usually need access to this class.''' _RESOURCE_LATEST_VERSION = "latest" @property
[docs] def available_resources(self): '''This readonly property returns the indexed resources by name.''' return self._available_resources
@property
[docs] def available_url_resources(self): '''This readonly property returns the indexed resources by urk.''' return self._available_url_resources
_available_resources = {} _available_url_resources = {}
[docs] def register_resource(self, resource): '''This method register a new resource into Fantastico framework. It first checks against name, url and version collision in order to detect as early as possible errors with the current defined resources. :param resource: The resource instance we want to register into Fantastico ROA registry. :type resource: :py:class:`fantastico.roa.resource_decorator.Resource` :raises fantastico.roa.roa_exceptions.FantasticoRoaDuplicateError: This exception is raised when: * resource name and version already registered. * resource url already registered.''' self._register_resource_in_resources(resource) self._register_resource_in_urls(resource)
def _register_resource_in_resources(self, resource): '''This method registers a given resource into AVAILABLE_RESOURCES dictionary.''' registry = self._available_resources if not registry.get(resource.name): registry[resource.name] = {} resource_versions = registry[resource.name] if resource_versions.get(resource.version): raise FantasticoRoaDuplicateError("Resource %s with version %s already registered." % \ (resource.name, resource.version)) resource_versions[resource.version] = resource self._update_latest_version(resource_versions, resource) def _register_resource_in_urls(self, resource): '''This method registers a given resource into AVAILABLE_URLS dictionary.''' registry_urls = self._available_url_resources if not registry_urls.get(resource.url): registry_urls[resource.url] = {} registry_url_versions = registry_urls[resource.url] if registry_url_versions.get(resource.version): raise FantasticoRoaDuplicateError("URL %s is already taken. Can not register resource %s." % \ (resource.url, resource.name)) registry_url_versions[resource.version] = resource self._update_latest_version(registry_url_versions, resource) def _update_latest_version(self, registry, resource): '''This method updates the registry latest version to point to the given resource (if necessary).''' for registered_version in registry.keys(): if registered_version == self._RESOURCE_LATEST_VERSION: continue if registered_version > resource.version: return registry[self._RESOURCE_LATEST_VERSION] = resource def _find_resource_in_registry(self, registry, resource_id, version): '''This method returns a resource from a given registry by a given id (resource name or resource url) and resource version.''' if not registry.get(resource_id): return if not registry[resource_id].get(version): return return registry[resource_id][version]
[docs] def find_by_name(self, name, version=_RESOURCE_LATEST_VERSION): '''This method returns a registered resource under the given name and version. :param name: The resource name. :type name: string :param version: The numeric version of the resource or **latest**. :type version: string :returns: The resource found or None. :rtype: :py:class:`fantastico.roa.resource_decorator.Resource` ''' registry = self._available_resources return self._find_resource_in_registry(registry, name, version)
[docs] def find_by_url(self, url, version=_RESOURCE_LATEST_VERSION): '''This method returns a registered resource under the given url and version. :param name: The resource name. :type name: string :param version: The numeric version of the resource or **latest**. :type version: string :returns: The resource found or None. :rtype: :py:class:`fantastico.roa.resource_decorator.Resource`''' registry = self._available_url_resources return self._find_resource_in_registry(registry, url, version)
[docs] def all_resources(self): '''This method returns a list of all registered resources order by name and version. It is extremely useful for introspecting Fantastico ROA platform.''' registry = self._available_resources resources = [] for name in registry.keys(): resources.extend(registry[name].values()) return sorted(resources)
def _get_latest_version(self, registry): '''This method obtains the latest version resource from the list of available versions.''' resource_latest = None for registered_version in registry.keys(): if registered_version == self._RESOURCE_LATEST_VERSION: continue resource = registry[registered_version] if not resource_latest: resource_latest = resource if resource.version > resource_latest.version: resource_latest = resource return resource_latest def _unregister_registry_resource(self, registry, resource_id, version): '''This method unregister a given resource from the given registry.''' versions = registry.get(resource_id) if not versions: return resource = versions.get(version) if resource: del versions[version] resource_latest = self._get_latest_version(versions) if resource_latest: versions[self._RESOURCE_LATEST_VERSION] = resource_latest else: del versions[self._RESOURCE_LATEST_VERSION] return resource
[docs] def unregister_resource(self, name, version): '''This method unregister a resource version. If the given resource is not found no exception is raised. Once a resource is unregistered latest version is recalculated. The resource is completely removed from AVAILABLE_RESOURCES and AVAILABLE_URLS dictionaries. :param name: Resource name. :type name: string :param version: Resource version. If you specify **latest** it will have no effect. :type version: float ''' if version == self._RESOURCE_LATEST_VERSION: return registry_resources = self._available_resources registry_urls = self._available_url_resources resource = self._unregister_registry_resource(registry_resources, name, version) if not resource: return self._unregister_registry_resource(registry_urls, resource.url, version)