# Path: bugsnag/middleware.py
# class MiddlewareStack:
#     """
#     Manages a stack of Bugsnag middleware.
#     """
#     def __init__(self):
#         self.stack = []
# 
#     def before_notify(self, func: Middleware):
#         """
#         Add a function to be run before bugsnag is notified.
# 
#         This lets you modify the payload that will be sent.
#         If your function returns False, nothing will be sent.
# 
#         >>> def add_request_data(event):
#         ...    event.add_tab("request", request_data)
#         >>>
#         >>> stack = MiddlewareStack()
#         >>> stack.before_notify(add_request_data)
#         """
#         self.append(SimpleMiddleware(before=func))
# 
#     def after_notify(self, func: Middleware):
#         """
#         Add a function to be run after bugsnag is notified.
# 
#         This lets you log errors in custom ways.
#         """
#         self.append(SimpleMiddleware(after=func))
# 
#     def append(self, middleware: Middleware):
#         """
#         Add a middleware to the end of the stack.
# 
#         It will be run after all middleware currently defined.
#         If you want to stop the event progress, return from
#         your __call__ method without calling the next level.
# 
#         >>> class ExampleMiddleware():
#         ...     def __init__(self, bugsnag):
#         ...         self.bugsnag = bugsnag
#         ...     def __call__(self, event):
#         ...         config = event.request_config
#         ...         event.add_tab("request", config.get("request"))
#         ...         self.bugsnag(event)
#         ...
#         >>> stack = MiddlewareStack()
#         >>> stack.append(ExampleMiddleware)
#         """
#         self.stack.append(middleware)
# 
#     def insert_before(self, target_class: Type, middleware: Middleware):
#         """
#         Adds a middleware to the stack in the position before
#         the target_class.
#         """
#         try:
#             index = self.stack.index(target_class)
#             self.stack.insert(index, middleware)
#         except ValueError:
#             self.append(middleware)
# 
#     def insert_after(self, target_class: Type, middleware: Middleware):
#         """
#         Adds a middleware to the stack in the position after
#         the target_class.
#         """
#         try:
#             index = self.stack.index(target_class)
#             self.stack.insert(index + 1, middleware)
#         except ValueError:
#             self.append(middleware)
# 
#     def run(self, event: Event, callback: Callable[[], None]):
#         """
#         Run all the middleware in order, then call the callback.
#         """
# 
#         # the last step in the event stack is to call the callback.
#         # we also do this inside the exception handler, so need to ensure that
#         # the callback is only called once.
#         def finish(event):
#             if not hasattr(finish, 'called'):
#                 finish.called = True
#                 callback()
# 
#         to_call = finish
#         for middleware in reversed(self.stack):
#             to_call = middleware(to_call)
# 
#         try:
#             to_call(event)
#         except Exception:
#             event.config.logger.exception(
#                 'Error in exception middleware'
#             )
# 
#             # still notify if middleware crashes before event
#             finish(event)
# 
# Path: bugsnag/configuration.py
# class RequestConfiguration:
#     """
#     Per-request Bugsnag configuration settings.
#     """
# 
#     @classmethod
#     def get_instance(cls):
#         """
#         Get this thread's instance of the RequestConfiguration.
#         """
# 
#         try:
#             instance = _request_info.get()
#         except LookupError:
#             instance = None
# 
#         if instance is None:
#             instance = RequestConfiguration()
#             _request_info.set(instance)  # type: ignore
# 
#         return instance
# 
#     @classmethod
#     def clear(cls):
#         """
#         Clear this thread's instance of the RequestConfiguration.
#         """
#         _request_info.set(None)
# 
#     def __init__(self):
#         self.context = None
#         self.grouping_hash = None
#         self.user = {}
#         self.metadata = {}
# 
#         # legacy fields
#         self.user_id = None
#         self.extra_data = {}
#         self.request_data = {}
#         self.environment_data = {}
#         self.session_data = {}
# 
#     def get(self, name) -> Any:
#         """
#         Get a single configuration option
#         """
#         return getattr(self, name)
# 
#     def configure(self, **options):
#         """
#         Set one or more configuration settings.
#         """
#         for name, value in options.items():
#             setattr(self, name, value)
# 
#         return self
# 
#     @property
#     def meta_data(self) -> Any:
#         warnings.warn('RequestConfiguration.meta_data has been renamed to ' +
#                       '"metadata"', DeprecationWarning)
#         return self.metadata


import unittest
import bugsnag
from bugsnag.middleware import MiddlewareStack
from bugsnag.configuration import RequestConfiguration
        m.insert_before(SampleMiddlewareClass, SampleMiddlewareClassC)
        m.run(a, lambda: a.append('Callback'))

        self.assertEqual(a, ['A', 'B', 'C', 'Callback'])

    def test_insert_after_ordering(self):
        a = []

        m = MiddlewareStack()
        m.append(SampleMiddlewareClassA)
        m.append(SampleMiddlewareClassB)
        m.insert_after(SampleMiddlewareClassA, SampleMiddlewareClassC)
        m.run(a, lambda: a.append('Callback'))

        self.assertEqual(a, ['A', 'C', 'B', 'Callback'])

    def test_insert_after_default_ordering(self):
        a = []

        m = MiddlewareStack()
        m.append(SampleMiddlewareClassA)
        m.append(SampleMiddlewareClassB)
        m.insert_after(SampleMiddlewareClass, SampleMiddlewareClassC)
        m.run(a, lambda: a.append('Callback'))

        self.assertEqual(a, ['A', 'B', 'C', 'Callback'])

    def test_callback_not_run_if_middleware_returns(self):
        a = []


# Path: bugsnag/middleware.py
# class MiddlewareStack:
#     """
#     Manages a stack of Bugsnag middleware.
#     """
#     def __init__(self):
#         self.stack = []
# 
#     def before_notify(self, func: Middleware):
#         """
#         Add a function to be run before bugsnag is notified.
# 
#         This lets you modify the payload that will be sent.
#         If your function returns False, nothing will be sent.
# 
#         >>> def add_request_data(event):
#         ...    event.add_tab("request", request_data)
#         >>>
#         >>> stack = MiddlewareStack()
#         >>> stack.before_notify(add_request_data)
#         """
#         self.append(SimpleMiddleware(before=func))
# 
#     def after_notify(self, func: Middleware):
#         """
#         Add a function to be run after bugsnag is notified.
# 
#         This lets you log errors in custom ways.
#         """
#         self.append(SimpleMiddleware(after=func))
# 
#     def append(self, middleware: Middleware):
#         """
#         Add a middleware to the end of the stack.
# 
#         It will be run after all middleware currently defined.
#         If you want to stop the event progress, return from
#         your __call__ method without calling the next level.
# 
#         >>> class ExampleMiddleware():
#         ...     def __init__(self, bugsnag):
#         ...         self.bugsnag = bugsnag
#         ...     def __call__(self, event):
#         ...         config = event.request_config
#         ...         event.add_tab("request", config.get("request"))
#         ...         self.bugsnag(event)
#         ...
#         >>> stack = MiddlewareStack()
#         >>> stack.append(ExampleMiddleware)
#         """
#         self.stack.append(middleware)
# 
#     def insert_before(self, target_class: Type, middleware: Middleware):
#         """
#         Adds a middleware to the stack in the position before
#         the target_class.
#         """
#         try:
#             index = self.stack.index(target_class)
#             self.stack.insert(index, middleware)
#         except ValueError:
#             self.append(middleware)
# 
#     def insert_after(self, target_class: Type, middleware: Middleware):
#         """
#         Adds a middleware to the stack in the position after
#         the target_class.
#         """
#         try:
#             index = self.stack.index(target_class)
#             self.stack.insert(index + 1, middleware)
#         except ValueError:
#             self.append(middleware)
# 
#     def run(self, event: Event, callback: Callable[[], None]):
#         """
#         Run all the middleware in order, then call the callback.
#         """
# 
#         # the last step in the event stack is to call the callback.
#         # we also do this inside the exception handler, so need to ensure that
#         # the callback is only called once.
#         def finish(event):
#             if not hasattr(finish, 'called'):
#                 finish.called = True
#                 callback()
# 
#         to_call = finish
#         for middleware in reversed(self.stack):
#             to_call = middleware(to_call)
# 
#         try:
#             to_call(event)
#         except Exception:
#             event.config.logger.exception(
#                 'Error in exception middleware'
#             )
# 
#             # still notify if middleware crashes before event
#             finish(event)
# 
# Path: bugsnag/configuration.py
# class RequestConfiguration:
#     """
#     Per-request Bugsnag configuration settings.
#     """
# 
#     @classmethod
#     def get_instance(cls):
#         """
#         Get this thread's instance of the RequestConfiguration.
#         """
# 
#         try:
#             instance = _request_info.get()
#         except LookupError:
#             instance = None
# 
#         if instance is None:
#             instance = RequestConfiguration()
#             _request_info.set(instance)  # type: ignore
# 
#         return instance
# 
#     @classmethod
#     def clear(cls):
#         """
#         Clear this thread's instance of the RequestConfiguration.
#         """
#         _request_info.set(None)
# 
#     def __init__(self):
#         self.context = None
#         self.grouping_hash = None
#         self.user = {}
#         self.metadata = {}
# 
#         # legacy fields
#         self.user_id = None
#         self.extra_data = {}
#         self.request_data = {}
#         self.environment_data = {}
#         self.session_data = {}
# 
#     def get(self, name) -> Any:
#         """
#         Get a single configuration option
#         """
#         return getattr(self, name)
# 
#     def configure(self, **options):
#         """
#         Set one or more configuration settings.
#         """
#         for name, value in options.items():
#             setattr(self, name, value)
# 
#         return self
# 
#     @property
#     def meta_data(self) -> Any:
#         warnings.warn('RequestConfiguration.meta_data has been renamed to ' +
#                       '"metadata"', DeprecationWarning)
#         return self.metadata


# Path: tests/test_middleware.py
import unittest
import bugsnag
from bugsnag.middleware import MiddlewareStack
from bugsnag.configuration import RequestConfiguration

        m.insert_before(SampleMiddlewareClass, SampleMiddlewareClassC)
        m.run(a, lambda: a.append('Callback'))

        self.assertEqual(a, ['A', 'B', 'C', 'Callback'])

    def test_insert_after_ordering(self):
        a = []

        m = MiddlewareStack()
        m.append(SampleMiddlewareClassA)
        m.append(SampleMiddlewareClassB)
        m.insert_after(SampleMiddlewareClassA, SampleMiddlewareClassC)
        m.run(a, lambda: a.append('Callback'))

        self.assertEqual(a, ['A', 'C', 'B', 'Callback'])

    def test_insert_after_default_ordering(self):
        a = []

        m = MiddlewareStack()
        m.append(SampleMiddlewareClassA)
        m.append(SampleMiddlewareClassB)
        m.insert_after(SampleMiddlewareClass, SampleMiddlewareClassC)
        m.run(a, lambda: a.append('Callback'))

        self.assertEqual(a, ['A', 'B', 'C', 'Callback'])

    def test_callback_not_run_if_middleware_returns(self):
        a = []


        m = MiddlewareStack()