def test_classgeneric_function_directive(): class app(morepath.App): pass @reg.dispatch(reg.match_class('o', lambda o: o)) def mygeneric(o): return "The object" class Foo(object): pass @app.function(mygeneric, o=Foo) def mygeneric_for_foo(o): return "The foo object" a = app() assert mygeneric(object, lookup=a.lookup) == 'The object' assert mygeneric(Foo, lookup=a.lookup) == 'The foo object'
class App(ChameleonApp, morpfw.SQLApp, DefaultAuthzPolicy): request_class = WebAppRequest portlet = dectate.directive(directive.PortletFactoryAction) portletprovider = dectate.directive(directive.PortletProviderFactoryAction) structure_column = dectate.directive(directive.StructureColumnAction) @reg.dispatch_method(reg.match_instance('model'), reg.match_instance('request'), reg.match_key('name')) def get_structure_column(self, model, request, name): raise NotImplementedError('Get structure columns for %s structure:%s' % (model, name)) def get_portletprovider(self, name): return self.config.portletprovider_registry.get_provider(name) @reg.dispatch_method(reg.match_class('schema')) def get_schemaextender(self, schema): return None
def __init__(self): self.get_converter = reg.dispatch( reg.match_class("type"), get_key_lookup=reg.DictCachingKeyLookup)(get_converter) self.register_converter(type(None), IDENTITY_CONVERTER)
def __init__(self): self.get_converter = reg.dispatch( reg.match_class('type'), get_key_lookup=reg.DictCachingKeyLookup)(get_converter) self.register_converter(type(None), IDENTITY_CONVERTER)
import reg from webob.exc import HTTPNotFound @reg.dispatch('obj') def path(obj): """Get the path and parameters for a model object in its own application. :param obj: model object or :class:`morepath.App` instance. :return: a tuple with a URL path and URL parameters, or ``None`` if path cannot be determined. """ return None @reg.dispatch(reg.match_class('cls', lambda cls: cls)) def class_path(cls, variables): """Get the path for a model class. :param cls: model class or :class:`morepath.App` subclass. :param variables: dictionary with variables to reconstruct the path and URL paramaters from path pattern. :return: a tuple with URL path and URL parameters, or ``None`` if path cannot be determined. """ return None @reg.dispatch('obj') def deferred_link_app(mounted, obj): """Get application used for link generation.
def __init__(self): self._registry = PredicateRegistry(match_class('cls', lambda cls: cls))
class app(morepath.App): @morepath.dispatch_method(reg.match_class('o')) def mygeneric(self, o): return "The object"
@reg.dispatch() def remember_identity(response, request, identity): """Modify response so that identity is remembered by client. """ raise NotImplementedError # pragma: nocoverage @reg.dispatch() def forget_identity(response, request): """Modify response so that identity is forgotten by client. """ raise NotImplementedError # pragma: nocoverage @reg.dispatch('identity', 'obj', reg.match_class('permission', lambda permission: permission)) def permits(identity, obj, permission): """Returns True if identity has permission for model. identity can be the special NO_IDENTITY singleton; register for NoIdentity to handle this case separately. """ return False @reg.dispatch() def load_json(request, json): """Load JSON as some object. Can return any Python object. """
The functions are made pluggable by the use of the :func:`reg.dispatch` and :func:`reg.dispatch_external_predicates` decorators. Morepath's configuration function uses this to register implementations using :meth:`reg.Registry.register_function`. :func:`morepath.remember_identity`, :func:`morepath.forget_identity` and :func:`morepath.settings`, currently exported to the public API, are now deprecated. """ import reg from webob.exc import HTTPNotFound @reg.dispatch(reg.match_class('model', lambda model: model)) def class_path(model, variables): """Get the path for a model class. :param model: model class or :class:`morepath.App` subclass. :param variables: dictionary with variables to reconstruct the path and URL paramaters from path pattern. :return: a tuple with URL path and URL parameters, or ``None`` if path cannot be determined. """ return None @reg.dispatch('obj') def path_variables(obj, lookup): """Get variables to use in path generation.
class App(ChameleonApp, morpfw.SQLApp, MorpCCAuthzPolicy): request_class = WebAppRequest portlet = dectate.directive(directive.PortletFactoryAction) portletprovider = dectate.directive(directive.PortletProviderFactoryAction) contextportletprovider = dectate.directive( directive.ContextPortletProviderFactoryAction) structure_column = dectate.directive(directive.StructureColumnAction) schemaextender = dectate.directive(directive.SchemaExtenderAction) messagingprovider = dectate.directive(directive.MessagingProviderAction) vocabulary = dectate.directive(directive.VocabularyAction) indexer = dectate.directive(directive.IndexerAction) indexresolver = dectate.directive(directive.IndexResolverAction) behavior = dectate.directive(directive.BehaviorAction) application_behavior = dectate.directive( directive.ApplicationBehaviorAction) default_factory = dectate.directive(directive.DefaultFactoryAction) restricted_module = dectate.directive(directive.RestrictedModuleAction) breadcrumb = dectate.directive(directive.BreadcrumbAction) setting_page = dectate.directive(directive.SettingPageAction) setting_modules = dectate.directive(directive.SettingModuleAction) license_cert = dectate.directive(directive.LicenseCertAction) license_key = dectate.directive(directive.LicenseKeyAction) copyright_notice = dectate.directive(directive.CopyrightNoticeAction) datasource = dectate.directive(directive.DataSourceAction) permission_resolver = dectate.directive(directive.PermissionResolverAction) @reg.dispatch_method(reg.match_instance("model"), reg.match_key("name")) def get_indexer(self, model, name): return None @reg.dispatch_method( reg.match_instance("model"), reg.match_instance("request"), reg.match_key("name"), ) def get_structure_column(self, model, request, name): raise NotImplementedError("Get structure columns for %s structure:%s" % (model, name)) def get_portletprovider(self, name): return self.config.portletprovider_registry.get_provider(name) @reg.dispatch_method(reg.match_instance("model"), reg.match_key("name")) def get_contextportletprovider(self, model, name): return None @reg.dispatch_method(reg.match_class("schema")) def get_schemaextender(self, schema): return schema @reg.dispatch_method(reg.match_instance("request"), reg.match_key("name")) def get_messagingprovider(self, request, name): raise NotImplementedError("Messaging provider %s is not available" % name) @reg.dispatch_method(reg.match_instance("request"), reg.match_key("name")) def get_vocabulary(self, request, name): return None @reg.dispatch_method(reg.match_key("name")) def get_behavior_factory(self, name): raise NotImplementedError @reg.dispatch_method(reg.match_key("name")) def get_application_behavior_factory(self, name): raise NotImplementedError @reg.dispatch_method(reg.match_key("name")) def get_default_factory(self, name): raise NotImplementedError @reg.dispatch_method(reg.match_key("name")) def get_index_resolver(self, name): raise NotImplementedError @reg.dispatch_method(reg.match_key("name")) def get_restricted_module(self, name): raise ImportError( "Module {} is not allowed to be imported in this context".format( name)) @reg.dispatch_method( reg.match_instance("model"), reg.match_instance("request"), ) def get_breadcrumb(self, model, request): return [] @reg.dispatch_method(reg.match_instance("request")) def get_license_cert(self, request): return None @reg.dispatch_method(reg.match_instance("request")) def get_license_key(self, request): return None @reg.dispatch_method(reg.match_instance("request")) def get_copyright_notice(self, request): dt = date.today() return ( "Morp Control Center. © 2018-%s Mohd Izhar Firdaus Bin Ismail" % dt.year) @reg.dispatch_method(reg.match_key("name")) def get_datasource_factory(self, name): raise NotImplementedError() def get_datasource(self, name, request): return self.config.datasource_registry.get(name=name, request=request) def resolve_permissionassignment(self, request, model, permission, identity): return self.config.permissionresolver_registry.resolve( request, model, permission, identity) def render_view(self, context, request, name=""): lookup = self.get_view.by_predicates(model=context.__class__, name=name) if lookup and lookup.component: try: return lookup.component(obj=context, request=request, app=self) except HTTPException as e: return None return None
class App(JsonSchemaApp, signals.SignalApp): jslcrud_dataprovider = dectate.directive(actions.DataProviderAction) jslcrud_jsonprovider = dectate.directive(actions.JSONProviderAction) jslcrud_jsontransfrom = dectate.directive(actions.JSONTransformAction) jslcrud_formvalidators = dectate.directive(actions.FormValidatorAction) jslcrud_identifierfields = dectate.directive( actions.IdentifierFieldsAction) jslcrud_default_identifier = dectate.directive( actions.DefaultIdentifierAction) jslcrud_rulesadapter = dectate.directive(actions.RulesAdapterAction) jslcrud_uuidfield = dectate.directive(actions.UUIDFieldAction) jslcrud_statemachine = dectate.directive(actions.StateMachineAction) @reg.dispatch_method( reg.match_class('schema', lambda self, schema, obj, storage: schema), reg.match_instance('obj'), reg.match_instance('storage')) def get_jslcrud_dataprovider(self, schema, obj, storage): raise NotImplementedError('Dataprovider for %s/%s' % (storage.__class__, obj.__class__)) @reg.dispatch_method(reg.match_instance('obj')) def get_jslcrud_jsonprovider(self, obj): raise NotImplementedError('JSONProvider for %s' % obj.__class__) @reg.dispatch_method(reg.match_class('schema', lambda self, schema: schema)) def get_jslcrud_jsontransform(self, schema): raise NotImplementedError('JSONTransform for %s' % schema) @reg.dispatch_method(reg.match_class('schema', lambda self, schema: schema)) def get_jslcrud_formvalidators(self, schema): return [] @reg.dispatch_method(reg.match_class('schema', lambda self, schema: schema)) def get_jslcrud_identifierfields(self, schema): raise NotImplementedError('IdentifierFields for %s' % schema) @reg.dispatch_method(reg.match_class('schema', lambda self, schema: schema)) def get_jslcrud_uuidfield(self, schema): return 'uuid' @reg.dispatch_method( reg.match_class('schema', lambda self, schema, obj, request: schema)) def get_jslcrud_default_identifier(self, schema, obj, request): return None @reg.dispatch_method(reg.match_instance('model', lambda self, obj: obj)) def _jslcrud_rulesadapter(self, obj): raise NotImplementedError @reg.dispatch_method( reg.match_instance('model', lambda self, context: context)) def _jslcrud_statemachine(self, context): raise NotImplementedError def get_jslcrud_compositekey_separator(self): morp_settings = getattr(self.settings, 'jslcrud', {}) return morp_settings.get('compositekey_separator', '!!!') def jslcrud_join_identifier(self, *args): separator = self.get_jslcrud_compositekey_separator() return separator.join(args)
def clear(self): self._registry = PredicateRegistry(match_class('cls', lambda cls: cls))
def __init__(self): self._registry = PredicateRegistry(match_class('cls'))
class App(ChameleonApp, morpfw.SQLApp, DefaultAuthzPolicy): request_class = WebAppRequest portlet = dectate.directive(directive.PortletFactoryAction) portletprovider = dectate.directive(directive.PortletProviderFactoryAction) structure_column = dectate.directive(directive.StructureColumnAction) schemaextender = dectate.directive(directive.SchemaExtenderAction) messagingprovider = dectate.directive(directive.MessagingProviderAction) vocabulary = dectate.directive(directive.VocabularyAction) indexer = dectate.directive(directive.IndexerAction) indexresolver = dectate.directive(directive.IndexResolverAction) behavior = dectate.directive(directive.BehaviorAction) application_behavior = dectate.directive( directive.ApplicationBehaviorAction) default_factory = dectate.directive(directive.DefaultFactoryAction) restricted_module = dectate.directive(directive.RestrictedModuleAction) @reg.dispatch_method(reg.match_instance("model"), reg.match_key("name")) def get_indexer(self, model, name): return None @reg.dispatch_method( reg.match_instance("model"), reg.match_instance("request"), reg.match_key("name"), ) def get_structure_column(self, model, request, name): raise NotImplementedError("Get structure columns for %s structure:%s" % (model, name)) def get_portletprovider(self, name): return self.config.portletprovider_registry.get_provider(name) @reg.dispatch_method(reg.match_class("schema")) def get_schemaextender(self, schema): return schema @reg.dispatch_method(reg.match_instance("request"), reg.match_key("name")) def get_messagingprovider(self, request, name): raise NotImplementedError("Messaging provider %s is not available" % name) @reg.dispatch_method(reg.match_instance("request"), reg.match_key("name")) def get_vocabulary(self, request, name): return None @reg.dispatch_method(reg.match_key("name")) def get_behavior_factory(self, name): raise NotImplementedError @reg.dispatch_method(reg.match_key("name")) def get_application_behavior_factory(self, name): raise NotImplementedError @reg.dispatch_method(reg.match_key("name")) def get_default_factory(self, name): raise NotImplementedError @reg.dispatch_method(reg.match_key("name")) def get_index_resolver(self, name): raise NotImplementedError @reg.dispatch_method(reg.match_key("name")) def get_restricted_module(self, name): raise ImportError( "Module {} is not allowed to be imported in this context".format( name)) def render_view(self, context, request, name=""): lookup = self.get_view.by_predicates(model=context.__class__, name=name) if lookup and lookup.component: try: return lookup.component(obj=context, request=request, app=self) except HTTPException as e: return None return None
class App(dectate.App): """A Morepath-based application object. You subclass App to create a morepath application class. You can then configure this class using Morepath decorator directives. An application can extend one or more other applications, if desired, by subclassing them. By subclassing App itself, you get the base configuration of the Morepath framework itself. Conflicting configuration within an app is automatically rejected. An subclass app cannot conflict with the apps it is subclassing however; instead configuration is overridden. You can turn your app class into a `WSGI`_ application by instantiating it. You can then call it with the ``environ`` and ``start_response`` arguments. .. _`WSGI`: https://www.python.org/dev/peps/pep-3333/ Subclasses from :class:`dectate.App`, which provides the :meth:`dectate.App.directive` decorator that lets you register new directives. """ parent = None """The parent in which this app was mounted.""" request_class = Request """The class of the Request to create. Must be a subclass of :class:`morepath.Request`. By default the request class is :class:`morepath.Request` """ logger_name = 'morepath.directive' """Prefix used by dectate to log configuration actions. """ setting = directive(action.SettingAction) setting_section = directive(action.SettingSectionAction) predicate_fallback = directive(action.PredicateFallbackAction) predicate = directive(action.PredicateAction) method = directive(action.MethodAction) converter = directive(action.ConverterAction) _path = directive(action.PathAction) path = directive(action.PathCompositeAction) permission_rule = directive(action.PermissionRuleAction) template_directory = directive(action.TemplateDirectoryAction) template_loader = directive(action.TemplateLoaderAction) template_render = directive(action.TemplateRenderAction) view = directive(action.ViewAction) json = directive(action.JsonAction) html = directive(action.HtmlAction) mount = directive(action.MountAction) defer_links = directive(action.DeferLinksAction) defer_class_links = directive(action.DeferClassLinksAction) tween_factory = directive(action.TweenFactoryAction) identity_policy = directive(action.IdentityPolicyAction) verify_identity = directive(action.VerifyIdentityAction) dump_json = directive(action.DumpJsonAction) load_json = directive(action.LoadJsonAction) link_prefix = directive(action.LinkPrefixAction) def __init__(self): pass def request(self, environ): """Create a :class:`Request` given WSGI environment for this app. :param environ: WSGI environment :return: :class:`morepath.Request` instance """ return self.request_class(environ, self) def __call__(self, environ, start_response): """This app as a WSGI application. See the WSGI_ spec for more information. Uses :meth:`App.request` to generate a :class:`morepath.Request` instance, then uses meth:`App.publish` get the :class:`morepath.Response` instance. :param environ: WSGI environment :param start_response: WSGI start_response :return: WSGI iterable. """ request = self.request(environ) response = self.publish(request) return response(environ, start_response) @reify def publish(self): """Publish functionality wrapped in tweens. You can use middleware (:doc:`tweens`) that can hooks in before a request is passed into the application and just after the response comes out of the application. Here we use :meth:`morepath.tween.TweenRegistry.wrap` to wrap the :func:`morepath.publish.publish` function into the configured tweens. This property uses :func:`morepath.reify.reify` so that the tween wrapping only happens once when the first request is handled and is cached afterwards. :return: a function that a :class:`morepath.Request` instance and returns a :class:`morepath.Response` instance. """ # the last chance we have to commit the app is here, the # lookup may not be touched yet at this point if not self.is_committed(): self.commit() return self.config.tween_registry.wrap(self) def ancestors(self): """Return iterable of all ancestors of this app. Includes this app itself as the first ancestor, all the way up to the root app in the mount chain. """ app = self while app is not None: yield app app = app.parent @reify def root(self): """The root application. """ return list(self.ancestors())[-1] def child(self, app, **variables): """Get app mounted in this app. Either give it an instance of the app class as the first parameter, or the app class itself (or name under which it was mounted) as the first parameter and as ``variables`` the parameters that go to its ``mount`` function. Returns the mounted application object, with its ``parent`` attribute set to this app object, or ``None`` if this application cannot be mounted in this one. """ if isinstance(app, App): result = app # XXX assert that variables is empty # XXX do we need to deal with subclasses of apps? if app.__class__ not in self.config.path_registry.mounted: return None else: if isinstance(app, compat.string_types): factory = self.config.path_registry.named_mounted.get(app) else: factory = self.config.path_registry.mounted.get(app) if factory is None: return None result = factory(**variables) result.parent = self return result def sibling(self, app, **variables): """Get app mounted next to this app. Either give it an instance of the app class as the first parameter, or the app class itself (or name under which it was mounted) as the first parameter and as ``variables`` the parameters that go to its ``mount`` function. Returns the mounted application object, with its ``parent`` attribute set to the same parent as this one, or ``None`` if such a sibling application does not exist. """ parent = self.parent if parent is None: return None return parent.child(app, **variables) @property def settings(self): """Returns the settings bound to this app.""" return self.config.setting_registry @classmethod def mounted_app_classes(cls, callback=None): """Returns a set of this app class and any mounted under it. This assumes all app classes involved have already been committed previously, for instance by :meth:`morepath.App.commit`. Mounted apps are discovered in breadth-first order. The optional ``callback`` argument is used to implement :meth:`morepath.App.commit`. :param callback: a function that is called with app classes as its arguments. This can be used to do something with the app classes when they are first discovered, like commit them. Optional. :return: the set of app classes. """ discovery = set() found = {cls} while found: discovery.update(found) if callback is not None: callback(*found) found = ( {c for a in found for c in a.config.path_registry.mounted} - discovery) return discovery @classmethod def commit(cls): """Commit the app, and recursively, the apps mounted under it. Mounted apps are discovered in breadth-first order. :return: the set of discovered app clasess. """ return cls.mounted_app_classes(dectate.commit) @classmethod def init_settings(cls, settings): """Pre-fill the settings before the app is started. Add settings to App, which can act as normal, can be overridden, etc. :param settings: a dictionary of setting sections which contain dictionaries of settings. """ def set_setting_section(section, section_settings): cls.setting_section(section)(lambda: section_settings) for section, section_settings in settings.items(): set_setting_section(section, section_settings) @dispatch_method() def get_view(self, obj, request): """Get the view that represents the obj in the context of a request. This view is a representation of the obj that can be rendered to a response. It may also return a :class:`morepath.Response` directly. Predicates are installed in :mod:`morepath.core` that inspect both ``obj`` and ``request`` to see whether a matching view can be found. You can also install additional predicates using the :meth:`morepath.App.predicate` and :meth:`morepath.App.precicate_fallback` directives. :param obj: model object to represent with view. :param request: :class:`morepath.Request` instance. :return: :class:`morepath.Response` object, or :class:`webob.exc.HTTPNotFound` if view cannot be found. """ return HTTPNotFound() @dispatch_method('identity') def _verify_identity(self, identity): """Returns True if the claimed identity can be verified. Look in the database to verify the identity, or in case of auth tokens, always consider known identities to be correct. :param: :class:`morepath.Identity` instance. :return: ``True`` if identity can be verified. By default no identity can be verified so this returns ``False``. """ return False @dispatch_method('identity', 'obj', reg.match_class('permission')) def _permits(self, identity, obj, permission): """Returns ``True`` if identity has permission for model object. identity can be the special :data:`morepath.NO_IDENTITY` singleton; register for :class:`morepath.NoIdentity` to handle this case separately. :param identity: :class:`morepath.Identity` :param obj: model object :param permission: permission class. :return: ``True`` if identity has permission for obj. """ return False def _load_json(self, json, request): """Load JSON as some object. By default JSON is loaded as itself. :param json: JSON (in Python form) to convert into object. :param request: :class:`morepath.Request` :return: Any Python object, including JSON. """ return json @dispatch_method('obj') def _dump_json(self, obj, request): """Dump an object as JSON. ``obj`` is any Python object, try to interpret it as JSON. :param obj: any Python object to convert to JSON. :param request: :class:`morepath.Request` :return: JSON representation (in Python form). """ return obj def _link_prefix(self, request): """Returns a prefix that's added to every link generated by request. By default :attr:`webob.request.BaseRequest.application_url` is used. :param request: :class:`morepath.Request` :return: prefix string to add before links. """ return request.application_url @dispatch_method(reg.match_class('model')) def _class_path(self, model, variables): """Get the path for a model class. :param model: model class or :class:`morepath.App` subclass. :param variables: dictionary with variables to reconstruct the path and URL paramaters from path pattern. :return: a :class:`morepath.path.PathInfo` with path within this app, or ``None`` if the path couldn't be determined. """ return None @dispatch_method('obj') def _path_variables(self, obj): """Get variables to use in path generation. :param obj: model object or :class:`morepath.App` instance. :return: a dict with the variables to use for constructing the path, or ``None`` if no such dict can be found. """ return self._default_path_variables(obj) @dispatch_method('obj') def _default_path_variables(self, obj): """Get default variables to use in path generation. Invoked if no specific ``path_variables`` is registered. :param obj: model object for ::class:`morepath.App` instance. :return: a dict with the variables to use for constructing the path, or ``None`` if no such dict can be found. """ return None @dispatch_method('obj') def _deferred_link_app(self, obj): """Get application used for link generation. :param obj: model object to link to. :return: instance of :class:`morepath.App` subclass that handles link generation for this model, or ``None`` if no app exists that can construct link. """ return None @dispatch_method(reg.match_class('model')) def _deferred_class_link_app(self, model, variables): """Get application used for link generation for a model class. :param model: model class :param variables: dict of variables used to construct class link :return: instance of :class:`morepath.App` subclass that handles link generation for this model class, or ``None`` if no app exists that can construct link. """ return None @classmethod def clean(cls): reg.clean_dispatch_methods(cls) def _identify(self, request): """Determine identity for request. :param request: a :class:`morepath.Request` instance. :return: a :class:`morepath.Identity` instance or ``None`` if no identity can be found. Can also return :data:`morepath.NO_IDENTITY`, but ``None`` is converted automatically to this. """ return None def remember_identity(self, response, request, identity): """Modify response so that identity is remembered by client. :param response: :class:`morepath.Response` to remember identity on. :param request: :class:`morepath.Request` :param identity: :class:`morepath.Identity` """ pass def forget_identity(self, response, request): """Modify response so that identity is forgotten by client. :param response: :class:`morepath.Response` to forget identity on. :param request: :class:`morepath.Request` """ pass def _get_path(self, obj): """Path for a model obj. Only includes path within the current app, does not take mounting into account. :param obj: model object :return: a :class:`morepath.path.PathInfo` with path within this app. """ return self._class_path(obj.__class__, self._path_variables(obj)) def _get_mounted_path(self, obj): """Path for model obj including mounted path. Includes path to this app itself, so takes mounting into account. :param obj: model object (or :class:`morepath.App` instance). :return: a :class:`morepath.path.PathInfo` with fully resolved path in mounts. """ paths = [] parameters = {} app = self while app is not None: info = app._get_path(obj) if info is None: return None paths.append(info.path) parameters.update(info.parameters) obj = app app = app.parent paths.reverse() return PathInfo('/'.join(paths).strip('/'), parameters) def _get_mounted_class_path(self, model, variables): """Path for model class and variables including mounted path. Includes path to this app itself, so takes mounting into account. :param model: model class :param variables: dict with variables to use in the path :return: a :class:`morepath.path.PathInfo` with fully resolved path in mounts. """ info = self._class_path(model, variables) if info is None: return None if self.parent is None: return info mount_info = self.parent._get_mounted_path(self) path = mount_info.path if info.path: path += '/' + info.path parameters = info.parameters.copy() parameters.update(mount_info.parameters) return PathInfo(path, parameters) def _get_deferred_mounted_path(self, obj): """Path for obj taking into account deferring apps. Like :meth:`morepath.App._get_mounted_path` but takes :meth:`morepath.App.defer_links` and :meth:`morepath.App.defer_class_links` directives into account. """ def find(app, obj): return app._get_mounted_path(obj) info, app = self._follow_defers(find, obj) return info def _get_deferred_mounted_class_path(self, model, variables): """Path for model and variables taking into account deferring apps. Like :meth:`morepath.App._get_mounted_class_path` but takes :meth:`morepath.App.defer_class_links` directive into account. """ def find(app, model, variables): return app._get_mounted_class_path(model, variables) info, app = self._follow_class_defers(find, model, variables) return info def _follow_defers(self, find, obj): """Resolve to deferring app and find something. For ``obj``, look up deferring app as defined by :class:`morepath.App.defer_links` recursively. Use the supplied ``find`` function to find something for ``obj`` in that app. When something found, return what is found and the app where it was found. :param find: a function that takes an ``app`` and ``obj`` parameter and should return something when it is found, or ``None`` when not. :param obj: the model object to find things for. :return: a tuple with the thing found (or ``None``) and the app in which it was found. """ seen = set() app = self while app is not None: if app in seen: raise LinkError("Circular defer. Cannot link to: %r" % obj) result = find(app, obj) if result is not None: return result, app seen.add(app) next_app = app._deferred_link_app(obj) if next_app is None: # only if we can establish the variables of the app here # fall back on using class link app variables = app._path_variables(obj) if variables is not None: next_app = app._deferred_class_link_app( obj.__class__, variables) app = next_app return None, app def _follow_class_defers(self, find, model, variables): """Resolve to deferring app and find something. For ``model`` and ``variables``, look up deferring app as defined by :class:`morepath.App.defer_class_links` recursively. Use the supplied ``find`` function to find something for ``model`` and ``variables`` in that app. When something found, return what is found and the app where it was found. :param find: a function that takes an ``app``, ``model`` and ``variables`` arguments and should return something when it is found, or ``None`` when not. :param model: the model class to find things for. :return: a tuple with the thing found (or ``None``) and the app in which it was found. """ seen = set() app = self while app is not None: if app in seen: raise LinkError("Circular defer. Cannot link to: %r" % model) result = find(app, model, variables) if result is not None: return result, app seen.add(app) app = app._deferred_class_link_app(model, variables) return None, app
class App(JsonSchemaApp, signals.SignalApp): dataprovider = dectate.directive(actions.DataProviderAction) jsonprovider = dectate.directive(actions.JSONProviderAction) formvalidators = dectate.directive(actions.FormValidatorAction) identifierfields = dectate.directive(actions.IdentifierFieldsAction) default_identifier = dectate.directive(actions.DefaultIdentifierAction) rulesprovider = dectate.directive(actions.RulesProviderAction) uuidfield = dectate.directive(actions.UUIDFieldAction) statemachine = dectate.directive(actions.StateMachineAction) searchprovider = dectate.directive(actions.SearchProviderAction) aggregateprovider = dectate.directive(actions.AggregateProviderAction) xattrprovider = dectate.directive(actions.XattrProviderAction) storage = dectate.directive(actions.StorageAction) blobstorage = dectate.directive(actions.BlobStorageAction) typeinfo = dectate.directive(actions.TypeInfoFactoryAction) def get_storage(self, model, request): blobstorage = self.get_blobstorage(model, request) return self._get_storage(model, request, blobstorage) def get_blobstorage(self, model, request): return self._get_blobstorage(model, request) @reg.dispatch_method(reg.match_class('model'), reg.match_instance('request'), reg.match_instance('blobstorage')) def _get_storage(self, model, request, blobstorage): raise NotImplementedError @reg.dispatch_method(reg.match_class('model'), reg.match_instance('request')) def _get_blobstorage(self, model, request): return NullBlobStorage() @reg.dispatch_method( reg.match_class('schema', lambda self, schema, obj, storage: schema), reg.match_instance('obj'), reg.match_instance('storage')) def get_dataprovider(self, schema, obj, storage): raise NotImplementedError('Dataprovider for %s/%s' % (storage.__class__, obj.__class__)) @reg.dispatch_method(reg.match_instance('obj')) def get_jsonprovider(self, obj): raise NotImplementedError('JSONProvider for %s' % obj.__class__) @reg.dispatch_method(reg.match_class('schema', lambda self, schema: schema)) def get_formvalidators(self, schema): return [] @reg.dispatch_method(reg.match_class('schema', lambda self, schema: schema)) def get_identifierfields(self, schema): raise NotImplementedError('IdentifierFields for %s' % schema) @reg.dispatch_method(reg.match_class('schema', lambda self, schema: schema)) def get_uuidfield(self, schema): return 'uuid' @reg.dispatch_method( reg.match_class('schema', lambda self, schema, obj, request: schema)) def get_default_identifier(self, schema, obj, request): return None @reg.dispatch_method( reg.match_instance('model', lambda self, context: context)) def get_rulesprovider(self, context): raise NotImplementedError @reg.dispatch_method( reg.match_instance('model', lambda self, context: context)) def get_statemachine(self, context): raise NotImplementedError @reg.dispatch_method( reg.match_instance('model', lambda self, context: context)) def get_searchprovider(self, context): raise NotImplementedError @reg.dispatch_method( reg.match_instance('model', lambda self, context: context)) def get_aggregateprovider(self, context): raise NotImplementedError @reg.dispatch_method( reg.match_instance('model', lambda self, context: context)) def get_xattrprovider(self, context): raise NotImplementedError @reg.dispatch_method(reg.match_key('name')) def get_typeinfo_factory(self, name): raise NotImplementedError def get_compositekey_separator(self): morp_settings = self.settings.application return morp_settings.compositekey_separator def join_identifier(self, *args): separator = self.get_compositekey_separator() return separator.join(args) def permits(self, request: morepath.Request, context: Model, permission: str): identity = request.identity return self._permits(identity, context, permission)
from zope.sqlalchemy import register as register_session from more.basicauth import BasicAuthIdentityPolicy from .exc import ConfigurationError import transaction import sqlalchemy from celery import Celery import yaml import copy default_settings = open( os.path.join(os.path.dirname(__file__), 'default_settings.yml')).read() default_settings = default_settings.replace(r'%(here)s', os.getcwd()) default_settings = yaml.load(default_settings) @reg.dispatch(reg.match_class('app', lambda app, *args, **kwargs: app)) def create_app(app, settings, scan=True, **kwargs): raise NotImplementedError @create_app.register(app=BaseApp) def create_baseapp(app, settings, scan=True, **kwargs): s = copy.deepcopy(default_settings) for k in settings.keys(): if k in s.keys(): for j, v in settings[k].items(): s[k][j] = v else: s[k] = settings[k]