├── t ├── __init__.py ├── docs │ ├── __init__.py │ └── testing │ │ ├── __init__.py │ │ └── test_figC_windowed_table.py ├── old │ ├── __init__.py │ ├── app.py │ └── test_simple.py ├── unit │ ├── __init__.py │ ├── cli │ │ ├── __init__.py │ │ ├── test_env.py │ │ ├── conftest.py │ │ ├── test_completion.py │ │ ├── test_clean_versions.py │ │ └── test_params.py │ ├── web │ │ ├── __init__.py │ │ ├── drivers │ │ │ └── __init__.py │ │ ├── test_exceptions.py │ │ └── test_blueprints.py │ ├── agents │ │ └── __init__.py │ ├── fixups │ │ ├── __init__.py │ │ └── test_base.py │ ├── livecheck │ │ ├── __init__.py │ │ ├── test_locals.py │ │ └── conftest.py │ ├── sensors │ │ └── __init__.py │ ├── stores │ │ └── __init__.py │ ├── tables │ │ └── __init__.py │ ├── utils │ │ ├── __init__.py │ │ ├── terminal │ │ │ └── __init__.py │ │ ├── test_utils.py │ │ ├── test_venusian.py │ │ ├── test_iso8601.py │ │ ├── test_functional.py │ │ └── test_cron.py │ ├── serializers │ │ └── __init__.py │ ├── transport │ │ └── drivers │ │ │ └── __init__.py │ ├── test_faust.py │ ├── conftest.py │ ├── windows │ │ └── test_tumbling_window.py │ └── test_joins.py ├── bench │ ├── __init__.py │ ├── baseline.py │ └── forward.py ├── stress │ ├── __init__.py │ ├── reports │ │ ├── __init__.py │ │ ├── web.py │ │ └── states.py │ ├── tests │ │ ├── __init__.py │ │ ├── simple │ │ │ ├── requirements.txt │ │ │ ├── __init__.py │ │ │ └── app.py │ │ ├── tables │ │ │ ├── requirements.txt │ │ │ └── __init__.py │ │ └── forwarder │ │ │ ├── requirements.txt │ │ │ └── __init__.py │ ├── requirements.txt │ ├── models.py │ └── config.py ├── consistency │ ├── __init__.py │ └── .gitignore ├── functional │ ├── __init__.py │ ├── web │ │ ├── __init__.py │ │ └── conftest.py │ ├── agents │ │ ├── __init__.py │ │ └── test_current_agent.py │ ├── sensors │ │ ├── __init__.py │ │ └── test_statsd.py │ ├── serializers │ │ └── __init__.py │ ├── test_faust.py │ ├── test_aiokafka.py │ └── helpers.py ├── regression │ ├── __init__.py │ ├── i323 │ │ ├── __init__.py │ │ ├── proj323 │ │ │ ├── foo │ │ │ │ ├── __init__.py │ │ │ │ └── bar │ │ │ │ │ ├── __init__.py │ │ │ │ │ └── baz │ │ │ │ │ ├── __init__.py │ │ │ │ │ └── commands.py │ │ │ ├── __init__.py │ │ │ └── faust.py │ │ ├── conftest.py │ │ └── test_autodiscover.py │ └── i324 │ │ ├── __init__.py │ │ ├── proj324 │ │ ├── foo │ │ │ ├── __init__.py │ │ │ ├── bar │ │ │ │ ├── __init__.py │ │ │ │ └── baz │ │ │ │ │ ├── __init__.py │ │ │ │ │ └── commands.py │ │ │ └── test_x.py │ │ ├── __main__.py │ │ ├── __init__.py │ │ └── faust.py │ │ ├── conftest.py │ │ └── test_autodiscover.py ├── integration │ ├── cli │ │ ├── __init__.py │ │ ├── test_base.py │ │ ├── test_models.py │ │ ├── test_agents.py │ │ └── test_model.py │ └── app.py ├── meticulous │ └── assignor │ │ └── __init__.py └── helpers.py ├── docs ├── _static │ └── .keep ├── _templates │ └── .keep ├── images │ ├── logo.png │ ├── favicon.ico │ ├── banner-alt1.png │ └── banner-alt2.png ├── changelog.rst ├── faq.rst ├── authors.rst ├── includes │ ├── tags.txt │ ├── resources.txt │ └── blurb.txt ├── userguide │ ├── installation.rst │ ├── kafka.rst │ └── index.rst ├── developerguide │ └── index.rst ├── reference │ ├── faust.utils.cron.rst │ ├── faust.rst │ ├── faust.app.rst │ ├── faust.auth.rst │ ├── faust.joins.rst │ ├── faust.agents.rst │ ├── faust.events.rst │ ├── faust.fixups.rst │ ├── faust.stores.rst │ ├── faust.tables.rst │ ├── faust.topics.rst │ ├── faust.worker.rst │ ├── faust.sensors.rst │ ├── faust.streams.rst │ ├── faust.windows.rst │ ├── faust.app.base.rst │ ├── faust.channels.rst │ ├── faust.cli.base.rst │ ├── faust.cli.faust.rst │ ├── faust.cli.model.rst │ ├── faust.cli.reset.rst │ ├── faust.cli.send.rst │ ├── faust.livecheck.rst │ ├── faust.transport.rst │ ├── faust.types.app.rst │ ├── faust.types.web.rst │ ├── faust.web.base.rst │ ├── faust.web.cache.rst │ ├── faust.web.views.rst │ ├── faust.app.router.rst │ ├── faust.cli.agents.rst │ ├── faust.cli.models.rst │ ├── faust.cli.params.rst │ ├── faust.cli.tables.rst │ ├── faust.cli.worker.rst │ ├── faust.exceptions.rst │ ├── faust.types.auth.rst │ ├── faust.types.core.rst │ ├── faust.utils.json.rst │ ├── faust.utils.urls.rst │ ├── faust.fixups.base.rst │ ├── faust.models.base.rst │ ├── faust.stores.base.rst │ ├── faust.tables.base.rst │ ├── faust.tables.sets.rst │ ├── faust.types.enums.rst │ ├── faust.types.joins.rst │ ├── faust.web.drivers.rst │ ├── faust.agents.actor.rst │ ├── faust.agents.agent.rst │ ├── faust.sensors.base.rst │ ├── faust.tables.table.rst │ ├── faust.types.agents.rst │ ├── faust.types.codecs.rst │ ├── faust.types.events.rst │ ├── faust.types.fixups.rst │ ├── faust.types.models.rst │ ├── faust.types.router.rst │ ├── faust.types.stores.rst │ ├── faust.types.tables.rst │ ├── faust.types.topics.rst │ ├── faust.types.tuples.rst │ ├── faust.agents.manager.rst │ ├── faust.agents.models.rst │ ├── faust.agents.replies.rst │ ├── faust.cli.completion.rst │ ├── faust.cli.livecheck.rst │ ├── faust.fixups.django.rst │ ├── faust.livecheck.app.rst │ ├── faust.livecheck.case.rst │ ├── faust.models.fields.rst │ ├── faust.models.record.rst │ ├── faust.sensors.statsd.rst │ ├── faust.stores.memory.rst │ ├── faust.stores.rocksdb.rst │ ├── faust.tables.manager.rst │ ├── faust.tables.objects.rst │ ├── faust.transport.base.rst │ ├── faust.types.assignor.rst │ ├── faust.types.channels.rst │ ├── faust.types.sensors.rst │ ├── faust.types.settings.rst │ ├── faust.types.streams.rst │ ├── faust.types.windows.rst │ ├── faust.utils.codegen.rst │ ├── faust.utils.iso8601.rst │ ├── faust.utils.terminal.rst │ ├── faust.utils.tracing.rst │ ├── faust.utils.venusian.rst │ ├── faust.web.apps.graph.rst │ ├── faust.web.apps.stats.rst │ ├── faust.web.blueprints.rst │ ├── faust.web.exceptions.rst │ ├── faust.sensors.datadog.rst │ ├── faust.sensors.monitor.rst │ ├── faust.tables.recovery.rst │ ├── faust.tables.wrappers.rst │ ├── faust.transport.utils.rst │ ├── faust.utils.platforms.rst │ ├── faust.web.apps.router.rst │ ├── faust.web.cache.cache.rst │ ├── faust.livecheck.locals.rst │ ├── faust.livecheck.models.rst │ ├── faust.types.transports.rst │ ├── faust.utils.functional.rst │ ├── faust.livecheck.patches.rst │ ├── faust.livecheck.runners.rst │ ├── faust.livecheck.signals.rst │ ├── faust.transport.drivers.rst │ ├── faust.types.serializers.rst │ ├── faust.cli.clean_versions.rst │ ├── faust.serializers.codecs.rst │ ├── faust.transport.conductor.rst │ ├── faust.transport.consumer.rst │ ├── faust.transport.producer.rst │ ├── faust.web.cache.backends.rst │ ├── faust.web.drivers.aiohttp.rst │ ├── faust.livecheck.exceptions.rst │ ├── faust.serializers.registry.rst │ ├── faust.web.cache.exceptions.rst │ ├── faust.utils.terminal.tables.rst │ ├── faust.assignor.leader_assignor.rst │ ├── faust.utils.terminal.spinners.rst │ ├── faust.web.cache.backends.base.rst │ ├── faust.web.cache.backends.redis.rst │ ├── faust.livecheck.patches.aiohttp.rst │ ├── faust.web.cache.backends.memory.rst │ ├── faust.assignor.client_assignment.rst │ ├── faust.transport.drivers.aiokafka.rst │ ├── faust.assignor.cluster_assignment.rst │ ├── faust.assignor.partition_assignor.rst │ └── faust.assignor.copartitioned_assignor.rst ├── playbooks │ └── index.rst ├── history │ └── index.rst ├── copyright.rst └── index.rst ├── examples ├── __init__.py ├── django │ ├── accounts │ │ ├── __init__.py │ │ ├── migrations │ │ │ ├── __init__.py │ │ │ └── 0001_initial.py │ │ ├── apps.py │ │ ├── models.py │ │ └── agents.py │ ├── faustapp │ │ ├── __init__.py │ │ ├── migrations │ │ │ └── __init__.py │ │ ├── apps.py │ │ └── app.py │ ├── requirements │ │ ├── test.txt │ │ └── default.txt │ ├── proj │ │ ├── __main__.py │ │ ├── wsgi.py │ │ ├── urls.py │ │ └── __init__.py │ ├── manage.py │ └── README.rst ├── kubernetes │ ├── consumer │ │ ├── requirements.txt │ │ ├── Dockerfile │ │ ├── consumer.yml │ │ ├── README.md │ │ └── consumer.py │ └── producer │ │ ├── requirements.txt │ │ ├── Dockerfile │ │ ├── producer.yml │ │ ├── README.md │ │ └── producer.py ├── leader.py ├── hello_world.py ├── concurrency.py ├── crontab │ ├── tz_unaware.py │ └── tz_aware.py ├── advanced │ ├── rpc.py │ └── service.py └── tableofset.py ├── requirements ├── extras │ ├── cython.txt │ ├── datadog.txt │ ├── aiodns.txt │ ├── ciso8601.txt │ ├── statsd.txt │ ├── uvloop.txt │ ├── cchardet.txt │ ├── gevent.txt │ ├── orjson.txt │ ├── redis.txt │ ├── aiomonitor.txt │ ├── ckafka.txt │ ├── rocksdb.txt │ ├── setproctitle.txt │ ├── eventlet.txt │ ├── debug.txt │ └── fast.txt ├── typecheck.txt ├── ci.txt ├── docs.txt ├── spell.txt ├── docs-plugins.txt ├── dist.txt ├── default.txt ├── flakes.txt ├── test.txt └── README.rst ├── CODE_OF_CONDUCT.rst ├── faust ├── utils │ ├── kafka │ │ ├── __init__.py │ │ └── protocol │ │ │ └── __init__.py │ ├── __init__.py │ ├── iso8601.py │ ├── terminal │ │ └── __init__.py │ ├── cron.py │ ├── venusian.py │ ├── platforms.py │ ├── functional.py │ └── urls.py ├── web │ ├── apps │ │ ├── __init__.py │ │ ├── production_index.py │ │ ├── graph.py │ │ └── stats.py │ ├── cache │ │ ├── __init__.py │ │ ├── exceptions.py │ │ └── backends │ │ │ └── __init__.py │ ├── __init__.py │ └── drivers │ │ └── __init__.py ├── _cython │ └── __init__.py ├── py.typed ├── transport │ ├── _cython │ │ └── __init__.py │ ├── __init__.py │ └── drivers │ │ └── __init__.py ├── __main__.py ├── app │ └── __init__.py ├── serializers │ └── __init__.py ├── types │ ├── enums.py │ ├── joins.py │ ├── fixups.py │ ├── codecs.py │ ├── router.py │ ├── windows.py │ ├── auth.py │ ├── _env.py │ └── serializers.py ├── assignor │ ├── __init__.py │ └── leader_assignor.py ├── cli │ ├── __init__.py │ ├── livecheck.py │ ├── tables.py │ ├── faust.py │ ├── clean_versions.py │ ├── completion.py │ └── reset.py ├── sensors │ └── __init__.py ├── livecheck │ ├── patches │ │ └── __init__.py │ ├── __init__.py │ ├── locals.py │ └── exceptions.py ├── tables │ └── __init__.py ├── models │ └── __init__.py ├── agents │ ├── __init__.py │ └── models.py ├── stores │ └── __init__.py ├── fixups │ ├── base.py │ └── __init__.py └── joins.py ├── readthedocs.yml ├── artwork ├── logo.png ├── favicon.ico ├── banner-alt1.png ├── banner-alt2.png └── LICENSE ├── extra ├── systemd │ ├── faust.tmpfiles │ ├── faust.service │ └── faust.conf ├── release │ └── sphinx2rst_config.py ├── tools │ ├── verify_ascending.py │ ├── verify_tabletest_changelog.py │ ├── benchmark.py │ └── verify_tabletest.sh ├── macOS │ └── com.fauststream.worker.plist └── supervisord │ ├── faust.conf │ └── supervisord.conf ├── .pyup.yml ├── .pre-commit-config.yaml ├── .editorconfig ├── environment.yml ├── .github ├── PULL_REQUEST_TEMPLATE.md └── ISSUE_TEMPLATE.md ├── .gitignore ├── MANIFEST.in └── .coveragerc /t/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/_static/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /t/docs/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /t/old/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /t/unit/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/_templates/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /t/bench/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /t/stress/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /t/unit/cli/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /t/unit/web/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /t/consistency/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /t/docs/testing/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /t/functional/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /t/functional/web/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /t/regression/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /t/stress/reports/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /t/stress/tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /t/unit/agents/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /t/unit/fixups/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /t/unit/livecheck/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /t/unit/sensors/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /t/unit/stores/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /t/unit/tables/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /t/unit/utils/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /t/functional/agents/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /t/functional/sensors/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /t/integration/cli/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /t/meticulous/assignor/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /t/regression/i323/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /t/regression/i324/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /t/unit/serializers/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /t/unit/utils/terminal/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /t/unit/web/drivers/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/django/accounts/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/django/faustapp/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /t/consistency/.gitignore: -------------------------------------------------------------------------------- 1 | *.logs 2 | -------------------------------------------------------------------------------- /t/functional/serializers/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /t/stress/tests/simple/requirements.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /t/stress/tests/tables/requirements.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /t/unit/transport/drivers/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/images/logo.png: -------------------------------------------------------------------------------- 1 | ../../artwork/logo.png -------------------------------------------------------------------------------- /requirements/extras/cython.txt: -------------------------------------------------------------------------------- 1 | cython 2 | -------------------------------------------------------------------------------- /requirements/extras/datadog.txt: -------------------------------------------------------------------------------- 1 | datadog 2 | -------------------------------------------------------------------------------- /requirements/typecheck.txt: -------------------------------------------------------------------------------- 1 | mypy<0.700 2 | -------------------------------------------------------------------------------- /t/regression/i323/proj323/foo/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /t/regression/i324/proj324/foo/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /t/stress/tests/forwarder/requirements.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.rst: -------------------------------------------------------------------------------- 1 | .github/CODE_OF_CONDUCT.md -------------------------------------------------------------------------------- /docs/images/favicon.ico: -------------------------------------------------------------------------------- 1 | ../../artwork/favicon.ico -------------------------------------------------------------------------------- /examples/django/accounts/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/django/faustapp/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /requirements/extras/aiodns.txt: -------------------------------------------------------------------------------- 1 | aiodns>=1.1 2 | -------------------------------------------------------------------------------- /requirements/extras/ciso8601.txt: -------------------------------------------------------------------------------- 1 | ciso8601 2 | -------------------------------------------------------------------------------- /requirements/extras/statsd.txt: -------------------------------------------------------------------------------- 1 | statsd~=3.2.1 2 | -------------------------------------------------------------------------------- /requirements/extras/uvloop.txt: -------------------------------------------------------------------------------- 1 | uvloop>=0.8.1 2 | -------------------------------------------------------------------------------- /t/regression/i323/proj323/foo/bar/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /t/regression/i324/proj324/foo/bar/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/changelog.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../Changelog.rst 2 | -------------------------------------------------------------------------------- /requirements/extras/cchardet.txt: -------------------------------------------------------------------------------- 1 | cchardet>=2.1 2 | -------------------------------------------------------------------------------- /requirements/extras/gevent.txt: -------------------------------------------------------------------------------- 1 | aiogevent~=0.2 2 | -------------------------------------------------------------------------------- /requirements/extras/orjson.txt: -------------------------------------------------------------------------------- 1 | orjson>=2.0,<3.0 2 | -------------------------------------------------------------------------------- /requirements/extras/redis.txt: -------------------------------------------------------------------------------- 1 | aredis>=1.1.3,<2.0 2 | -------------------------------------------------------------------------------- /t/regression/i323/proj323/foo/bar/baz/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /t/regression/i324/proj324/foo/bar/baz/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/images/banner-alt1.png: -------------------------------------------------------------------------------- 1 | ../../artwork/banner-alt1.png -------------------------------------------------------------------------------- /docs/images/banner-alt2.png: -------------------------------------------------------------------------------- 1 | ../../artwork/banner-alt2.png -------------------------------------------------------------------------------- /examples/kubernetes/consumer/requirements.txt: -------------------------------------------------------------------------------- 1 | faust 2 | -------------------------------------------------------------------------------- /faust/utils/kafka/__init__.py: -------------------------------------------------------------------------------- 1 | """Kafka utilities.""" 2 | -------------------------------------------------------------------------------- /faust/web/apps/__init__.py: -------------------------------------------------------------------------------- 1 | """Built-in Web Apps.""" 2 | -------------------------------------------------------------------------------- /readthedocs.yml: -------------------------------------------------------------------------------- 1 | conda: 2 | file: environment.yml 3 | -------------------------------------------------------------------------------- /requirements/extras/aiomonitor.txt: -------------------------------------------------------------------------------- 1 | aiomonitor>=0.4.4 2 | -------------------------------------------------------------------------------- /requirements/extras/ckafka.txt: -------------------------------------------------------------------------------- 1 | confluent-kafka~=0.11.0 2 | -------------------------------------------------------------------------------- /requirements/extras/rocksdb.txt: -------------------------------------------------------------------------------- 1 | python-rocksdb>=0.6.7 2 | -------------------------------------------------------------------------------- /requirements/extras/setproctitle.txt: -------------------------------------------------------------------------------- 1 | setproctitle>=1.1 2 | -------------------------------------------------------------------------------- /examples/kubernetes/producer/requirements.txt: -------------------------------------------------------------------------------- 1 | kafka-python 2 | -------------------------------------------------------------------------------- /faust/_cython/__init__.py: -------------------------------------------------------------------------------- 1 | """Cython optimized Faust features.""" 2 | -------------------------------------------------------------------------------- /requirements/ci.txt: -------------------------------------------------------------------------------- 1 | -r typecheck.txt 2 | pytest-cov 3 | codecov 4 | -------------------------------------------------------------------------------- /requirements/docs.txt: -------------------------------------------------------------------------------- 1 | -r docs-plugins.txt 2 | sphinx>=2.0,<3.0 3 | -------------------------------------------------------------------------------- /requirements/extras/eventlet.txt: -------------------------------------------------------------------------------- 1 | aioeventlet~=0.5.1 2 | dnspython 3 | -------------------------------------------------------------------------------- /t/regression/i324/proj324/foo/test_x.py: -------------------------------------------------------------------------------- 1 | print('TEST FILE IMPORTED') 2 | -------------------------------------------------------------------------------- /examples/django/requirements/test.txt: -------------------------------------------------------------------------------- 1 | pytest~=3.0 2 | pytest-asyncio>=0.8 3 | -------------------------------------------------------------------------------- /faust/py.typed: -------------------------------------------------------------------------------- 1 | # PEP-0561 -- https://www.python.org/dev/peps/pep-0561/ 2 | -------------------------------------------------------------------------------- /faust/utils/kafka/protocol/__init__.py: -------------------------------------------------------------------------------- 1 | """Kafka protocol definitions.""" 2 | -------------------------------------------------------------------------------- /requirements/extras/debug.txt: -------------------------------------------------------------------------------- 1 | -r setproctitle.txt 2 | -r aiomonitor.txt 3 | -------------------------------------------------------------------------------- /artwork/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomasbedrich/faust/master/artwork/logo.png -------------------------------------------------------------------------------- /faust/transport/_cython/__init__.py: -------------------------------------------------------------------------------- 1 | """Cython optimized transport components.""" 2 | -------------------------------------------------------------------------------- /requirements/spell.txt: -------------------------------------------------------------------------------- 1 | -r docs-plugins.txt 2 | sphinx<2.0 3 | sphinxcontrib-spelling 4 | -------------------------------------------------------------------------------- /t/stress/tests/forwarder/__init__.py: -------------------------------------------------------------------------------- 1 | from .app import app 2 | 3 | __all__ = ['app'] 4 | -------------------------------------------------------------------------------- /t/stress/tests/simple/__init__.py: -------------------------------------------------------------------------------- 1 | from .app import app 2 | 3 | __all__ = ['app'] 4 | -------------------------------------------------------------------------------- /t/stress/tests/tables/__init__.py: -------------------------------------------------------------------------------- 1 | from .app import app 2 | 3 | __all__ = ['app'] 4 | -------------------------------------------------------------------------------- /artwork/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomasbedrich/faust/master/artwork/favicon.ico -------------------------------------------------------------------------------- /artwork/banner-alt1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomasbedrich/faust/master/artwork/banner-alt1.png -------------------------------------------------------------------------------- /artwork/banner-alt2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomasbedrich/faust/master/artwork/banner-alt2.png -------------------------------------------------------------------------------- /examples/django/requirements/default.txt: -------------------------------------------------------------------------------- 1 | django 2 | faust[rocksdb] 3 | eventlet 4 | aioeventlet 5 | -------------------------------------------------------------------------------- /t/functional/test_faust.py: -------------------------------------------------------------------------------- 1 | import faust 2 | 3 | 4 | def test_dir(): 5 | assert dir(faust) 6 | -------------------------------------------------------------------------------- /extra/systemd/faust.tmpfiles: -------------------------------------------------------------------------------- 1 | d /var/run/faust 0755 faust faust - 2 | d /var/log/faust 0755 faust faust - 3 | -------------------------------------------------------------------------------- /faust/web/cache/__init__.py: -------------------------------------------------------------------------------- 1 | """Caching.""" 2 | from .cache import Cache 3 | 4 | __all__ = ['Cache'] 5 | -------------------------------------------------------------------------------- /t/stress/requirements.txt: -------------------------------------------------------------------------------- 1 | raven>=6.7.0 2 | raven-aiohttp>=0.7.0 3 | envoy 4 | setproctitle 5 | jinja2 6 | -------------------------------------------------------------------------------- /.pyup.yml: -------------------------------------------------------------------------------- 1 | # Label PRs with `deps-update` label 2 | label_prs: deps-update 3 | 4 | pin: False 5 | 6 | schedule: every week 7 | -------------------------------------------------------------------------------- /faust/__main__.py: -------------------------------------------------------------------------------- 1 | """Command-line entry point.""" 2 | # pragma: no cover 3 | from faust.cli.faust import cli 4 | 5 | cli() 6 | -------------------------------------------------------------------------------- /faust/app/__init__.py: -------------------------------------------------------------------------------- 1 | """Application.""" 2 | from .base import App, BootStrategy 3 | 4 | __all__ = ['App', 'BootStrategy'] 5 | -------------------------------------------------------------------------------- /t/regression/i324/proj324/__main__.py: -------------------------------------------------------------------------------- 1 | from proj324.faust import app 2 | 3 | print('IMPORTS __MAIN__') 4 | 5 | app.main() 6 | -------------------------------------------------------------------------------- /faust/transport/__init__.py: -------------------------------------------------------------------------------- 1 | """Transports.""" 2 | from .drivers import by_name, by_url 3 | 4 | __all__ = ['by_name', 'by_url'] 5 | -------------------------------------------------------------------------------- /requirements/docs-plugins.txt: -------------------------------------------------------------------------------- 1 | alabaster 2 | sphinx_autodoc_annotation 3 | sphinx_celery>=1.4.8,<2.0 4 | sphinxcontrib-asyncio 5 | -------------------------------------------------------------------------------- /examples/django/accounts/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class AccountsConfig(AppConfig): 5 | name = 'accounts' 6 | -------------------------------------------------------------------------------- /examples/django/faustapp/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class FaustappConfig(AppConfig): 5 | name = 'faustapp' 6 | -------------------------------------------------------------------------------- /requirements/extras/fast.txt: -------------------------------------------------------------------------------- 1 | -r aiodns.txt 2 | -r cchardet.txt 3 | -r ciso8601.txt 4 | -r cython.txt 5 | -r orjson.txt 6 | -r setproctitle.txt 7 | -------------------------------------------------------------------------------- /t/regression/i323/proj323/__init__.py: -------------------------------------------------------------------------------- 1 | from .faust import app 2 | 3 | __all__ = ['app', 'main'] 4 | 5 | 6 | def main() -> None: 7 | app.main() 8 | -------------------------------------------------------------------------------- /t/regression/i324/proj324/__init__.py: -------------------------------------------------------------------------------- 1 | from .faust import app 2 | 3 | __all__ = ['app', 'main'] 4 | 5 | 6 | def main() -> None: 7 | app.main() 8 | -------------------------------------------------------------------------------- /faust/serializers/__init__.py: -------------------------------------------------------------------------------- 1 | """Serializers and Codecs.""" 2 | from .codecs import Codec 3 | from .registry import Registry 4 | 5 | __all__ = ['Codec', 'Registry'] 6 | -------------------------------------------------------------------------------- /faust/types/enums.py: -------------------------------------------------------------------------------- 1 | from enum import Enum 2 | 3 | 4 | class ProcessingGuarantee(Enum): 5 | AT_LEAST_ONCE = 'at_least_once' 6 | EXACTLY_ONCE = 'exactly_once' 7 | -------------------------------------------------------------------------------- /t/regression/i323/proj323/foo/bar/baz/commands.py: -------------------------------------------------------------------------------- 1 | from proj323 import app 2 | 3 | 4 | @app.command() 5 | async def my_process_command_i323(): 6 | print('HELLO WORLD #323') 7 | -------------------------------------------------------------------------------- /t/regression/i324/proj324/foo/bar/baz/commands.py: -------------------------------------------------------------------------------- 1 | from proj324 import app 2 | 3 | 4 | @app.command() 5 | async def my_process_command_i324(): 6 | print('HELLO WORLD #324') 7 | -------------------------------------------------------------------------------- /docs/faq.rst: -------------------------------------------------------------------------------- 1 | .. _faq: 2 | 3 | ================================== 4 | Frequently Asked Questions (FAQ) 5 | ================================== 6 | 7 | .. include:: includes/faq.txt 8 | -------------------------------------------------------------------------------- /faust/assignor/__init__.py: -------------------------------------------------------------------------------- 1 | from .leader_assignor import LeaderAssignor 2 | from .partition_assignor import PartitionAssignor 3 | 4 | __all__ = ['LeaderAssignor', 'PartitionAssignor'] 5 | -------------------------------------------------------------------------------- /t/unit/test_faust.py: -------------------------------------------------------------------------------- 1 | import faust.exceptions # noqa: F401 2 | import faust.transport.drivers.aiokafka # noqa: F401 3 | import faust.transport.base # noqa: F401 4 | -------------------------------------------------------------------------------- /faust/web/cache/exceptions.py: -------------------------------------------------------------------------------- 1 | """Cache-related errors.""" 2 | 3 | __all__ = ['CacheUnavailable'] 4 | 5 | 6 | class CacheUnavailable(Exception): 7 | """The cache is currently unavailable.""" 8 | -------------------------------------------------------------------------------- /docs/authors.rst: -------------------------------------------------------------------------------- 1 | .. _authors: 2 | 3 | =============================== 4 | Authors 5 | =============================== 6 | 7 | .. contents:: 8 | :local: 9 | 10 | .. include:: ../AUTHORS.rst 11 | -------------------------------------------------------------------------------- /faust/cli/__init__.py: -------------------------------------------------------------------------------- 1 | """Command-line Interface.""" 2 | from .base import AppCommand, Command, argument, call_command, option 3 | 4 | __all__ = ['AppCommand', 'Command', 'argument', 'call_command', 'option'] 5 | -------------------------------------------------------------------------------- /t/integration/cli/test_base.py: -------------------------------------------------------------------------------- 1 | def test_command_returns_nonzero_exit_status(*, faust): 2 | exitcode, stdout, stderr = faust('error_command') 3 | assert not stdout 4 | assert stderr 5 | assert exitcode 6 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: local 3 | hooks: 4 | - id: flake8 5 | name: flake8 6 | entry: flake8 7 | language: system 8 | files: .*\.py$ 9 | python_version: python3.6 10 | -------------------------------------------------------------------------------- /t/unit/utils/test_utils.py: -------------------------------------------------------------------------------- 1 | from faust.utils import uuid 2 | 3 | 4 | def test_uuid(): 5 | seen = set() 6 | for _ in range(100): 7 | uid = uuid() 8 | assert uid not in seen 9 | seen.add(uid) 10 | -------------------------------------------------------------------------------- /docs/includes/tags.txt: -------------------------------------------------------------------------------- 1 | :Version: 1.7.0 2 | :Web: http://faust.readthedocs.io/ 3 | :Download: http://pypi.org/project/faust 4 | :Source: http://github.com/robinhood/faust 5 | :Keywords: distributed, stream, async, processing, data, queue 6 | 7 | -------------------------------------------------------------------------------- /t/stress/reports/web.py: -------------------------------------------------------------------------------- 1 | from jinja2 import Environment, PackageLoader, select_autoescape 2 | 3 | env = Environment( 4 | loader=PackageLoader('t.stress.reports', 'templates'), 5 | autoescape=select_autoescape(['html', 'xml']), 6 | ) 7 | -------------------------------------------------------------------------------- /examples/django/proj/__main__.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'proj.settings') 4 | from django.core.management import execute_from_command_line # noqa: E402 5 | execute_from_command_line(sys.argv) 6 | -------------------------------------------------------------------------------- /t/regression/i323/proj323/faust.py: -------------------------------------------------------------------------------- 1 | import faust 2 | 3 | 4 | def create_app(): 5 | return faust.App( 6 | 'proj323', 7 | origin='proj323', 8 | autodiscover=True, 9 | ) 10 | 11 | 12 | app = create_app() 13 | -------------------------------------------------------------------------------- /t/regression/i324/proj324/faust.py: -------------------------------------------------------------------------------- 1 | import faust 2 | 3 | 4 | def create_app(): 5 | return faust.App( 6 | 'proj324', 7 | origin='proj324', 8 | autodiscover=True, 9 | ) 10 | 11 | 12 | app = create_app() 13 | -------------------------------------------------------------------------------- /faust/sensors/__init__.py: -------------------------------------------------------------------------------- 1 | """Sensors.""" 2 | from .base import Sensor, SensorDelegate 3 | from .monitor import Monitor, TableState 4 | 5 | __all__ = [ 6 | 'Monitor', 7 | 'Sensor', 8 | 'SensorDelegate', 9 | 'TableState', 10 | ] 11 | -------------------------------------------------------------------------------- /t/functional/test_aiokafka.py: -------------------------------------------------------------------------------- 1 | from aiokafka.structs import TopicPartition 2 | from faust.types import TP 3 | 4 | 5 | def test_TP_TopicPartition_hashability(): 6 | d = {} 7 | d[TP('foo', 33)] = 33 8 | assert d[TopicPartition('foo', 33)] == 33 9 | -------------------------------------------------------------------------------- /faust/utils/__init__.py: -------------------------------------------------------------------------------- 1 | """Utilities.""" 2 | from uuid import uuid4 3 | 4 | __all__ = ['uuid'] 5 | 6 | 7 | def uuid() -> str: 8 | """Generate random UUID string. 9 | 10 | Shortcut to ``str(uuid4())``. 11 | """ 12 | return str(uuid4()) 13 | -------------------------------------------------------------------------------- /docs/userguide/installation.rst: -------------------------------------------------------------------------------- 1 | .. _installation: 2 | 3 | ================================= 4 | Installation 5 | ================================= 6 | 7 | .. contents:: 8 | :local: 9 | :depth: 1 10 | 11 | .. include:: ../includes/installation.txt 12 | -------------------------------------------------------------------------------- /t/stress/reports/states.py: -------------------------------------------------------------------------------- 1 | OK = 'OK' 2 | FAIL = 'FAIL' 3 | SLOW = 'SLOW' 4 | STALL = 'STALL' 5 | UNASSIGNED = 'UNASSIGNED' 6 | REBALANCING = 'REBALANCING' 7 | PAUSED = 'PAUSED' 8 | 9 | OK_STATES = {OK, UNASSIGNED} 10 | MAYBE_STATES = {REBALANCING, PAUSED} 11 | -------------------------------------------------------------------------------- /t/unit/cli/test_env.py: -------------------------------------------------------------------------------- 1 | import os 2 | import pytest 3 | from faust.types._env import _getenv 4 | 5 | 6 | def test_getenv_not_set(): 7 | os.environ.pop('THIS_IS_NOT_SET', None) 8 | with pytest.raises(KeyError): 9 | _getenv('THIS_IS_NOT_SET') 10 | -------------------------------------------------------------------------------- /docs/userguide/kafka.rst: -------------------------------------------------------------------------------- 1 | ============================================= 2 | Kafka - The basics you need to know 3 | ============================================= 4 | 5 | .. contents:: 6 | :local: 7 | :depth: 1 8 | 9 | .. include:: ../includes/kafka.txt 10 | -------------------------------------------------------------------------------- /examples/kubernetes/producer/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.7.1-alpine3.7 2 | 3 | RUN mkdir -p /app 4 | WORKDIR /app 5 | 6 | COPY requirements.txt requirements.txt 7 | 8 | RUN pip install -r requirements.txt 9 | 10 | COPY . . 11 | 12 | CMD ["python", "producer.py"] 13 | -------------------------------------------------------------------------------- /t/unit/cli/conftest.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from mode.utils.mocks import Mock 3 | 4 | 5 | @pytest.fixture() 6 | def context(*, app, request): 7 | context = Mock() 8 | context.app = app 9 | context.find_root.return_value = context 10 | return context 11 | -------------------------------------------------------------------------------- /artwork/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017-2019 Robinhood Markets, Inc. 2 | All rights reserved. 3 | 4 | This logo or a modified version may be used by media organizations 5 | to refer to the project. The logo shall not be used in any way 6 | that indicates endorsment by the project. 7 | -------------------------------------------------------------------------------- /requirements/dist.txt: -------------------------------------------------------------------------------- 1 | -r flakes.txt 2 | asyncio-ipython-magic 3 | bumpversion>=0.5.1 4 | packaging 5 | pre-commit 6 | pydocstyle 7 | pytest-sugar 8 | setuptools>=30.3.0 9 | sphinx-autobuild 10 | sphinx2rst>=1.0 11 | tox>=2.3.1 12 | twine 13 | vulture 14 | wheel>=0.29.0 15 | -------------------------------------------------------------------------------- /docs/developerguide/index.rst: -------------------------------------------------------------------------------- 1 | .. _developers-guide: 2 | 3 | ================= 4 | Developer Guide 5 | ================= 6 | 7 | :Release: |version| 8 | :Date: |today| 9 | 10 | .. toctree:: 11 | :maxdepth: 2 12 | 13 | overview 14 | partition_assignor 15 | 16 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | indent_style = space 7 | indent_size = 4 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | charset = utf-8 11 | end_of_line = lf 12 | 13 | [Makefile] 14 | indent_style = tab 15 | -------------------------------------------------------------------------------- /docs/reference/faust.utils.cron.rst: -------------------------------------------------------------------------------- 1 | ``faust.utils.cron`` 2 | ===================================================== 3 | 4 | .. contents:: 5 | :local: 6 | .. currentmodule:: faust.utils.cron 7 | 8 | .. automodule:: faust.utils.cron 9 | :members: 10 | :undoc-members: 11 | -------------------------------------------------------------------------------- /t/bench/baseline.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import faust 3 | sys.path.insert(0, '.') 4 | from t.bench.base import Benchmark # noqa 5 | 6 | app = faust.App('bench-baseline') 7 | topic = app.topic('bench-baseline', value_serializer='raw', value_type=int) 8 | Benchmark(app, topic).install(__name__) 9 | -------------------------------------------------------------------------------- /t/regression/i323/conftest.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from pathlib import Path 3 | import pytest 4 | 5 | sys.path.append(str(Path(__file__).parent)) 6 | 7 | 8 | @pytest.fixture() 9 | def app(): 10 | from proj323 import faust 11 | faust.app = faust.create_app() 12 | return faust.app 13 | -------------------------------------------------------------------------------- /t/regression/i324/conftest.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from pathlib import Path 3 | import pytest 4 | 5 | sys.path.append(str(Path(__file__).parent)) 6 | 7 | 8 | @pytest.fixture() 9 | def app(): 10 | from proj324 import faust 11 | faust.app = faust.create_app() 12 | return faust.app 13 | -------------------------------------------------------------------------------- /docs/reference/faust.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust 8 | 9 | .. automodule:: faust 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /examples/kubernetes/consumer/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.7.1-alpine3.7 2 | 3 | RUN mkdir -p /app 4 | WORKDIR /app 5 | 6 | COPY requirements.txt requirements.txt 7 | 8 | RUN pip install -r requirements.txt 9 | 10 | COPY . . 11 | 12 | CMD ["faust", "-A", "consumer", "worker", "-l", "info"] 13 | -------------------------------------------------------------------------------- /faust/livecheck/patches/__init__.py: -------------------------------------------------------------------------------- 1 | """Patches - LiveCheck integration with other frameworks/libraries.""" 2 | from . import aiohttp 3 | 4 | __all__ = ['aiohttp', 'patch_all'] 5 | 6 | 7 | def patch_all() -> None: 8 | """Apply all LiveCheck monkey patches.""" 9 | aiohttp.patch_all() 10 | -------------------------------------------------------------------------------- /docs/reference/faust.app.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.app`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.app 8 | 9 | .. automodule:: faust.app 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.auth.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.auth`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.auth 8 | 9 | .. automodule:: faust.auth 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/playbooks/index.rst: -------------------------------------------------------------------------------- 1 | .. _playbooks: 2 | 3 | =============== 4 | Playbooks 5 | =============== 6 | 7 | :Release: |version| 8 | :Date: |today| 9 | 10 | .. toctree:: 11 | :maxdepth: 1 12 | 13 | quickstart 14 | pageviews 15 | leaderelection 16 | vskafka 17 | vscelery 18 | cheatsheet 19 | -------------------------------------------------------------------------------- /docs/reference/faust.joins.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.joins`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.joins 8 | 9 | .. automodule:: faust.joins 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /faust/utils/iso8601.py: -------------------------------------------------------------------------------- 1 | """Parsing ISO-8601 string and converting to :class:`~datetime.datetime`.""" 2 | try: # pragma: no cover 3 | import ciso8601 4 | except ImportError: # pragma: no cover 5 | from ._iso8601_python import parse 6 | else: 7 | parse = ciso8601.parse_datetime 8 | 9 | __all__ = ['parse'] 10 | -------------------------------------------------------------------------------- /requirements/default.txt: -------------------------------------------------------------------------------- 1 | aiohttp>=3.5.2,<4.0 2 | aiohttp_cors>=0.7,<2.0 3 | robinhood-aiokafka>=1.0.3,<1.1 4 | click>=6.7,<7.0 5 | colorclass>=2.2,<3.0 6 | mode>=4.0,<4.1 7 | opentracing>=1.3.0,<2.0.0 8 | terminaltables>=3.1,<4.0 9 | venusian>=1.1,<2.0 10 | yarl>=1.0,<2.0 11 | croniter>=0.3.16 12 | mypy_extensions 13 | -------------------------------------------------------------------------------- /docs/reference/faust.agents.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.agents`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.agents 8 | 9 | .. automodule:: faust.agents 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.events.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.events`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.events 8 | 9 | .. automodule:: faust.events 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.fixups.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.fixups`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.fixups 8 | 9 | .. automodule:: faust.fixups 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.stores.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.stores`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.stores 8 | 9 | .. automodule:: faust.stores 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.tables.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.tables`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.tables 8 | 9 | .. automodule:: faust.tables 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.topics.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.topics`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.topics 8 | 9 | .. automodule:: faust.topics 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.worker.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.worker`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.worker 8 | 9 | .. automodule:: faust.worker 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /environment.yml: -------------------------------------------------------------------------------- 1 | channels: 2 | - conda-forge 3 | name: py36 4 | dependencies: 5 | - pip 6 | - python=3.6 7 | - setuptools 8 | - wheel 9 | - pip: 10 | - Sphinx 11 | - sphinx_celery 12 | - sphinxcontrib-asyncio 13 | - sphinx-autodoc-annotation 14 | - alabaster 15 | -------------------------------------------------------------------------------- /faust/livecheck/__init__.py: -------------------------------------------------------------------------------- 1 | """LiveCheck - End-to-end testing of asynchronous systems.""" 2 | from .app import LiveCheck 3 | from .case import Case 4 | from .locals import current_test 5 | from .runners import TestRunner 6 | from .signals import Signal 7 | 8 | __all__ = ['LiveCheck', 'Case', 'Signal', 'TestRunner', 'current_test'] 9 | -------------------------------------------------------------------------------- /requirements/flakes.txt: -------------------------------------------------------------------------------- 1 | flake8-blind-except 2 | flake8-bugbear 3 | flake8-builtins-unleashed 4 | flake8-class-newline 5 | flake8-commas 6 | flake8-comprehensions 7 | flake8-debugger 8 | flake8-import-order 9 | flake8-logging-format 10 | flake8-mock 11 | flake8-pep3101 12 | flake8-tuple 13 | flake8-quotes 14 | flake8>=3.6.0 15 | -------------------------------------------------------------------------------- /docs/reference/faust.sensors.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.sensors`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.sensors 8 | 9 | .. automodule:: faust.sensors 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.streams.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.streams`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.streams 8 | 9 | .. automodule:: faust.streams 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.windows.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.windows`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.windows 8 | 9 | .. automodule:: faust.windows 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.app.base.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.app.base`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.app.base 8 | 9 | .. automodule:: faust.app.base 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.channels.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.channels`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.channels 8 | 9 | .. automodule:: faust.channels 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.cli.base.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.cli.base`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.cli.base 8 | 9 | .. automodule:: faust.cli.base 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.cli.faust.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.cli.faust`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.cli.faust 8 | 9 | .. automodule:: faust.cli.faust 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.cli.model.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.cli.model`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.cli.model 8 | 9 | .. automodule:: faust.cli.model 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.cli.reset.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.cli.reset`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.cli.reset 8 | 9 | .. automodule:: faust.cli.reset 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.cli.send.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.cli.send`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.cli.send 8 | 9 | .. automodule:: faust.cli.send 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.livecheck.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.livecheck`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.livecheck 8 | 9 | .. automodule:: faust.livecheck 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.transport.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.transport`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.transport 8 | 9 | .. automodule:: faust.transport 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.types.app.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.types.app`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.types.app 8 | 9 | .. automodule:: faust.types.app 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.types.web.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.types.web`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.types.web 8 | 9 | .. automodule:: faust.types.web 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.web.base.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.web.base`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.web.base 8 | 9 | .. automodule:: faust.web.base 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.web.cache.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.web.cache`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.web.cache 8 | 9 | .. automodule:: faust.web.cache 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.web.views.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.web.views`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.web.views 8 | 9 | .. automodule:: faust.web.views 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /t/old/app.py: -------------------------------------------------------------------------------- 1 | from typing import Any, AsyncIterator 2 | import faust 3 | 4 | app = faust.App('faust.stress') 5 | rpc_topic = app.topic('faust.stress.rpc') 6 | 7 | 8 | @app.agent(rpc_topic, concurrency=10) 9 | async def simple(it: AsyncIterator[Any]) -> AsyncIterator[Any]: 10 | async for value in it: 11 | yield value 12 | -------------------------------------------------------------------------------- /docs/reference/faust.app.router.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.app.router`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.app.router 8 | 9 | .. automodule:: faust.app.router 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.cli.agents.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.cli.agents`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.cli.agents 8 | 9 | .. automodule:: faust.cli.agents 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.cli.models.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.cli.models`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.cli.models 8 | 9 | .. automodule:: faust.cli.models 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.cli.params.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.cli.params`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.cli.params 8 | 9 | .. automodule:: faust.cli.params 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.cli.tables.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.cli.tables`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.cli.tables 8 | 9 | .. automodule:: faust.cli.tables 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.cli.worker.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.cli.worker`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.cli.worker 8 | 9 | .. automodule:: faust.cli.worker 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.exceptions.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.exceptions`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.exceptions 8 | 9 | .. automodule:: faust.exceptions 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.types.auth.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.types.auth`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.types.auth 8 | 9 | .. automodule:: faust.types.auth 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.types.core.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.types.core`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.types.core 8 | 9 | .. automodule:: faust.types.core 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.utils.json.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.utils.json`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.utils.json 8 | 9 | .. automodule:: faust.utils.json 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.utils.urls.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.utils.urls`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.utils.urls 8 | 9 | .. automodule:: faust.utils.urls 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.fixups.base.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.fixups.base`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.fixups.base 8 | 9 | .. automodule:: faust.fixups.base 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.models.base.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.models.base`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.models.base 8 | 9 | .. automodule:: faust.models.base 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.stores.base.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.stores.base`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.stores.base 8 | 9 | .. automodule:: faust.stores.base 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.tables.base.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.tables.base`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.tables.base 8 | 9 | .. automodule:: faust.tables.base 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.tables.sets.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.tables.sets`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.tables.sets 8 | 9 | .. automodule:: faust.tables.sets 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.types.enums.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.types.enums`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.types.enums 8 | 9 | .. automodule:: faust.types.enums 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.types.joins.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.types.joins`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.types.joins 8 | 9 | .. automodule:: faust.types.joins 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.web.drivers.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.web.drivers`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.web.drivers 8 | 9 | .. automodule:: faust.web.drivers 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.agents.actor.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.agents.actor`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.agents.actor 8 | 9 | .. automodule:: faust.agents.actor 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.agents.agent.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.agents.agent`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.agents.agent 8 | 9 | .. automodule:: faust.agents.agent 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.sensors.base.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.sensors.base`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.sensors.base 8 | 9 | .. automodule:: faust.sensors.base 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.tables.table.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.tables.table`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.tables.table 8 | 9 | .. automodule:: faust.tables.table 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.types.agents.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.types.agents`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.types.agents 8 | 9 | .. automodule:: faust.types.agents 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.types.codecs.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.types.codecs`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.types.codecs 8 | 9 | .. automodule:: faust.types.codecs 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.types.events.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.types.events`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.types.events 8 | 9 | .. automodule:: faust.types.events 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.types.fixups.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.types.fixups`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.types.fixups 8 | 9 | .. automodule:: faust.types.fixups 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.types.models.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.types.models`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.types.models 8 | 9 | .. automodule:: faust.types.models 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.types.router.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.types.router`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.types.router 8 | 9 | .. automodule:: faust.types.router 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.types.stores.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.types.stores`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.types.stores 8 | 9 | .. automodule:: faust.types.stores 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.types.tables.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.types.tables`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.types.tables 8 | 9 | .. automodule:: faust.types.tables 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.types.topics.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.types.topics`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.types.topics 8 | 9 | .. automodule:: faust.types.topics 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.types.tuples.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.types.tuples`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.types.tuples 8 | 9 | .. automodule:: faust.types.tuples 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /requirements/test.txt: -------------------------------------------------------------------------------- 1 | hypothesis>=3.31 2 | freezegun>=0.3.11 3 | pytest-aiofiles>=0.2.0 4 | pytest-aiohttp>=0.3.0 5 | pytest-asyncio>=0.8 6 | pytest-forked 7 | pytest-openfiles>=0.2.0 8 | pytest-picked 9 | pytest-random-order>=0.5.4 10 | pytest~=3.6 11 | pytz>=2018.7 12 | -r extras/datadog.txt 13 | -r extras/redis.txt 14 | -r extras/statsd.txt 15 | -------------------------------------------------------------------------------- /docs/reference/faust.agents.manager.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.agents.manager`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.agents.manager 8 | 9 | .. automodule:: faust.agents.manager 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.agents.models.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.agents.models`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.agents.models 8 | 9 | .. automodule:: faust.agents.models 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.agents.replies.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.agents.replies`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.agents.replies 8 | 9 | .. automodule:: faust.agents.replies 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.cli.completion.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.cli.completion`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.cli.completion 8 | 9 | .. automodule:: faust.cli.completion 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.cli.livecheck.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.cli.livecheck`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.cli.livecheck 8 | 9 | .. automodule:: faust.cli.livecheck 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.fixups.django.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.fixups.django`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.fixups.django 8 | 9 | .. automodule:: faust.fixups.django 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.livecheck.app.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.livecheck.app`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.livecheck.app 8 | 9 | .. automodule:: faust.livecheck.app 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.livecheck.case.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.livecheck.case`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.livecheck.case 8 | 9 | .. automodule:: faust.livecheck.case 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.models.fields.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.models.fields`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.models.fields 8 | 9 | .. automodule:: faust.models.fields 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.models.record.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.models.record`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.models.record 8 | 9 | .. automodule:: faust.models.record 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.sensors.statsd.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.sensors.statsd`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.sensors.statsd 8 | 9 | .. automodule:: faust.sensors.statsd 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.stores.memory.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.stores.memory`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.stores.memory 8 | 9 | .. automodule:: faust.stores.memory 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.stores.rocksdb.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.stores.rocksdb`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.stores.rocksdb 8 | 9 | .. automodule:: faust.stores.rocksdb 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.tables.manager.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.tables.manager`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.tables.manager 8 | 9 | .. automodule:: faust.tables.manager 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.tables.objects.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.tables.objects`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.tables.objects 8 | 9 | .. automodule:: faust.tables.objects 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.transport.base.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.transport.base`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.transport.base 8 | 9 | .. automodule:: faust.transport.base 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.types.assignor.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.types.assignor`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.types.assignor 8 | 9 | .. automodule:: faust.types.assignor 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.types.channels.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.types.channels`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.types.channels 8 | 9 | .. automodule:: faust.types.channels 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.types.sensors.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.types.sensors`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.types.sensors 8 | 9 | .. automodule:: faust.types.sensors 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.types.settings.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.types.settings`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.types.settings 8 | 9 | .. automodule:: faust.types.settings 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.types.streams.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.types.streams`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.types.streams 8 | 9 | .. automodule:: faust.types.streams 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.types.windows.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.types.windows`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.types.windows 8 | 9 | .. automodule:: faust.types.windows 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.utils.codegen.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.utils.codegen`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.utils.codegen 8 | 9 | .. automodule:: faust.utils.codegen 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.utils.iso8601.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.utils.iso8601`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.utils.iso8601 8 | 9 | .. automodule:: faust.utils.iso8601 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.utils.terminal.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.utils.terminal`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.utils.terminal 8 | 9 | .. automodule:: faust.utils.terminal 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.utils.tracing.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.utils.tracing`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.utils.tracing 8 | 9 | .. automodule:: faust.utils.tracing 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.utils.venusian.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.utils.venusian`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.utils.venusian 8 | 9 | .. automodule:: faust.utils.venusian 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.web.apps.graph.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.web.apps.graph`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.web.apps.graph 8 | 9 | .. automodule:: faust.web.apps.graph 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.web.apps.stats.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.web.apps.stats`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.web.apps.stats 8 | 9 | .. automodule:: faust.web.apps.stats 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.web.blueprints.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.web.blueprints`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.web.blueprints 8 | 9 | .. automodule:: faust.web.blueprints 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.web.exceptions.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.web.exceptions`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.web.exceptions 8 | 9 | .. automodule:: faust.web.exceptions 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.sensors.datadog.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.sensors.datadog`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.sensors.datadog 8 | 9 | .. automodule:: faust.sensors.datadog 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.sensors.monitor.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.sensors.monitor`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.sensors.monitor 8 | 9 | .. automodule:: faust.sensors.monitor 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.tables.recovery.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.tables.recovery`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.tables.recovery 8 | 9 | .. automodule:: faust.tables.recovery 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.tables.wrappers.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.tables.wrappers`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.tables.wrappers 8 | 9 | .. automodule:: faust.tables.wrappers 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.transport.utils.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.transport.utils`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.transport.utils 8 | 9 | .. automodule:: faust.transport.utils 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.utils.platforms.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.utils.platforms`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.utils.platforms 8 | 9 | .. automodule:: faust.utils.platforms 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.web.apps.router.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.web.apps.router`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.web.apps.router 8 | 9 | .. automodule:: faust.web.apps.router 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.web.cache.cache.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.web.cache.cache`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.web.cache.cache 8 | 9 | .. automodule:: faust.web.cache.cache 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.livecheck.locals.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.livecheck.locals`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.livecheck.locals 8 | 9 | .. automodule:: faust.livecheck.locals 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.livecheck.models.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.livecheck.models`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.livecheck.models 8 | 9 | .. automodule:: faust.livecheck.models 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.types.transports.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.types.transports`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.types.transports 8 | 9 | .. automodule:: faust.types.transports 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.utils.functional.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.utils.functional`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.utils.functional 8 | 9 | .. automodule:: faust.utils.functional 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /faust/tables/__init__.py: -------------------------------------------------------------------------------- 1 | """Tables: Distributed object K/V-store.""" 2 | from .base import Collection, CollectionT 3 | from .manager import TableManager, TableManagerT 4 | from .table import Table, TableT 5 | 6 | __all__ = [ 7 | 'Collection', 8 | 'CollectionT', 9 | 'TableManager', 10 | 'TableManagerT', 11 | 'Table', 12 | 'TableT', 13 | ] 14 | -------------------------------------------------------------------------------- /docs/reference/faust.livecheck.patches.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.livecheck.patches`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.livecheck.patches 8 | 9 | .. automodule:: faust.livecheck.patches 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.livecheck.runners.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.livecheck.runners`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.livecheck.runners 8 | 9 | .. automodule:: faust.livecheck.runners 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.livecheck.signals.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.livecheck.signals`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.livecheck.signals 8 | 9 | .. automodule:: faust.livecheck.signals 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.transport.drivers.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.transport.drivers`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.transport.drivers 8 | 9 | .. automodule:: faust.transport.drivers 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.types.serializers.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.types.serializers`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.types.serializers 8 | 9 | .. automodule:: faust.types.serializers 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.cli.clean_versions.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.cli.clean_versions`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.cli.clean_versions 8 | 9 | .. automodule:: faust.cli.clean_versions 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.serializers.codecs.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.serializers.codecs`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.serializers.codecs 8 | 9 | .. automodule:: faust.serializers.codecs 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.transport.conductor.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.transport.conductor`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.transport.conductor 8 | 9 | .. automodule:: faust.transport.conductor 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.transport.consumer.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.transport.consumer`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.transport.consumer 8 | 9 | .. automodule:: faust.transport.consumer 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.transport.producer.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.transport.producer`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.transport.producer 8 | 9 | .. automodule:: faust.transport.producer 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.web.cache.backends.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.web.cache.backends`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.web.cache.backends 8 | 9 | .. automodule:: faust.web.cache.backends 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.web.drivers.aiohttp.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.web.drivers.aiohttp`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.web.drivers.aiohttp 8 | 9 | .. automodule:: faust.web.drivers.aiohttp 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /faust/models/__init__.py: -------------------------------------------------------------------------------- 1 | """Models.""" 2 | from .base import Model, ModelOptions, maybe_model, registry 3 | from .fields import FieldDescriptor, StringField 4 | from .record import Record 5 | 6 | __all__ = [ 7 | 'FieldDescriptor', 8 | 'Model', 9 | 'ModelOptions', 10 | 'Record', 11 | 'StringField', 12 | 'maybe_model', 13 | 'registry', 14 | ] 15 | -------------------------------------------------------------------------------- /docs/reference/faust.livecheck.exceptions.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.livecheck.exceptions`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.livecheck.exceptions 8 | 9 | .. automodule:: faust.livecheck.exceptions 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.serializers.registry.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.serializers.registry`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.serializers.registry 8 | 9 | .. automodule:: faust.serializers.registry 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.web.cache.exceptions.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.web.cache.exceptions`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.web.cache.exceptions 8 | 9 | .. automodule:: faust.web.cache.exceptions 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /faust/utils/terminal/__init__.py: -------------------------------------------------------------------------------- 1 | """Terminal utilities.""" 2 | from mode.utils.compat import isatty 3 | from .spinners import Spinner, SpinnerHandler 4 | from .tables import Table, TableDataT, logtable, table 5 | 6 | __all__ = [ 7 | 'Spinner', 8 | 'SpinnerHandler', 9 | 'Table', 10 | 'TableDataT', 11 | 'isatty', 12 | 'logtable', 13 | 'table', 14 | ] 15 | -------------------------------------------------------------------------------- /docs/reference/faust.utils.terminal.tables.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.utils.terminal.tables`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.utils.terminal.tables 8 | 9 | .. automodule:: faust.utils.terminal.tables 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.assignor.leader_assignor.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.assignor.leader_assignor`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.assignor.leader_assignor 8 | 9 | .. automodule:: faust.assignor.leader_assignor 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.utils.terminal.spinners.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.utils.terminal.spinners`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.utils.terminal.spinners 8 | 9 | .. automodule:: faust.utils.terminal.spinners 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.web.cache.backends.base.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.web.cache.backends.base`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.web.cache.backends.base 8 | 9 | .. automodule:: faust.web.cache.backends.base 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.web.cache.backends.redis.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.web.cache.backends.redis`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.web.cache.backends.redis 8 | 9 | .. automodule:: faust.web.cache.backends.redis 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.livecheck.patches.aiohttp.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.livecheck.patches.aiohttp`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.livecheck.patches.aiohttp 8 | 9 | .. automodule:: faust.livecheck.patches.aiohttp 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.web.cache.backends.memory.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.web.cache.backends.memory`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.web.cache.backends.memory 8 | 9 | .. automodule:: faust.web.cache.backends.memory 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /t/unit/web/test_exceptions.py: -------------------------------------------------------------------------------- 1 | from faust.web import exceptions 2 | 3 | 4 | def test_WebError(): 5 | exc = exceptions.WebError(detail='detail', code=400) 6 | assert exc.detail == 'detail' 7 | assert exc.code == 400 8 | 9 | 10 | def test_WebError_defaults(): 11 | exc = exceptions.WebError() 12 | assert exc.detail == exceptions.WebError.detail 13 | assert exc.code is None 14 | -------------------------------------------------------------------------------- /docs/reference/faust.assignor.client_assignment.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.assignor.client_assignment`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.assignor.client_assignment 8 | 9 | .. automodule:: faust.assignor.client_assignment 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.transport.drivers.aiokafka.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.transport.drivers.aiokafka`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.transport.drivers.aiokafka 8 | 9 | .. automodule:: faust.transport.drivers.aiokafka 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /faust/agents/__init__.py: -------------------------------------------------------------------------------- 1 | """Agents.""" 2 | from .agent import Agent, AgentFun, AgentT, SinkT, current_agent 3 | from .manager import AgentManager, AgentManagerT 4 | from .replies import ReplyConsumer 5 | 6 | __all__ = [ 7 | 'Agent', 8 | 'AgentFun', 9 | 'AgentT', 10 | 'SinkT', 11 | 'AgentManager', 12 | 'AgentManagerT', 13 | 'ReplyConsumer', 14 | 'current_agent', 15 | ] 16 | -------------------------------------------------------------------------------- /docs/reference/faust.assignor.cluster_assignment.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.assignor.cluster_assignment`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.assignor.cluster_assignment 8 | 9 | .. automodule:: faust.assignor.cluster_assignment 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.assignor.partition_assignor.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.assignor.partition_assignor`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.assignor.partition_assignor 8 | 9 | .. automodule:: faust.assignor.partition_assignor 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/reference/faust.assignor.copartitioned_assignor.rst: -------------------------------------------------------------------------------- 1 | ===================================================== 2 | ``faust.assignor.copartitioned_assignor`` 3 | ===================================================== 4 | 5 | .. contents:: 6 | :local: 7 | .. currentmodule:: faust.assignor.copartitioned_assignor 8 | 9 | .. automodule:: faust.assignor.copartitioned_assignor 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /faust/web/__init__.py: -------------------------------------------------------------------------------- 1 | """Faust Web.""" 2 | from .base import Request, Response, Web 3 | from .blueprints import Blueprint 4 | from .views import View, gives_model, takes_model 5 | from faust.types.web import ResourceOptions 6 | 7 | __all__ = [ 8 | 'Request', 9 | 'Response', 10 | 'ResourceOptions', 11 | 'Web', 12 | 'Blueprint', 13 | 'View', 14 | 'gives_model', 15 | 'takes_model', 16 | ] 17 | -------------------------------------------------------------------------------- /extra/systemd/faust.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Faust Service 3 | After=network.target 4 | 5 | [Service] 6 | Type=simple 7 | User=faust 8 | Group=faust 9 | EnvironmentFile=-/etc/conf.d/faust 10 | WorkingDirectory=/opt/faust 11 | ExecStart=/bin/sh -c '${FAUST_BIN} worker \ 12 | -A $FAUST_APP --logfile=${FAUST_LOG_FILE} \ 13 | --loglevel="${FAUST_LOG_LEVEL}" $FAUST_OPTS' 14 | 15 | [Install] 16 | WantedBy=multi-user.target 17 | -------------------------------------------------------------------------------- /faust/web/drivers/__init__.py: -------------------------------------------------------------------------------- 1 | """Web server driver registry.""" 2 | from typing import Type 3 | from mode.utils.imports import FactoryMapping 4 | from faust.web.base import Web 5 | 6 | __all__ = ['by_name', 'by_url'] 7 | 8 | DRIVERS: FactoryMapping[Type[Web]] = FactoryMapping( 9 | aiohttp='faust.web.drivers.aiohttp:Web', 10 | ) 11 | DRIVERS.include_setuptools_namespace('faust.web.drivers') 12 | by_name = DRIVERS.by_name 13 | by_url = DRIVERS.by_url 14 | -------------------------------------------------------------------------------- /docs/userguide/index.rst: -------------------------------------------------------------------------------- 1 | .. _guide: 2 | 3 | =============== 4 | User Guide 5 | =============== 6 | 7 | :Release: |version| 8 | :Date: |today| 9 | 10 | .. toctree:: 11 | :maxdepth: 2 12 | 13 | application 14 | agents 15 | streams 16 | channels 17 | models 18 | tables 19 | tasks 20 | cli 21 | sensors 22 | testing 23 | livecheck 24 | settings 25 | installation 26 | kafka 27 | debugging 28 | workers 29 | -------------------------------------------------------------------------------- /faust/stores/__init__.py: -------------------------------------------------------------------------------- 1 | """Storage registry.""" 2 | from typing import Type 3 | from mode.utils.imports import FactoryMapping 4 | from faust.types import StoreT 5 | 6 | __all__ = ['by_name', 'by_url'] 7 | 8 | STORES: FactoryMapping[Type[StoreT]] = FactoryMapping( 9 | memory='faust.stores.memory:Store', 10 | rocksdb='faust.stores.rocksdb:Store', 11 | ) 12 | STORES.include_setuptools_namespace('faust.stores') 13 | by_name = STORES.by_name 14 | by_url = STORES.by_url 15 | -------------------------------------------------------------------------------- /examples/django/proj/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for proj project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/1.11/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'proj.settings') 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /t/unit/fixups/test_base.py: -------------------------------------------------------------------------------- 1 | from faust.fixups.base import Fixup 2 | 3 | 4 | class test_Fixup: 5 | 6 | def test_init(self, *, app): 7 | assert Fixup(app).app is app 8 | 9 | def test_enabled(self, *, app): 10 | assert not Fixup(app).enabled() 11 | 12 | def test_autodiscover_modules(self, *, app): 13 | assert Fixup(app).autodiscover_modules() == [] 14 | 15 | def test_on_worker_init(self, *, app): 16 | Fixup(app).on_worker_init() 17 | -------------------------------------------------------------------------------- /docs/history/index.rst: -------------------------------------------------------------------------------- 1 | .. _history: 2 | 3 | ========= 4 | History 5 | ========= 6 | 7 | This section contains historical change histories, for the latest 8 | version please visit :ref:`changelog`. 9 | 10 | :Release: |version| 11 | :Date: |today| 12 | 13 | .. toctree:: 14 | :maxdepth: 2 15 | 16 | changelog-1.6 17 | changelog-1.5 18 | changelog-1.4 19 | changelog-1.3 20 | changelog-1.2 21 | changelog-1.1 22 | changelog-1.0 23 | changelog-0.9 24 | -------------------------------------------------------------------------------- /examples/kubernetes/producer/producer.yml: -------------------------------------------------------------------------------- 1 | apiVersion: batch/v1 2 | kind: Job 3 | metadata: 4 | creationTimestamp: null 5 | labels: 6 | run: producer 7 | name: producer 8 | spec: 9 | template: 10 | metadata: 11 | creationTimestamp: null 12 | labels: 13 | run: producer 14 | spec: 15 | containers: 16 | - image: producer 17 | name: producer 18 | resources: {} 19 | imagePullPolicy: IfNotPresent 20 | restartPolicy: OnFailure 21 | status: {} 22 | -------------------------------------------------------------------------------- /examples/leader.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import random 3 | import faust 4 | 5 | 6 | app = faust.App( 7 | 'leader-example', 8 | broker='kafka://localhost:9092', 9 | value_serializer='raw', 10 | ) 11 | 12 | 13 | @app.timer(2.0, on_leader=True) 14 | async def publish_greetings(): 15 | print('PUBLISHING ON LEADER!') 16 | await say.send(value=str(random.random())) 17 | 18 | 19 | @app.agent() 20 | async def say(greetings): 21 | async for greeting in greetings: 22 | print(greeting) 23 | -------------------------------------------------------------------------------- /extra/systemd/faust.conf: -------------------------------------------------------------------------------- 1 | 2 | # Path to your app: if `from foo.bar import app`, use "foo.bar:app". 3 | FAUST_APP="proj" 4 | 5 | # Additional arguments to the ``faust`` program. 6 | FAUST_OPTS="" 7 | 8 | # Path to he ``faust`` program. 9 | FAUST_BIN="/usr/bin/faust" 10 | 11 | # Path to worker pid file. 12 | FAUST_PID_FILE="/var/run/faust/worker.pid" 13 | 14 | # Path to worker log file. 15 | FAUST_LOG_FILE="/var/log/faust/worker.log" 16 | 17 | # Worker log level: one of crit, error, warn, info, debug. 18 | FAUST_LOG_LEVEL="info" 19 | -------------------------------------------------------------------------------- /examples/django/accounts/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | from django.utils.translation import ugettext_lazy as _ 3 | 4 | 5 | class Account(models.Model): 6 | name = models.CharField(_('name'), max_length=100) 7 | score = models.DecimalField(_('score'), default=0.0, 8 | max_digits=1000, decimal_places=1000) 9 | active = models.BooleanField(_('active'), default=True) 10 | 11 | class Meta: 12 | verbose_name = _('account') 13 | verbose_name_plural = _('accounts') 14 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | *Note*: Before submitting this pull request, please review our [contributing 2 | guidelines](https://faust.readthedocs.io/en/master/contributing.html). 3 | 4 | ## Description 5 | 6 | Please describe your pull request. 7 | 8 | NOTE: All patches should be made against master, not a maintenance branch like 9 | 3.1, 2.5, etc. That is unless the bug is already fixed in master, but not in 10 | that version series. 11 | 12 | If it fixes a bug or resolves a feature request, 13 | be sure to link to that issue via (Fixes #4412) for example. 14 | -------------------------------------------------------------------------------- /examples/hello_world.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import faust 3 | 4 | app = faust.App( 5 | 'hello-world', 6 | broker='kafka://localhost:9092', 7 | ) 8 | 9 | greetings_topic = app.topic('greetings', value_type=str) 10 | 11 | 12 | @app.agent(greetings_topic) 13 | async def print_greetings(greetings): 14 | async for greeting in greetings: 15 | print(greeting) 16 | 17 | 18 | @app.timer(5) 19 | async def produce(): 20 | for i in range(100): 21 | await print_greetings.send(value=f'hello {i}') 22 | 23 | if __name__ == '__main__': 24 | app.main() 25 | -------------------------------------------------------------------------------- /faust/web/apps/production_index.py: -------------------------------------------------------------------------------- 1 | """HTTP endpoint showing statistics from the Faust monitor.""" 2 | from typing import List, MutableMapping 3 | from faust import web 4 | 5 | __all__ = ['Index', 'blueprint'] 6 | 7 | TPMap = MutableMapping[str, List[int]] 8 | 9 | 10 | blueprint = web.Blueprint('production_index') 11 | 12 | 13 | @blueprint.route('/', name='index') 14 | class Index(web.View): 15 | """Dummy Index.""" 16 | 17 | async def get(self, request: web.Request) -> web.Response: 18 | """Simple status page.""" 19 | return self.json({'status': 'OK'}) 20 | -------------------------------------------------------------------------------- /extra/release/sphinx2rst_config.py: -------------------------------------------------------------------------------- 1 | REFBASE = 'http://faust.readthedocs.io/en/latest' 2 | REFS = { 3 | 'mailing-list': 4 | 'https://groups.google.com/group/faust-users', 5 | 'irc-channel': 'getting-started/resources.html#irc-channel', 6 | 'slack-channel': 'getting-started/resources.html#slack-channel', 7 | 'bundles': 'introduction/installation.html#bundles', 8 | 'reporting-bugs': 'contributing.html#reporting-bugs', 9 | 'introduction': 'introduction.html', 10 | 'quickstart': 'playbooks/quickstart.html', 11 | 'guide': 'userguide/index.html', 12 | } 13 | -------------------------------------------------------------------------------- /t/unit/utils/test_venusian.py: -------------------------------------------------------------------------------- 1 | from faust.utils import venusian 2 | from mode.utils.mocks import Mock, patch 3 | 4 | 5 | def test_attach(): 6 | callable = Mock(name='callable') 7 | category = 'category' 8 | with patch('faust.utils.venusian._attach') as _attach: 9 | with patch('faust.utils.venusian._on_found') as _on_found: 10 | venusian.attach(callable, category) 11 | _attach.assert_called_with(callable, _on_found, category=category) 12 | 13 | 14 | def test_on_found(): 15 | venusian._on_found(Mock(name='scanner'), 'name', Mock(name='obj')) 16 | -------------------------------------------------------------------------------- /examples/kubernetes/consumer/consumer.yml: -------------------------------------------------------------------------------- 1 | apiVersion: extensions/v1beta1 2 | kind: Deployment 3 | metadata: 4 | creationTimestamp: null 5 | labels: 6 | run: consumer 7 | name: consumer 8 | spec: 9 | replicas: 2 10 | selector: 11 | matchLabels: 12 | run: consumer 13 | strategy: {} 14 | template: 15 | metadata: 16 | creationTimestamp: null 17 | labels: 18 | run: consumer 19 | spec: 20 | containers: 21 | - image: consumer 22 | name: consumer 23 | resources: {} 24 | imagePullPolicy: IfNotPresent 25 | status: {} 26 | -------------------------------------------------------------------------------- /t/functional/agents/test_current_agent.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from faust.agents import current_agent 3 | 4 | 5 | @pytest.mark.asyncio 6 | async def test_sets_current_agent(*, app, event_loop): 7 | assert current_agent() is None 8 | 9 | agent_body_executed = event_loop.create_future() 10 | 11 | @app.agent() 12 | async def agent(stream): 13 | agent_body_executed.set_result(True) 14 | assert current_agent() is agent 15 | async for item in stream: 16 | ... 17 | 18 | await agent.start() 19 | await agent_body_executed 20 | await agent.stop() 21 | -------------------------------------------------------------------------------- /faust/transport/drivers/__init__.py: -------------------------------------------------------------------------------- 1 | """Transport registry.""" 2 | from typing import Type 3 | from mode.utils.imports import FactoryMapping 4 | from faust.types import TransportT 5 | 6 | __all__ = ['by_name', 'by_url'] 7 | 8 | TRANSPORTS: FactoryMapping[Type[TransportT]] = FactoryMapping( 9 | aiokafka='faust.transport.drivers.aiokafka:Transport', 10 | confluent='faust.transport.drivers.confluent:Transport', 11 | kafka='faust.transport.drivers.aiokafka:Transport', 12 | ) 13 | TRANSPORTS.include_setuptools_namespace('faust.transports') 14 | by_name = TRANSPORTS.by_name 15 | by_url = TRANSPORTS.by_url 16 | -------------------------------------------------------------------------------- /faust/web/cache/backends/__init__.py: -------------------------------------------------------------------------------- 1 | """Cache backend registry.""" 2 | from typing import Type 3 | from mode.utils.imports import FactoryMapping 4 | from faust.types.web import CacheBackendT 5 | 6 | __all__ = ['by_name', 'by_url'] 7 | 8 | BACKENDS: FactoryMapping[Type[CacheBackendT]] = FactoryMapping( 9 | memory='faust.web.cache.backends.memory:CacheBackend', 10 | redis='faust.web.cache.backends.redis:CacheBackend', 11 | rediscluster='faust.web.cache.backends.redis:CacheBackend', 12 | ) 13 | BACKENDS.include_setuptools_namespace('faust.web.cache') 14 | by_name = BACKENDS.by_name 15 | by_url = BACKENDS.by_url 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.pyc 3 | *$py.class 4 | *~ 5 | .sw* 6 | .*.sw* 7 | dist/ 8 | *.egg-info 9 | *.egg 10 | *.egg/ 11 | *.eggs/ 12 | build/ 13 | .build/ 14 | _build/ 15 | pip-log.txt 16 | .directory 17 | erl_crash.dump 18 | *.db 19 | Documentation/ 20 | .tox/ 21 | .ropeproject/ 22 | .project 23 | .pydevproject 24 | .idea/ 25 | .coverage 26 | celery/tests/cover/ 27 | .ve* 28 | cover/ 29 | .vagrant/ 30 | .cache/ 31 | .hypothesis/ 32 | .mypy_cache/ 33 | .pytest_cache/ 34 | htmlcov/ 35 | *-cache* 36 | .checkpoint 37 | .python-version 38 | .pyre/ 39 | .dmypy.json 40 | *.so 41 | faust/_cython/*.c 42 | faust/transport/_cython/*.c 43 | -------------------------------------------------------------------------------- /faust/types/joins.py: -------------------------------------------------------------------------------- 1 | import abc 2 | from typing import MutableMapping, Optional, Tuple, Type 3 | 4 | from .events import EventT 5 | from .models import FieldDescriptorT, ModelT 6 | from .streams import JoinableT 7 | 8 | __all__ = ['JoinT'] 9 | 10 | 11 | class JoinT(abc.ABC): 12 | fields: MutableMapping[Type[ModelT], FieldDescriptorT] 13 | stream: JoinableT 14 | 15 | @abc.abstractmethod 16 | def __init__(self, *, stream: JoinableT, 17 | fields: Tuple[FieldDescriptorT, ...]) -> None: 18 | ... 19 | 20 | @abc.abstractmethod 21 | async def process(self, event: EventT) -> Optional[EventT]: 22 | ... 23 | -------------------------------------------------------------------------------- /faust/cli/livecheck.py: -------------------------------------------------------------------------------- 1 | """Program ``faust worker`` used to start application from console.""" 2 | from typing import Any 3 | from .worker import worker 4 | 5 | __all__ = ['livecheck'] 6 | 7 | 8 | class livecheck(worker): 9 | """Manage LiveCheck instances.""" 10 | 11 | def __init__(self, *args: Any, **kwargs: Any) -> None: 12 | super().__init__(*args, **kwargs) 13 | try: 14 | livecheck = self.app.livecheck 15 | except AttributeError: 16 | raise self.UsageError( 17 | f'App {self.app!r} is not associated with LiveCheck') 18 | self.app = livecheck 19 | self._finalize_concrete_app(self.app) 20 | -------------------------------------------------------------------------------- /t/functional/web/conftest.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from faust.exceptions import SameNode 3 | from mode.utils.mocks import Mock 4 | 5 | 6 | @pytest.yield_fixture() 7 | def web_client(loop, aiohttp_client, web): 8 | try: 9 | yield aiohttp_client(web.web_app) 10 | finally: 11 | # Cleanup threads started by loop.run_in_executor 12 | # at shutdown. 13 | if loop._default_executor is not None: 14 | loop._default_executor.shutdown() 15 | 16 | 17 | @pytest.fixture() 18 | def router_same(app): 19 | app.router.route_req = Mock(name='app.router.route_req') 20 | app.router.route_req.side_effect = SameNode() 21 | return app.router 22 | -------------------------------------------------------------------------------- /faust/types/fixups.py: -------------------------------------------------------------------------------- 1 | import abc 2 | import typing 3 | from typing import Iterable 4 | 5 | if typing.TYPE_CHECKING: 6 | from .app import AppT as _AppT 7 | else: 8 | class _AppT: ... # noqa 9 | 10 | __all__ = ['FixupT'] 11 | 12 | 13 | class FixupT(abc.ABC): 14 | 15 | app: _AppT 16 | 17 | @abc.abstractmethod 18 | def __init__(self, app: _AppT) -> None: 19 | ... 20 | 21 | @abc.abstractmethod 22 | def enabled(self) -> bool: 23 | ... 24 | 25 | @abc.abstractmethod 26 | def autodiscover_modules(self) -> Iterable[str]: 27 | ... 28 | 29 | @abc.abstractmethod 30 | def on_worker_init(self) -> None: 31 | ... 32 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Checklist 2 | 3 | - [ ] I have included information about relevant versions 4 | - [ ] I have verified that the issue persists when using the `master` branch of Faust. 5 | 6 | ## Steps to reproduce 7 | 8 | Tell us what you did to cause something to happen. 9 | 10 | ## Expected behavior 11 | 12 | Tell us what you expected to happen. 13 | 14 | ## Actual behavior 15 | 16 | Tell us what happened instead. 17 | 18 | ## Full traceback 19 | 20 | ```pytb 21 | Paste the full traceback (if there is any) 22 | ``` 23 | 24 | # Versions 25 | 26 | * Python version 27 | * Faust version 28 | * Operating system 29 | * Kafka version 30 | * RocksDB version (if applicable) 31 | 32 | -------------------------------------------------------------------------------- /faust/utils/cron.py: -------------------------------------------------------------------------------- 1 | """Crontab Utilities.""" 2 | from datetime import datetime, tzinfo 3 | import time 4 | from croniter.croniter import croniter 5 | 6 | 7 | def secs_for_next(cron_format: str, tz: tzinfo = None) -> float: 8 | """Return seconds until next execution given Crontab style format.""" 9 | now_ts = time.time() 10 | # If we have a tz object we'll make now timezone aware, and 11 | # if not will set now to be the current timestamp (tz 12 | # unaware) 13 | # If we have tz, now will be a datetime, if not an integer 14 | now = tz and datetime.now(tz) or now_ts 15 | cron_it = croniter(cron_format, start_time=now) 16 | return cron_it.get_next(float) - now_ts 17 | -------------------------------------------------------------------------------- /faust/cli/tables.py: -------------------------------------------------------------------------------- 1 | """Program ``faust tables`` used to list tables.""" 2 | from .base import AppCommand 3 | 4 | DEFAULT_TABLE_HELP = 'Missing description: use Table(.., help="str")' 5 | 6 | 7 | class tables(AppCommand): 8 | """List available tables.""" 9 | 10 | title = 'Tables' 11 | 12 | async def run(self) -> None: 13 | """Dump list of application tables to terminal.""" 14 | self.say( 15 | self.tabulate( 16 | [(self.bold(table.name), 17 | self.dark(table.help or DEFAULT_TABLE_HELP)) 18 | for table in self.app.tables.values()], 19 | title=self.title, 20 | headers=['name', 'help'])) 21 | -------------------------------------------------------------------------------- /examples/django/faustapp/app.py: -------------------------------------------------------------------------------- 1 | import os 2 | import faust 3 | 4 | # make sure the gevent event loop is used as early as possible. 5 | os.environ.setdefault('FAUST_LOOP', 'eventlet') 6 | 7 | # set the default Django settings module for the 'faust' program. 8 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'proj.settings') 9 | 10 | app = faust.App('django-proj', autodiscover=True, origin='faustapp') 11 | 12 | 13 | @app.on_configured.connect 14 | def configure_from_settings(app, conf, **kwargs): 15 | from django.conf import settings 16 | conf.broker = settings.FAUST_BROKER_URL 17 | conf.store = settings.FAUST_STORE_URL 18 | 19 | 20 | def main(): 21 | app.main() 22 | 23 | 24 | if __name__ == '__main__': 25 | main() 26 | -------------------------------------------------------------------------------- /t/stress/tests/simple/app.py: -------------------------------------------------------------------------------- 1 | from ...app import create_stress_app 2 | from ...models import Withdrawal, generate_withdrawals 3 | 4 | app = create_stress_app( 5 | name='f-stress-simple', 6 | version=7, 7 | origin='t.stress.tests.simple', 8 | ) 9 | 10 | withdrawals_topic = app.topic('f-stress-withdrawals', value_type=Withdrawal) 11 | 12 | 13 | @app.register_stress_producer 14 | async def produce_withdrawals(max_messages): 15 | for withdrawal in generate_withdrawals(max_messages): 16 | yield await withdrawals_topic.send(key=None, value=withdrawal) 17 | 18 | 19 | @app.agent(withdrawals_topic) 20 | async def track_user_withdrawal(withdrawals): 21 | async for _withdrawal in withdrawals: # noqa 22 | app.count_received_events += 1 23 | -------------------------------------------------------------------------------- /t/unit/livecheck/test_locals.py: -------------------------------------------------------------------------------- 1 | from mode.utils.mocks import Mock 2 | from faust.livecheck.locals import current_execution, current_execution_stack 3 | 4 | 5 | def test_current_execution(): 6 | m1 = Mock(name='m1') 7 | assert current_execution() is None 8 | with current_execution_stack.push(m1): 9 | assert current_execution() is m1 10 | m2 = Mock(name='m2') 11 | with current_execution_stack.push(m2): 12 | assert current_execution() is m2 13 | m3 = Mock(name='m3') 14 | with current_execution_stack.push(m3): 15 | assert current_execution() is m3 16 | assert current_execution() is m2 17 | assert current_execution() is m1 18 | assert current_execution() is None 19 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include AUTHORS.rst 2 | include CODE_OF_CONDUCT.rst 3 | include Changelog.rst 4 | include LICENSE 5 | include README.rst 6 | include MANIFEST.in 7 | include setup.cfg 8 | include setup.py 9 | recursive-include artwork * 10 | recursive-include docs * 11 | recursive-include extra/* 12 | recursive-include examples * 13 | recursive-include faust *.py *.html *.typed *.pyx 14 | recursive-include requirements *.txt *.rst 15 | recursive-include t *.py *.sh *.txt 16 | recursive-include t/stress/reports/assets LICENSE *.py *.js *.css *.scss *.map *.eot *.svg *.ttf *.woff *.woff2 17 | recursive-include t/stress/reports/templates *.html 18 | 19 | recursive-exclude * __pycache__ 20 | recursive-exclude * *.py[co] 21 | recursive-exclude * .*.sw[a-z] 22 | recursive-exclude * *.c *.so 23 | -------------------------------------------------------------------------------- /faust/cli/faust.py: -------------------------------------------------------------------------------- 1 | """Program ``faust`` (umbrella command).""" 2 | 3 | # Note: The command options above are defined in .cli.base.builtin_options 4 | from .agents import agents 5 | from .base import call_command, cli 6 | from .clean_versions import clean_versions 7 | from .completion import completion 8 | from .livecheck import livecheck 9 | from .model import model 10 | from .models import models 11 | from .reset import reset 12 | from .send import send 13 | from .tables import tables 14 | from .worker import worker 15 | 16 | __all__ = [ 17 | 'agents', 18 | 'call_command', 19 | 'clean_versions', 20 | 'cli', 21 | 'completion', 22 | 'livecheck', 23 | 'model', 24 | 'models', 25 | 'reset', 26 | 'send', 27 | 'tables', 28 | 'worker', 29 | ] 30 | -------------------------------------------------------------------------------- /extra/tools/verify_ascending.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """ 3 | Usage: 4 | 5 | .. sourcecode:: console 6 | 7 | $ kafka-console-consumer --bootstrap-server localhost:9092 \ 8 | --topic example-source-topic2 \ 9 | --from-beginning | \ 10 | python extra/tools/verify_ascending.py 11 | 12 | """ 13 | 14 | 15 | import fileinput 16 | import os 17 | import sys 18 | 19 | STOP = os.environ.get('STOP', 50000) 20 | 21 | expected = 0 22 | prev = None 23 | for i, line in enumerate(fileinput.input()): 24 | expected = i + 1 25 | found = int(line.strip().strip('"')) 26 | if found != expected: 27 | print(f'At line {i} found {found} expected {expected}') 28 | sys.exit(445) 29 | if found >= STOP: 30 | print('Ok') 31 | sys.exit(0) 32 | -------------------------------------------------------------------------------- /examples/concurrency.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import asyncio 3 | import aiohttp 4 | import faust 5 | 6 | 7 | class Record(faust.Record): 8 | value: int 9 | 10 | 11 | app = faust.App('concurrency', broker='kafka://localhost') 12 | topic = app.topic('concurrency', value_type=Record) 13 | 14 | 15 | @app.agent(topic, concurrency=200) 16 | async def mytask(records): 17 | session = aiohttp.ClientSession() 18 | async for record in records: 19 | await session.get(f'http://www.google.com/?#q={record.value}') 20 | 21 | 22 | async def producer(): 23 | for i in range(10_000): 24 | await topic.send(value=Record(value=i)) 25 | 26 | 27 | if __name__ == '__main__': 28 | loop = asyncio.get_event_loop() 29 | loop.run_until_complete(producer()) 30 | loop.stop() 31 | -------------------------------------------------------------------------------- /t/unit/cli/test_completion.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from faust.cli.completion import completion 3 | from mode.utils.mocks import patch 4 | 5 | 6 | class test_completion: 7 | 8 | @pytest.fixture() 9 | def command(self, *, context): 10 | return completion(context) 11 | 12 | @pytest.mark.asyncio 13 | async def test_run(self, *, command): 14 | with patch('faust.cli.completion.click_completion') as cc: 15 | await command.run() 16 | cc.get_code.assert_called_once_with(shell=command.shell()) 17 | 18 | @pytest.mark.asyncio 19 | async def test_run__no_completion(self, *, command): 20 | with patch('faust.cli.completion.click_completion', None): 21 | with pytest.raises(command.UsageError): 22 | await command.run() 23 | -------------------------------------------------------------------------------- /examples/kubernetes/consumer/README.md: -------------------------------------------------------------------------------- 1 | ## Consume 10,000 messages 2 | 3 | This process assumes a Kafka broker accessible at `host.docker.internal:9092` 4 | 5 | 6 | Consumes 10,000 messages from Kafka topic named "test". Each message 7 | is a mapping representing a score. Each score has 2 keys: 8 | * index 9 | * value 10 | 11 | 12 | 1. Build the consumer docker image 13 | ```bash 14 | cd consumer 15 | # -t consumer => names the image consumer, is used in kubernetes yaml file 16 | docker build . -t consumer 17 | ``` 18 | 19 | 2. Apply the consumer as a Kubernetes deployment. 20 | ```bash 21 | kubectl apply -f consumer.yml 22 | ``` 23 | 24 | 3. Log consumer output 25 | ```bash 26 | # Discover the pod running the job, e.g. consumer-32452 27 | kubectl get pods 28 | 29 | kubectl logs -f 30 | ``` 31 | -------------------------------------------------------------------------------- /faust/utils/venusian.py: -------------------------------------------------------------------------------- 1 | """Venusian (see :pypi:`venusian`). 2 | 3 | We define our own interface so we don't have to specify the 4 | callback argument. 5 | """ 6 | import venusian 7 | from typing import Any, Callable 8 | from venusian import Scanner, attach as _attach 9 | 10 | __all__ = ['Scanner', 'attach'] 11 | 12 | 13 | def attach(fun: Callable, category: str, *, 14 | callback: Callable[[Scanner, str, Any], None] = None, 15 | **kwargs: Any) -> None: 16 | """Shortcut for :func:`venusian.attach`. 17 | 18 | This shortcut makes the callback argument optional. 19 | """ 20 | callback = _on_found if callback is None else callback 21 | return _attach(fun, callback, category=category, **kwargs) 22 | 23 | 24 | def _on_found(scanner: venusian.Scanner, name: str, obj: Any) -> None: 25 | ... 26 | -------------------------------------------------------------------------------- /extra/tools/verify_tabletest_changelog.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """ 3 | Usage: 4 | 5 | .. sourcecode:: console 6 | 7 | $ kafka-console-consumer --bootstrap-server localhost:9092 \ 8 | --topic tabletest-counts-changelog \ 9 | --partition=0 --from-beginning | \ 10 | python extra/tools/verify_tabletest_changelog.py 11 | 12 | """ 13 | 14 | 15 | import fileinput 16 | import os 17 | import sys 18 | 19 | EXPECTED_SUM = int(os.environ.get('EXPECTED_SUM', 49995000)) 20 | 21 | expected = 0 22 | prev = None 23 | for i, line in enumerate(fileinput.input()): 24 | expected += i 25 | found = int(line) 26 | if found != expected: 27 | print(f'At line {i} found {found} expected {expected}') 28 | sys.exit(445) 29 | if found == EXPECTED_SUM: 30 | print('DONE!') 31 | sys.exit(0) 32 | -------------------------------------------------------------------------------- /faust/fixups/base.py: -------------------------------------------------------------------------------- 1 | """Fixups - Base implementation.""" 2 | from typing import Iterable 3 | from faust.types import AppT, FixupT 4 | 5 | __all__ = ['Fixup'] 6 | 7 | 8 | class Fixup(FixupT): 9 | """Base class for fixups. 10 | 11 | Fixups are things that hook into Faust to make things 12 | work for other frameworks, such as Django. 13 | """ 14 | 15 | def __init__(self, app: AppT) -> None: 16 | self.app = app 17 | 18 | def enabled(self) -> bool: 19 | """Return if fixup should be enabled in this environment.""" 20 | return False 21 | 22 | def autodiscover_modules(self) -> Iterable[str]: 23 | """Return list of additional autodiscover modules.""" 24 | return [] 25 | 26 | def on_worker_init(self) -> None: 27 | """Call when initializing worker/CLI commands.""" 28 | ... 29 | -------------------------------------------------------------------------------- /examples/django/proj/urls.py: -------------------------------------------------------------------------------- 1 | """proj URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/1.11/topics/http/urls/ 5 | Examples: 6 | Function views 7 | 1. Add an import: from my_app import views 8 | 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home') 9 | Class-based views 10 | 1. Add an import: from other_app.views import Home 11 | 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home') 12 | Including another URLconf 13 | 1. Import the include() function: from django.conf.urls import url, include 14 | 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) 15 | """ 16 | from django.conf.urls import url 17 | from django.contrib import admin 18 | 19 | urlpatterns = [ 20 | url(r'^admin/', admin.site.urls), 21 | ] 22 | -------------------------------------------------------------------------------- /t/old/test_simple.py: -------------------------------------------------------------------------------- 1 | from typing import Mapping 2 | from mode import setup_logging 3 | import pytest 4 | from .app import simple 5 | 6 | 7 | setup_logging(loglevel='INFO') 8 | 9 | 10 | def _build_data(i: int) -> Mapping: 11 | return {'A': {'the': {'quick': {'brown': {'fox': i}}}}} 12 | 13 | 14 | @pytest.mark.asyncio 15 | async def test_simple_ask() -> None: 16 | for i in range(100): 17 | value = _build_data(i) 18 | assert await simple.ask(value=value) == value 19 | 20 | 21 | @pytest.mark.asyncio 22 | async def test_simple_map() -> None: 23 | values = [_build_data(i) for i in range(100)] 24 | check = set(range(100)) 25 | replies = set() 26 | async for reply in simple.map(values): 27 | v = reply['A']['the']['quick']['brown']['fox'] 28 | assert v in check 29 | replies.add(v) 30 | assert replies == check 31 | -------------------------------------------------------------------------------- /faust/cli/clean_versions.py: -------------------------------------------------------------------------------- 1 | """Program ``faust reset`` used to delete local table state.""" 2 | from shutil import rmtree 3 | from .base import AppCommand 4 | 5 | __all__ = ['clean_versions'] 6 | 7 | 8 | class clean_versions(AppCommand): 9 | """Delete old version directories. 10 | 11 | Warning: 12 | This command will result in the destruction of the following files: 13 | 14 | 1) Table data for previous versions of the app. 15 | """ 16 | 17 | async def run(self) -> None: 18 | """Execute command.""" 19 | self.remove_old_versiondirs() 20 | 21 | def remove_old_versiondirs(self) -> None: 22 | """Remove data from old application versions from data directory.""" 23 | for dir in self.app.conf.find_old_versiondirs(): 24 | self.say(f'Removing old version directory {dir}...') 25 | rmtree(str(dir)) 26 | -------------------------------------------------------------------------------- /faust/fixups/__init__.py: -------------------------------------------------------------------------------- 1 | """Transport registry.""" 2 | from typing import Iterator, Type 3 | from mode.utils.imports import FactoryMapping 4 | from faust.types import AppT, FixupT 5 | 6 | __all__ = ['by_name', 'by_url', 'fixups'] 7 | 8 | FIXUPS: FactoryMapping[Type[FixupT]] = FactoryMapping( 9 | django='faust.fixups.django:Fixup', 10 | ) 11 | FIXUPS.include_setuptools_namespace('faust.fixups') 12 | by_name = FIXUPS.by_name 13 | by_url = FIXUPS.by_url 14 | 15 | 16 | def fixups(app: AppT) -> Iterator[FixupT]: 17 | """Iterate over enabled fixups. 18 | 19 | Fixups are installed by setuptools, using the 'faust.fixups' 20 | namespace. 21 | 22 | Fixups modify the Faust library to work with frameworks 23 | such as Django. 24 | """ 25 | for Fixup in FIXUPS.iterate(): 26 | fixup = Fixup(app) 27 | if fixup.enabled(): 28 | yield fixup 29 | -------------------------------------------------------------------------------- /examples/crontab/tz_unaware.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from random import random 4 | from datetime import datetime 5 | import faust 6 | 7 | app = faust.App('tz_unaware', broker='kafka://localhost:9092') 8 | 9 | 10 | class Model(faust.Record, serializer='json'): 11 | random: float 12 | 13 | 14 | tz_unaware_topic = app.topic('tz_unaware_topic', value_type=Model) 15 | 16 | 17 | @app.agent(tz_unaware_topic) 18 | async def consume(stream): 19 | async for record in stream: 20 | print(f'record: {record}') 21 | 22 | 23 | @app.crontab('*/1 * * * *', on_leader=True) 24 | async def publish_every_minute(): 25 | print('-- We should send a message every minute --') 26 | print(f'Sending message at: {datetime.now()}') 27 | msg = Model(random=round(random(), 2)) 28 | await tz_unaware_topic.send(value=msg) 29 | 30 | 31 | if __name__ == '__main__': 32 | app.main() 33 | -------------------------------------------------------------------------------- /examples/django/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == '__main__': 6 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'proj.settings') 7 | try: 8 | from django.core.management import execute_from_command_line 9 | except ImportError: 10 | # The above import may fail for some other reason. Ensure that the 11 | # issue is really that Django is missing to avoid masking other 12 | # exceptions on Python 2. 13 | try: 14 | import django # noqa 15 | except ImportError: 16 | raise ImportError( 17 | "Couldn't import Django. Are you sure it's installed and " 18 | 'available on your PYTHONPATH environment variable? Did you ' 19 | 'forget to activate a virtual environment?') 20 | raise 21 | execute_from_command_line(sys.argv) 22 | -------------------------------------------------------------------------------- /t/unit/utils/test_iso8601.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from datetime import datetime, timezone 3 | from faust.utils._iso8601_python import InvalidTZ, parse, parse_tz 4 | 5 | 6 | def test_python(): 7 | dt1 = datetime.now().astimezone(timezone.utc) 8 | dt2 = parse(dt1.isoformat()) 9 | assert dt1 == dt2 10 | 11 | 12 | def test_timezone_no_sep(): 13 | dt = parse('2018-12-04T19:36:08-0500') 14 | assert dt.tzinfo 15 | assert str(dt.tzinfo) == 'UTC-05:00' 16 | 17 | 18 | def test_parse_error(): 19 | with pytest.raises(ValueError): 20 | parse('foo') 21 | 22 | 23 | @pytest.mark.parametrize('tz', [ 24 | 'Z', 25 | '+00:10', 26 | '-01:20', 27 | '+0300', 28 | '-0600', 29 | ]) 30 | def test_parse_tz(tz): 31 | assert parse_tz(tz) is not None 32 | 33 | 34 | def test_parse_tz__no_match(): 35 | with pytest.raises(InvalidTZ): 36 | parse_tz('foo') 37 | -------------------------------------------------------------------------------- /t/functional/helpers.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | from mode.utils.aiter import anext 3 | import pytest 4 | from t.helpers import message 5 | 6 | __all__ = ['channel_empty', 'times_out', 'is_empty', 'message', 'put'] 7 | 8 | 9 | async def channel_empty(channel, *, timeout=0.01): 10 | assert channel.empty() 11 | with pytest.raises(asyncio.TimeoutError): 12 | await channel.get(timeout=timeout) 13 | return True 14 | 15 | 16 | async def times_out(coro, *, timeout=0.01): 17 | with pytest.raises(asyncio.TimeoutError): 18 | await asyncio.wait_for(coro, timeout=timeout) 19 | return True 20 | 21 | 22 | async def is_empty(it, *, timeout=0.01): 23 | return await times_out(anext(it), timeout=timeout) 24 | 25 | 26 | async def put(channel, key=None, value=None, **kwargs): 27 | msg = message(key=key, value=value, **kwargs) 28 | await channel.deliver(msg) 29 | return msg 30 | -------------------------------------------------------------------------------- /examples/django/accounts/agents.py: -------------------------------------------------------------------------------- 1 | from decimal import Decimal 2 | import faust 3 | from faust.types import StreamT 4 | from faustapp.app import app 5 | from .models import Account 6 | 7 | 8 | class AccountRecord(faust.Record): 9 | name: str 10 | score: float 11 | active: bool 12 | 13 | 14 | @app.agent() 15 | async def add_account(accounts: StreamT[AccountRecord]): 16 | async for account in accounts: 17 | result = Account.objects.create( 18 | name=account.name, 19 | score=Decimal(str(account.score)), 20 | active=account.active, 21 | ) 22 | yield result.pk 23 | 24 | 25 | @app.agent() 26 | async def disable_account(account_ids: StreamT[int]): 27 | async for account_id in account_ids: 28 | account = Account.objects.get(pk=account_id) 29 | account.active = False 30 | account.save() 31 | yield account.active 32 | -------------------------------------------------------------------------------- /extra/tools/benchmark.py: -------------------------------------------------------------------------------- 1 | import faust 2 | from time import monotonic 3 | 4 | app = faust.App( 5 | 'benchmark', 6 | version=1, 7 | stream_buffer_maxsize=32_768, 8 | ) 9 | 10 | benchmark_topic = app.topic('benchmark') 11 | 12 | 13 | @app.agent(benchmark_topic) 14 | async def process(stream): 15 | time_start = None 16 | async for i, value in stream.enumerate(): 17 | if time_start is None: 18 | time_start = monotonic() 19 | if not i % 10_000: 20 | now = monotonic() 21 | print(f'TIME SPENT PROCESSING 10k: {now - time_start}') 22 | time_start = now 23 | 24 | 25 | @app.command() 26 | async def produce(): 27 | for i in range(100_000): 28 | await process.send(value=i) 29 | 30 | 31 | if __name__ == '__main__': 32 | import sys 33 | if len(sys.argv) == 1: 34 | sys.argv.extend(['worker', '-l', 'info']) 35 | app.main() 36 | -------------------------------------------------------------------------------- /faust/web/apps/graph.py: -------------------------------------------------------------------------------- 1 | """Web endpoint showing graph of running :pypi:`mode` services.""" 2 | import io 3 | from faust import web 4 | 5 | __all__ = ['Graph', 'blueprint'] 6 | 7 | blueprint = web.Blueprint('graph') 8 | 9 | 10 | @blueprint.route('/', name='detail') 11 | class Graph(web.View): 12 | """Render image from graph of running services.""" 13 | 14 | async def get(self, request: web.Request) -> web.Response: 15 | """Draw image of the services running in this worker.""" 16 | try: 17 | import pydot 18 | except ImportError: 19 | return self.text('Please install pydot: pip install pydot', 20 | status=500) 21 | o = io.StringIO() 22 | beacon = self.app.beacon.root or self.app.beacon 23 | beacon.as_graph().to_dot(o) 24 | graph, = pydot.graph_from_dot_data(o.getvalue()) 25 | return self.bytes(graph.create_png(), content_type='image/png') 26 | -------------------------------------------------------------------------------- /examples/kubernetes/producer/README.md: -------------------------------------------------------------------------------- 1 | ## Produce 10,000 messages 2 | 3 | This process assumes a Kafka broker accessible at `host.docker.internal:9092` 4 | 5 | 6 | Producer that places 10,000 messages into a Kafka topic named "test". Each message 7 | is a mapping representing a score. Each score has 2 keys: 8 | * index 9 | * value 10 | 11 | 12 | 1. Build the producer docker image 13 | ```bash 14 | cd producer 15 | # -t producer => names the image producer, is used in kubernetes yaml file 16 | docker build . -t producer 17 | ``` 18 | 19 | 2. Apply the producer as a Kubernetes job. 20 | ```bash 21 | kubectl apply -f producer.yml 22 | ``` 23 | 24 | 3. Log producer output 25 | ```bash 26 | # Discover the pod running the job, e.g. producer-32452 27 | kubectl get pods 28 | 29 | kubectl logs -f 30 | ``` 31 | 32 | 4. To send a second batch of 10,000 messages 33 | ```bash 34 | kubectl delete -f producer.yml 35 | kubectl apply -f producer.yml 36 | ``` 37 | -------------------------------------------------------------------------------- /t/helpers.py: -------------------------------------------------------------------------------- 1 | from time import time 2 | from faust.events import Event 3 | from faust.types.tuples import Message 4 | 5 | __all__ = ['message', 'new_event'] 6 | 7 | 8 | def message(key=None, value=None, 9 | *, 10 | topic='topic', 11 | partition=0, 12 | timestamp=None, 13 | headers=None, 14 | offset=1, 15 | checksum=None): 16 | return Message( 17 | key=key, 18 | value=value, 19 | topic=topic, 20 | partition=partition, 21 | offset=offset, 22 | timestamp=timestamp or time(), 23 | timestamp_type=1 if timestamp else 0, 24 | headers=headers, 25 | checksum=checksum, 26 | ) 27 | 28 | 29 | def new_event(app, key=None, value=None, *, 30 | headers=None, 31 | **kwargs): 32 | return Event(app, key, value, headers, message( 33 | key=key, value=value, headers=headers, **kwargs)) 34 | -------------------------------------------------------------------------------- /faust/types/codecs.py: -------------------------------------------------------------------------------- 1 | import abc 2 | from typing import Any, Optional, Tuple, Union 3 | 4 | __all__ = ['CodecArg', 'CodecT'] 5 | 6 | 7 | class CodecT(metaclass=abc.ABCMeta): 8 | """Abstract type for an encoder/decoder. 9 | 10 | See Also: 11 | :class:`faust.serializers.codecs.Codec`. 12 | """ 13 | 14 | @abc.abstractmethod 15 | def __init__(self, children: Tuple['CodecT', ...] = None, 16 | **kwargs: Any) -> None: 17 | ... 18 | 19 | @abc.abstractmethod 20 | def dumps(self, obj: Any) -> bytes: 21 | ... 22 | 23 | @abc.abstractmethod 24 | def loads(self, s: bytes) -> Any: 25 | ... 26 | 27 | @abc.abstractmethod 28 | def clone(self, *children: 'CodecT') -> 'CodecT': 29 | ... 30 | 31 | @abc.abstractmethod 32 | def __or__(self, other: Any) -> Any: 33 | ... 34 | 35 | 36 | # `serializer` argument can be str or Codec instance. 37 | CodecArg = Optional[Union[CodecT, str]] 38 | -------------------------------------------------------------------------------- /t/integration/app.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | from typing import List 3 | import faust 4 | 5 | 6 | class Point(faust.Record): 7 | x: int 8 | y: int 9 | 10 | 11 | class Arena(faust.Record): 12 | points: List[Point] 13 | timestamp: float = None 14 | 15 | 16 | app = faust.App('t-integration', origin='t.integration.app') 17 | add_topic = app.topic('add-topic') 18 | local_channel = app.channel() 19 | 20 | 21 | @app.agent() 22 | async def mul(stream): 23 | """Foo agent help.""" 24 | async for event in stream: 25 | yield event * 2 26 | 27 | 28 | @app.agent(add_topic) 29 | async def add(stream): 30 | async for event in stream: 31 | yield event + 2 32 | 33 | 34 | @app.agent(local_channel) 35 | async def internal(stream): 36 | async for event in stream: 37 | yield event / 2 38 | 39 | 40 | @app.command() 41 | async def error_command(): 42 | raise Exception('foo') 43 | 44 | 45 | if __name__ == '__main__': 46 | app.main() 47 | -------------------------------------------------------------------------------- /extra/macOS/com.fauststream.worker.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Disabled 6 | 7 | GroupName 8 | faust-worker 9 | KeepAlive 10 | 11 | Label 12 | com.fauststream.worker 13 | Program 14 | faust 15 | ProgramArguments 16 | 17 | worker 18 | --datadir=/var/faust/myapp/ 19 | -A myapp 20 | --loglevel=warn 21 | 22 | RunAtLoad 23 | 24 | Umask 25 | 7 26 | UserName 27 | nobody 28 | WorkingDirectory 29 | / 30 | 31 | 32 | -------------------------------------------------------------------------------- /t/bench/forward.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import faust 3 | sys.path.insert(0, '.') 4 | from t.bench.base import Benchmark # noqa 5 | 6 | app = faust.App('bench-forward') 7 | topic = app.topic( 8 | 'bench-forward-1st', 9 | value_serializer='raw', 10 | value_type=int, 11 | ) 12 | consume_topic = app.topic( 13 | 'bench-forward-2nd', 14 | value_serializer='raw', 15 | value_type=int, 16 | ) 17 | 18 | # Producer sends to topic1 (1st) 19 | # Agent forwarder consumes from topic1 and forwards to topic2 20 | # Benchmark agent consumes from topic2 21 | # 22 | # 23 | # So we are measuring the time it takes to go through an 24 | # additional agent. 25 | 26 | 27 | @app.agent(topic) 28 | async def forwarder(stream): 29 | i = 0 30 | async for event in stream.events(): 31 | if i and not i % 10_000: 32 | print(f'Forwarded: {i}') 33 | await event.forward(consume_topic) 34 | i += 1 35 | 36 | 37 | Benchmark(app, topic, consume_topic=consume_topic).install(__name__) 38 | -------------------------------------------------------------------------------- /t/unit/utils/test_functional.py: -------------------------------------------------------------------------------- 1 | from collections import deque 2 | import pytest 3 | from faust.utils.functional import ( 4 | consecutive_numbers, 5 | deque_pushpopmax, 6 | ) 7 | 8 | 9 | @pytest.mark.parametrize('numbers,expected', [ 10 | ([1, 2, 3, 4, 6, 7, 8], [1, 2, 3, 4]), 11 | ([1, 4, 6, 8, 10], [1]), 12 | ([1], [1]), 13 | ([103, 104, 105, 106, 100000000000], [103, 104, 105, 106]), 14 | ]) 15 | def test_consecutive_numbers(numbers, expected): 16 | assert next(consecutive_numbers(numbers), None) == expected 17 | 18 | 19 | def test_deque_pushpop_max(): 20 | d = deque([]) 21 | deque_pushpopmax(d, 1, max=None) 22 | assert d == deque([1]) 23 | deque_pushpopmax(d, 2, max=3) 24 | assert d == deque([1, 2]) 25 | deque_pushpopmax(d, 3, max=3) 26 | assert d == deque([1, 2, 3]) 27 | deque_pushpopmax(d, 4, max=3) 28 | assert d == deque([2, 3, 4]) 29 | for i in range(5, 100): 30 | deque_pushpopmax(d, i, max=3) 31 | assert d == deque([i - 2, i - 1, i]) 32 | -------------------------------------------------------------------------------- /t/unit/conftest.py: -------------------------------------------------------------------------------- 1 | import os 2 | import faust 3 | import pytest 4 | from faust.transport.producer import Producer 5 | from faust.utils.tracing import set_current_span 6 | from mode.utils.mocks import AsyncMock, Mock 7 | 8 | 9 | @pytest.fixture() 10 | def app(event_loop, request): 11 | settings = request.node.get_closest_marker('conf') 12 | kwargs = settings.kwargs or {} if settings else {} 13 | 14 | os.environ.pop('F_DATADIR', None) 15 | os.environ.pop('FAUST_DATADIR', None) 16 | os.environ.pop('F_WORKDIR', None) 17 | os.environ.pop('FAUST_WORKDIR', None) 18 | instance = faust.App('testid', **kwargs) 19 | instance.producer = Mock( 20 | name='producer', 21 | autospec=Producer, 22 | maybe_start=AsyncMock(), 23 | start=AsyncMock(), 24 | send=AsyncMock(), 25 | send_and_wait=AsyncMock(), 26 | ) 27 | instance.finalize() 28 | set_current_span(None) 29 | return instance 30 | 31 | 32 | @pytest.fixture() 33 | def web(app): 34 | return app.web 35 | -------------------------------------------------------------------------------- /docs/copyright.rst: -------------------------------------------------------------------------------- 1 | Copyright 2 | ========= 3 | 4 | *Faust User Manual* 5 | 6 | .. |copy| unicode:: U+000A9 .. COPYRIGHT SIGN 7 | 8 | Copyright |copy| 2017-2019, Robinhood Markets, Inc. 9 | 10 | All rights reserved. This material may be copied or distributed only 11 | subject to the terms and conditions set forth in the `Creative Commons 12 | Attribution-ShareAlike 4.0 International` 13 | `_ license. 14 | 15 | You may share and adapt the material, even for commercial purposes, but 16 | you must give the original author credit. 17 | If you alter, transform, or build upon this 18 | work, you may distribute the resulting work only under the same license or 19 | a license compatible to this one. 20 | 21 | .. note:: 22 | 23 | While the Faust *documentation* is offered under the 24 | Creative Commons *Attribution-ShareAlike 4.0 International* license 25 | the Faust *software* is offered under the 26 | `BSD License (3 Clause) `_ 27 | -------------------------------------------------------------------------------- /examples/kubernetes/consumer/consumer.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import faust 3 | TOPIC = 'test' 4 | 5 | # host.docker.internal is how a docker container connects to the local machine. 6 | # Don't use in production, this only works with Docker for Mac in development 7 | app = faust.App('scores', broker='kafka://host.docker.internal:9092') 8 | table = app.Table('totals', default=int) 9 | 10 | 11 | class Score(faust.Record, serializer='json'): 12 | index: int 13 | value: int 14 | 15 | 16 | test_topic = app.topic(TOPIC, value_type=Score) 17 | 18 | 19 | def get_score_key(score): 20 | return f'partition: {score.index % 2}' 21 | 22 | 23 | @app.agent(test_topic) 24 | async def print_totals(stream): 25 | async for score in stream.group_by(get_score_key, name='index_partition'): 26 | ind = f'partition: {score.index % 2}' 27 | table['totals'] += 1 28 | table[ind] += 1 29 | print(f'Total: {table["totals"]}, Partition {ind}: {table[ind]}') 30 | 31 | 32 | if __name__ == '__main__': 33 | app.main() 34 | -------------------------------------------------------------------------------- /t/unit/cli/test_clean_versions.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | import pytest 3 | from faust.cli.clean_versions import clean_versions 4 | from mode.utils.mocks import Mock, call, patch 5 | 6 | 7 | class test_clean_versions: 8 | 9 | @pytest.fixture() 10 | def command(self, *, context): 11 | return clean_versions(context) 12 | 13 | @pytest.mark.asyncio 14 | async def test_run(self, *, command): 15 | command.remove_old_versiondirs = Mock() 16 | await command.run() 17 | command.remove_old_versiondirs.assert_called_with() 18 | 19 | def test_remove_old_versiondirs(self, *, app, command): 20 | app.conf.find_old_versiondirs = Mock(return_value=[ 21 | Path('A1'), Path('B2'), Path('C3'), 22 | ]) 23 | with patch('faust.cli.clean_versions.rmtree') as rmtree: 24 | command.remove_old_versiondirs() 25 | rmtree.assert_has_calls([ 26 | call('A1'), 27 | call('B2'), 28 | call('C3'), 29 | ]) 30 | -------------------------------------------------------------------------------- /faust/livecheck/locals.py: -------------------------------------------------------------------------------- 1 | """Locals - Current test & execution context.""" 2 | import typing 3 | from typing import Optional 4 | from mode.locals import LocalStack 5 | from .models import TestExecution 6 | 7 | if typing.TYPE_CHECKING: 8 | from .runners import TestRunner as _TestRunner 9 | else: # pragma: no cover 10 | class _TestRunner: ... # noqa 11 | 12 | __all__ = [ 13 | 'current_execution', 14 | 'current_execution_stack', 15 | 'current_test', 16 | 'current_test_stack', 17 | ] 18 | 19 | current_test_stack: LocalStack[TestExecution] 20 | current_test_stack = LocalStack() 21 | 22 | current_execution_stack: LocalStack[_TestRunner] 23 | current_execution_stack = LocalStack() 24 | 25 | 26 | def current_execution() -> Optional[_TestRunner]: 27 | """Return the current :class:`~faust.livecheck.TestRunner`.""" 28 | return current_execution_stack.top 29 | 30 | 31 | def current_test() -> Optional[TestExecution]: 32 | """Return information about the current test (if any).""" 33 | return current_test_stack.top 34 | -------------------------------------------------------------------------------- /t/functional/sensors/test_statsd.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from faust.sensors.statsd import StatsdMonitor 3 | 4 | PREFIX = 'faust-test' 5 | 6 | 7 | @pytest.fixture() 8 | def mon(): 9 | return StatsdMonitor(prefix=PREFIX) 10 | 11 | 12 | def stream_from_channel(app): 13 | return app.stream(app.channel()) 14 | 15 | 16 | def stream_from_topic(app): 17 | return app.stream(app.topic('withdrawals')) 18 | 19 | 20 | def stream_from_multiple_topics(app): 21 | return app.stream(app.topic('foo', 'bar')) 22 | 23 | 24 | def stream_from_combined_streams(app): 25 | return app.stream(app.topic('foo')) & app.stream(app.topic('bar')) 26 | 27 | 28 | @pytest.mark.parametrize('make_stream,expected', [ 29 | (stream_from_channel, 'channel_anon'), 30 | (stream_from_topic, 'topic_withdrawals'), 31 | (stream_from_multiple_topics, 'topic_foo,bar'), 32 | (stream_from_combined_streams, 'topic_foo&topic_bar'), 33 | ]) 34 | def test_stream_label(make_stream, expected, *, app, mon): 35 | assert mon._stream_label(make_stream(app)) == expected 36 | -------------------------------------------------------------------------------- /t/unit/windows/test_tumbling_window.py: -------------------------------------------------------------------------------- 1 | from faust.windows import TumblingWindow 2 | 3 | 4 | class test_TumblingWindow: 5 | 6 | def test_tumbling_window_has_just_one_range(self): 7 | tumbling = TumblingWindow(10) 8 | assert len(tumbling.ranges(0)) == 1 9 | assert len(tumbling.ranges(5)) == 1 10 | assert len(tumbling.ranges(10)) == 1 11 | 12 | def test_end_range_in_tumbling_window_is_within_range(self): 13 | tumbling = TumblingWindow(10) 14 | 15 | # tumbling windows only have one range 16 | base_range = tumbling.ranges(0)[0] 17 | base_range_end = base_range[1] 18 | 19 | compare_range = tumbling.ranges(base_range_end)[0] 20 | 21 | assert base_range[0] == compare_range[0] 22 | assert base_range[1] == compare_range[1] 23 | 24 | def test_earliest_and_current_range_are_the_same(self): 25 | size = 57 26 | timestamp = 456 27 | window = TumblingWindow(size) 28 | 29 | assert window.current(timestamp) == window.earliest(timestamp) 30 | -------------------------------------------------------------------------------- /examples/crontab/tz_aware.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # This example needs pytz so that we can set the approprate timezone when 4 | # setting the crontab 5 | 6 | from random import random 7 | from datetime import datetime 8 | import faust 9 | import pytz 10 | 11 | app = faust.App('tz_aware', broker='kafka://localhost:9092') 12 | pacific = pytz.timezone('US/Pacific') 13 | 14 | 15 | class Model(faust.Record, serializer='json'): 16 | random: float 17 | 18 | 19 | tz_aware_topic = app.topic('tz_aware_topic', value_type=Model) 20 | 21 | 22 | @app.agent(tz_aware_topic) 23 | async def consume(stream): 24 | async for record in stream: 25 | print(f'record: {record}') 26 | 27 | 28 | @app.crontab('16 20 * * *', tz=pacific, on_leader=True) 29 | async def publish_at_8_20_pm_pacific(): 30 | print('-- This should be sent at 20:16 Pacific time --') 31 | print(f'Sending message at: {datetime.now()}') 32 | msg = Model(random=round(random(), 2)) 33 | await tz_aware_topic.send(value=msg) 34 | 35 | 36 | if __name__ == '__main__': 37 | app.main() 38 | -------------------------------------------------------------------------------- /extra/supervisord/faust.conf: -------------------------------------------------------------------------------- 1 | ; ================================== 2 | ; faust worker supervisor example 3 | ; ================================== 4 | 5 | [program:faust] 6 | ; Set full path to faust program if using virtualenv 7 | command=faust -A proj worker --loglevel=info 8 | 9 | ; Alternatively, 10 | ;command=faust --app=module:app_attr_name worker --loglevel=info 11 | ; Or run a script 12 | ;command=start_faust_worker.sh 13 | 14 | directory=/path/to/project 15 | user=nobody 16 | numprocs=1 17 | stdout_logfile=/var/log/faust/worker.log 18 | stderr_logfile=/var/log/faust/worker.log 19 | autostart=true 20 | autorestart=true 21 | startsecs=10 22 | 23 | ; Need to wait for currently executing tasks to finish at shutdown. 24 | ; Increase this if you have very long running tasks. 25 | stopwaitsecs = 600 26 | 27 | ; Causes supervisor to send the termination signal (SIGTERM) to the whole process group. 28 | stopasgroup=true 29 | 30 | ; Set Faust priority higher than default (999) 31 | ; so hopefully, if Kafka/Zookeeper is supervised, they will start first. 32 | priority=1000 33 | -------------------------------------------------------------------------------- /faust/types/router.py: -------------------------------------------------------------------------------- 1 | """Types for module :mod:`faust.router`.""" 2 | import abc 3 | import typing 4 | 5 | from yarl import URL 6 | 7 | from .assignor import HostToPartitionMap 8 | from .core import K 9 | from . import web 10 | 11 | if typing.TYPE_CHECKING: 12 | from .app import AppT as _AppT 13 | else: 14 | class _AppT: ... # noqa 15 | 16 | 17 | class RouterT(abc.ABC): 18 | """Router type class.""" 19 | 20 | app: _AppT 21 | 22 | @abc.abstractmethod 23 | def __init__(self, app: _AppT) -> None: 24 | ... 25 | 26 | @abc.abstractmethod 27 | def key_store(self, table_name: str, key: K) -> URL: 28 | ... 29 | 30 | @abc.abstractmethod 31 | def table_metadata(self, table_name: str) -> HostToPartitionMap: 32 | ... 33 | 34 | @abc.abstractmethod 35 | def tables_metadata(self) -> HostToPartitionMap: 36 | ... 37 | 38 | @abc.abstractmethod 39 | async def route_req(self, table_name: str, key: K, web: web.Web, 40 | request: web.Request) -> web.Response: 41 | ... 42 | -------------------------------------------------------------------------------- /faust/utils/platforms.py: -------------------------------------------------------------------------------- 1 | """Platform/OS utilities.""" 2 | import platform 3 | import subprocess 4 | from typing import Optional 5 | 6 | 7 | def max_open_files() -> Optional[int]: 8 | """Return max number of open files, or :const:`None`.""" 9 | try: 10 | from resource import RLIM_INFINITY, RLIMIT_NOFILE, getrlimit 11 | except ImportError: 12 | return None 13 | else: 14 | _, hard_limit = getrlimit(RLIMIT_NOFILE) 15 | if hard_limit == RLIM_INFINITY: 16 | # macOS bash always returns infinity, even though there 17 | # is an actual system limit. 18 | if platform.system() == 'Darwin': 19 | output = subprocess.check_output([ 20 | 'sysctl', '-q', 'kern.maxfilesperproc', 21 | ]) 22 | # $ sysctl -q kern.maxfilesperproc 23 | # kern.maxfilesperproc: 24576 24 | _, _, svalue = output.decode().partition(':') 25 | return int(svalue.strip()) 26 | return None 27 | return hard_limit 28 | -------------------------------------------------------------------------------- /t/stress/models.py: -------------------------------------------------------------------------------- 1 | import random 2 | from datetime import datetime, timezone 3 | from itertools import count 4 | import faust 5 | 6 | 7 | class Withdrawal(faust.Record, isodates=True, serializer='json'): 8 | user: str 9 | country: str 10 | amount: float 11 | date: datetime = None 12 | 13 | 14 | def generate_withdrawals(n: int = None): 15 | for d in generate_withdrawals_dict(n): 16 | yield Withdrawal(**d) 17 | 18 | 19 | def generate_withdrawals_dict(n: int = None): 20 | num_countries = 5 21 | countries = [f'country_{i}' for i in range(num_countries)] 22 | country_dist = [0.9] + ([0.10 / num_countries] * (num_countries - 1)) 23 | num_users = 500 24 | users = [f'user_{i}' for i in range(num_users)] 25 | for _ in range(n) if n is not None else count(): 26 | yield { 27 | 'user': random.choice(users), 28 | 'amount': random.uniform(0, 25_000), 29 | 'country': random.choices(countries, country_dist)[0], 30 | 'date': datetime.utcnow().replace(tzinfo=timezone.utc).isoformat(), 31 | } 32 | -------------------------------------------------------------------------------- /t/stress/config.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import os 3 | from typing import List 4 | from raven import Client 5 | from raven.handlers.logging import SentryHandler 6 | from raven_aiohttp import AioHttpTransport 7 | 8 | __all__ = [ 9 | 'broker', 10 | 'store', 11 | 'topic_partitions', 12 | 'sentry_dsn', 13 | 'loghandlers', 14 | ] 15 | 16 | broker: str = os.environ.get('STRESS_BROKER', 'kafka://127.0.0.1:9092') 17 | store: str = os.environ.get('STRESS_STORE', 'rocksdb://') 18 | topic_partitions: int = int(os.environ.get('STRESS_PARTITIONS', 4)) 19 | sentry_dsn: str = os.environ.get('SENTRY_DSN') 20 | 21 | 22 | def loghandlers() -> List[SentryHandler]: 23 | handlers = [] 24 | if sentry_dsn: 25 | client = Client( 26 | dsn=sentry_dsn, 27 | include_paths=[__name__.split('.', 1)[0]], 28 | transport=AioHttpTransport, 29 | disable_existing_loggers=False, 30 | ) 31 | handler = SentryHandler(client) 32 | handler.setLevel(logging.ERROR) 33 | handler.propagate = False 34 | handlers.append(handler) 35 | return handlers 36 | -------------------------------------------------------------------------------- /faust/utils/functional.py: -------------------------------------------------------------------------------- 1 | """Functional utilities.""" 2 | from itertools import groupby 3 | from typing import Iterable, Iterator, Optional, Sequence, TypeVar 4 | from mode.utils.typing import Deque 5 | 6 | __all__ = ['consecutive_numbers', 'deque_prune', 'deque_pushpopmax'] 7 | 8 | T = TypeVar('T') 9 | 10 | 11 | def consecutive_numbers(it: Iterable[int]) -> Iterator[Sequence[int]]: 12 | """Find runs of consecutive numbers. 13 | 14 | Notes: 15 | See https://docs.python.org/2.6/library/itertools.html#examples 16 | """ 17 | for _, g in groupby(enumerate(it), lambda a: a[0] - a[1]): 18 | yield [a[1] for a in g] 19 | 20 | 21 | def deque_prune(l: Deque[T], max: int = None) -> Optional[T]: 22 | """Prune oldest element in deque if size exceeds ``max``.""" 23 | if max is not None: 24 | size = len(l) 25 | if size > max: 26 | return l.popleft() 27 | return None 28 | 29 | 30 | def deque_pushpopmax(l: Deque[T], item: T, max: int = None) -> Optional[T]: 31 | """Append to deque and remove oldest element if size exceeds ``max``.""" 32 | l.append(item) 33 | return deque_prune(l, max) 34 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | ======================================================================= 2 | Faust - Python Stream Processing 3 | ======================================================================= 4 | 5 | .. sourcecode:: python 6 | 7 | # Python Streams ٩(◕‿◕)۶ 8 | # Forever scalable event processing & in-memory durable K/V store; 9 | # w/ asyncio & static typing. 10 | import faust 11 | 12 | .. include:: includes/intro.txt 13 | 14 | ----------------------------------- 15 | 16 | Contents 17 | ======== 18 | 19 | .. toctree:: 20 | :maxdepth: 1 21 | 22 | copyright 23 | 24 | .. toctree:: 25 | :maxdepth: 2 26 | 27 | introduction 28 | 29 | .. toctree:: 30 | :maxdepth: 2 31 | 32 | playbooks/index 33 | 34 | .. toctree:: 35 | :maxdepth: 2 36 | 37 | userguide/index 38 | 39 | .. toctree:: 40 | :maxdepth: 1 41 | 42 | faq 43 | reference/index 44 | changelog 45 | contributing 46 | developerguide/index 47 | history/index 48 | authors 49 | glossary 50 | 51 | Indices and tables 52 | ================== 53 | 54 | * :ref:`genindex` 55 | * :ref:`modindex` 56 | * :ref:`search` 57 | 58 | -------------------------------------------------------------------------------- /examples/django/README.rst: -------------------------------------------------------------------------------- 1 | Directory Layout 2 | 3 | - ``proj/`` 4 | 5 | This is the main Django project. 6 | 7 | We have also added a ``proj/__main__.py`` that executes if you do 8 | ``python -m proj``, and it will work as the manage.py for the project. 9 | 10 | This is also installed by setup.py as an entry point, so after 11 | ``python setup.py install`` or ``python setup.py develop`` the 12 | ``proj`` command will be available:: 13 | 14 | $ python setup.py develop 15 | $ proj runserver 16 | 17 | The above is the same as running ``manage.py runserver``, but it will 18 | be installed in the system path. 19 | 20 | - ``faustapp/`` 21 | 22 | This is a Django App that defines the Faust app used by the project, 23 | and it also configures Faust using Django settings. 24 | 25 | This faustapp is also installed by setup.py as the ``proj-faust`` program, 26 | and can be used to start a Faust worker for your Django project by doing:: 27 | 28 | $ python setup.py develop 29 | $ proj-faust worker -l info 30 | 31 | - ``accounts/`` 32 | 33 | This is an example Django App with stream processors. 34 | -------------------------------------------------------------------------------- /t/unit/utils/test_cron.py: -------------------------------------------------------------------------------- 1 | import pytz 2 | from freezegun import freeze_time 3 | from faust.utils.cron import secs_for_next 4 | 5 | SECS_IN_HOUR = 60 * 60 6 | 7 | 8 | @freeze_time('2000-01-01 00:00:00') 9 | def test_secs_for_next(): 10 | every_minute_cron_format = '*/1 * * * *' 11 | assert secs_for_next(every_minute_cron_format) == 60 12 | 13 | every_8pm_cron_format = '0 20 * * *' 14 | assert secs_for_next(every_8pm_cron_format) == 20 * SECS_IN_HOUR 15 | 16 | every_4th_july_1pm_cron_format = '0 13 4 7 *' 17 | days_until_4th_july = 31 + 28 + 31 + 30 + 31 + 30 + 4 18 | secs_until_4th_july = SECS_IN_HOUR * 24 * days_until_4th_july 19 | secs_until_1_pm = 13 * SECS_IN_HOUR 20 | total_secs = secs_until_4th_july + secs_until_1_pm 21 | assert secs_for_next(every_4th_july_1pm_cron_format) == total_secs 22 | 23 | 24 | @freeze_time('2000-01-01 00:00:00') 25 | def test_secs_for_next_with_tz(): 26 | pacific = pytz.timezone('US/Pacific') 27 | 28 | every_8pm_cron_format = '0 20 * * *' 29 | # In Pacific time it's 16:00 so only 4 hours until 8:00pm 30 | assert secs_for_next(every_8pm_cron_format, tz=pacific) == 4 * SECS_IN_HOUR 31 | -------------------------------------------------------------------------------- /t/unit/web/test_blueprints.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | import pytest 3 | from faust import web 4 | from mode.utils.mocks import Mock 5 | 6 | 7 | class test_Blueprint: 8 | 9 | @pytest.fixture() 10 | def bp(self): 11 | return web.Blueprint('test') 12 | 13 | def test_cache__with_prefix(self, *, bp): 14 | assert bp.cache(key_prefix='kp_').key_prefix == 'kp_' 15 | 16 | def test_apply_static(self, *, bp): 17 | bp.static('/static/', '/opt/static/', name='statici') 18 | assert bp.static_routes 19 | route = bp.static_routes[0] 20 | assert route.name == 'test.statici' 21 | app = Mock(name='app') 22 | bp.register(app, url_prefix='/foo/') 23 | app.web.add_static.assert_called_once_with( 24 | '/foo/static/', Path('/opt/static/'), 25 | ) 26 | 27 | def test_apply_static__already_prefixed(self, *, bp): 28 | bp.static('/static/', '/opt/static/', name='test.statici') 29 | assert bp.static_routes 30 | route = bp.static_routes[0] 31 | assert route.name == 'test.statici' 32 | 33 | def test_repr(self, *, bp): 34 | assert repr(bp) 35 | -------------------------------------------------------------------------------- /examples/advanced/rpc.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from typing import AsyncIterable 3 | import faust 4 | from faust import StreamT 5 | 6 | 7 | app = faust.App('RPC99', reply_create_topic=True) 8 | pow_topic = app.topic('RPC__pow') 9 | mul_topic = app.topic('RPC__mul') 10 | 11 | 12 | @app.agent(pow_topic) 13 | async def pow(stream: StreamT[float]) -> AsyncIterable[float]: 14 | async for value in stream: 15 | yield await mul.ask(value=value ** 2) 16 | 17 | 18 | @app.agent(mul_topic) 19 | async def mul(stream: StreamT[float]) -> AsyncIterable[float]: 20 | async for value in stream: 21 | yield value * 100.0 22 | 23 | 24 | @app.timer(interval=10.0) 25 | async def _sender() -> None: 26 | # join' gives list with order preserved. 27 | res = await pow.join([30.3, 40.4, 50.5, 60.6, 70.7, 80.8, 90.9]) 28 | print(f'JOINED: {res!r}') 29 | 30 | # map' gives async iterator to stream results (unordered) 31 | # note: the argument can also be an async iterator. 32 | async for value in pow.map([30.3, 40.4, 50.5, 60.6, 70.7, 80.8, 90.9]): 33 | print(f'RECEIVED REPLY: {value!r}') 34 | 35 | if __name__ == '__main__': 36 | app.main() 37 | -------------------------------------------------------------------------------- /faust/cli/completion.py: -------------------------------------------------------------------------------- 1 | """completion - Command line utility for completion. 2 | 3 | Supports ``bash``, ``ksh``, ``zsh``, etc. 4 | """ 5 | import os 6 | from pathlib import Path 7 | from .base import AppCommand 8 | 9 | try: 10 | import click_completion 11 | except ImportError: # pragma: no cover 12 | click_completion = None # noqa 13 | else: # pragma: no cover 14 | click_completion.init() 15 | 16 | 17 | class completion(AppCommand): 18 | """Output shell completion to be evaluated by the shell.""" 19 | 20 | require_app = False 21 | 22 | async def run(self) -> None: 23 | """Dump click completion script for Faust CLI.""" 24 | if click_completion is None: 25 | raise self.UsageError( 26 | 'Missing required dependency, but this is easy to fix.\n' 27 | 'Run `pip install click_completion` from your virtualenv\n' 28 | 'and try again!') 29 | self.say(click_completion.get_code(shell=self.shell())) 30 | 31 | def shell(self) -> str: 32 | """Return the current shell used in this environment.""" 33 | shell_path = Path(os.environ.get('SHELL', 'auto')) 34 | return shell_path.stem 35 | -------------------------------------------------------------------------------- /.coveragerc: -------------------------------------------------------------------------------- 1 | [run] 2 | branch = 1 3 | cover_pylib = 0 4 | include=*faust/* 5 | omit = t.* 6 | 7 | [report] 8 | omit = 9 | */python?.?/* 10 | */site-packages/* 11 | */pypy/* 12 | 13 | # tested by functional tests 14 | */faust/cli/agents.py 15 | */faust/cli/livecheck.py 16 | */faust/cli/model.py 17 | */faust/cli/models.py 18 | */faust/cli/reset.py 19 | */faust/cli/send.py 20 | */faust/cli/tables.py 21 | */faust/cli/worker.py 22 | */faust/web/apps/* 23 | */faust/assignor/* 24 | */faust/transport/drivers/memory.py 25 | */faust/transport/drivers/confluent.py 26 | 27 | # tested by integration 28 | */faust/tables/recovery.py 29 | 30 | # not needed 31 | */faust/utils/functional.py 32 | */faust/utils/kafka/* 33 | */faust/utils/iso8601.py 34 | */faust/utils/platforms.py 35 | */faust/utils/tracing.py 36 | */faust/types/* 37 | */faust/__main__.py 38 | 39 | # deprecated 40 | */faust/app/_attached.py 41 | exclude_lines = 42 | # Have to re-enable the standard pragma 43 | if\ typing\.TYPE_CHECKING\: 44 | 45 | pragma: no cover 46 | 47 | if sys.platform == 'win32': 48 | 49 | \@abc\.abstractmethod 50 | -------------------------------------------------------------------------------- /faust/agents/models.py: -------------------------------------------------------------------------------- 1 | """Models used by agents internally.""" 2 | from typing import Any 3 | 4 | from faust.models import Record 5 | from faust.types import K, ModelT 6 | 7 | __all__ = ['ReqRepRequest', 'ReqRepResponse'] 8 | 9 | 10 | class ReqRepRequest(Record, 11 | serializer='json', 12 | namespace='@ReqRepRequest', # internal namespace 13 | # any stream should allow this type 14 | # to wrap other values. 15 | polymorphic_fields=True): 16 | """Value wrapped in a Request-Reply request.""" 17 | 18 | # agent.ask(value) wraps the value in this record 19 | # so that the receiving agent knows where to send the reply. 20 | 21 | value: Any 22 | reply_to: str 23 | correlation_id: str 24 | 25 | 26 | class ModelReqRepRequest(ReqRepRequest): 27 | """Request-Reply request where value is a model.""" 28 | 29 | value: ModelT 30 | 31 | 32 | class ReqRepResponse(Record, serializer='json', namespace='@ReqRepResponse'): 33 | """Request-Reply response.""" 34 | 35 | key: K 36 | value: Any 37 | correlation_id: str 38 | 39 | 40 | class ModelReqRepResponse(ReqRepResponse): 41 | value: Any 42 | -------------------------------------------------------------------------------- /faust/types/windows.py: -------------------------------------------------------------------------------- 1 | """Types related to windowing.""" 2 | import abc 3 | from datetime import timezone 4 | from typing import List, Optional, Tuple 5 | 6 | from mode import Seconds 7 | 8 | __all__ = ['WindowRange', 'WindowT'] 9 | 10 | 11 | WindowRange = Tuple[float, float] 12 | 13 | 14 | def WindowRange_from_start(start: float, size: float) -> WindowRange: 15 | """Create new windowrange from start and size.""" 16 | end = start + size - 0.1 17 | return (start, end) 18 | 19 | 20 | class WindowT(abc.ABC): 21 | """Type class for windows.""" 22 | 23 | expires: Optional[float] = None 24 | tz: Optional[timezone] = None 25 | 26 | @abc.abstractmethod 27 | def ranges(self, timestamp: float) -> List[WindowRange]: 28 | ... 29 | 30 | @abc.abstractmethod 31 | def stale(self, timestamp: float, latest_timestamp: float) -> bool: 32 | ... 33 | 34 | @abc.abstractmethod 35 | def current(self, timestamp: float) -> WindowRange: 36 | ... 37 | 38 | @abc.abstractmethod 39 | def earliest(self, timestamp: float) -> WindowRange: 40 | ... 41 | 42 | @abc.abstractmethod 43 | def delta(self, timestamp: float, d: Seconds) -> WindowRange: 44 | ... 45 | -------------------------------------------------------------------------------- /examples/django/proj/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """Example Django project using Faust.""" 3 | # :copyright: (c) 2017-2019, Robinhood Markets, Inc. 4 | # All rights reserved. 5 | # :license: BSD (3 Clause), see LICENSE for more details. 6 | 7 | # -- Faust is a Python stream processing library 8 | # mainly used with Kafka, but is generic enough to be used for general 9 | # agent and channel based programming. 10 | 11 | import re 12 | from typing import NamedTuple 13 | 14 | __version__ = '0.9.3' 15 | __author__ = 'Robinhood Markets, Inc.' 16 | __contact__ = 'opensource@robinhood.com' 17 | __homepage__ = 'http://faust.readthedocs.io' 18 | __docformat__ = 'restructuredtext' 19 | 20 | # -eof meta- 21 | 22 | 23 | class version_info_t(NamedTuple): 24 | major: int 25 | minor: int 26 | micro: int 27 | releaselevel: str 28 | serial: str 29 | 30 | 31 | # bumpversion can only search for {current_version} 32 | # so we have to parse the version here. 33 | _temp = re.match( 34 | r'(\d+)\.(\d+).(\d+)(.+)?', __version__).groups() 35 | VERSION = version_info = version_info_t( 36 | int(_temp[0]), int(_temp[1]), int(_temp[2]), _temp[3] or '', '') 37 | del(_temp) 38 | del(re) 39 | 40 | __all__ = [] 41 | -------------------------------------------------------------------------------- /extra/supervisord/supervisord.conf: -------------------------------------------------------------------------------- 1 | ; example supervisord.conf 2 | ; This is probably outdated, so look at supervisor documentation. 3 | 4 | [unix_http_server] 5 | file=/tmp/supervisor.sock ; path to your socket file 6 | 7 | [supervisord] 8 | logfile=/var/log/supervisord/supervisord.log ; supervisord log file 9 | logfile_maxbytes=50MB ; maximum size of logfile before rotation 10 | logfile_backups=10 ; number of backed up logfiles 11 | loglevel=info ; info, debug, warn, trace 12 | pidfile=/var/run/supervisord.pid ; pidfile location 13 | nodaemon=false ; run supervisord as a daemon 14 | minfds=1024 ; number of startup file descriptors 15 | minprocs=200 ; number of process descriptors 16 | user=root ; default user 17 | childlogdir=/var/log/supervisord/ ; where child log files will live 18 | 19 | 20 | [rpcinterface:supervisor] 21 | supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface 22 | 23 | [supervisorctl] 24 | serverurl=unix:///tmp/supervisor.sock ; use unix:// schem for a unix sockets. 25 | 26 | 27 | [include] 28 | 29 | # Uncomment this line to add the Faust configuration. 30 | ;files=faust.conf 31 | 32 | -------------------------------------------------------------------------------- /extra/tools/verify_tabletest.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | _INFO=$( 4 | python -c' 5 | from examples.tabletest import EXPECTED_SUM, ITERATIONS, counts, app 6 | print("{0}:{1}:{2}:{3}".format( 7 | counts.changelog_topic.get_topic_name(), 8 | counts.changelog_topic.partitions or app.conf.topic_partitions, 9 | ITERATIONS, 10 | EXPECTED_SUM, 11 | )) 12 | ') 13 | 14 | CHANGELOG_TOPIC=$(echo $_INFO | cut -d: -f1) 15 | CHANGELOG_PARTITIONS=$(echo $_INFO | cut -d: -f2) 16 | ITERATIONS=$(echo $_INFO | cut -d: -f3) 17 | export EXPECTED_SUM=$(echo $_INFO | cut -d: -f4) 18 | 19 | if [ -z "$CHANGELOG_TOPIC" ]; then 20 | echo "Cannot find changelog topic name :-(" 21 | exit 1 22 | fi 23 | 24 | for i in $(seq 0 $(($CHANGELOG_PARTITIONS - 1))); do 25 | echo "Verifying changelog partition $i for $CHANGELOG_TOPIC..." 26 | kafka-console-consumer \ 27 | --bootstrap-server localhost:9092 \ 28 | --max-messages=$ITERATIONS \ 29 | --topic "$CHANGELOG_TOPIC" \ 30 | --partition=$i \ 31 | --from-beginning | 32 | python extra/tools/verify_tabletest_changelog.py 33 | if [[ $? != 0 ]]; then 34 | echo "exiting" 35 | exit $? 36 | fi 37 | done 38 | echo "ALL GOOD!" 39 | -------------------------------------------------------------------------------- /faust/cli/reset.py: -------------------------------------------------------------------------------- 1 | """Program ``faust reset`` used to delete local table state.""" 2 | from .base import AppCommand 3 | 4 | __all__ = ['reset'] 5 | 6 | 7 | class reset(AppCommand): 8 | """Delete local table state. 9 | 10 | Warning: 11 | This command will result in the destruction of the following files: 12 | 13 | 1) The local database directories/files backing tables 14 | (does not apply if an in-memory store like memory:// is used). 15 | 16 | Notes: 17 | This data is technically recoverable from the Kafka cluster (if 18 | intact), but it'll take a long time to get the data back as 19 | you need to consume each changelog topic in total. 20 | 21 | It'd be faster to copy the data from any standbys that happen 22 | to have the topic partitions you require. 23 | """ 24 | 25 | async def run(self) -> None: 26 | """Execute command.""" 27 | await self.reset_tables() 28 | 29 | async def reset_tables(self) -> None: 30 | """Reset local state for all tables.""" 31 | for table in self.app.tables.values(): 32 | self.say(f'Removing database for table {table.name}...') 33 | table.reset_state() 34 | -------------------------------------------------------------------------------- /docs/includes/resources.txt: -------------------------------------------------------------------------------- 1 | .. _getting-help: 2 | 3 | Getting Help 4 | ============ 5 | 6 | .. _mailing-list: 7 | 8 | Mailing list 9 | ------------ 10 | 11 | For discussions about the usage, development, and future of Faust, 12 | please join the `faust-users`_ mailing list. 13 | 14 | .. _`faust-users`: https://groups.google.com/group/faust-users/ 15 | 16 | .. _slack-channel: 17 | 18 | Slack 19 | ----- 20 | 21 | Come chat with us on Slack: 22 | 23 | https://join.slack.com/t/fauststream/shared_invite/enQtNDEzMTIyMTUyNzU2LTRkM2Q2ODkwZTk5MzczNmUxOGU0NWYxNzA2YzYwNTAyZmRiOTRmMzkyMDk0ODY2MjIzOTg2NGI0ODlmNTYxNTc 24 | 25 | Resources 26 | ========= 27 | 28 | .. _bug-tracker: 29 | 30 | Bug tracker 31 | ----------- 32 | 33 | If you have any suggestions, bug reports, or annoyances please report them 34 | to our issue tracker at https://github.com/robinhood/faust/issues/ 35 | 36 | .. _wiki: 37 | 38 | Wiki 39 | ---- 40 | 41 | https://wiki.github.com/robinhood/faust/ 42 | 43 | .. _license: 44 | 45 | License 46 | ======= 47 | 48 | This software is licensed under the `New BSD License`. See the :file:`LICENSE` 49 | file in the top distribution directory for the full license text. 50 | 51 | .. # vim: syntax=rst expandtab tabstop=4 shiftwidth=4 shiftround 52 | -------------------------------------------------------------------------------- /examples/advanced/service.py: -------------------------------------------------------------------------------- 1 | """examples/service.py 2 | 3 | This examples starts a separate :pypi:`mode` service with the app. 4 | 5 | If you want the service instance to be generally available 6 | you may create a subclass of app, to define a new app.myservice attribute: 7 | 8 | .. sourcecode:: python 9 | 10 | class App(faust.App): 11 | myservice: MyService 12 | 13 | def __init__(self, *args: Any, **kwargs: Any) -> None: 14 | self.myservice = self.service( 15 | MyService(loop=self.loop, beacon=self.beacon), 16 | ) 17 | 18 | app = App('service-example') 19 | """ 20 | import faust 21 | 22 | 23 | app = faust.App('service-example') 24 | 25 | 26 | @app.service 27 | class MyService(faust.Service): 28 | 29 | async def on_start(self) -> None: 30 | self.log.info('STARTED') 31 | 32 | async def on_stop(self) -> None: 33 | self.log.info('STOPPED') 34 | 35 | 36 | @app.agent(value_type=str) 37 | async def consumer(stream): 38 | async for message in stream: 39 | print(f'Received: {message!r}') 40 | 41 | 42 | @app.timer(1.0) 43 | async def producer(): 44 | await consumer.send('hello') 45 | 46 | 47 | if __name__ == '__main__': 48 | app.main() 49 | -------------------------------------------------------------------------------- /requirements/README.rst: -------------------------------------------------------------------------------- 1 | ==================================== 2 | Faust Requirement Files 3 | ==================================== 4 | 5 | + ``default.txt`` 6 | 7 | The requirements that are installed when you do ``pip install faust``. 8 | 9 | These are the core dependencies required for Faust to work. 10 | 11 | + ``extras/`` 12 | 13 | Extra requirements for Faust features like RocksDB storage, 14 | transports, and so on. These are added to ``setup.py`` so 15 | that you can do ``pip install faust[rocksdb]`` (see the 16 | installation guide in the documentation.) 17 | 18 | + ``docs.txt`` 19 | 20 | Requirements necessary to build the documentation 21 | with ``make Documentation``. 22 | 23 | + ``test.txt`` 24 | 25 | Requirements that are necessary to run the test suite. 26 | 27 | + ``ci.txt`` 28 | 29 | Requirements that are necessary to run the continuous integration 30 | test suite at Travis CI. 31 | 32 | + ``typecheck.txt`` 33 | 34 | Requirements that are necessary to run `make typecheck`. 35 | 36 | + ``dist.txt`` 37 | 38 | Requirements that are necessary when developing Faust. 39 | F.example these are needed for ``make flakes`` and doing 40 | releases to PyPI. 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /t/regression/i323/test_autodiscover.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import io 3 | import os 4 | import sys 5 | from contextlib import ExitStack, redirect_stderr, redirect_stdout 6 | import pytest 7 | from mode.utils.mocks import patch 8 | 9 | 10 | def test_main(*, app, loop): 11 | from proj323 import main 12 | 13 | neu_loop = asyncio.set_event_loop(asyncio.new_event_loop()) # noqa 14 | 15 | # must use the event loop fixture to ensure not using old loop. 16 | stdout = io.StringIO() 17 | stderr = io.StringIO() 18 | environ = dict(os.environ) 19 | try: 20 | with ExitStack() as stack: 21 | stack.enter_context(patch( 22 | 'sys.argv', 23 | ['proj', 'my_process_command_i323'])) 24 | stack.enter_context(pytest.raises(SystemExit)) 25 | stack.enter_context(redirect_stdout(stdout)) 26 | stack.enter_context(redirect_stderr(stderr)) 27 | assert sys.argv == ['proj', 'my_process_command_i323'] 28 | 29 | main() 30 | finally: 31 | os.environ.clear() 32 | os.environ.update(environ) 33 | print(f'STDOUT: {stdout.getvalue()!r}') 34 | print(f'STDERR: {stderr.getvalue()!r}') 35 | assert 'HELLO WORLD #323' in stdout.getvalue() 36 | -------------------------------------------------------------------------------- /t/integration/cli/test_models.py: -------------------------------------------------------------------------------- 1 | def test_json(faust_json): 2 | exitcode, models, stderr = faust_json('models', '--builtins') 3 | assert not exitcode 4 | 5 | assert {'name': 'app.Arena', 'help': ''} in models 6 | assert {'name': 'app.Point', 'help': ''} in models 7 | assert {'name': '@ReqRepResponse', 8 | 'help': 'Request-Reply response.'} in models 9 | 10 | names = [model['name'] for model in models] 11 | assert (names.index('@ReqRepResponse') < 12 | names.index('app.Arena') < 13 | names.index('app.Point')) # sorted 14 | 15 | 16 | def test_tabulated(faust): 17 | exitcode, stdout, stderr = faust('models', '--builtins') 18 | assert not exitcode 19 | assert b'Arena' in stdout 20 | 21 | 22 | def test_colors(faust_color): 23 | exitcode, stdout, stderr = faust_color('models', '--builtins') 24 | assert not exitcode 25 | assert b'Point' in stdout 26 | 27 | 28 | def test_json_no_local(faust_json): 29 | exitcode, models, stderr = faust_json('models') 30 | assert not exitcode 31 | 32 | names = [model['name'] for model in models] 33 | assert 'app.Arena' in names 34 | assert 'app.Point' in names 35 | assert names.index('app.Arena') < names.index('app.Point') # sorted 36 | -------------------------------------------------------------------------------- /faust/utils/urls.py: -------------------------------------------------------------------------------- 1 | """URL utilities - Working with URLs.""" 2 | from typing import List, Optional, Union 3 | from yarl import URL 4 | 5 | 6 | def urllist(arg: Union[URL, str, List[str], List[URL]], *, 7 | default_scheme: str = None) -> List[URL]: 8 | """Create list of URLs. 9 | 10 | You can pass in a comma-separated string, or an actual list 11 | and this will convert that into a list of :class:`yarl.URL` objects. 12 | """ 13 | if not arg: 14 | raise ValueError('URL argument cannot be falsy') 15 | 16 | if isinstance(arg, URL): 17 | arg = [arg] 18 | elif isinstance(arg, str): 19 | arg = arg.split(';') 20 | 21 | scheme = URL(arg[0]).scheme or default_scheme 22 | return [_ensure_scheme(scheme, URL(u)) for u in arg] 23 | 24 | 25 | def _ensure_scheme(default_scheme: Optional[str], url: Union[URL]) -> URL: 26 | """Ensure URL has a default scheme. 27 | 28 | An URL like "localhost" will be returned with the default scheme 29 | added, while an URL with existing scheme is returned unmodified. 30 | """ 31 | if default_scheme and not url.scheme: 32 | if url.is_absolute(): 33 | return url.with_scheme(default_scheme) 34 | else: 35 | return URL(f'{default_scheme}://{url}') 36 | return url 37 | -------------------------------------------------------------------------------- /t/unit/test_joins.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from faust import Event, Record, Stream 3 | from faust.joins import InnerJoin, Join, LeftJoin, OuterJoin, RightJoin 4 | from mode.utils.mocks import Mock 5 | 6 | 7 | class User(Record): 8 | id: str 9 | name: str 10 | 11 | 12 | @pytest.mark.asyncio 13 | @pytest.mark.parametrize('join_cls,fields', [ 14 | (Join, (User.id, User.name)), 15 | (InnerJoin, (User.id, User.name)), 16 | (LeftJoin, (User.id, User.name)), 17 | (OuterJoin, (User.id, User.name)), 18 | (RightJoin, (User.id, User.name)), 19 | ]) 20 | async def test_Join(join_cls, fields): 21 | stream = Mock(name='stream', autospec=Stream) 22 | j = join_cls(stream=stream, fields=fields) 23 | assert j.fields 24 | assert j.stream is stream 25 | 26 | with pytest.raises(NotImplementedError): 27 | await j.process(Mock(name='event', autospec=Event)) 28 | 29 | 30 | def test_eq_ne(): 31 | stream = Mock(name='stream', autospec=Stream) 32 | assert (InnerJoin(stream=stream, fields=(User.id,)) == 33 | InnerJoin(stream=stream, fields=(User.id,))) 34 | assert (InnerJoin(stream=stream, fields=(User.id,)) != 35 | Join(stream=stream, fields=(User.id,))) 36 | assert (InnerJoin(stream=stream, fields=(User.name,)) != 37 | InnerJoin(stream=stream, fields=(User.id,))) 38 | -------------------------------------------------------------------------------- /t/integration/cli/test_agents.py: -------------------------------------------------------------------------------- 1 | def test_json(faust_json): 2 | exitcode, agents, stderr = faust_json('agents', '--local') 3 | assert not exitcode 4 | 5 | assert {'name': '@app.mul', 6 | 'topic': 't-integration-app.mul', 7 | 'help': 'Foo agent help.'} in agents 8 | assert {'name': '@app.add', 9 | 'topic': 'add-topic', 10 | 'help': ''} in agents 11 | assert {'name': '@app.internal', 12 | 'topic': '', 13 | 'help': ''} in agents 14 | 15 | names = [agent['name'] for agent in agents] 16 | assert names.index('@app.add') < \ 17 | names.index('@app.internal') < \ 18 | names.index('@app.mul') 19 | 20 | 21 | def test_tabulated(faust): 22 | exitcode, stdout, stderr = faust('agents', '--local') 23 | assert not exitcode 24 | assert b'@app.mul' in stdout 25 | 26 | 27 | def test_colors(faust_color): 28 | exitcode, stdout, stderr = faust_color('agents', '--local') 29 | assert not exitcode 30 | assert b'@app.mul' in stdout 31 | 32 | 33 | def test_json_no_local(faust_json): 34 | exitcode, agents, stderr = faust_json('agents') 35 | assert not exitcode 36 | 37 | names = [agent['name'] for agent in agents] 38 | assert '@app.mul' in names 39 | assert '@app.add' in names 40 | assert '@app.internal' not in names 41 | -------------------------------------------------------------------------------- /faust/joins.py: -------------------------------------------------------------------------------- 1 | """Join strategies.""" 2 | from typing import Any, Optional, Tuple 3 | from .types import EventT, FieldDescriptorT, JoinT, JoinableT 4 | 5 | __all__ = [ 6 | 'Join', 7 | 'RightJoin', 8 | 'LeftJoin', 9 | 'InnerJoin', 10 | 'OuterJoin', 11 | ] 12 | 13 | 14 | class Join(JoinT): 15 | """Base class for join strategies.""" 16 | 17 | def __init__(self, *, stream: JoinableT, 18 | fields: Tuple[FieldDescriptorT, ...]) -> None: 19 | self.fields = {field.model: field for field in fields} 20 | self.stream = stream 21 | 22 | async def process(self, event: EventT) -> Optional[EventT]: 23 | """Process event to be joined with another event.""" 24 | raise NotImplementedError() 25 | 26 | def __eq__(self, other: Any) -> bool: 27 | if isinstance(other, type(self)): 28 | return (other.fields == self.fields and 29 | other.stream is self.stream) 30 | return False 31 | 32 | def __ne__(self, other: Any) -> bool: 33 | return not self.__eq__(other) 34 | 35 | 36 | class RightJoin(Join): 37 | """Right-join strategy.""" 38 | 39 | 40 | class LeftJoin(Join): 41 | """Left-join strategy.""" 42 | 43 | 44 | class InnerJoin(Join): 45 | """Inner-join strategy.""" 46 | 47 | 48 | class OuterJoin(Join): 49 | """Outer-join strategy.""" 50 | -------------------------------------------------------------------------------- /examples/django/accounts/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.1.4 on 2018-12-24 12:13 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | initial = True 9 | 10 | dependencies = [ 11 | ] 12 | 13 | operations = [ 14 | migrations.CreateModel( 15 | name='Account', 16 | fields=[ 17 | ('id', models.AutoField(auto_created=True, 18 | primary_key=True, 19 | serialize=False, 20 | verbose_name='ID')), 21 | ('name', models.CharField(max_length=100, 22 | verbose_name='name')), 23 | ('score', models.DecimalField(decimal_places=1000, 24 | default=0.0, 25 | max_digits=1000, 26 | verbose_name='score')), 27 | ('active', models.BooleanField(default=True, 28 | verbose_name='active')), 29 | ], 30 | options={ 31 | 'verbose_name': 'account', 32 | 'verbose_name_plural': 'accounts', 33 | }, 34 | ), 35 | ] 36 | -------------------------------------------------------------------------------- /t/docs/testing/test_figC_windowed_table.py: -------------------------------------------------------------------------------- 1 | import faust 2 | import pytest 3 | 4 | 5 | class Order(faust.Record, serializer='json'): 6 | account_id: str 7 | product_id: str 8 | amount: int 9 | price: float 10 | 11 | 12 | app = faust.App('test-example') 13 | orders_topic = app.topic('orders', value_type=Order) 14 | 15 | # order count within the last hour (window is a 1-hour TumblingWindow). 16 | orders_for_account = app.Table( 17 | 'order-count-by-account', default=int, 18 | ).tumbling(3600).relative_to_stream() 19 | 20 | 21 | @app.agent(orders_topic) 22 | async def process_order(orders): 23 | async for order in orders.group_by(Order.account_id): 24 | orders_for_account[order.account_id] += 1 25 | yield order 26 | 27 | 28 | @pytest.mark.asyncio() 29 | async def test_process_order(): 30 | app.finalize() 31 | app.conf.store = 'memory://' 32 | app.flow_control.resume() 33 | async with process_order.test_context() as agent: 34 | order = Order(account_id='1', product_id='2', amount=1, price=300) 35 | event = await agent.put(order) 36 | 37 | # windowed table: we select window relative to the current event 38 | assert orders_for_account['1'].current(event) == 1 39 | 40 | # in the window 3 hours ago there were no orders: 41 | assert not orders_for_account['1'].delta(3600 * 3, event) 42 | -------------------------------------------------------------------------------- /t/regression/i324/test_autodiscover.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import io 3 | import os 4 | import sys 5 | from contextlib import ExitStack, redirect_stderr, redirect_stdout 6 | import pytest 7 | from mode.utils.mocks import patch 8 | 9 | 10 | def test_main(*, app, loop): 11 | from proj324 import main 12 | 13 | neu_loop = asyncio.set_event_loop(asyncio.new_event_loop()) # noqa 14 | 15 | # must use the event loop fixture to ensure not using old loop. 16 | stdout = io.StringIO() 17 | stderr = io.StringIO() 18 | environ = dict(os.environ) 19 | try: 20 | with ExitStack() as stack: 21 | stack.enter_context(patch( 22 | 'sys.argv', 23 | ['proj', 'my_process_command_i324'])) 24 | assert sys.argv == ['proj', 'my_process_command_i324'] 25 | stack.enter_context(pytest.raises(SystemExit)) 26 | stack.enter_context(redirect_stdout(stdout)) 27 | stack.enter_context(redirect_stderr(stderr)) 28 | 29 | main() 30 | finally: 31 | os.environ.clear() 32 | os.environ.update(environ) 33 | print(f'STDOUT: {stdout.getvalue()!r}') 34 | print(f'STDERR: {stderr.getvalue()!r}') 35 | assert 'IMPORTS __MAIN__' not in stdout.getvalue() 36 | assert 'TEST FILE IMPORTED' not in stdout.getvalue() 37 | assert 'HELLO WORLD #324' in stdout.getvalue() 38 | -------------------------------------------------------------------------------- /faust/types/auth.py: -------------------------------------------------------------------------------- 1 | import ssl 2 | from enum import Enum 3 | from typing import Optional, Union 4 | 5 | __all__ = [ 6 | 'AUTH_PROTOCOLS_SSL', 7 | 'AUTH_PROTOCOLS_SASL', 8 | 'AuthProtocol', 9 | 'CredentialsArg', 10 | 'CredentialsT', 11 | 'SASLMechanism', 12 | 'to_credentials', 13 | ] 14 | 15 | 16 | class AuthProtocol(Enum): 17 | SSL = 'SSL' 18 | PLAINTEXT = 'PLAINTEXT' 19 | SASL_PLAINTEXT = 'SASL_PLAINTEXT' 20 | SASL_SSL = 'SASL_SSL' 21 | 22 | 23 | class SASLMechanism(Enum): 24 | PLAIN = 'PLAIN' 25 | GSSAPI = 'GSSAPI' 26 | 27 | 28 | AUTH_PROTOCOLS_SSL = {AuthProtocol.SSL, AuthProtocol.SASL_SSL} 29 | AUTH_PROTOCOLS_SASL = {AuthProtocol.SASL_PLAINTEXT, AuthProtocol.SASL_SSL} 30 | 31 | 32 | class CredentialsT: 33 | protocol: AuthProtocol 34 | 35 | 36 | CredentialsArg = Union[CredentialsT, ssl.SSLContext] 37 | 38 | 39 | def to_credentials(obj: CredentialsArg = None) -> Optional[CredentialsT]: 40 | if obj is not None: 41 | from faust.auth import SSLCredentials # XXX :( 42 | if isinstance(obj, ssl.SSLContext): 43 | return SSLCredentials(obj) 44 | if isinstance(obj, CredentialsT): 45 | return obj 46 | from faust.exceptions import ImproperlyConfigured 47 | raise ImproperlyConfigured( 48 | f'Unknown credentials type {type(obj)}: {obj}') 49 | return None 50 | -------------------------------------------------------------------------------- /faust/livecheck/exceptions.py: -------------------------------------------------------------------------------- 1 | """LiveCheck - related exceptions.""" 2 | 3 | __all__ = [ 4 | 'LiveCheckError', 5 | 'SuiteFailed', 6 | 'ServiceDown', 7 | 'SuiteStalled', 8 | 'TestSkipped', 9 | 'TestFailed', 10 | 'TestRaised', 11 | 'TestTimeout', 12 | ] 13 | 14 | 15 | class LiveCheckError(Exception): 16 | """Generic base class for LiveCheck test errors.""" 17 | 18 | 19 | class SuiteFailed(LiveCheckError): 20 | """The whole test suite failed (not just a test).""" 21 | 22 | 23 | class ServiceDown(SuiteFailed): 24 | """Suite failed after a depending service is not responding. 25 | 26 | Used when for example a test case is periodically sending 27 | requests to a HTTP service, and that HTTP server is not responding. 28 | """ 29 | 30 | 31 | class SuiteStalled(SuiteFailed): 32 | """The suite is not running. 33 | 34 | Raised when ``warn_stalled_after=3600`` is set and there has not 35 | been any execution requests in the last hour. 36 | """ 37 | 38 | 39 | class TestSkipped(LiveCheckError): 40 | """Test was skipped.""" 41 | 42 | 43 | class TestFailed(LiveCheckError): 44 | """The test failed an assertion.""" 45 | 46 | 47 | class TestRaised(LiveCheckError): 48 | """The test raised an exception.""" 49 | 50 | 51 | class TestTimeout(LiveCheckError): 52 | """The test timed out waiting for an event or during processing.""" 53 | -------------------------------------------------------------------------------- /docs/includes/blurb.txt: -------------------------------------------------------------------------------- 1 | **Faust** is a Python library for event processing and streaming applications 2 | that are decentralized and fault-tolerant. 3 | 4 | It's inspired by tools such as `Kafka Streams`_, `Apache Spark`_, 5 | `Apache Storm`_, `Apache Samza`_ and `Apache Flink`_; but takes 6 | a radically more straightforward approach to stream processing. 7 | 8 | Modern web applications are increasingly built as a collection 9 | of micro services and even before this, it has been difficult to write 10 | data reporting operations at scale. In a reactive stream based system, 11 | you don't have to strain your database with costly queries. In Faust, 12 | a streaming data pipeline updates information as events happen 13 | in your system, in real-time. 14 | 15 | Faust also enables you to take advantage of :mod:`asyncio` and asynchronous 16 | processing, moving complicated and costly operations outside 17 | of the web server process: converting video, notifying third-party services, 18 | etc. are common use cases for event processing. 19 | 20 | You may not know it yet, but if you're writing a modern web application, 21 | you probably already need Faust. 22 | 23 | .. _`Kafka Streams`: https://kafka.apache.org/documentation/streams 24 | .. _`Apache Spark`: http://spark.apache.org 25 | .. _`Apache Storm`: http://storm.apache.org 26 | .. _`Apache Flink`: http://flink.apache.org 27 | .. _`Apache Samza`: http://samza.apache.org 28 | 29 | -------------------------------------------------------------------------------- /t/unit/cli/test_params.py: -------------------------------------------------------------------------------- 1 | import click.exceptions 2 | import pytest 3 | from yarl import URL 4 | from faust.cli.params import CaseInsensitiveChoice, TCPPort, URLParam 5 | 6 | 7 | def test_CaseInsensitiveChoice(): 8 | choices = CaseInsensitiveChoice([ 9 | 'FOO', 10 | 'BAR', 11 | 'baz', 12 | ]) 13 | 14 | assert choices.convert('FOO', None, None) == 'FOO' 15 | assert choices.convert('foo', None, None) == 'foo' 16 | assert choices.convert('Foo', None, None) == 'Foo' 17 | assert choices.convert('BAZ', None, None) == 'BAZ' 18 | 19 | with pytest.raises(click.exceptions.BadParameter): 20 | choices.convert('xuz', None, None) 21 | 22 | 23 | def test_TCPPort(): 24 | port = TCPPort() 25 | assert port.convert(1, None, None) == 1 26 | assert port.convert(30, None, None) == 30 27 | assert port.convert(65535, None, None) == 65535 28 | with pytest.raises(click.exceptions.BadParameter): 29 | port.convert(0, None, None) 30 | with pytest.raises(click.exceptions.BadParameter): 31 | port.convert(-312, None, None) 32 | with pytest.raises(click.exceptions.BadParameter): 33 | port.convert(513412321, None, None) 34 | with pytest.raises(click.exceptions.BadParameter): 35 | port.convert(65536, None, None) 36 | 37 | 38 | def test_URLParam(): 39 | urlp = URLParam() 40 | assert repr(urlp) == 'URL' 41 | 42 | url = urlp.convert('http://foo.com/path/', None, None) 43 | assert isinstance(url, URL) 44 | assert url.host == 'foo.com' 45 | -------------------------------------------------------------------------------- /examples/tableofset.py: -------------------------------------------------------------------------------- 1 | import faust 2 | from faust.cli import argument 3 | 4 | app = faust.App( 5 | 'table-of-sets-windowed', 6 | origin='examples.tableofset', 7 | topic_partitions=4, 8 | version=2, 9 | ) 10 | 11 | table = app.SetTable( 12 | 'people', value_type=str, 13 | ) 14 | 15 | joining_topic = app.topic('people_joining2', key_type=str, value_type=str) 16 | leaving_topic = app.topic('people_leaving2', key_type=str, value_type=str) 17 | 18 | 19 | @app.agent(joining_topic) 20 | async def join(stream): 21 | async for key, name in stream.items(): 22 | print(f'- {name.capitalize()} joined {key}') 23 | table[key].add(name) 24 | print(f'TABLE CUR: {table[key]!r}') 25 | 26 | 27 | @app.agent(leaving_topic) 28 | async def leave(stream): 29 | async for key, name in stream.items(): 30 | print(f'- {name.capitalize()} left {key}') 31 | table[key].discard(name) 32 | print(f'TABLE CUR: {table[key]!r}') 33 | 34 | 35 | @app.command( 36 | argument('location'), 37 | argument('name'), 38 | ) 39 | async def joining(self, location: str, name: str): 40 | await joining_topic.send(key=location, value=name) 41 | 42 | 43 | @app.command( 44 | argument('location'), 45 | argument('name'), 46 | ) 47 | async def leaving(self, location: str, name: str): 48 | await leaving_topic.send(key=location, value=name) 49 | 50 | 51 | @app.timer(10.0) 52 | async def _dump(): 53 | print(f'TABLE NOW:\n{table.as_ansitable()}') 54 | 55 | 56 | if __name__ == '__main__': 57 | app.main() 58 | -------------------------------------------------------------------------------- /faust/types/_env.py: -------------------------------------------------------------------------------- 1 | """Faust environment variables.""" 2 | import os 3 | from typing import Any, Sequence 4 | from yarl import URL 5 | 6 | __all__ = [ 7 | 'BLOCKING_TIMEOUT', 8 | 'CONSOLE_PORT', 9 | 'DATADIR', 10 | 'DEBUG', 11 | 'STRICT', 12 | 'WEB_PORT', 13 | 'WEB_BIND', 14 | 'WEB_TRANSPORT', 15 | 'WORKDIR', 16 | ] 17 | 18 | PREFICES: Sequence[str] = ['FAUST_', 'F_'] 19 | 20 | 21 | def _getenv(name: str, *default: Any, 22 | prefices: Sequence[str] = PREFICES) -> Any: 23 | for prefix in prefices: 24 | try: 25 | return os.environ[prefix + name] 26 | except KeyError: 27 | pass 28 | if default: 29 | return default[0] 30 | raise KeyError(prefices[0] + name) 31 | 32 | 33 | #: Enables debugging features (like blockdetection). 34 | DEBUG: bool = bool(_getenv('DEBUG', False)) 35 | 36 | #: Working directory to change into at start. 37 | WORKDIR: str = _getenv('WORKDIR', None) 38 | 39 | #: Directory to keep the application state (tables, checkpoints, etc). 40 | DATADIR: str = _getenv('DATADIR', '{conf.name}-data') 41 | 42 | #: Blocking detection timeout 43 | BLOCKING_TIMEOUT: float = float(_getenv('BLOCKING_TIMEOUT', '10.0')) 44 | 45 | #: :pypi:`aiomonitor` console default port 46 | CONSOLE_PORT: int = int(_getenv('CONSOLE_PORT', 50101)) 47 | 48 | STRICT: bool = bool(_getenv('STRICT', False)) 49 | 50 | WEB_PORT: int = int(_getenv('WEB_PORT', '6066')) 51 | WEB_BIND: str = _getenv('F_WEB_BIND', '0.0.0.0') 52 | WEB_TRANSPORT: URL = URL(_getenv('WEB_TRANSPORT', 'tcp://')) 53 | -------------------------------------------------------------------------------- /t/integration/cli/test_model.py: -------------------------------------------------------------------------------- 1 | class test_Arena: 2 | 3 | def test_json(self, faust_json): 4 | exitcode, model, stderr = faust_json('model', 'app.Arena') 5 | assert not exitcode 6 | 7 | assert model == [ 8 | {'field': 'points', 9 | 'type': 'typing.List[__main__.Point]', 10 | 'default': '*'}, 11 | {'field': 'timestamp', 12 | 'type': 'float', 13 | 'default': 'None'}, 14 | ] 15 | 16 | def test_tabulated(self, faust): 17 | exitcode, stdout, stderr = faust('model', 'app.Arena') 18 | assert not exitcode 19 | assert b'typing.List' in stdout 20 | 21 | def test_colors(self, faust_color): 22 | exitcode, stdout, stderr = faust_color('model', 'app.Arena') 23 | assert b'typing.List' in stdout 24 | 25 | 26 | class test_Point: 27 | 28 | def test_json(self, faust_json): 29 | exitcode, model, stderr = faust_json('model', 'app.Point') 30 | assert not exitcode 31 | 32 | assert model == [ 33 | {'field': 'x', 'type': 'int', 'default': '*'}, 34 | {'field': 'y', 'type': 'int', 'default': '*'}, 35 | ] 36 | 37 | def test_tabulated(self, faust): 38 | exitcode, stdout, stderr = faust('model', 'app.Point') 39 | assert not exitcode 40 | assert b'int' in stdout 41 | 42 | def test_colors(self, faust_color): 43 | exitcode, stdout, stderr = faust_color('model', 'app.Point') 44 | assert not exitcode 45 | assert b'int' in stdout 46 | -------------------------------------------------------------------------------- /faust/web/apps/stats.py: -------------------------------------------------------------------------------- 1 | """HTTP endpoint showing statistics from the Faust monitor.""" 2 | from collections import defaultdict 3 | from typing import List, MutableMapping, Set 4 | from faust import web 5 | from faust.types.tuples import TP 6 | 7 | __all__ = ['Assignment', 'Stats', 'blueprint'] 8 | 9 | TPMap = MutableMapping[str, List[int]] 10 | 11 | 12 | blueprint = web.Blueprint('monitor') 13 | 14 | 15 | @blueprint.route('/', name='index') 16 | class Stats(web.View): 17 | """Monitor statistics.""" 18 | 19 | async def get(self, request: web.Request) -> web.Response: 20 | """Return JSON response with sensor information.""" 21 | return self.json( 22 | {f'Sensor{i}': s.asdict() 23 | for i, s in enumerate(self.app.sensors)}) 24 | 25 | 26 | @blueprint.route('/assignment/', name='assignment') 27 | class Assignment(web.View): 28 | """Cluster assignment information.""" 29 | 30 | @classmethod 31 | def _topic_grouped(cls, assignment: Set[TP]) -> TPMap: 32 | tps: MutableMapping[str, List[int]] = defaultdict(list) 33 | for tp in sorted(assignment): 34 | tps[tp.topic].append(tp.partition) 35 | return dict(tps) 36 | 37 | async def get(self, request: web.Request) -> web.Response: 38 | """Return current assignment as a JSON response.""" 39 | assignor = self.app.assignor 40 | return self.json({ 41 | 'actives': self._topic_grouped(assignor.assigned_actives()), 42 | 'standbys': self._topic_grouped(assignor.assigned_standbys()), 43 | }) 44 | -------------------------------------------------------------------------------- /t/unit/livecheck/conftest.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime, timedelta, timezone 2 | import pytest 3 | from mode.utils.mocks import ContextMock, patch 4 | from faust.livecheck.models import TestExecution 5 | from faust.livecheck.runners import TestRunner 6 | 7 | 8 | @pytest.fixture() 9 | def livecheck(*, app): 10 | return app.LiveCheck() 11 | 12 | 13 | @pytest.fixture() 14 | def execution(): 15 | now = datetime.now().astimezone(timezone.utc) 16 | expires = now + timedelta(hours=3) 17 | return TestExecution( 18 | id='id', 19 | case_name='t.examples.test_foo', 20 | timestamp=now, 21 | test_args=('foo',), 22 | test_kwargs={'kw1': 1.03}, 23 | expires=expires, 24 | ) 25 | 26 | 27 | @pytest.fixture() 28 | def case(*, livecheck): 29 | @livecheck.case() 30 | class test_foo(livecheck.Case): 31 | 32 | async def run(self, arg1, kw1=None): 33 | assert arg1 == 'foo' 34 | assert kw1 == 1.03 35 | assert True 36 | return test_foo 37 | 38 | 39 | @pytest.fixture() 40 | def runner(*, execution, case): 41 | return TestRunner(case, execution, started=100.0) 42 | 43 | 44 | @pytest.yield_fixture() 45 | def current_test_stack(): 46 | with patch('faust.livecheck.case.current_test_stack') as cts: 47 | cts.push = ContextMock() 48 | yield cts 49 | 50 | 51 | @pytest.yield_fixture() 52 | def current_execution_stack(): 53 | with patch('faust.livecheck.case.current_execution_stack') as ces: 54 | ces.push = ContextMock() 55 | yield ces 56 | -------------------------------------------------------------------------------- /examples/kubernetes/producer/producer.py: -------------------------------------------------------------------------------- 1 | import json 2 | from random import random 3 | from kafka import KafkaProducer 4 | 5 | TOPIC = 'test' 6 | KEY = 'score' 7 | 8 | 9 | def publish_message(producer_instance, topic_name, key, value): 10 | try: 11 | key_bytes = bytes(key, encoding='utf-8') 12 | value_bytes = bytes(value, encoding='utf-8') 13 | producer_instance.send(topic_name, key=key_bytes, value=value_bytes) 14 | producer_instance.flush() 15 | print('Message published successfully.') 16 | except Exception as ex: 17 | print('Exception in publishing message') 18 | print(ex) 19 | 20 | 21 | def connect_kafka_producer(): 22 | _producer = None 23 | try: 24 | # host.docker.internal is how a docker container connects to the local 25 | # machine. 26 | # Don't use in production, this only works with Docker for Mac in 27 | # development 28 | _producer = KafkaProducer( 29 | bootstrap_servers=['host.docker.internal:9092'], 30 | api_version=(0, 10)) 31 | except Exception as ex: 32 | print('Exception while connecting Kafka') 33 | print(ex) 34 | finally: 35 | return _producer 36 | 37 | 38 | if __name__ == '__main__': 39 | kafka_producer = connect_kafka_producer() 40 | for index in range(0, 10000): 41 | message = { 42 | 'index': index, 43 | 'value': round(random(), 2), 44 | } 45 | publish_message(kafka_producer, TOPIC, KEY, json.dumps(message)) 46 | if kafka_producer is not None: 47 | kafka_producer.close() 48 | -------------------------------------------------------------------------------- /faust/assignor/leader_assignor.py: -------------------------------------------------------------------------------- 1 | """Leader assignor.""" 2 | from typing import Any 3 | from mode import Service 4 | from mode.utils.objects import cached_property 5 | from faust.types import AppT, TP, TopicT 6 | from faust.types.assignor import LeaderAssignorT 7 | 8 | __all__ = ['LeaderAssignor'] 9 | 10 | 11 | class LeaderAssignor(Service, LeaderAssignorT): 12 | """Leader assignor, ensures election of a leader.""" 13 | 14 | def __init__(self, app: AppT, **kwargs: Any) -> None: 15 | Service.__init__(self, **kwargs) 16 | self.app = app 17 | 18 | async def on_start(self) -> None: 19 | if not self.app.conf.topic_disable_leader: 20 | await self._enable_leader_topic() 21 | 22 | async def _enable_leader_topic(self) -> None: 23 | leader_topic = self._leader_topic 24 | await leader_topic.maybe_declare() 25 | self.app.topics.add(leader_topic) 26 | self.app.consumer.randomly_assigned_topics.add( 27 | leader_topic.get_topic_name()) 28 | 29 | @cached_property 30 | def _leader_topic(self) -> TopicT: 31 | return self.app.topic( 32 | self._leader_topic_name, 33 | partitions=1, 34 | acks=False, 35 | internal=True, 36 | ) 37 | 38 | @cached_property 39 | def _leader_topic_name(self) -> str: 40 | return f'{self.app.conf.id}-__assignor-__leader' 41 | 42 | @cached_property 43 | def _leader_tp(self) -> TP: 44 | return TP(self._leader_topic_name, 0) 45 | 46 | def is_leader(self) -> bool: 47 | return self._leader_tp in self.app.consumer.assignment() 48 | -------------------------------------------------------------------------------- /faust/types/serializers.py: -------------------------------------------------------------------------------- 1 | import abc 2 | import typing 3 | from typing import Any, Optional 4 | 5 | from .codecs import CodecArg 6 | from .core import K, V 7 | 8 | if typing.TYPE_CHECKING: 9 | from .models import ModelArg as _ModelArg 10 | else: 11 | class _ModelArg: ... # noqa 12 | 13 | __all__ = ['RegistryT'] 14 | 15 | 16 | class RegistryT(abc.ABC): 17 | 18 | key_serializer: CodecArg 19 | value_serializer: CodecArg 20 | 21 | @abc.abstractmethod 22 | def __init__(self, 23 | key_serializer: CodecArg = None, 24 | value_serializer: CodecArg = 'json') -> None: 25 | ... 26 | 27 | @abc.abstractmethod 28 | def loads_key(self, 29 | typ: Optional[_ModelArg], 30 | key: Optional[bytes], 31 | *, 32 | serializer: CodecArg = None) -> K: 33 | ... 34 | 35 | @abc.abstractmethod 36 | def loads_value(self, 37 | typ: Optional[_ModelArg], 38 | value: Optional[bytes], 39 | *, 40 | serializer: CodecArg = None) -> Any: 41 | ... 42 | 43 | @abc.abstractmethod 44 | def dumps_key(self, 45 | typ: Optional[_ModelArg], 46 | key: K, 47 | *, 48 | serializer: CodecArg = None) -> Optional[bytes]: 49 | ... 50 | 51 | @abc.abstractmethod 52 | def dumps_value(self, 53 | typ: Optional[_ModelArg], 54 | value: V, 55 | *, 56 | serializer: CodecArg = None) -> Optional[bytes]: 57 | ... 58 | --------------------------------------------------------------------------------