temporalint
Static checks for Temporal Python SDK code. Temporal's workflow APIs fail at runtime for mistakes Python will not catch: a missing activity timeout, a discarded coroutine, a workflow class the worker will reject, or a nondeterministic call that breaks replay.
Install
pip install temporalint
Usage
temporalint [paths...] [--select TPL001,TPL007] [--ignore TPL009]
Rules
| ID | Name | Description |
|---|---|---|
| TPL001 | activity-timeout | Activity call without start_to_close_timeout or schedule_to_close_timeout. |
| TPL002 | arg-and-args | Activity or child workflow call passing both arg and a non-empty args. |
| TPL003 | activity-unlimited-retry | Activity call whose retries are unbounded: no maximum_attempts in its retry_policy and no schedule_to_close_timeout. Off by default. |
| TPL004 | missing-heartbeat | Activity started with heartbeat_timeout whose same-module definition never calls activity.heartbeat. |
| TPL005 | workflow-defn-shape | @workflow.defn class without exactly one async @workflow.run method. |
| TPL006 | query-without-return | @workflow.query method that never returns a value. |
| TPL007 | missing-await | Async workflow API called without await. |
| TPL008 | nondeterministic-call | Nondeterministic call such as datetime.now(), random.*, or uuid.uuid4() in workflow code. |
| TPL009 | workflow-logger | print or logging in workflow code instead of workflow.logger. |
| TPL010 | workflow-exception | Workflow uses assert or raises an exception other than a Temporal failure such as ApplicationError. |
Configuration
Settings can live in temporalint.toml, .temporalint.toml, or pyproject.toml. Discovery starts at the working directory and walks toward the filesystem root. In each directory, temporalint.toml wins over .temporalint.toml, which wins over pyproject.toml. Every rule except TPL003 is enabled when select and ignore are omitted. List TPL003 in select to turn it on.
temporalint.toml and .temporalint.toml put the keys at the top level:
select = ["TPL001", "TPL002", "TPL003", "TPL004", "TPL005", "TPL006", "TPL007", "TPL008", "TPL009", "TPL010"]
ignore = ["TPL009"]
exclude = ["tests/**", "**/migrations/**"]
The same settings in pyproject.toml sit under [tool.temporalint]:
[tool.temporalint]
select = ["TPL001", "TPL002", "TPL003", "TPL004", "TPL005", "TPL006", "TPL007", "TPL008", "TPL009", "TPL010"]
ignore = ["TPL009"]
exclude = ["tests/**", "**/migrations/**"]
--select and --ignore replace the corresponding config values when you pass them. exclude is a list of glob patterns matched against the path relative to the config file's directory. An explicit file argument is still linted when it matches an exclude pattern.
Limitations
- Helper functions called from a workflow are not analyzed. Keep determinism-sensitive code in the workflow class, or review helpers separately.
from temporalio.workflow import *and relative imports are not resolved.- The timeout check looks for the keyword, not the value.
start_to_close_timeout=Noneis not reported, and**kwargssuppresses TPL001. - Argument counts, payload types, and activity names passed as strings are not checked yet.
- TPL004 only follows activities and helpers defined in the same module. It stays quiet when the activity has another decorator or calls an imported non-stdlib function or an unknown name, because those may heartbeat. Method calls on objects other than
selfare assumed not to heartbeat. - TPL010 cannot see
workflow_failure_exception_typeson the worker. A type allowed only there is still reported.
Metadata
Release files for temporalint 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| temporalint-0.1.1.tar.gz | 16.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| temporalint-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 34.5 kB
Release files / temporalint-0.1.1.tar.gz
| Download URL | temporalint-0.1.1.tar.gz |
|---|---|
| Size | 16.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
cfaf5df950278e6cbe4f9d17e01fef999c3e1444fb31ded25d2fad8ea9bfde76
|
|
BLAKE2b-256 checksum How to use checksums |
7dd3e668b51076594d898ce86e9d25d773e4ec57edd3962b8d5f6e11e39c6677
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 8, 2026.
Transparency logRelease files / temporalint-0.1.1-py3-none-any.whl
| Download URL | temporalint-0.1.1-py3-none-any.whl |
|---|---|
| Size | 18.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
4e198d4ec19a1b19fcd84e1c15b2952cc694f63b76b720f37d2adde97d643af7
|
|
BLAKE2b-256 checksum How to use checksums |
3c09a85d5df145075634d7b7047963ca5742c6c3e4089abc98b5c0ed8aa90629
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 8, 2026.
Transparency log