PK!VdNwwhugo/__init__.py""" The MIT License (MIT) Copyright (c) 2017-2018 Nariman Safiulin 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. """ __version__ = "0.5.0" PK!@E  hugo/client.py""" The MIT License (MIT) Copyright (c) 2017-2018 Nariman Safiulin 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. """ import asyncio import discord from .constants import EventType from .context import Context from .middleware import Middleware class Client(discord.Client): """Wrapper around default library client. Parameters ---------- root_middleware : :class:`Middleware` A middleware to run on new events. """ def __init__(self, root_middleware: Middleware, *args, **kwargs): super().__init__(*args, **kwargs) self.root_middleware = root_middleware async def default_next_callable(ctx, *args, **kwargs): # noqa: D401 """Default callable as the `next` parameter. Ideally, it should not be called due to it is just a "right" argument for event handlers that should ignore next callables. """ pass def dispatch(self, event, *args, **kwargs): # noqa: D401 """Wrapper around default event dispatcher for a client.""" super().dispatch(event, *args, **kwargs) try: event_type = EventType(event) except ValueError: event_type = EventType.UNKNOWN # ctx = Context(self, event_type, *args, **kwargs) asyncio.ensure_future( self._run_event( self.root_middleware.run, event, ctx=ctx, next=self.default_next_callable, ), loop=self.loop, ) PK! hugo/constants.py""" The MIT License (MIT) Copyright (c) 2017-2018 Nariman Safiulin 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. """ import enum class EventType(enum.Enum): """List of event types which can be received.""" UNKNOWN = None CONNECT = "connect" READY = "ready" SHARD_READY = "shard_ready" RESUMED = "resumed" ERROR = "error" SOCKET_RAW_RECEIVE = "socket_raw_receive" SOCKET_RAW_SEND = "socket_raw_send" TYPING = "typing" MESSAGE = "message" MESSAGE_DELETE = "message_delete" RAW_MESSAGE_DELETE = "raw_message_delete" RAW_BULK_MESSAGE_DELETE = "raw_bulk_message_delete" MESSAGE_EDIT = "message_edit" RAW_MESSAGE_EDIT = "raw_message_edit" REACTION_ADD = "reaction_add" RAW_REACTION_ADD = "raw_reaction_add" REACTION_REMOVE = "reaction_remove" RAW_REACTION_REMOVE = "raw_reaction_remove" REACTION_CLEAR = "reaction_clear" RAW_REACTION_CLEAR = "raw_reaction_clear" PRIVATE_CHANNEL_CREATE = "private_channel_create" PRIVATE_CHANNEL_DELETE = "private_channel_delete" PRIVATE_CHANNEL_UPDATE = "private_channel_update" PRIVATE_CHANNEL_PINS_UPDATE = "private_channel_pins_update" GUILD_CHANNEL_CREATE = "guild_channel_create" GUILD_CHANNEL_DELETE = "guild_channel_delete" GUILD_CHANNEL_UPDATE = "guild_channel_update" GUILD_CHANNEL_PINS_UPDATE = "guild_channel_pins_update" MEMBER_JOIN = "member_join" MEMBER_REMOVE = "member_remove" MEMBER_UPDATE = "member_update" GUILD_JOIN = "guild_join" GUILD_REMOVE = "guild_remove" GUILD_UPDATE = "guild_update" GUILD_ROLE_CREATE = "guild_role_create" GUILD_ROLE_DELETE = "guild_role_delete" GUILD_ROLE_UPDATE = "guild_role_update" GUILD_EMOJIS_UPDATE = "guild_emojis_update" GUILD_AVAILABLE = "guild_available" GUILD_UNAVAILABLE = "guild_unavailable" VOICE_STATE_UPDATE = "voice_state_update" MEMBER_BAN = "member_ban" MEMBER_UNBAN = "member_unban" GROUP_JOIN = "group_join" GROUP_REMOVE = "group_remove" RELATIONSHIP_ADD = "relationship_add" RELATIONSHIP_REMOVE = "relationship_remove" RELATIONSHIP_UPDATE = "relationship_update" PK!R`yyhugo/context.py""" The MIT License (MIT) Copyright (c) 2017-2018 Nariman Safiulin 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. """ from .constants import EventType class Context: """Event processing context.""" def __init__(self, client, event: EventType, *args, **kwargs): self.client = client self.event = event self.args = list(args) self.kwargs = kwargs PK!iIhugo/exceptions.py""" The MIT License (MIT) Copyright (c) 2017-2018 Nariman Safiulin 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. """ class HugoException(Exception): """Base exception class for the library.""" pass PK!>!!hugo/handler.py""" The MIT License (MIT) Copyright (c) 2017-2018 Nariman Safiulin 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. """ import re import discord from .constants import EventType from .context import Context from .middleware import Middleware, MiddlewareResult, middleware class EventNormalization(Middleware): """Event parameters normalization. A middleware for converting positional parameters into keyword for known events. """ EVENTS = { EventType.CONNECT: tuple(), EventType.READY: tuple(), EventType.SHARD_READY: ("shard_id",), EventType.RESUMED: tuple(), EventType.ERROR: tuple(), EventType.SOCKET_RAW_RECEIVE: ("msg",), EventType.SOCKET_RAW_SEND: ("payload",), EventType.TYPING: ("channel", "user", "when"), EventType.MESSAGE: ("message",), EventType.MESSAGE_DELETE: ("message",), EventType.RAW_MESSAGE_DELETE: ("payload",), EventType.RAW_BULK_MESSAGE_DELETE: ("payload",), EventType.MESSAGE_EDIT: ("before", "after"), EventType.RAW_MESSAGE_EDIT: ("payload",), EventType.REACTION_ADD: ("reaction", "user"), EventType.RAW_REACTION_ADD: ("payload",), EventType.REACTION_REMOVE: ("reaction, user",), EventType.RAW_REACTION_REMOVE: ("payload",), EventType.REACTION_CLEAR: ("message", "reactions"), EventType.RAW_REACTION_CLEAR: ("payload",), EventType.PRIVATE_CHANNEL_CREATE: ("channel",), EventType.PRIVATE_CHANNEL_DELETE: ("channel",), EventType.PRIVATE_CHANNEL_UPDATE: ("before", "after"), EventType.PRIVATE_CHANNEL_PINS_UPDATE: ("channel", "last_pin"), EventType.GUILD_CHANNEL_CREATE: ("channel",), EventType.GUILD_CHANNEL_DELETE: ("channel",), EventType.GUILD_CHANNEL_UPDATE: ("before", "after"), EventType.GUILD_CHANNEL_PINS_UPDATE: ("channel", "last_pin"), EventType.MEMBER_JOIN: ("member",), EventType.MEMBER_REMOVE: ("member",), EventType.MEMBER_UPDATE: ("before", "after"), EventType.GUILD_JOIN: ("guild",), EventType.GUILD_REMOVE: ("guild",), EventType.GUILD_UPDATE: ("before", "after"), EventType.GUILD_ROLE_CREATE: ("role",), EventType.GUILD_ROLE_DELETE: ("role",), EventType.GUILD_ROLE_UPDATE: ("before", "after"), EventType.GUILD_EMOJIS_UPDATE: ("guild", "before", "after"), EventType.GUILD_AVAILABLE: ("guild",), EventType.GUILD_UNAVAILABLE: ("guild",), EventType.VOICE_STATE_UPDATE: ("member", "before", "after"), EventType.MEMBER_BAN: ("guild", "user"), EventType.MEMBER_UNBAN: ("guild", "user"), EventType.GROUP_JOIN: ("channel", "user"), EventType.GROUP_REMOVE: ("channel", "user"), EventType.RELATIONSHIP_ADD: ("relationship",), EventType.RELATIONSHIP_REMOVE: ("relationship",), EventType.RELATIONSHIP_UPDATE: ("before", "after"), } async def run(self, *args, ctx: Context, next, **kwargs): if ctx.event in self.EVENTS: for i, parameter in enumerate(self.EVENTS[ctx.event]): ctx.kwargs[parameter] = ctx.args[i] plen = len(self.EVENTS[ctx.event]) ctx.args = ctx.args[plen:] # return await next(*args, ctx=ctx, **kwargs) class EventConstraint(Middleware): """Event type filter. Attributes ---------- event : :class:`.constants.EventType` Event type to allow. """ def __init__(self, event: EventType): self.event = event async def run(self, *args, ctx: Context, next, **kwargs): if ctx.event == self.event: return await next(*args, ctx=ctx, **kwargs) return MiddlewareResult.IGNORE def event(event: EventType): """Append a :class:`EventConstraint` middleware to the chain with given event type constraint. """ return middleware(EventConstraint(event)) class Pattern(Middleware): """Message context filter. The message should match the given regex pattern to invoke the next middleware. Only named subgroups will be passed to the next middleware. Attributes ---------- pattern : str The source regex string. """ def __init__(self, pattern: str): self.pattern = pattern async def run(self, *args, ctx: Context, next, **kwargs): result = re.search(self.pattern, ctx.kwargs["message"].content) if result: kwargs.update(result.groupdict()) return await next(*args, ctx=ctx, **kwargs) # return MiddlewareResult.IGNORE def pattern(pattern: str): """Append a :class:`Pattern` middleware to the chain. Parameters ---------- pattern : str The source regex string. """ return middleware(Pattern(pattern)) class BotConstraint(Middleware): """Message context filter. The message should be authored by or not authored by a real user to invoke the next middleware. Attributes ---------- authored_by_bot : bool Is the message should be authored by bot or not. """ def __init__(self, *, authored_by_bot: bool): self.authored_by_bot = authored_by_bot async def run(self, *args, ctx: Context, next, **kwargs): if not self.authored_by_bot ^ ctx.kwargs["message"].author.bot: return await next(*args, ctx=ctx, **kwargs) return MiddlewareResult.IGNORE def not_authored_by_bot(): """Append a :class:`BotConstraint` middleware to the chain with a "not authored by bot" constraint. """ return middleware(BotConstraint(authored_by_bot=False)) def authored_by_bot(): """Append a :class:`BotConstraint` middleware to the chain with a "authored by bot" constraint. """ return middleware(BotConstraint(authored_by_bot=True)) class ChannelType(Middleware): """Message context filter. The message should be sent in the given channel types to invoke the next middleware. """ def __init__( self, *, guild: bool = False, private: bool = False, text: bool = False, # voice: bool = False, dm: bool = False, group: bool = False, ): self.text = guild or text # self.voice = guild or voice self.dm = private or dm self.group = private or group async def run(self, *args, ctx: Context, next, **kwargs): channel = ctx.kwargs["message"].channel # fmt: off if ( self.text and isinstance(channel, discord.TextChannel) # or self.voice and isinstance(channel, discord.VoiceChannel) or self.dm and isinstance(channel, discord.DMChannel) or self.group and isinstance(channel, discord.GroupChannel) ): return await next(*args, ctx=ctx, **kwargs) # fmt: on return MiddlewareResult.IGNORE def channel_type( *, guild: bool = False, private: bool = False, text: bool = False, # voice: bool = False, dm: bool = False, group: bool = False, ): """Append a :class:`ChannelType` middleware to the chain with given constraints. """ return middleware( ChannelType( guild=guild, private=private, text=text, # voice=voice, dm=dm, group=group, ) ) PK!"cw!t,t,hugo/middleware.py""" The MIT License (MIT) Copyright (c) 2017-2018 Nariman Safiulin 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. """ import abc import asyncio import enum import typing from . import context class MiddlewareResult(enum.Enum): """Enum values for middleware results. One of these values can be returned in a middleware instead of actual data. Anything returned by a middleware and is not a enum value is considered as a success of the process. """ OK = enum.auto() IGNORE = enum.auto() class Middleware(abc.ABC): """Event processing middleware. Middleware are useful for filtering events or extending functionality. Middleware should return something (even `None`) to indicate success, otherwise :class:`MiddlewareResult` values can be used. Functions can also be converted into a middleware by using :class:`MiddlewareFunction` or :func:`as_middleware` decorator. Attributes ---------- fn : Optional[Callable] The source function, when the last middleware in the middleware chain is a converted function or it is a converted function itself. Can be not presented, if middleware chain created not with :func:`middleware` decorator. .. seealso:: :class:`MiddlewareChain`. """ def __init__(self): self.fn = None @abc.abstractmethod async def run(self, *args, ctx: context.Context, next, **kwargs): """Middleware's main logic. .. note:: Context is a keyword parameter. Parameters ---------- ctx : :class:`.context.Context` Event processing context. .. note:: Provided context can be replaced and passed to the next middleware, but do it only if needed. next : Callable The next function to call. Not necessarily a middleware. Pass context, all positional and keyword parameters, even if unused. Should be awaited. .. warning:: Context is a keyword parameter. If you will pass it as a positional parameter, this can cause errors on all next middleware in a chain. Returns ------- :class:`MiddlewareResult` A enum value when no actual data can be provided. :any:`typing.Any` Middleware data. """ pass # pragma: no cover @staticmethod def is_successful_result(value): """Return `True`, if given value is a successful middleware result.""" if value == MiddlewareResult.IGNORE: return False return True async def __call__(self, *args, ctx: context.Context, next, **kwargs): """Invoke middleware with given parameters.""" return await self.run(*args, ctx=ctx, next=next, **kwargs) class MiddlewareFunction(Middleware): """Middleware class for converting functions into valid middleware. Parameters ---------- fn : Callable A function to convert into a middleware. Should be a coroutine. Raises ------ ValueError If given function is not a coroutine. Attributes ---------- fn : Callable A function converted into a middleware. A coroutine. """ def __init__(self, fn): super().__init__() if not asyncio.iscoroutinefunction(fn): raise ValueError("Not a coroutine") self.fn = fn async def run(self, *args, ctx: context.Context, next, **kwargs): """Invoke function as a middleware with given parameters.""" return await self.fn(*args, ctx=ctx, next=next, **kwargs) class MiddlewareState(Middleware): """Middleware class that can provide a state for next middleware. It is an alternative to middleware as class methods. By default, just adds given state to parameters for the next middleware as `state` parameter. Parameters ---------- state : :any:`typing.Any` A state to provide. Attributes ---------- fn : Callable A state for the next middleware. """ def __init__(self, state): super().__init__() self.state = state async def run(self, *args, ctx: context.Context, next, **kwargs): # noqa: D102 return await next(*args, ctx=ctx, state=self.state, **kwargs) class MiddlewareCollection(Middleware, abc.ABC): """Class for grouping middleware. It is a middleware itself. Method :meth:`run` is abstract. Each subclass should implement own behavior of how to run group of middleware. For example, run only one middleware, if success, or run all middleware, or run middleware until desired results is obtained, etc. Useful, when it is known, what middleware can return. Attributes ---------- collection : List[:class:`Middleware`] List of middleware to run. Take a note that order of middleware in the list can be used in a subclass implementation. """ def __init__(self): super().__init__() self.collection = [] def add_middleware(self, middleware: Middleware): """Add middleware to the list. Can be used as a decorator. Parameters ---------- middleware : :class:`Middleware` A middleware to add to the list. Returns ------- :class:`Middleware` A given middleware. Raises ------ ValueError If given parameter is not a middleware. """ if not isinstance(middleware, Middleware): raise ValueError("Not a middleware") # self.collection.append(middleware) return middleware @abc.abstractmethod async def run(self, *args, ctx: context.Context, next, **kwargs): # noqa: D102 pass # pragma: no cover class MiddlewareChain(MiddlewareCollection): """Class for chaining middleware. It is a middleware itself. Attributes ---------- collection : List[:class:`Middleware`] List of middleware to run in a certain order. The first items is a last-to-call middleware (in other words, list is reversed). """ def __init__(self): super().__init__() def add_middleware(self, middleware: Middleware): # noqa: D102 super().add_middleware(middleware) if len(self.collection) == 1: self.fn = middleware.fn return middleware async def run(self, *args, ctx: context.Context, next, **kwargs): # noqa: D102 # Oh dear! Please, rewrite it... for current in self.collection: next = ( lambda current, next: lambda *args, ctx, **kwargs: current.run( *args, ctx=ctx, next=next, **kwargs ) )(current, next) return await next(*args, ctx=ctx, **kwargs) def as_middleware(fn: typing.Callable): """Convert function into a middleware. If you are planning to chain the converted function with another middleware, just use :func:`middleware` helper. It will convert the function into a middleware for you, if needed. .. warning:: Do not use it, if not sure. Parameters ---------- fn : Callable A function to convert into a middleware. """ # We don't care, when somebody is convering a middleware into another one... return MiddlewareFunction(fn) def collection_of( collection_class: typing.Type[MiddlewareCollection], middleware: typing.Sequence[typing.Union[Middleware, typing.Callable]], ): """Create a new collection of given middleware. If any of given parameters is not a middleware, it will be converted into a middleware for you. Parameters ---------- collection : Type[:class:`MiddlewareCollection`] A collection class to create collection of. middleware : Sequence[Union[Middleware, Callable]] A list of middleware to create collection of. """ collection = collection_class() for mw in middleware: if not isinstance(mw, Middleware): mw = as_middleware(mw) collection.add_middleware(mw) # return collection def chain_of( middleware: typing.Sequence[typing.Union[Middleware, typing.Callable]] ): """Create a new chain of given middleware. If any of given parameters is not a middleware, it will be converted into a middleware for you. Parameters ---------- middleware : Sequence[Union[Middleware, Callable]] A list of middleware to create collection of. """ return collection_of(MiddlewareChain, middleware) def middleware(outer_middleware: Middleware): """Append a middleware to the chain. If decorated function is not a middleware, it will be converted into a middleware by decorator. Parameters ---------- outer_middleware : :class:`Middleware` A middleware to append to the chain. """ if not isinstance(outer_middleware, Middleware): outer_middleware = as_middleware(outer_middleware) def decorator(inner_middleware: Middleware): if isinstance(inner_middleware, MiddlewareChain): inner_middleware.add_middleware(outer_middleware) return inner_middleware # return collection_of( MiddlewareChain, [inner_middleware, outer_middleware] ) return decorator class OneOfAll(MiddlewareCollection): """Middleware group with "first success" condition. It will process middleware list until one of them return successful result. See :class:`Middleware` for information about successful results. """ async def run(self, *args, ctx: context.Context, next, **kwargs): # noqa: D102 for mw in self.collection: result = await mw.run(*args, ctx=ctx, next=next, **kwargs) if self.is_successful_result(result): return result return MiddlewareResult.IGNORE PK!VbKKhugo-0.5.0.dist-info/LICENSEMIT License Copyright (c) 2017-2018 Nariman Safiulin 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. PK!HlŃTThugo-0.5.0.dist-info/WHEEL A н#J@Z|Jmqvh&#hڭw!Ѭ"J˫( } %PK!H1hugo-0.5.0.dist-info/METADATAn0EiKrM" bq(螖2QTɡ]}V"+Q3HVvVi~"Vʠmlx_(1:Tװv^{`֩&uAEiyLaF٠6:I~+/{ '2fKXET@FV޹n7?=+wC3ɍ\_sU!FV[%)sg4BN{g(3YXB[c Xk&px':b$\qnٍI>ͧjry_CuGl7z`W 3yoa/WPK!Hrhugo-0.5.0.dist-info/RECORDmɒ@< f8ҀIYy%W 0_TG Ƶ1+6 :e!!@&hugo/handler.pyPK!"cw!t,t,YHhugo/middleware.pyPK!VbKKthugo-0.5.0.dist-info/LICENSEPK!HlŃTTyhugo-0.5.0.dist-info/WHEELPK!H1zhugo-0.5.0.dist-info/METADATAPK!Hr{hugo-0.5.0.dist-info/RECORDPK ;~