Skip to main content

springcalc

A Python library for spring calculations: compression, extension, and torsion springs. Includes material data, wire characteristic calculations, and fatigue analysis via the Goodman diagram.

Visit the library in my guithub https://github.com/ErnestoAvedillo/springcalc and clone my repository using:

git clone git@github.com:ErnestoAvedillo/springcalc.git

Structure

src/springcalc/         Library package
├── lineal/             Calculation engine (compression, extension, torsion, Goodman,
│                       3D visualization, progressive-compression animation)
├── pymodels/           Data models (pydantic): material, units, wire, positions
├── material/           Material and tolerance tables (CSV, package data)
├── regresiones/        Fitted models loaded at runtime
│   └── factor_f/       Shigley's factor f (plain JSON coefficients + loader)
├── plots/              Goodman diagram generation
└── report/             PDF report generation (SpringPDFReport)

tests/                  Tests (pytest)
scripts/regresiones/    Training scripts that regenerate the JSON coefficients (not runtime)
docs/                   Reference material (spreadsheet, figures)

Installation

I recommend to use uv to install the library (https://docs.astral.sh/uv/):

# create the environment and install dependencies
uv init
uv add springcalc

Usage

from springcalc import Material, CompressionSpring

material = Material(material_name="SH")
spring = CompressionSpring(material=material, wire_diameter=1.0)
spring.set_geometry(outer_diameter=10.0, free_length=50.0, nr_coils=10)
properties = compression_spring.get_spring_data()
    for key, value in properties.items():
        print(f"{key}: {value}")                       )

Generating a PDF report (spring data, load/travel/diameter curves, and the Goodman fatigue diagram):

from springcalc.report import SpringPDFReport

report = SpringPDFReport(spring, title="Spring XYZ-123")
report.build("spring_report.pdf")

API Reference

All physical quantities are pint Quantity objects (a number with a unit, e.g. 20.0 millimeter). Plain numbers passed into a field are usually interpreted in that field's default unit (mm, N, degrees...), but a few methods require an explicit Quantity — those are called out below. Import the shared unit registry with:

from springcalc.pymodels.units import ureg

length = 20 * ureg.mm
angle = 90 * ureg.degree

Material data

Material (springcalc.pymodels.material.Material) is a pydantic model that looks up a named material's mechanical properties from material/materials.csv and auto-fills any field you don't pass explicitly.

Member Description
Material(material_name, young_modulus=None, shear_modulus=None, elastic_limit_factor=None, poisson_coef=None, RMa_file=None) Construct a material by name; unset fields are auto-filled from materials.csv.
.young_modulus Young's modulus E, as a Quantity in MPa.
.shear_modulus Shear modulus G, as a Quantity in MPa.
.elastic_limit_factor Dimensionless factor used to derive the fatigue limit.
.poisson_coef Poisson's ratio (dimensionless).
.RMa_file Name of the CSV (in material/) with tensile-strength ranges by wire diameter.
get_available_materials() Module-level function: list of valid material_name values.
Material.material_exists(material_name) Classmethod: whether a material is already registered.
Material.create_material(material_name, young_modulus, shear_modulus, elastic_limit_factor, poisson_coef, description="", RMa_file=None, RMa_data=None, overwrite=False) Classmethod: register a new material in materials.csv (and optionally its RMa_file table) and return it. Raises ValueError if the name already exists, unless overwrite=True.
from springcalc import Material, get_available_materials

print(get_available_materials())
# ['SL', 'SM', 'DM', 'SH', 'DH', 'TDC', 'TDCrV', ...]

material = Material(material_name="SH")
print(material.young_modulus)    # 206000.0 megapascal
print(material.shear_modulus)    # 81500.0 megapascal
print(material.poisson_coef)     # 0.3 dimensionless

Adding a new material — young_modulus/shear_modulus accept a unit string, a plain number (assumed MPa), or a Quantity; elastic_limit_factor and poisson_coef are dimensionless. Once created, the material is loadable by name like any built-in one:

from springcalc import Material

custom = Material.create_material(
    material_name="CustomSteel",
    young_modulus="210000 MPa",
    shear_modulus=81000,
    elastic_limit_factor=0.5,
    poisson_coef=0.3,
    description="Custom steel for a special order",
    RMa_data=[(1.0, 1600, 1800), (2.0, 1500, 1700)],  # (diameter mm, RMa_min, RMa_max)
)

# From now on it behaves like any other material
same_material = Material(material_name="CustomSteel")

Wire characteristics

WireCharacteristics (springcalc.pymodels.wire_characteristics.WireCharacteristics) is the base class of every spring type. Given a material and a wire diameter, it looks up the wire diameter tolerance and the tensile-strength range (RMa) for that diameter.

Member Description
WireCharacteristics(material, wire_diameter) wire_diameter may be a plain number (interpreted in mm) or a Quantity.
.diameter_tolerance Manufacturing tolerance for this diameter (from DIAMETRO_TOLERANCIAS.csv).
.RMa_min / .RMa_max Tensile-strength range for this material and diameter, from material.RMa_file.
.set_material(material, wire_diameter) Re-assign the material/diameter and refresh the derived fields.
from springcalc import Material
from springcalc.pymodels.wire_characteristics import WireCharacteristics

material = Material(material_name="SH")
wire = WireCharacteristics(material=material, wire_diameter=2.0)
print(wire.diameter_tolerance)          # 0.025
print(wire.RMa_min, wire.RMa_max)       # 1980.0 2200.0

Compression springs

CompressionSpring (springcalc.lineal.compresion.CompressionSpring, also exported as springcalc.CompressionSpring) is the main entry point for helical compression springs. It extends LinealSpring (springcalc.lineal.lineal.LinealSpring), the shared calculation engine also used by ExtensionSpring.

Method Description
CompressionSpring(material, wire_diameter, **data) Create the spring.
.set_geometry(mean_diameter=None, outer_diameter=None, inner_diameter=None, nr_coils=None, pitch=None, free_length=None, type_of_end=None, type_conforming=None) Set the full geometry in one call: exactly one diameter and exactly two of nr_coils/pitch/free_length. type_of_end (one of constants.COMPRESSION_SPRING_END_TYPES, e.g. "open_ground") and type_conforming (one of constants.FORMING_TYPES, e.g. "cold_formed") are optional and, if given, override the spring's defaults before the active-coil count is computed. Equivalent to calling .set_diameter() followed by .calculate_spring_properties(). Returns .get_spring_data().
.set_diameter(mean_diameter=None, outer_diameter=None, inner_diameter=None) Set exactly one of the three diameters; derives the others and the spring index/Wahl factor.
.calculate_spring_properties(nr_coils=None, pitch=None, free_length=None) Provide exactly two of the three; computes coils, active coils, Wahl factor, spring constant, solid length, and wire length.
.add_load_position(length) Record the load/stress/outer-diameter at a given compressed length, for the load-position table and fatigue analysis.
.empty_tables() Clear the recorded load positions.
.get_spring_data() dict with all computed spring properties (material, diameters, constants, Wahl factor, etc.).
.get_data_positions() / .get_data_travels() List of LinearLoadPosition recorded via add_load_position.
.get_forces_vs_position_graph(show=False) Load vs. absolute position curve; returns a base64-encoded PNG.
.get_forces_vs_travel_graph(show=False) Load vs. travel (compression from free length) curve; returns a base64 PNG.
.get_diameter_graph(show=False) Outer diameter vs. position curve; returns a base64 PNG.
.get_diameter_vs_position_graph(show=False) Outer diameter curve plus a to-scale cross-section diagram; returns a base64 PNG.
.get_3d_plot(num_points=200, show=False, isometric=True) Renders the coiled wire geometry in 3D (constant mean diameter and pitch); returns a base64 PNG. Defaults to an orthographic isometric view, matching how spring drawings are conventionally presented.
.create_goodman_diagram(show=False) Runs the fatigue (Goodman) analysis from the recorded positions; returns {"image", "analysis", "stresses"} or {"error", "traceback"}.
.get_stress_max() / .get_stress_min() Max/min stress across recorded positions (raises if none are recorded).
.get_load_max() / .get_load_min() Max/min load across recorded positions.
.calculate_solid_length() Coils-stacked solid (fully compressed) length.
.calculate_wire_length() Total wire length needed to wind the spring.
.set_number_cycles(number_cycles) Design life, in cycles, used by the fatigue analysis (default 1e6).
from springcalc import Material, CompressionSpring

material = Material(material_name="SL")
spring = CompressionSpring(material=material, wire_diameter=2.5)
spring.set_geometry(outer_diameter=30, pitch=20, free_length=100)  # mm

# Equivalent to calling separately:
#   spring.set_diameter(outer_diameter=30)
#   spring.calculate_spring_properties(pitch=20, free_length=100)

for length_mm in [30, 40, 50, 60, 70, 80, 90, 100]:
    spring.add_load_position(length=length_mm)

data = spring.get_spring_data()
print(data["spring_constant"])          # ~7.09 N / mm
print(data["wahl_factor_category"])     # 'green' -> C=11 is in a normal manufacturable range

# Graphs (base64 PNGs, ready to embed in HTML or a PDF)
load_vs_position_png = spring.get_forces_vs_position_graph()
diameter_png = spring.get_diameter_vs_position_graph()

# Fatigue analysis from the recorded positions
result = spring.create_goodman_diagram()
print(result["analysis"]["safety_factor"])

Extension springs

ExtensionSpring (springcalc.lineal.extension.ExtensionSpring, also exported as springcalc.ExtensionSpring) models helical extension springs. It extends LinealSpring directly (not CompressionSpring) and its diameter/length setters require explicit Quantity values rather than plain numbers.

Method Description
ExtensionSpring(material, wire_diameter, **data) Create the spring.
.set_diameter(outer_diameter=None, inner_diameter=None, mean_diameter=None) Set exactly one diameter. Must be a Quantity (e.g. 15 * ureg.mm), not a plain number.
.calculate_spring_properties(nr_coils=None, pitch=None, free_length=None) Provide exactly two of the three; computes active coils, spring constant, and wire length.
.add_load_position(length) Record the load/stress/outer-diameter at a given extended length (must be ≥ free length).
.calculate_positions_table(step: list) Convenience: call add_load_position for each length in step.
.empty_tables() Clear the recorded load positions.
.get_spring_data() dict with all computed spring properties.
.get_data_positions() / .get_data_travels() List of recorded LinearLoadPosition.
.get_forces_vs_position_graph(show=False) / .get_forces_vs_travel_graph(show=False) Load curves; return base64 PNGs.
.get_diameter_graph() / .get_diameter_vs_position_graph() Diameter curves (no show parameter on this class); return base64 PNGs.
.create_goodman_diagram() Fatigue analysis from the recorded positions; returns {"image", "analysis", "stresses"} or {"error", "traceback"} (no show parameter).
.get_stress_max() / .get_stress_min() / .get_load_max() / .get_load_min() Extremes across recorded positions.
.set_number_cycles(number_cycles) Design life in cycles for the fatigue analysis.
.set_initial_stress(initial_stress) Set the spring's initial tension (pre-load) stress.
from springcalc import Material, ExtensionSpring
from springcalc.pymodels.units import ureg

material = Material(material_name="SH")
spring = ExtensionSpring(material=material, wire_diameter=1.5)
spring.set_diameter(outer_diameter=15 * ureg.mm)   # note: needs a Quantity, unlike CompressionSpring
spring.calculate_spring_properties(nr_coils=10, free_length=60)

spring.calculate_positions_table([65, 70, 75, 80])  # extend beyond the free length

data = spring.get_spring_data()
print(data["spring_constant"])   # ~2.33 N / mm

result = spring.create_goodman_diagram()
print(result["analysis"]["safety_factor"])

Torsion springs

TorsionSpring (springcalc.lineal.torsion.TorsionSpring, also exported as springcalc.TorsionSpring) models helical torsion springs, tracking angular position/travel and torque instead of linear load. It extends WireCharacteristics directly and has no Goodman/fatigue integration.

Method Description
TorsionSpring(material, wire_diameter, **data) Create the spring.
.set_geometry(mean_diameter, nr_coils, pitch, free_angle, fixed_leg_radius, mobile_leg_radius) One-call setup: sets geometry and computes every derived property. Returns .get_spring_properties().
.calculate_spring_properties() Re-run the derived-property calculations after changing an input.
.add_position(angle_travel=None, torque=None) Record a working position from either an angular travel or a torque (exactly one).
.clean_positions() Clear the recorded positions.
.get_positions() / .get_data_positions() / .get_data_travels() List of recorded AngularLoadPosition.
.get_spring_properties() dict with all computed properties (diameters, angles, leg lengths, spring constant, Wahl factor, etc.).
.calculate_torque(rotation_angle) Torque required for a given rotation angle.
.calculate_stress(torque) Max wire stress for a given torque.
.get_forces_vs_position_graph(show=False) / .get_forces_vs_travel_graph(show=False) Torque vs. angular position/travel curves; return base64 PNGs.
.get_diameter_vs_position_graph(show=False) Outer diameter curve plus a cross-section diagram; returns a base64 PNG.
.set_number_cycles(number_cycles) / .set_shot_peening(shot_peening) Fatigue-related inputs (stored but not yet used by a Goodman analysis for this class).
from springcalc import Material, TorsionSpring
from springcalc.pymodels.units import ureg

material = Material(material_name="SH")
spring = TorsionSpring(material=material, wire_diameter=1.0)
spring.set_geometry(
    mean_diameter=10 * ureg.mm,
    nr_coils=8,
    pitch=1.2 * ureg.mm,
    free_angle=180 * ureg.degree,
    fixed_leg_radius=15 * ureg.mm,
    mobile_leg_radius=15 * ureg.mm,
)
print(spring.spring_constant)   # ~35 mm*N/rad

spring.add_position(angle_travel=30 * ureg.degree)
for position in spring.get_positions():
    print(position)

Fatigue analysis (Goodman diagram)

springcalc.lineal.goodman implements the modified-Goodman fatigue check (Shigley, ch. 6/10) for spring wire in torsion, axial, or flexural loading. CompressionSpring.create_goodman_diagram() and ExtensionSpring.create_goodman_diagram() use this internally, but it can also be used directly.

Member Description
GoodmanData(material, diameter, load_type="axial", cycles=1e6) Pydantic input model. load_type is "axial", "torsion", or "flexion".
GoodmanAnalyzer(data, shot_peening=False) Computes the Marin correction factors, the corrected endurance limit Sse and fatigue strength Ssf.
.calculate_safety_factor(sigma_max, sigma_min) Modified-Goodman safety factor for an operating stress cycle.
.get_analysis_summary(sigma_max, sigma_min) dict with the correction factors, strengths, operating point, and safety factor.
.plot_diagram(sigma_max, sigma_min, show_plot=True) Returns a matplotlib Figure with the Goodman envelope and the operating point plotted.
.get_diagram_image(sigma_max, sigma_min) Same diagram, returned as a base64 PNG string.
Goodman(material, diameter, load_type="axial", number_cycles=1e6, shot_peening=False) Backwards-compatible wrapper around GoodmanAnalyzer with the same methods (plot_goodman_graph, get_goodman_graph, etc.).
generate_goodman_diagram(spring, initial_length, final_length, shot_peening=False, number_cycles=1e6) Module function in springcalc.plots: derives max/min load and stress for a spring compressed between two lengths, and returns the same {"image", "analysis", "stresses"} dict. initial_length/final_length must be Quantity values (they're subtracted directly from spring.free_length).
from springcalc import Material, GoodmanData, GoodmanAnalyzer

material = Material(material_name="DH")
data = GoodmanData(material=material, diameter=1.0, load_type="torsion", cycles=1e5)
analyzer = GoodmanAnalyzer(data)

sigma_max, sigma_min = 400, 100   # MPa
print(analyzer.calculate_safety_factor(sigma_max, sigma_min))
summary = analyzer.get_analysis_summary(sigma_max, sigma_min)
print(summary["strengths"]["Se_MPa"], summary["strengths"]["Sf_MPa"])

Using the standalone helper directly on a CompressionSpring instance (see the Compression springs example for how spring was built), instead of calling spring.create_goodman_diagram():

from springcalc.plots import generate_goodman_diagram
from springcalc.pymodels.units import ureg

result = generate_goodman_diagram(spring, initial_length=100 * ureg.mm, final_length=40 * ureg.mm)
print(result["analysis"]["safety_factor"])

Position tables

Every spring stores its recorded working positions in a pydantic list model under .positions, populated via each spring's add_load_position/ add_position method rather than built by hand — but they're documented here since .get_data_positions() returns their contents.

Model Used by Fields
LinearLoadPosition (springcalc.pymodels.positions) CompressionSpring, ExtensionSpring .position, .travel, .load (N), .stress (MPa), .outer_diameter, .inner_diameter — all Quantity.
LinearPositionsTable same .positions: list[LinearLoadPosition]. .add_load_position(...), .clear_table().
AngularLoadPosition TorsionSpring Same fields as above, with .position/.travel in degrees and .load in N·mm (torque).
AngularPositionsTable TorsionSpring .positions: list[AngularLoadPosition]. .add_load_position(...), .clear_table().
# `spring` is any CompressionSpring/ExtensionSpring/TorsionSpring instance
# with load positions already recorded via add_load_position/add_position.
for position in spring.get_data_positions():
    print(position.position, position.load, position.stress)

PDF reports

SpringPDFReport (springcalc.report.SpringPDFReport, also exported as springcalc.SpringPDFReport) renders a CompressionSpring's data, a 3D isometric view, curves, and the Goodman diagram into a printable PDF using reportlab.

Method Description
SpringPDFReport(spring, title=None) Wrap a CompressionSpring (with load positions already added via add_load_position, for the fullest report).
.build(output_path) Render the report and write it to output_path. Returns the path. Includes the spring data table, a 3D isometric view (from spring.get_3d_plot()), the load/geometry curves, the load-position table, and the Goodman diagram. Degrades gracefully (with a placeholder message) if a graph or the Goodman analysis can't be generated, e.g. no load positions recorded yet.
from springcalc.report import SpringPDFReport

# `spring` is a CompressionSpring instance (see the Compression springs example)
report = SpringPDFReport(spring, title="Spring XYZ-123")
report.build("spring_report.pdf")

Advanced: variable-geometry springs

VariableLinealSpring and CompressionSpringGeneral (springcalc.lineal.generic_lineal / springcalc.lineal.generic_compression) model compression springs whose mean diameter and/or pitch vary along their length (e.g. conical or barrel springs), by numerically integrating along the helix instead of using the constant-geometry closed-form equations. They are not exported from the top-level springcalc package — import them from their modules directly. For a constant-diameter, constant-pitch spring they agree with the closed-form CompressionSpring results.

Method Description
CompressionSpringGeneral(material, wire_diameter, **data) Create the spring. Set .mean_diameter_init, .pitch_constant, and .free_length for a constant-geometry spring, or...
.establish_geometrical_function(func_D, func_p) ...inject custom functions h -> mean_diameter and h -> pitch (both Quantity -> Quantity) for a true variable-geometry spring.
.set_geometry(func_D, func_p, free_length=None, type_of_end=None, type_conforming=None) One-call setup: calls .establish_geometrical_function(func_D, func_p), sets .free_length, and optionally type_of_end (one of constants.COMPRESSION_SPRING_END_TYPES, e.g. "open_ground") and type_conforming (one of constants.FORMING_TYPES, e.g. "cold_formed") — both default to the spring's current value when omitted.
.calculate_theta_max() Total helix rotation angle (rad) needed to reach free_length; also updates .nr_coils.
.calculate_active_coils() Number of active coils (.nr_active_coils), discounting the ground/squared end coils that don't deform, based on type_of_end/type_conforming — same formula as CompressionSpring.
.calculate_spring_constant(num_points=500) Equivalent stiffness, integrating the local flexibility along the helix over the active coils only (end coils excluded per .calculate_active_coils()).
.calculate_wire_length(num_points=500) Total wire length, integrating the 3D arc length along the helix.
.calculate_solid_length() Solid (fully compressed) length, accounting for coil telescoping/nesting when the diameter varies enough.
.get_3d_plot(num_points=500, show=False, isometric=True) Renders the helix centerline in 3D, following the actual f_mean_diameter/f_pitch functions (so variable geometries show up as a non-uniform helix); returns a base64 PNG. Defaults to an orthographic isometric view.
.simulate_progressive_compression(max_deflection, steps=100, num_points=500, capture_geometry=False) Step-by-step compression simulation that detects coil-to-coil (oblique) contact; returns (deflection, force, instantaneous_stiffness) arrays. With capture_geometry=True, also returns a 4th value: {"thetas", "z_history"}, the instantaneous coil shape at every step (used by CompressionAnimator, see below).
from springcalc import Material
from springcalc.pymodels.units import ureg
from springcalc.lineal.generic_compression import CompressionSpringGeneral

material = Material(material_name="SH")
spring = CompressionSpringGeneral(material=material, wire_diameter=2.0)
spring.set_geometry(
    func_D=lambda h: 20 * ureg.mm,
    func_p=lambda h: 6 * ureg.mm,
    free_length=60 * ureg.mm,
    type_of_end="open_ground",     # optional; this is the default
    type_conforming="cold_formed", # optional; this is the default
)

spring.calculate_theta_max()
print(spring.calculate_spring_constant())   # matches G*d^4/(8*D^3*n_active) for constant geometry
print(spring.nr_active_coils)               # 7.7 (10 total coils minus the non-deforming ground ends)

deflection, force, stiffness = spring.simulate_progressive_compression(max_deflection=20 * ureg.mm, steps=20)
print(force[-1])   # ~52.92 N

Animating progressive compression

CompressionAnimator (springcalc.lineal.animation.CompressionAnimator) renders simulate_progressive_compression's result as an animated GIF of the coils closing up under load, reusing the same helix geometry as get_3d_plot. It takes any VariableLinealSpring (e.g. CompressionSpringGeneral). Saving is done with matplotlib's PillowWriter, so no extra system dependency (like ffmpeg) is required.

Method Description
CompressionAnimator(spring) Wrap a CompressionSpringGeneral (or other VariableLinealSpring) instance.
.create_gif(max_deflection, output_path="compression.gif", steps=60, num_points=300, fps=12, isometric=True) Runs simulate_progressive_compression(capture_geometry=True) internally and writes the resulting animation to output_path. Returns output_path. Axis limits are fixed from the free-state geometry so the camera doesn't jump between frames.
from springcalc import Material
from springcalc.pymodels.units import ureg
from springcalc.lineal.generic_compression import CompressionSpringGeneral
from springcalc.lineal.animation import CompressionAnimator

material = Material(material_name="SH")
spring = CompressionSpringGeneral(material=material, wire_diameter=2.0)
spring.set_geometry(func_D=lambda h: 20 * ureg.mm, func_p=lambda h: 6 * ureg.mm, free_length=60 * ureg.mm)

animator = CompressionAnimator(spring)
animator.create_gif(max_deflection=25 * ureg.mm, output_path="compression.gif")

Tests

uv run pytest

Retraining the regression models

The included JSON coefficient files are already fitted. To regenerate them:

uv run python scripts/regresiones/factor_f/factor_f.py

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

springcalc-0.1.3.tar.gz (2.4 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

springcalc-0.1.3-py3-none-any.whl (64.9 kB view details)

Uploaded Python 3

File details

Details for the file springcalc-0.1.3.tar.gz.

File metadata

  • Download URL: springcalc-0.1.3.tar.gz
  • Upload date:
  • Size: 2.4 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.12

File hashes

Hashes for springcalc-0.1.3.tar.gz
Algorithm Hash digest
SHA256 e8f5c36deb8fac19d7bc35f814e76dccc9cf7872e87f734144915b0c228785ed
MD5 299c5cc082b9fd838ef645c6d9e8c768
BLAKE2b-256 d436d21bcb5afa584152d1888a7c6c689783ef6d7242599120c8aa48648622a9

See more details on using hashes here.

File details

Details for the file springcalc-0.1.3-py3-none-any.whl.

File metadata

  • Download URL: springcalc-0.1.3-py3-none-any.whl
  • Upload date:
  • Size: 64.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.12

File hashes

Hashes for springcalc-0.1.3-py3-none-any.whl
Algorithm Hash digest
SHA256 25052ee3a1238af32bde283957a209899d30bdb53604554a86389de1b5af9320
MD5 5ff3a60acd12796dda435c578c977098
BLAKE2b-256 5f36d830f9c57d87c1bb191a48bec2b157f00807c4838884e25f70da30b69f9f

See more details on using hashes here.

Release history Release notifications | RSS feed

0.1.23

2 files

0.1.22

2 files

0.1.21

2 files

0.1.20

2 files

0.1.18

2 files

0.1.17

2 files

0.1.13

2 files

0.1.12

2 files

This release

0.1.3 This release

2 files

0.1.2

2 files

0.1.1

2 files

0.1.0

2 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