# Path: rep0st/framework/data/database.py
# B = TypeVar('B')
# class DatabaseModule(Module):
#   def __init__(self, url: URL, base: B):
#   def configure(self, binder: Binder):
#   def provide_database_engine(self) -> DatabaseEngine:
#   def provide_database_session_factory(
#       self, database_engine: DatabaseEngine) -> DatabaseSessionFactory:
#   def provide_database_session(
#       self, database_session_factory: DatabaseSessionFactory) -> Session:
# 
# Path: rep0st/framework/decorator.py
# class DecoratorProcessor(ABC):
# 
#   @abstractmethod
#   def process(self, bindings: List[Any]) -> None:
#     pass
# 
#   def methods_by_decorated_name(
#       self, bindings: List[Any],
#       search_name: str) -> Iterator[Tuple[Type, T, Callable[[Any], Any]]]:
#     for binding in bindings:
#       interface = binding
#       for name, fun in inspect.getmembers(interface):
#         data = getattr(fun, '__' + search_name + '__', None)
#         if data is not None:
#           yield (interface, data, fun)
# 
#   @staticmethod
#   def wrap_function(instance: Any, fun: Callable,
#                     injector: Injector) -> Callable:
#     fun = types.MethodType(fun, instance)
# 
#     @functools.wraps(fun)
#     def wrapper(*args: Any, **kwargs: Any) -> Any:
#       return injector.call_with_injection(
#           callable=fun, args=args, kwargs=kwargs)
# 
#     return wrapper  # type: ignore


import functools
import logging
from threading import local
from typing import Any, Callable, List
from injector import Binder, Module, ProviderOf, inject, multiprovider, singleton
from sqlalchemy.orm import Session
from rep0st.framework.data.database import DatabaseSessionFactory
from rep0st.framework.decorator import DecoratorProcessor
              f'Rolling back transaction on method {transactional_configuration.name}'
          )
          # We reached the outer most @transactional(). Rollback the transaction.
          session.rollback()
        raise
      finally:
        if transactional_state.depth == 0:
          log.debug(
              f'Removing session on method {transactional_configuration.name}')
          # Close the session, to remove invalid state in case of errors.
          session.close()
          # We reached the outer most @transactional(). Close the session.
          session_factory = transactional_configuration.database_session_factory_provider.get(
          )
          session_factory.remove()
          delattr(transactional_state, 'depth')
      return ret

    wrapper.__transactional__ = transactional_configuration
    return wrapper

  return decorator


@singleton
class TransactionalProcessor(DecoratorProcessor):

  @inject
  def __init__(
      self, database_session_provider: ProviderOf[Session],

# Path: rep0st/framework/data/database.py
# B = TypeVar('B')
# class DatabaseModule(Module):
#   def __init__(self, url: URL, base: B):
#   def configure(self, binder: Binder):
#   def provide_database_engine(self) -> DatabaseEngine:
#   def provide_database_session_factory(
#       self, database_engine: DatabaseEngine) -> DatabaseSessionFactory:
#   def provide_database_session(
#       self, database_session_factory: DatabaseSessionFactory) -> Session:
# 
# Path: rep0st/framework/decorator.py
# class DecoratorProcessor(ABC):
# 
#   @abstractmethod
#   def process(self, bindings: List[Any]) -> None:
#     pass
# 
#   def methods_by_decorated_name(
#       self, bindings: List[Any],
#       search_name: str) -> Iterator[Tuple[Type, T, Callable[[Any], Any]]]:
#     for binding in bindings:
#       interface = binding
#       for name, fun in inspect.getmembers(interface):
#         data = getattr(fun, '__' + search_name + '__', None)
#         if data is not None:
#           yield (interface, data, fun)
# 
#   @staticmethod
#   def wrap_function(instance: Any, fun: Callable,
#                     injector: Injector) -> Callable:
#     fun = types.MethodType(fun, instance)
# 
#     @functools.wraps(fun)
#     def wrapper(*args: Any, **kwargs: Any) -> Any:
#       return injector.call_with_injection(
#           callable=fun, args=args, kwargs=kwargs)
# 
#     return wrapper  # type: ignore


# Path: rep0st/framework/data/transaction.py
import functools
import logging
from threading import local
from typing import Any, Callable, List
from injector import Binder, Module, ProviderOf, inject, multiprovider, singleton
from sqlalchemy.orm import Session
from rep0st.framework.data.database import DatabaseSessionFactory
from rep0st.framework.decorator import DecoratorProcessor

              f'Rolling back transaction on method {transactional_configuration.name}'
          )
          # We reached the outer most @transactional(). Rollback the transaction.
          session.rollback()
        raise
      finally:
        if transactional_state.depth == 0:
          log.debug(
              f'Removing session on method {transactional_configuration.name}')
          # Close the session, to remove invalid state in case of errors.
          session.close()
          # We reached the outer most @transactional(). Close the session.
          session_factory = transactional_configuration.database_session_factory_provider.get(
          )
          session_factory.remove()
          delattr(transactional_state, 'depth')
      return ret

    wrapper.__transactional__ = transactional_configuration
    return wrapper

  return decorator


@singleton
class TransactionalProcessor(DecoratorProcessor):

  @inject
  def __init__(
      self, database_session_provider: ProviderOf[Session],

      database_session_factory_provider: ProviderOf[DatabaseSessionFactory]