Skip to main content

trcks 🚂🐍

trcks is a Python library that allows railway-oriented programming (ROP) in two different type-safe programming styles.

Setup

trcks is available on PyPI. Use your favorite package manager (e.g. pip, poetry, or uv) to install it. Check the documentation for detailed setup instructions, including how to install the trcks skill for AI coding agents.

Usage

The following subsections demonstrate both styles of railway-oriented programming (ROP) supported by trcks.

Object-oriented style

The object-oriented style is based on method chaining, as demonstrated by the get_subscription_fee_by_email function in the following example.

>>> from typing import Literal
>>> from trcks import Result
>>> from trcks.oop import Wrapper
>>>
>>> UserDoesNotExist = Literal["User does not exist"]
>>> UserDoesNotHaveASubscription = Literal["User does not have a subscription"]
>>> FailureDescription = UserDoesNotExist | UserDoesNotHaveASubscription
>>>
>>> def get_user_id(user_email: str) -> Result[UserDoesNotExist, int]:
...     if user_email == "erika.mustermann@domain.org":
...         return "success", 1
...     if user_email == "john_doe@provider.com":
...         return "success", 2
...     return "failure", "User does not exist"
>>>
>>> def get_subscription_id(user_id: int) -> Result[UserDoesNotHaveASubscription, int]:
...     if user_id == 1:
...         return "success", 42
...     return "failure", "User does not have a subscription"
>>>
>>> def get_subscription_fee(subscription_id: int) -> float:
...     return subscription_id * 0.1
>>>
>>> def get_subscription_fee_by_email(user_email: str) -> Result[FailureDescription, float]:
...     return (
...         Wrapper(core=user_email)
...         .map_to_result(get_user_id)
...         .map_success_to_result(get_subscription_id)
...         .map_success(get_subscription_fee)
...         .core
...     )
>>>
>>> get_subscription_fee_by_email("erika.mustermann@domain.org")
('success', 4.2)
>>> get_subscription_fee_by_email("john_doe@provider.com")
('failure', 'User does not have a subscription')
>>> get_subscription_fee_by_email("jane_doe@provider.com")
('failure', 'User does not exist')

Notes w.r.t. object-oriented style

  1. The generic type trcks.Result allows domain errors to become part of a function's return type (subject to static type checking).
  2. The class trcks.oop.Wrapper provides a convenient way to chain trcks.Result-returning functions and "regular" functions (in a type-safe way).
  3. The map* and tap* methods of trcks.oop.Wrapper (and the other wrapper classes) accept extra positional and keyword arguments, which are forwarded to the given function.
  4. See the OOP and FP equivalence table for a side-by-side comparison with the functional style, and the glossary for definitions of key terms.

Functional style

The functional style is based on function composition, as demonstrated by the get_subscription_fee_by_email function in the following example.

>>> from typing import Literal
>>> from trcks import Result
>>> from trcks.fp.composition import Pipeline3, pipe
>>> from trcks.fp.monads import result as r
>>>
>>> UserDoesNotExist = Literal["User does not exist"]
>>> UserDoesNotHaveASubscription = Literal["User does not have a subscription"]
>>> FailureDescription = UserDoesNotExist | UserDoesNotHaveASubscription
>>>
>>> def get_user_id(user_email: str) -> Result[UserDoesNotExist, int]:
...     if user_email == "erika.mustermann@domain.org":
...         return "success", 1
...     if user_email == "john_doe@provider.com":
...         return "success", 2
...     return "failure", "User does not exist"
>>>
>>> def get_subscription_id(user_id: int) -> Result[UserDoesNotHaveASubscription, int]:
...     if user_id == 1:
...         return "success", 42
...     return "failure", "User does not have a subscription"
>>>
>>> def get_subscription_fee(subscription_id: int) -> float:
...     return subscription_id * 0.1
>>>
>>> def get_subscription_fee_by_email(user_email: str) -> Result[FailureDescription, float]:
...     # Explicitly assigning a type to `pipeline` might
...     # help your static type checker understand that
...     # `pipeline` is a valid argument for `pipe`:
...     pipeline: Pipeline3[
...         str,
...         Result[UserDoesNotExist, int],
...         Result[FailureDescription, int],
...         Result[FailureDescription, float],
...     ] = (
...         user_email,
...         get_user_id,
...         r.map_success_to_result(get_subscription_id),
...         r.map_success(get_subscription_fee),
...     )
...     return pipe(pipeline)
>>>
>>> get_subscription_fee_by_email("erika.mustermann@domain.org")
('success', 4.2)
>>> get_subscription_fee_by_email("john_doe@provider.com")
('failure', 'User does not have a subscription')
>>> get_subscription_fee_by_email("jane_doe@provider.com")
('failure', 'User does not exist')

Notes w.r.t. functional style

  1. The generic type trcks.Result allows domain errors to become part of a function's return type (subject to static type checking).
  2. The modules trcks.fp.composition and trcks.fp.monads.result provide a convenient way to chain trcks.Result-returning functions and "regular" functions (in a type-safe way).
  3. The map* and tap* functions in the modules under trcks.fp.monads accept extra positional and keyword arguments, which are forwarded to the given function.
  4. See the OOP and FP equivalence table for a side-by-side comparison with the object-oriented style, and the glossary for definitions of key terms.

Still not convinced?

Explore these repositories for more ways to use trcks:

  1. trcks-example-cyclopts (CLI application)
  2. trcks-example-fastapi (REST backend application)

Or check the motivation for railway-oriented programming and for trcks.

Metadata

Release files for trcks 0.7.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for trcks 0.7.3
File Size Uploaded
trcks-0.7.3.tar.gz 84.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for trcks 0.7.3
File Interpreter ABI Platform
trcks-0.7.3-py3-none-any.whl Python 3 none any Details

Total release size: 185.2 kB

Release files / trcks-0.7.3.tar.gz

Download URL trcks-0.7.3.tar.gz
Size 84.7 kB
Tags Source
SHA-256 checksum
How to use checksums
3d2f01b8856e618bf95359b46e3800af216fb3b2e7e89334cc5c1995f1883b23
BLAKE2b-256 checksum
How to use checksums
3050a6e389c6fcfe81f09f72237a74e9604e7713ee59a7355e429425b5390349
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.13 {"installer":{"name":"uv","version":"0.12.13","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / trcks-0.7.3-py3-none-any.whl

Download URL trcks-0.7.3-py3-none-any.whl
Size 100.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
fc43358b63445be60d6fb41f369e4fe50db7a4f6084d5b036fb02f057a265aa8
BLAKE2b-256 checksum
How to use checksums
54a14c734eb449ad1bb407b4f5618cfc696ec024807f80b1f71c67070a1996b6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.13 {"installer":{"name":"uv","version":"0.12.13","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release history Release notifications | RSS feed

0.9.1

2 release files

0.9.0

2 release files

0.8.0

2 release files

This release

0.7.3 This release

2 release files

0.7.2

2 release files

0.7.1

2 release files

0.7.0

2 release files

0.6.2

2 release files

0.6.1

2 release files

0.6.0

2 release files

0.5.0

2 release files

0.4.5

2 release files

0.4.4

2 release files

0.4.3

2 release files

0.4.2

2 release files

0.4.1

2 release files

0.4.0

2 release files

0.3.7

2 release files

0.3.6

2 release files

0.3.5

2 release files

0.3.4

2 release files

0.3.3

2 release files

0.3.2

2 release files

0.3.1

2 release files

0.3.0

2 release files

0.2.9

2 release files

0.2.8

2 release files

0.2.7

2 release files

0.2.6

2 release files

0.2.5

2 release files

0.2.4

2 release files

0.2.3

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.2.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page