async def create_feed(ctx: Context, reader: Union[str, type] = None, **reader_args) -> FeedReader:
    """
    Create and start a syndication feed.

    .. note:: This function does **NOT** add the feed to the context as a resource.

    :param ctx: a context object (passed to the :meth:`~asphalt.feedreader.api.FeedReader.start`
        method)
    :param reader: specifies the feed reader class by one of the following means:

       * a subclass of :class:`~asphalt.feedreader.api.FeedReader`
       * the entry point name of one
       * a ``module:varname`` reference to one
       * ``None`` to attempt automatic detection of the feed type
    :param reader_args: keyword arguments passed to the feed reader class
    :return: a feed reader

    """
    assert check_argument_types()
    if isinstance(reader, type):
        feed_class = reader
    elif reader:
        feed_class = feed_readers.resolve(reader)
    else:
        try:
            url = reader_args['url']
        except KeyError:
            raise LookupError('no "url" option was specified – it is required for feed reader '
                              'autodetection') from None

        feed_class = None
        async with aiohttp.request('GET', url) as response:
            response.raise_for_status()
            text = await response.text()
            for cls in feed_readers.all():
                logger.info('Attempting autodetection of feed reader class for %s', url)
                reason = cls.can_parse(text, response.content_type)
                if reason:
                    logger.info('%s: %s', qualified_name(cls), reason)
                else:
                    logger.info('Selected reader class %s for %s', qualified_name(cls), url)
                    feed_class = cls
                    break
            else:
                raise RuntimeError('unable to detect the feed type for url: ' + url)

    feed = feed_class(**reader_args)
    await feed.start(ctx)
    return feed
    async def test_sentry_extras_provider_procedure(self, wampclient: WAMPClient,
                                                    context: Context, monkeypatch):
        class DummyReporter(ExceptionReporter):
            def report_exception(self, ctx: Context, exception: BaseException, message: str,
                                 extra: Dict[str, Any]) -> None:
                errors.append((exception, message, extra))

        def handler(ctx):
            raise Exception('foo')

        errors = []
        context.add_resource(DummyReporter(), types=[ExceptionReporter])
        context.add_resource(WAMPExtrasProvider(), types=[ExtrasProvider])
        await wampclient.register(handler, 'dummyprocedure')
        monkeypatch.setattr('asphalt.wamp.extras_providers.SENTRY_CLASS_NAME',
                            qualified_name(DummyReporter))
        with pytest.raises(ApplicationError):
            await wampclient.call('dummyprocedure')

        assert len(errors) == 1
        exc, message, extra = errors[0]
        assert type(exc) is Exception
        assert str(exc) == 'foo'
        assert message == "Error running handler for procedure 'dummyprocedure'"
        assert extra == {'extra': {'procedure': 'dummyprocedure'},
                         'user_context': {'auth_role': 'authorized_users',
                                          'id': 'device1',
                                          'session_id': wampclient.session_id}
                         }
    async def test_sentry_extras_provider_subscriber(self, wampclient: WAMPClient,
                                                     context: Context, monkeypatch):
        class DummyReporter(ExceptionReporter):
            def report_exception(self, ctx: Context, exception: BaseException, message: str,
                                 extra: Dict[str, Any]) -> None:
                errors.append((exception, message, extra))

        def handler(ctx):
            ctx.loop.call_soon(event.set)
            raise Exception('foo')

        event = asyncio.Event()
        errors = []
        context.add_resource(DummyReporter(), types=[ExceptionReporter])
        context.add_resource(WAMPExtrasProvider(), types=[ExtrasProvider])
        await wampclient.subscribe(handler, 'dummytopic')
        monkeypatch.setattr('asphalt.wamp.extras_providers.SENTRY_CLASS_NAME',
                            qualified_name(DummyReporter))
        await wampclient.publish('dummytopic', options=dict(acknowledge=True, exclude_me=False))

        await event.wait()
        assert len(errors) == 1
        exc, message, extra = errors[0]
        assert type(exc) is Exception
        assert str(exc) == 'foo'
        assert message == "Error running subscription handler for topic 'dummytopic'"
        assert extra == {'extra': {'topic': 'dummytopic'},
                         'user_context': {'auth_role': 'authorized_users',
                                          'id': 'device1',
                                          'session_id': wampclient.session_id}
                         }
Esempio n. 4
0
 async def start(self, ctx: Context):
     proxymaker = partial(TemplateRendererProxy, renderer=self.renderer)
     types = [TemplateRenderer, type(self.renderer)]
     ctx.add_resource_factory(proxymaker, types, self.resource_name)
     logger.info(
         "Configured template renderer (%s; class=%s)",
         self.resource_name,
         qualified_name(self.renderer),
     )
Esempio n. 5
0
    def default_encoder(self, obj):
        obj_type = obj.__class__
        try:
            typename, marshaller, wrap_state = self.serializer.marshallers[obj_type]
        except KeyError:
            raise LookupError('no marshaller found for type "{}"'
                              .format(qualified_name(obj_type))) from None

        state = marshaller(obj)
        return self.wrap_callback(typename, state) if wrap_state else state
    def default_encoder(self, obj):
        obj_type = obj.__class__
        try:
            typename, marshaller, wrap_state = self.serializer.marshallers[obj_type]
        except KeyError:
            raise LookupError('no marshaller found for type "{}"'
                              .format(qualified_name(obj_type))) from None

        state = marshaller(obj)
        return self.wrap_callback(typename, state) if wrap_state else state
    async def start(self, ctx: Context):
        for resource_name, store in self.stores:
            await store.start(ctx)
            ctx.add_resource(store, resource_name)
            logger.info('Configured feed state store (%s; class=%s)', resource_name,
                        qualified_name(store))

        for resource_name, context_attr, config in self.feeds:
            feed = await create_feed(ctx, **config)
            ctx.add_resource(feed, resource_name, context_attr, types=[type(feed), FeedReader])
            logger.info('Configured feed (%s / ctx.%s; url=%s)', resource_name, context_attr,
                        feed.url)
    def cbor_tag_encoder(self, encoder: cbor2.CBOREncoder, obj):
        try:
            typename, marshaller, wrap_state = self.serializer.marshallers[obj.__class__]
        except KeyError:
            raise LookupError('no marshaller found for type "{}"'
                              .format(qualified_name(type(obj)))) from None

        marshalled_state = marshaller(obj)
        if wrap_state:
            serialized_state = encoder.encode_to_bytes(marshalled_state)
            wrapped_state = [typename, serialized_state]
            with encoder.disable_value_sharing():
                encoder.encode(cbor2.CBORTag(self.type_tag, wrapped_state))
        else:
            encoder.encode(marshalled_state)
Esempio n. 9
0
    def cbor_tag_encoder(self, encoder: cbor2.CBOREncoder, obj):
        try:
            typename, marshaller, wrap_state = self.serializer.marshallers[obj.__class__]
        except KeyError:
            raise LookupError('no marshaller found for type "{}"'
                              .format(qualified_name(type(obj)))) from None

        marshalled_state = marshaller(obj)
        if wrap_state:
            serialized_state = encoder.encode_to_bytes(marshalled_state)
            wrapped_state = [typename, serialized_state]
            with encoder.disable_value_sharing():
                encoder.encode(cbor2.CBORTag(self.type_tag, wrapped_state))
        else:
            encoder.encode(marshalled_state)
def default_marshaller(obj):
    """
    Retrieve the state of the given object.

    Calls the ``__getstate__()`` method of the object if available, otherwise returns the
    ``__dict__`` of the object.

    :param obj: the object to marshal
    :return: the marshalled object state

    """
    if hasattr(obj, '__getstate__'):
        return obj.__getstate__()

    try:
        return obj.__dict__
    except AttributeError:
        raise TypeError('{!r} has no __dict__ attribute and does not implement __getstate__()'
                        .format(qualified_name(obj.__class__))) from None
def default_unmarshaller(instance, state) -> None:
    """
    Restore the state of an object.

    If the ``__setstate__()`` method exists on the instance, it is called with the state object
    as the argument. Otherwise, the instance's ``__dict__`` is replaced with ``state``.

    :param instance: an uninitialized instance
    :param state: the state object, as returned by :func:`default_marshaller`

    """
    if hasattr(instance, '__setstate__'):
        instance.__setstate__(state)
    else:
        try:
            instance.__dict__.update(state)
        except AttributeError:
            raise TypeError('{!r} has no __dict__ attribute and does not implement __setstate__()'
                            .format(qualified_name(instance.__class__))) from None
Esempio n. 12
0
def default_marshaller(obj):
    """
    Retrieve the state of the given object.

    Calls the ``__getstate__()`` method of the object if available, otherwise returns the
    ``__dict__`` of the object.

    :param obj: the object to marshal
    :return: the marshalled object state

    """
    if hasattr(obj, '__getstate__'):
        return obj.__getstate__()

    try:
        return obj.__dict__
    except AttributeError:
        raise TypeError(
            '{!r} has no __dict__ attribute and does not implement __getstate__()'
            .format(qualified_name(obj.__class__))) from None
Esempio n. 13
0
def default_unmarshaller(instance, state) -> None:
    """
    Restore the state of an object.

    If the ``__setstate__()`` method exists on the instance, it is called with the state object
    as the argument. Otherwise, the instance's ``__dict__`` is replaced with ``state``.

    :param instance: an uninitialized instance
    :param state: the state object, as returned by :func:`default_marshaller`

    """
    if hasattr(instance, '__setstate__'):
        instance.__setstate__(state)
    else:
        try:
            instance.__dict__.update(state)
        except AttributeError:
            raise TypeError(
                '{!r} has no __dict__ attribute and does not implement __setstate__()'
                .format(qualified_name(instance.__class__))) from None
    def get_extras(self, ctx: Context, reporter: ExceptionReporter) -> Optional[Dict[str, Any]]:
        from asphalt.wamp import CallContext, EventContext

        extra = None
        if qualified_name(reporter) == SENTRY_CLASS_NAME:
            if isinstance(ctx, CallContext):
                extra = {'extra': {'procedure': ctx.procedure}}
                if ctx.caller_auth_id:
                    extra['user_context'] = {
                        'id': ctx.caller_auth_id,
                        'auth_role': ctx.caller_auth_role,
                        'session_id': ctx.caller_session_id
                    }
            elif isinstance(ctx, EventContext):
                extra = {'extra': {'topic': ctx.topic}}
                if ctx.publisher_auth_id:
                    extra['user_context'] = {
                        'id': ctx.publisher_auth_id,
                        'auth_role': ctx.publisher_auth_role,
                        'session_id': ctx.publisher_session_id
                    }

        return extra