def import_relative_to_app(self, attr: str) -> Any: """Import string like "module.Model", or "Model" to model class.""" try: return symbol_by_name(attr) except ImportError as original_exc: if not self.app.conf.origin: raise root, _, _ = self.app.conf.origin.partition(':') try: return symbol_by_name(f'{root}.models.{attr}') except ImportError: try: return symbol_by_name(f'{root}.{attr}') except ImportError: raise original_exc from original_exc
def apply(self, web: "Web") -> None: """Apply all blueprints.""" if not self.applied: self.applied = True for prefix, blueprint in self._enabled: bp: BlueprintT = symbol_by_name(blueprint) self._apply_blueprint(web, prefix, bp)
def tables(self) -> TableManagerT: """Map of available tables, and the table manager service.""" TableManager = (self.conf.TableManager if self.finalized else symbol_by_name('faust.tables:TableManager')) return TableManager( app=self, loop=self.loop, beacon=self.beacon, )
def find_app( app: str, *, symbol_by_name: Callable = symbol_by_name, imp: Callable = import_from_cwd, attr_name: str = "app", ) -> AppT: """Find app by string like ``examples.simple``. Notes: This function uses ``import_from_cwd`` to temporarily add the current working directory to :envvar:`PYTHONPATH`, such that when importing the app it will search the current working directory last. You can think of it as temporarily running with the :envvar:`PYTHONPATH` set like this: .. sourcecode: console $ PYTHONPATH="${PYTHONPATH}:." You can disable this with the ``imp`` keyword argument, for example passing ``imp=importlib.import_module``. Examples: >>> # If providing the name of a module, it will attempt >>> # to find an attribute name (.app) in that module. >>> # Example below is the same as importing:: >>> # from examples.simple import app >>> find_app('examples.simple') >>> # If you want an attribute other than .app you can >>> # use : to separate module and attribute. >>> # Examples below is the same as importing:: >>> # from examples.simple import my_app >>> find_app('examples.simple:my_app') >>> # You can also use period for the module/attribute separator >>> find_app('examples.simple.my_app') """ try: # Try to import name' as is. val = symbol_by_name(app, imp=imp) except AttributeError: # last part (of "pkg.x") was not an attribute, # but a module instead: use imp to import_module. val = imp(app) if isinstance(val, ModuleType) and ":" not in app: # if we found a module, try to get .app attribute found = getattr(val, attr_name) if isinstance(found, ModuleType): # proj.app:x where x is a module raise AttributeError(f"Looks like module, not app: -A {app}") val = found return prepare_app(val, app)
def test_constructor(self, app): w = Worker(app) assert w.app is app assert w.sensors == set() assert w.workdir == Path.cwd() assert w.Website == symbol_by_name(WEBSITE_CLS) assert w.web_port is None assert w.web_bind is None assert w.web_host == socket.gethostname() assert isinstance(w.spinner, terminal.Spinner)
def _inner(fun: AgentFun) -> AgentT: Agent = (self.conf.Agent if self.finalized else symbol_by_name('faust:Agent')) agent = Agent(fun, name=name, app=self, channel=channel, concurrency=concurrency, supervisor_strategy=supervisor_strategy, sink=sink, isolated_partitions=isolated_partitions, on_error=self._on_agent_error, help=fun.__doc__, **kwargs) self.agents[agent.name] = agent venusian.attach(agent, category=SCAN_AGENT) return agent
def topic(self, *topics: str, pattern: Union[str, Pattern] = None, key_type: ModelArg = None, value_type: ModelArg = None, key_serializer: CodecArg = None, value_serializer: CodecArg = None, partitions: int = None, retention: Seconds = None, compacting: bool = None, deleting: bool = None, replicas: int = None, acks: bool = True, internal: bool = False, config: Mapping[str, Any] = None, maxsize: int = None, loop: asyncio.AbstractEventLoop = None) -> TopicT: """Create topic description. Topics are named channels (for example a Kafka topic), that exist on a server. To make an ephemeral local communication channel use: :meth:`channel`. See Also: :class:`faust.topics.Topic` """ Topic = (self.conf.Topic if self.finalized else symbol_by_name('faust:Topic')) return Topic( self, topics=topics, pattern=pattern, key_type=key_type, value_type=value_type, key_serializer=key_serializer, value_serializer=value_serializer, partitions=partitions, retention=retention, compacting=compacting, deleting=deleting, replicas=replicas, acks=acks, internal=internal, config=config, loop=loop, )
def __init__(self, app: AppT, *services: ServiceT, sensors: Iterable[SensorT] = None, debug: bool = DEBUG, quiet: bool = False, loglevel: Union[str, int] = None, logfile: Union[str, IO] = None, stdout: IO = sys.stdout, stderr: IO = sys.stderr, blocking_timeout: float = BLOCKING_TIMEOUT, workdir: Union[Path, str] = None, Website: SymbolArg[Type[_Website]] = WEBSITE_CLS, web_port: int = None, web_bind: str = None, web_host: str = None, console_port: int = 50101, loop: asyncio.AbstractEventLoop = None, **kwargs: Any) -> None: self.app = app self.sensors = set(sensors or []) self.workdir = Path(workdir or Path.cwd()) self.Website = symbol_by_name(Website) self.web_port = web_port self.web_bind = web_bind self.web_host = web_host or socket.gethostname() super().__init__( *services, debug=debug, quiet=quiet, loglevel=loglevel, logfile=logfile, loghandlers=app.conf.loghandlers, stdout=stdout, stderr=stderr, blocking_timeout=blocking_timeout, console_port=console_port, redirect_stdouts=app.conf.worker_redirect_stdouts, redirect_stdouts_level=app.conf.worker_redirect_stdouts_level, loop=loop, **kwargs) self.spinner = terminal.Spinner(file=self.stdout)
def Table(self, name: str, *, default: Callable[[], Any] = None, window: WindowT = None, partitions: int = None, help: str = None, **kwargs: Any) -> TableT: """Define new table. Arguments: name: Name used for table, note that two tables living in the same application cannot have the same name. default: A callable, or type that will return a default value for keys missing in this table. window: A windowing strategy to wrap this window in. Examples: >>> table = app.Table('user_to_amount', default=int) >>> table['George'] 0 >>> table['Elaine'] += 1 >>> table['Elaine'] += 1 >>> table['Elaine'] 2 """ Table = (self.conf.Table if self.finalized else symbol_by_name('faust:Table')) table = self.tables.add( Table( self, name=name, default=default, beacon=self.beacon, partitions=partitions, help=help, **kwargs)) return table.using_window(window) if window else table
def Stream(self, Stream: SymbolArg[Type[StreamT]]) -> None: self._Stream = symbol_by_name(Stream)
def ConsumerScheduler(self, value: SymbolArg[Type[SchedulingStrategyT]]) -> None: self._ConsumerScheduler = symbol_by_name(value)
def Agent(self, Agent: SymbolArg[Type[AgentT]]) -> None: self._Agent = symbol_by_name(Agent)
def agent_supervisor(self, sup: SymbolArg[Type[SupervisorStrategyT]]) -> None: self._agent_supervisor = symbol_by_name(sup)
def Topic(self, Topic: SymbolArg[Type[TopicT]]) -> None: self._Topic = symbol_by_name(Topic)
def LeaderAssignor(self, Assignor: SymbolArg[Type[LeaderAssignorT]]) -> None: self._LeaderAssignor = symbol_by_name(Assignor)
def Worker(self, Worker: SymbolArg[Type[_WorkerT]]) -> None: self._Worker = symbol_by_name(Worker)
def TableManager(self, Manager: SymbolArg[Type[TableManagerT]]) -> None: self._TableManager = symbol_by_name(Manager)
def Table(self, Table: SymbolArg[Type[TableT]]) -> None: self._Table = symbol_by_name(Table)
def settings(self) -> Settings: return symbol_by_name('django.conf:settings')
def apps(self) -> Apps: return symbol_by_name('django.apps:apps')
def SetTable(self, SetTable: SymbolArg[Type[TableT]]) -> None: self._SetTable = symbol_by_name(SetTable)
def apply(self, web: 'Web') -> None: if not self.applied: self.applied = True for prefix, blueprint in self._enabled: self._apply_blueprint(web, prefix, symbol_by_name(blueprint))
def Serializers(self, Serializers: SymbolArg[Type[RegistryT]]) -> None: self._Serializers = symbol_by_name(Serializers)
def to_python(self, conf: _Settings, value: IT) -> OT: return cast(OT, symbol_by_name(value))
def PartitionAssignor( self, Assignor: SymbolArg[Type[PartitionAssignorT]]) -> None: self._PartitionAssignor = symbol_by_name(Assignor)
W_ALREADY_CONFIGURED_KEY = '''\ Setting new value for configuration key {key!r} that was already used. Reconfiguring late may mean parts of your program are still using the old value of {old_value!r}. Code such as: app.conf.{key} = {value!r} Should appear before calling app.topic/@app.agent/etc. ''' # XXX mypy borks if we do `from faust import __version__` faust_version: str = symbol_by_name('faust:__version__') TIMEZONE = timezone.utc #: Broker URL, used as default for :setting:`broker`. BROKER_URL = 'kafka://localhost:9092' #: Default transport used when no scheme specified. DEFAULT_BROKER_SCHEME = 'kafka' #: Table storage URL, used as default for :setting:`store`. STORE_URL = 'memory://' #: Cache storage URL, used as default for setting:`cache`. CACHE_URL = 'memory://'
def Router(self, Router: SymbolArg[Type[RouterT]]) -> None: self._Router = symbol_by_name(Router)
def Monitor(self, Monitor: SymbolArg[Type[SensorT]]) -> None: self._Monitor = symbol_by_name(Monitor)
def HttpClient(self, HttpClient: SymbolArg[Type[HttpClientT]]) -> None: self._HttpClient = symbol_by_name(HttpClient)
def producer_partitioner( self, handler: Optional[SymbolArg[PartitionerT]]) -> None: self._producer_partitioner = symbol_by_name(handler)