Example #1
0
import peewee
from contextvars import ContextVar

db_state_default = {"closed": None, "conn": None, "ctx": None, "transactions": None}
db_state = ContextVar("db_state", default=db_state_default.copy())


class PeeweeConnectionState(peewee._ConnectionState):
    def __init__(self, **kwargs):
        super().__setattr__("_state", db_state)
        super().__init__(**kwargs)

    def __setattr__(self, name, value):
        self._state.get()[name] = value

    def __getattr__(self, name):
        return self._state.get()[name]


db = peewee.SqliteDatabase('database.db', check_same_thread=False)
db._state = PeeweeConnectionState()




Example #2
0
def trace_stack_top(trace_stack_var: ContextVar) -> Any | None:
    """Return the element at the top of a trace stack."""
    trace_stack = trace_stack_var.get()
    return trace_stack[-1] if trace_stack else None
Example #3
0
import logging
from contextvars import ContextVar, Token
from typing import Optional
from uuid import UUID, uuid4

from aiohttp.web_log import AccessLogger

logger = logging.getLogger(__name__)

_request_id_ctx_var: ContextVar[str] = ContextVar("belvo_request_id", default="")


def set_request_id(request_id: Optional[str] = None) -> Token:
    if request_id:
        try:
            UUID(request_id)
        except (ValueError, AttributeError):
            logger.exception("Received invalid request id. Using a new one.")
            request_id = None

    request_id = request_id or uuid4().hex
    return _request_id_ctx_var.set(request_id)


def get_request_id() -> str:
    return _request_id_ctx_var.get()


def reset_request_id(request_id: Token):
    _request_id_ctx_var.reset(request_id)
Example #4
0
    def __init__(self, name):

        self._context_var = ContextVar(name, default=None)
Example #5
0
def trace_stack_push(trace_stack_var: ContextVar, node: Any) -> None:
    """Push an element to the top of a trace stack."""
    if (trace_stack := trace_stack_var.get()) is None:
        trace_stack = []
        trace_stack_var.set(trace_stack)
Example #6
0
logger = logging.getLogger(__name__)

__all__ = [
    'run',
    'run_trio_task',
    'run_trio',
    'run_future',
    'run_coroutine',
    'run_asyncio',
    'wrap_generator',
    'run_iterator',
    'TrioChildWatcher',
    'TrioPolicy',
]

current_loop = ContextVar('trio_aio_loop', default=None)
current_policy = ContextVar('trio_aio_policy', default=None)

_faked_policy = threading.local()

# We can monkey-patch asyncio's get_event_loop_policy but if asyncio is
# imported before Trio, the asyncio acceleration C code in 3.7+ caches
# get_event_loop_policy.
# Thus we always set our policy. After that, our monkeypatched
# setter stores the policy in a thread-local variable to which our policy
# will forward all requests when Trio is not running.


class _TrioPolicy(asyncio.events.BaseDefaultEventLoopPolicy):
    _loop_factory = TrioEventLoop
Example #7
0
# http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import random
import asyncio
import requests
from contextlib import contextmanager
from contextvars import ContextVar

trace_stack_var = ContextVar('trace_stack', default=None)


def _load_http_headers(headers):
    from py_zipkin.zipkin import ZipkinAttrs  # pylint: disable=E0401

    if not headers or "X-B3-TraceId" not in headers:
        return None

    return ZipkinAttrs(
        headers.get("X-B3-TraceId"),
        headers.get("X-B3-SpanId"),
        headers.get("X-B3-ParentSpanId"),
        headers.get("X-B3-Flags") or '0',
        False if headers.get("X-B3-Sampled") == '0' else True,
    )
Example #8
0
    import aiocontextvars

from inspect import signature
from contextlib import contextmanager
from contextvars import ContextVar
import aiohttp
from aiohttp.helpers import sentinel
import asyncio

from funcy import compose, decorator, project, merge, cut_prefix
from parsechain import Response

__all__ = ['settings', 'run', 'fetch', 'fetchall', 'save']

# Used to store dynamically scoped settings, part of them are session keyword params
SETTINGS = ContextVar('settings', default={})
SESSION = ContextVar('session')
SESSION_PARAMS = [
    p.name for p in signature(aiohttp.ClientSession).parameters.values()
    if p.kind == p.KEYWORD_ONLY
]


def run(coro):
    loop = asyncio.get_event_loop()
    return loop.run_until_complete(with_session(coro))


@contextmanager
def settings(**values):
    old_values = SETTINGS.get()
Example #9
0
from datetime import datetime
from contextvars import ContextVar
from collections import defaultdict

from nonebot.rule import Rule
from nonebot.permission import Permission, USER
from nonebot.typing import Type, List, Dict, Union, Callable, Optional, NoReturn
from nonebot.typing import Bot, Event, Handler, Message, ArgsParser, MessageSegment
from nonebot.exception import PausedException, RejectedException, FinishedException

matchers: Dict[int, List[Type["Matcher"]]] = defaultdict(list)
"""
:类型: ``Dict[int, List[Type[Matcher]]]``
:说明: 用于存储当前所有的事件响应器
"""
current_bot: ContextVar = ContextVar("current_bot")
current_event: ContextVar = ContextVar("current_event")


class MatcherMeta(type):

    def __repr__(self) -> str:
        return (f"<Matcher from {self.module or 'unknow'}, "  # type: ignore
                f"type={self.type}, priority={self.priority}, "  # type: ignore
                f"temp={self.temp}>")  # type: ignore

    def __str__(self) -> str:
        return repr(self)


class Matcher(metaclass=MatcherMeta):
Example #10
0
File: proxy.py Project: ddqof/proxy
class ProxyServer:
    def __init__(self, port: int = 8080, block_images: bool = False, cfg=None):
        self.connection = ContextVar("connection")
        self.block_images = block_images
        self.port = port
        self._spent_data = {}
        if cfg is not None:
            if isinstance(cfg, dict):
                self._cfg = cfg
            else:
                raise ValueError(f"Config should be {dict.__name__} object")
            for rsc in chain(cfg["limited"], cfg["black-list"]):
                self._spent_data[rsc] = 0
        self.context_token = None

    async def run(self):
        """
        Launch async proxy-server at specified host and port.
        """
        srv = await asyncio.start_server(self._handle_connection, LOCALHOST,
                                         self.port)

        addr = srv.sockets[0].getsockname()
        LOGGER.info(START_SERVER_MSG.format(app_address=addr))

        async with srv:
            await srv.serve_forever()

    async def _handle_connection(self, client_reader: StreamReader,
                                 client_writer: StreamWriter) -> None:
        """
        Handle every client response.
        Called whenever a new connection is established.
        """
        try:
            raw_request = await client_reader.read(CHUNK_SIZE)
            print(raw_request)
            await client_writer.drain()
            if not raw_request:
                return
            pr = ProxyRequest(raw_request, self._cfg)
            LOGGER.info(f"{pr.method:<{len('CONNECT')}} " f"{pr.abs_url}")
            try:
                server_reader, server_writer = await asyncio.open_connection(
                    pr.hostname, pr.port)
            except OSError:
                LOGGER.info(
                    CONNECTION_REFUSED_MSG.format(method=pr.method,
                                                  url=pr.abs_url))
                return
            client_endpoint = Endpoint(client_reader, client_writer)
            server_endpoint = Endpoint(server_reader, server_writer)
            conn = Connection(client_endpoint, server_endpoint, pr,
                              self.block_images)
            self.context_token = self.connection.set(conn)
            if self.block_images and pr.is_image_request:
                await self.connection.get().reset()
                return
            if pr.scheme is HTTPScheme.HTTPS:
                await self._handle_https()
            else:
                await self._handle_http()
        except Exception as e:
            if isinstance(e, ConnectionResetError):
                LOGGER.info(CONNECTION_CLOSED_MSG.format(url=pr.abs_url))
            else:
                LOGGER.exception(e)
                asyncio.get_event_loop().stop()
            if self.context_token is not None:
                self.connection.reset(self.context_token)

    async def _handle_http(self) -> None:
        """
        Send HTTP request and then forwards the following HTTP requests.
        """
        conn = self.connection.get()
        LOGGER.debug(
            HANDLING_HTTP_REQUEST_MSG.format(method=conn.pr.method,
                                             url=conn.pr.abs_url))
        await conn.server.write_and_drain(conn.pr.raw)
        await asyncio.gather(conn.forward_to_client(self._spent_data),
                             conn.forward_to_server())

    async def _handle_https(self) -> None:
        """
        Handles https connection by making HTTP tunnel.
        """
        conn = self.connection.get()
        hostname = conn.pr.hostname
        LOGGER.debug(HANDLING_HTTPS_CONNECTION_MSG.format(url=hostname))
        rsc = conn.pr.restriction
        if rsc:
            if self._spent_data[rsc.initiator] >= rsc.data_limit:
                await conn.reset()
                return
        await conn.client.write_and_drain(CONNECTION_ESTABLISHED_HTTP_MSG)
        LOGGER.debug(CONNECTION_ESTABLISHED_MSG.format(url=conn.pr.abs_url))
        await asyncio.gather(conn.forward_to_server(),
                             conn.forward_to_client(self._spent_data))
Example #11
0
    Ret = Union[None, Awaitable[None]]
    OptAwait = TypeVar('OptAwait', None, Awaitable[None])

    ctxCensor = Callable[[QQbot, Context], bool]
    ctxFunc = Callable[[QQbot, Context], Ret]
    ctxFuncGen = Callable[[QQbot, Context], OptAwait]
    ctxFuncWrap = Callable[[ctxFuncGen], ctxFuncGen]

    eventFunc = Callable[[QQbot, Event], Ret]
    eventFuncGen = Callable[[QQbot, Event], OptAwait]
    eventFuncWrap = Callable[[eventFuncGen], eventFuncGen]

logger = logging.getLogger(__name__)

contextStore: ContextVar[Context] = ContextVar('context')


class SolveUnit(BotBase):
    _ctxLst: list[ctxFunc]
    _eventLst: dict[Type[Event], list[eventFunc]]

    def __new__(cls, *args, **kwargs) -> Any:
        obj = super().__new__(cls)
        obj._ctxLst = []
        obj._eventLst = {}
        return obj

    def addFunction(self, check: Optional[ctxCensor] = None) -> ctxFuncWrap:
        def wrapper(func: ctxFuncGen) -> ctxFuncGen:
            def inner(bot: QQbot, context: Context) -> Ret:
Example #12
0
from pymongo.database import Database
from pymongo.cursor import Cursor
from pymongo.errors import DuplicateKeyError
import marshmallow as ma

from ..builder import BaseBuilder
from ..instance import Instance
from ..document import DocumentImplementation
from ..data_objects import Reference
from ..exceptions import NotCreatedError, UpdateError, DeleteError, NoneReferenceError
from ..fields import ReferenceField, ListField, EmbeddedField
from ..query_mapper import map_query

from .tools import cook_find_filter

SESSION = ContextVar("session", default=None)


# pymongo.Cursor defines __del__ method, hence mongomock's WrappedCursor should
# not inherit from this class otherwise garbage collection will crash...
class BaseWrappedCursor:

    __slots__ = ('raw_cursor', 'document_cls')

    def __init__(self, document_cls, cursor, *args, **kwargs):
        # Such a cunning plan my lord !
        # We inherit from Cursor but don't call its __init__ because
        # we act as a proxy to the underlying raw_cursor
        WrappedCursor.raw_cursor.__set__(self, cursor)
        WrappedCursor.document_cls.__set__(self, document_cls)
Example #13
0
    resource = request.match_info.route.resource
    # available only in aiohttp >= 3.3.1
    if getattr(resource, 'canonical', None) is not None:
        route = request.match_info.route.resource.canonical
        span.tag(HTTP_ROUTE, route)

    _set_remote_endpoint(span, request)


PY37 = sys.version_info >= (3, 7)

if PY37:
    from contextvars import ContextVar
    OptTraceVar = ContextVar[Optional[TraceContext]]
    zipkin_context = ContextVar('zipkin_context',
                                default=None)  # type: OptTraceVar

    @contextmanager
    def set_context_value(
            context_var: OptTraceVar,
            value: TraceContext) -> Generator[OptTraceVar, None, None]:
        token = context_var.set(value)
        try:
            yield context_var
        finally:
            context_var.reset(token)


def middleware_maker(skip_routes: Optional[AbstractRoute] = None,
                     tracer_key: str = APP_AIOZIPKIN_KEY,
                     request_key: str = REQUEST_AIOZIPKIN_KEY) -> Middleware:
Example #14
0
import threading
from functools import wraps
from typing import Callable, Optional, Union, List
from sentry_sdk import start_span, capture_exception as sentry_capture_exception, set_tag
from sentry_sdk.tracing import Span
from contextvars import ContextVar

span: ContextVar[Span] = ContextVar('span')


def instrument_span(op: str,
                    description: Optional[Union[str, Callable]] = None,
                    force_new_span: bool = False,
                    **instrument_kwargs):
    def wrapper(wrapped):
        @wraps(wrapped)
        def with_instrumentation(*args, **kwargs):
            try:
                parent_span = span.get()

            except LookupError:
                parent_span = None

            if parent_span and not force_new_span:
                _span = parent_span.start_child(
                    description=description(*args, **kwargs)
                    if callable(description) else description,
                    **instrument_kwargs,
                )

            else:
Example #15
0
        return datetime

    def process_result_value(self, value, _):
        if value is not None:
            value = timezone.make_aware(value, timezone=pytz.utc)

        return value

    def process_bind_param(self, value, _):
        if value is not None and timezone.is_aware(value):
            value = timezone.make_naive(value, timezone=pytz.utc)

        return value


context_auto_commit = ContextVar('context_auto_commit', default=True)


def get_base_model(db):
    class BaseModel(db.Model):
        __abstract__ = True
        __asdict_include_hybrid_properties__ = False

        created_time = Column(DateTime, default=datetime.utcnow)
        updated_time = Column(DateTime,
                              default=datetime.utcnow,
                              onupdate=datetime.utcnow)
        is_active = Column(Boolean, default=True)

        @classmethod
        def exists(cls, **attrs):
Example #16
0
class I18nMiddleware(BaseMiddleware):
    """
    I18n middleware based on gettext util

    >>> dp = Dispatcher(bot)
    >>> i18n = I18nMiddleware(DOMAIN, LOCALES_DIR)
    >>> dp.middleware.setup(i18n)
    and then
    >>> _ = i18n.gettext
    or
    >>> _ = i18n = I18nMiddleware(DOMAIN_NAME, LOCALES_DIR)
    """

    ctx_locale = ContextVar('ctx_user_locale', default=None)

    def __init__(self, domain, path=None, default='en'):
        """
        :param domain: domain
        :param path: path where located all *.mo files
        :param default: default locale name
        """
        super(I18nMiddleware, self).__init__()

        if path is None:
            path = os.path.join(os.getcwd(), 'locales')

        self.domain = domain
        self.path = path
        self.default = default

        self.locales = self.find_locales()

    def find_locales(self) -> Dict[str, gettext.GNUTranslations]:
        """
        Load all compiled locales from path

        :return: dict with locales
        """
        translations = {}

        for name in os.listdir(self.path):
            if not os.path.isdir(os.path.join(self.path, name)):
                continue
            mo_path = os.path.join(self.path, name, 'LC_MESSAGES',
                                   self.domain + '.mo')

            if os.path.exists(mo_path):
                with open(mo_path, 'rb') as fp:
                    translations[name] = gettext.GNUTranslations(fp)
            elif os.path.exists(mo_path[:-2] + 'po'):
                raise RuntimeError(
                    f"Found locale '{name} but this language is not compiled!")

        return translations

    def reload(self):
        """
        Hot reload locles
        """
        self.locales = self.find_locales()

    @property
    def available_locales(self) -> Tuple[str]:
        """
        list of loaded locales

        :return:
        """
        return tuple(self.locales.keys())

    def __call__(self, singular, plural=None, n=1, locale=None) -> str:
        return self.gettext(singular, plural, n, locale)

    def gettext(self, singular, plural=None, n=1, locale=None) -> str:
        """
        Get text

        :param singular:
        :param plural:
        :param n:
        :param locale:
        :return:
        """
        if locale is None:
            locale = self.ctx_locale.get()

        if locale not in self.locales:
            if n is 1:
                return singular
            else:
                return plural

        translator = self.locales[locale]

        if plural is None:
            return translator.gettext(singular)
        else:
            return translator.ngettext(singular, plural, n)

    def lazy_gettext(self,
                     singular,
                     plural=None,
                     n=1,
                     locale=None,
                     enable_cache=True) -> LazyProxy:
        """
        Lazy get text

        :param singular:
        :param plural:
        :param n:
        :param locale:
        :param enable_cache:
        :return:
        """
        return LazyProxy(self.gettext,
                         singular,
                         plural,
                         n,
                         locale,
                         enable_cache=enable_cache)

    # noinspection PyMethodMayBeStatic,PyUnusedLocal
    async def get_user_locale(self, action: str, args: Tuple[Any]) -> str:
        """
        User locale getter
        You can override the method if you want to use different way of getting user language.

        :param action: event name
        :param args: event arguments
        :return: locale name
        """
        user: types.User = types.User.get_current()
        locale: Locale = user.locale

        if locale:
            *_, data = args
            language = data['locale'] = locale.language
            return language

    async def trigger(self, action, args):
        """
        Event trigger

        :param action: event name
        :param args: event arguments
        :return:
        """
        if 'update' not in action \
                and 'error' not in action \
                and action.startswith('pre_process'):
            locale = await self.get_user_locale(action, args)
            self.ctx_locale.set(locale)
            return True
Example #17
0
from contextvars import ContextVar

from opentelemetry.trace import get_tracer, SpanKind
from opentelemetry.propagators import inject

from grpclib.client import Channel
from grpclib.events import listen, SendRequest, RecvTrailingMetadata

from harness import grpc_pb2
from harness.wires.base import Wire

_client_span = ContextVar("client_span")


async def _send_request(event: SendRequest) -> None:
    tracer = get_tracer(__name__)
    span = tracer.start_span(
        event.method_name,
        kind=SpanKind.CLIENT,
        attributes={
            "component": "grpc",
            "grpc.method": event.method_name
        },
    )
    _client_span.set(span)
    inject(type(event.metadata).__setitem__, event.metadata)


async def _recv_trailing_metadata(event: RecvTrailingMetadata) -> None:
    _client_span.get().end()
Example #18
0
                            H.div("Thread ", H.strong(word), reason),
                            type="info",
                        )

        thread = KillableThread(target=run, daemon=True)

        if not self.words:
            self.words.append(f"t{next(self.count)}")
        word = self.words.pop()

        thread.start()
        return word, thread


threads = NamedThreads()
_current_session = ContextVar("current_session", default=None)
_current_print_session = ContextVar("current_print_session", default=None)
_current_evalid = ContextVar("current_evalid", default=None)


def current_session():
    return _current_session.get()


def current_print_session():
    return _current_print_session.get()


@contextmanager
def new_evalid():
    token = _current_evalid.set(next(_c))
Example #19
0
 def __init__(self) -> None:
     self._current_context = ContextVar(self._CONTEXT_KEY,
                                        default=Context())
Example #20
0
from warnings import warn
from weakref import WeakValueDictionary

from pydantic import BaseModel as PydanticBaseModel
from pydantic.error_wrappers import ErrorWrapper, ValidationError
from pydantic.fields import PrivateAttr

from hydrolib.core.io.base import DummmyParser, DummySerializer
from hydrolib.core.utils import to_key

logger = logging.getLogger(__name__)

# We use ContextVars to keep a reference to the folder
# we're currently parsing files in. In the future
# we could move to https://github.com/samuelcolvin/pydantic/issues/1549
context_file_loading: ContextVar["FileLoadContext"] = ContextVar(
    "file_loading")


class BaseModel(PydanticBaseModel):
    class Config:
        arbitrary_types_allowed = True
        validate_assignment = True
        use_enum_values = True
        extra = "forbid"  # will throw errors so we can fix our models
        allow_population_by_field_name = True
        alias_generator = to_key

    def __init__(self, **data: Any) -> None:
        """Initializes a BaseModel with the provided data.

        Raises:
)
from uuid import (
    UUID,
)

from minos.common import (
    AvroDataEncoder,
)

from ..exceptions import (
    MinosException,
    NotHasContentException,
    NotHasParamsException,
)

REQUEST_USER_CONTEXT_VAR: Final[ContextVar[Optional[UUID]]] = ContextVar("user", default=None)


class Request(ABC):
    """Request interface."""

    @property
    @abstractmethod
    def user(self) -> Optional[UUID]:
        """
        Returns the UUID of the user making the Request.
        """
        raise NotImplementedError

    async def content(self, **kwargs) -> Any:
        """Get the request content.
Example #22
0
    # Compatibility with Python 2.6
    from distutils.sysconfig import get_python_lib
import warnings

from bugsnag.sessiontracker import SessionMiddleware
from bugsnag.middleware import DefaultMiddleware, MiddlewareStack
from bugsnag.utils import (fully_qualified_class_name, validate_str_setter,
                           validate_bool_setter, validate_iterable_setter,
                           validate_required_str_setter)
from bugsnag.delivery import (create_default_delivery, DEFAULT_ENDPOINT,
                              DEFAULT_SESSIONS_ENDPOINT)
from bugsnag.uwsgi import warn_if_running_uwsgi_without_threads

try:
    from contextvars import ContextVar
    _request_info = ContextVar('bugsnag-request', default=None)  # type: ignore
except ImportError:
    from bugsnag.utils import ThreadContextVar
    _request_info = ThreadContextVar(
        'bugsnag-request', default=None)  # type: ignore  # noqa: E501

__all__ = ('Configuration', 'RequestConfiguration')


class _BaseConfiguration(object):
    def get(self, name, overrides=None):
        """
        Get a single configuration option, using values from overrides
        first if they exist.
        """
        if overrides:
Example #23
0
                "item_id": item_id,
                "run_id": str(self._child_run_id),
            }
        if self._variables:
            result["changed_variables"] = self._variables
        if self._error is not None:
            result["error"] = str(self._error)
        if self._result is not None:
            result["result"] = self._result
        return result


# Context variables for tracing
# Current trace
trace_cv: ContextVar[dict[str, deque[TraceElement]] | None] = ContextVar(
    "trace_cv", default=None
)
# Stack of TraceElements
trace_stack_cv: ContextVar[list[TraceElement] | None] = ContextVar(
    "trace_stack_cv", default=None
)
# Current location in config tree
trace_path_stack_cv: ContextVar[list[str] | None] = ContextVar(
    "trace_path_stack_cv", default=None
)
# Copy of last variables
variables_cv: ContextVar[Any | None] = ContextVar("variables_cv", default=None)
# (domain.item_id, Run ID)
trace_id_cv: ContextVar[tuple[str, str] | None] = ContextVar(
    "trace_id_cv", default=None
)
Example #24
0
                self.scan_interval,
            )
            return

        async with self._process_updates:
            tasks = []
            for entity in self.entities.values():
                if not entity.should_poll:
                    continue
                tasks.append(entity.async_update_ha_state(True))

            if tasks:
                await asyncio.gather(*tasks)


current_platform: ContextVar[EntityPlatform | None] = ContextVar(
    "current_platform", default=None)


@callback
def async_get_platforms(hass: HomeAssistant,
                        integration_name: str) -> list[EntityPlatform]:
    """Find existing platforms."""
    if (DATA_ENTITY_PLATFORM not in hass.data
            or integration_name not in hass.data[DATA_ENTITY_PLATFORM]):
        return []

    platforms: list[EntityPlatform] = hass.data[DATA_ENTITY_PLATFORM][
        integration_name]

    return platforms
Example #25
0
def trace_stack_pop(trace_stack_var: ContextVar) -> None:
    """Remove the top element from a trace stack."""
    trace_stack = trace_stack_var.get()
    trace_stack.pop()
Example #26
0
    def test_context_assignment_while_running(self):
        id_var = ContextVar("id", default=None)

        def target():
            self.assertIsNone(id_var.get())
            self.assertIsNone(gr.gr_context)

            # Context is created on first use
            id_var.set(1)
            self.assertIsInstance(gr.gr_context, Context)
            self.assertEqual(id_var.get(), 1)
            self.assertEqual(gr.gr_context[id_var], 1)

            # Clearing the context makes it get re-created as another
            # empty context when next used
            old_context = gr.gr_context
            gr.gr_context = None  # assign None while running
            self.assertIsNone(id_var.get())
            self.assertIsNone(gr.gr_context)
            id_var.set(2)
            self.assertIsInstance(gr.gr_context, Context)
            self.assertEqual(id_var.get(), 2)
            self.assertEqual(gr.gr_context[id_var], 2)

            new_context = gr.gr_context
            getcurrent().parent.switch((old_context, new_context))
            # parent switches us back to old_context

            self.assertEqual(id_var.get(), 1)
            gr.gr_context = new_context  # assign non-None while running
            self.assertEqual(id_var.get(), 2)

            getcurrent().parent.switch()
            # parent switches us back to no context
            self.assertIsNone(id_var.get())
            self.assertIsNone(gr.gr_context)
            gr.gr_context = old_context
            self.assertEqual(id_var.get(), 1)

            getcurrent().parent.switch()
            # parent switches us back to no context
            self.assertIsNone(id_var.get())
            self.assertIsNone(gr.gr_context)

        gr = greenlet(target)

        with self.assertRaisesRegex(AttributeError, "can't delete attr"):
            del gr.gr_context

        self.assertIsNone(gr.gr_context)
        old_context, new_context = gr.switch()
        self.assertIs(new_context, gr.gr_context)
        self.assertEqual(old_context[id_var], 1)
        self.assertEqual(new_context[id_var], 2)
        self.assertEqual(new_context.run(id_var.get), 2)
        gr.gr_context = old_context  # assign non-None while suspended
        gr.switch()
        self.assertIs(gr.gr_context, new_context)
        gr.gr_context = None  # assign None while suspended
        gr.switch()
        self.assertIs(gr.gr_context, old_context)
        gr.gr_context = None
        gr.switch()
        self.assertIsNone(gr.gr_context)

        # Make sure there are no reference leaks
        gr = None
        gc.collect()
        self.assertEqual(sys.getrefcount(old_context), 2)
        self.assertEqual(sys.getrefcount(new_context), 2)
Example #27
0
    SkippedException,
    FinishedException,
    RejectedException,
)

if TYPE_CHECKING:
    from nonebot.plugin import Plugin

T = TypeVar("T")

matchers: Dict[int, List[Type["Matcher"]]] = defaultdict(list)
"""
:类型: ``Dict[int, List[Type[Matcher]]]``
:说明: 用于存储当前所有的事件响应器
"""
current_bot: ContextVar[Bot] = ContextVar("current_bot")
current_event: ContextVar[Event] = ContextVar("current_event")
current_matcher: ContextVar["Matcher"] = ContextVar("current_matcher")
current_handler: ContextVar[Dependent] = ContextVar("current_handler")


class MatcherMeta(type):
    if TYPE_CHECKING:
        module: Optional[str]
        plugin_name: Optional[str]
        module_name: Optional[str]
        module_prefix: Optional[str]
        type: str
        rule: Rule
        permission: Permission
        handlers: List[T_Handler]
Example #28
0
        warnings.warn(
            f"{name} is deprecated and will be removed in a future release. "
            f"Please use {use_instead} instead.",
            category=FutureWarning,
            stacklevel=2,
        )
        return import_term(use_instead)
    else:
        raise AttributeError(f"module {__name__} has no attribute {name}")


# Used internally by recursive_to_dict to stop infinite recursion. If an object has
# already been encountered, a string representation will be returned instead. This is
# necessary since we have multiple cyclic referencing data structures.
_recursive_to_dict_seen: ContextVar[set[int]] = ContextVar("_recursive_to_dict_seen")


def recursive_to_dict(obj: AnyType, *, exclude: Container[str] = ()) -> AnyType:
    """Recursively convert arbitrary Python objects to a JSON-serializable
    representation. This is intended for debugging purposes only and calls ``_to_dict``
    methods on encountered objects, if available.

    Parameters
    ----------
    exclude:
        A list of attribute names to be excluded from the dump.
        This will be forwarded to the objects ``_to_dict`` methods and these methods
        are required to accept this parameter.
    """
    if isinstance(obj, (int, float, bool, str)) or obj is None:
Example #29
0
class SentryReporter:
    """SentryReporter designed for sending reports to the Sentry server from
    a Tribler Client.
    """

    scrubber = None
    last_event = None
    ignored_exceptions = [KeyboardInterrupt, SystemExit]
    # more info about how SentryReporter choose a strategy see in
    # SentryReporter.get_actual_strategy()
    global_strategy = SentryStrategy.SEND_ALLOWED_WITH_CONFIRMATION
    thread_strategy = ContextVar('context_strategy', default=None)

    _sentry_logger_name = 'SentryReporter'
    _logger = logging.getLogger(_sentry_logger_name)

    @staticmethod
    def init(sentry_url='',
             release_version='',
             scrubber=None,
             strategy=SentryStrategy.SEND_ALLOWED_WITH_CONFIRMATION):
        """Initialization.

        This method should be called in each process that uses SentryReporter.

        Args:
            sentry_url: URL for Sentry server. If it is empty then Sentry's
                sending mechanism will not be initialized.

            scrubber: a class that will be used for scrubbing sending events.
                Only a single method should be implemented in the class:
                ```
                    def scrub_event(self, event):
                        pass
                ```
            release_version: string that represents a release version.
                See Also: https://docs.sentry.io/platforms/python/configuration/releases/
            strategy: a Sentry strategy for sending events (see class Strategy
                for more information)
        Returns:
            Sentry Guard.
        """
        SentryReporter._logger.debug(f"Init: {sentry_url}")
        SentryReporter.scrubber = scrubber
        SentryReporter.global_strategy = strategy

        rv = sentry_sdk.init(
            sentry_url,
            release=release_version,
            # https://docs.sentry.io/platforms/python/configuration/integrations/
            integrations=[
                LoggingIntegration(
                    level=logging.
                    INFO,  # Capture info and above as breadcrumbs
                    event_level=None,  # Send no errors as events
                ),
                ThreadingIntegration(propagate_hub=True),
            ],
            before_send=SentryReporter._before_send,
        )

        ignore_logger(SentryReporter._sentry_logger_name)

        return rv

    @staticmethod
    def ignore_logger(logger_name):
        SentryReporter._logger.debug(f"Ignore logger: {logger_name}")
        ignore_logger(logger_name)

    @staticmethod
    def add_breadcrumb(message='', category='', level='info', **kwargs):
        """Adds a breadcrumb for current Sentry client.

        It is necessary to specify a message, a category and a level to make this
        breadcrumb visible in Sentry server.

        Args:
            **kwargs: named arguments that will be added to Sentry event as well
        """
        crumb = {'message': message, 'category': category, 'level': level}

        SentryReporter._logger.debug(f"Add the breadcrumb: {crumb}")

        return sentry_sdk.add_breadcrumb(crumb, **kwargs)

    @staticmethod
    def send_event(event=None,
                   post_data=None,
                   sys_info=None,
                   additional_tags=None):
        """Send the event to the Sentry server

        This method
            1. Enable Sentry's sending mechanism.
            2. Extend sending event by the information from post_data.
            3. Send the event.
            4. Disables Sentry's sending mechanism.

        Scrubbing the information will be performed in the `_before_send` method.

        During the execution of this method, all unhandled exceptions that
        will be raised, will be sent to Sentry automatically.

        Args:
            event: event to send. It should be taken from SentryReporter at
            post_data: dictionary made by the feedbackdialog.py
                previous stages of executing.
            sys_info: dictionary made by the feedbackdialog.py
            additional_tags: tags that will be added to the event

        Returns:
            Event that was sent to Sentry server
        """
        SentryReporter._logger.info(f"Send: {post_data}, {event}")

        if event is None:
            return event

        post_data = post_data or dict()
        sys_info = sys_info or dict()
        additional_tags = additional_tags or dict()

        if CONTEXTS not in event:
            event[CONTEXTS] = {}

        if TAGS not in event:
            event[TAGS] = {}

        event[CONTEXTS][REPORTER] = {}

        # tags
        tags = event[TAGS]
        tags['version'] = get_value(post_data, 'version')
        tags['machine'] = get_value(post_data, 'machine')
        tags['os'] = get_value(post_data, 'os')
        tags['platform'] = get_first_item(get_value(sys_info, 'platform'))
        tags[f'{PLATFORM_DETAILS}'] = get_first_item(
            get_value(sys_info, PLATFORM_DETAILS))
        tags.update(additional_tags)

        # context
        context = event[CONTEXTS]
        reporter = context[REPORTER]
        version = get_value(post_data, 'version')

        context['browser'] = {'version': version, 'name': 'Tribler'}

        stacktrace_parts = parse_stacktrace(get_value(post_data, 'stack'))
        reporter[STACKTRACE] = next(stacktrace_parts, [])
        reporter[f'{STACKTRACE}_extra'] = next(stacktrace_parts, [])
        reporter[f'{STACKTRACE}_context'] = next(stacktrace_parts, [])

        reporter['comments'] = get_value(post_data, 'comments')

        reporter[OS_ENVIRON] = parse_os_environ(get_value(
            sys_info, OS_ENVIRON))
        delete_item(sys_info, OS_ENVIRON)

        reporter['events'] = extract_dict(sys_info, r'^(event|request)')
        reporter[SYSINFO] = {
            key: sys_info[key]
            for key in sys_info if key not in reporter['events']
        }

        with this_sentry_strategy(SentryStrategy.SEND_ALLOWED):
            sentry_sdk.capture_event(event)

        return event

    @staticmethod
    def get_confirmation(exception):
        """Get confirmation on sending exception to the Team.

        There are two message boxes, that will be triggered:
        1. Message box with the error_text
        2. Message box with confirmation about sending this report to the Tribler
            team.

        Args:
            exception: exception to be sent.
        """
        # Prevent importing PyQt globally in tribler-common module.
        # pylint: disable=import-outside-toplevel
        try:
            from PyQt5.QtWidgets import QApplication, QMessageBox
        except ImportError:
            SentryReporter._logger.debug(
                "PyQt5 is not available. User confirmation is not possible.")
            return False

        SentryReporter._logger.debug(f"Get confirmation: {exception}")

        _ = QApplication(sys.argv)
        messagebox = QMessageBox(icon=QMessageBox.Critical,
                                 text=f'{exception}.')
        messagebox.setWindowTitle("Error")
        messagebox.exec()

        messagebox = QMessageBox(
            icon=QMessageBox.Question,
            text='Do you want to send this crash report to the Tribler team? '
            'We anonymize all your data, who you are and what you downloaded.',
        )
        messagebox.setWindowTitle("Error")
        messagebox.setStandardButtons(QMessageBox.Yes | QMessageBox.No)

        return messagebox.exec() == QMessageBox.Yes

    @staticmethod
    def capture_exception(exception):
        SentryReporter._logger.info(f"Capture exception: {exception}")
        sentry_sdk.capture_exception(exception)

    @staticmethod
    def event_from_exception(exception):
        """This function format the exception by passing it through sentry
        Args:
            exception: an exception that will be passed to `sentry_sdk.capture_exception(exception)`

        Returns:
            the event that has been saved in `_before_send` method
        """
        SentryReporter._logger.info(f"Event from exception: {exception}")

        if not exception:
            return exception

        with this_sentry_strategy(SentryStrategy.SEND_SUPPRESSED):
            sentry_sdk.capture_exception(exception)
            return SentryReporter.last_event

    @staticmethod
    def set_user(user_id):
        """Set the user to identify the event on a Sentry server

        The algorithm is the following:
        1. Calculate hash from `user_id`.
        2. Generate fake user, based on the hash.

        No real `user_id` will be used in Sentry.

        Args:
            user_id: Real user id.

        Returns:
            Generated user (dictionary: {id, username}).
        """
        # calculate hash to keep real `user_id` in secret
        user_id_hash = md5(user_id).hexdigest()

        SentryReporter._logger.debug(f"Set user: {user_id_hash}")

        Faker.seed(user_id_hash)
        user_name = Faker().name()
        user = {'id': user_id_hash, 'username': user_name}

        sentry_sdk.set_user(user)
        return user

    @staticmethod
    def get_actual_strategy():
        """This method is used to determine actual strategy.

        Strategy can be global: SentryReporter.strategy
        and local: SentryReporter._context_strategy.

        Returns: the local strategy if it is defined, the global strategy otherwise
        """
        strategy = SentryReporter.thread_strategy.get()
        return strategy if strategy else SentryReporter.global_strategy

    @staticmethod
    def _before_send(event, hint):
        """The method that is called before each send. Both allowed and
        disallowed.

        The algorithm:
        1. If sending is allowed, then scrub the event and send.
        2. If sending is disallowed, then store the event in
            `SentryReporter.last_event`

        Args:
            event: event that generated by Sentry
            hint: root exception (can be used in some cases)

        Returns:
            The event, prepared for sending, or `None`, if sending is suppressed.
        """
        if not event:
            return event

        # trying to get context-depending strategy first
        strategy = SentryReporter.get_actual_strategy()

        SentryReporter._logger.info(f"Before send strategy: {strategy}")

        exc_info = get_value(hint, 'exc_info')
        error_type = get_first_item(exc_info)

        if error_type in SentryReporter.ignored_exceptions:
            SentryReporter._logger.debug(
                f"Exception is in ignored: {hint}. Skipped.")
            return None

        if strategy == SentryStrategy.SEND_SUPPRESSED:
            SentryReporter._logger.debug(
                "Suppress sending. Storing the event.")
            SentryReporter.last_event = event
            return None

        if strategy == SentryStrategy.SEND_ALLOWED_WITH_CONFIRMATION:
            SentryReporter._logger.debug("Request confirmation.")
            if not SentryReporter.get_confirmation(hint):
                return None

        # clean up the event
        SentryReporter._logger.debug(
            f"Clean up the event with scrubber: {SentryReporter.scrubber}")
        if SentryReporter.scrubber:
            event = SentryReporter.scrubber.scrub_event(event)

        return event
Example #30
0
"""
context var for jinja2 templates path
"""
from contextvars import ContextVar

env_var: ContextVar[str] = ContextVar("var")