GithubHelp home page GithubHelp logo

achevrot / impunity Goto Github PK

View Code? Open in Web Editor NEW
9.0 2.0 0.0 3.65 MB

A Python library to check physical units

Home Page: https://achevrot.github.io/impunity/

License: MIT License

Python 97.56% C++ 1.22% F# 0.89% OCaml 0.33%
converter quantity static units

impunity's Introduction

tests Code Coverage License Checked with mypy

impunity is a Python library consisting of a single decorator function designed to ensure consistency of physical quantities. Compared to other libraries (pint, etc.), it has a minimal overhead on performance because physical units are only manipulated through static analysis and disappear at runtime.

impunity is based on Python “flexible variable and function annotations” (PEP 593) and checks consistency between variables and arguments of functions. If physical units are consistent, impunity rewrites the code by automatically applying conversions in the code of the function.

impunity is compatible with regular type annotations, and functions decorated with impunity remain compatible with other static analysis tools and type checkers like mypy.

In most situations, impunity will only perform minimal sanity checks on your code at import time and not edit anything.

Installation

impunity is available on pip (and soon conda):

pip install impunity

For development purposes, clone the repository and use poetry:

git clone --depth=1 https://github.com/achevrot/impunity
cd impunity
poetry install

Usage

Full documentation available at website

  • The most simple usage consists of using units placed as annotations: code is checked and rewritten if need be.

    from impunity import impunity
    
    def speed(distance: "m", time: "s") -> "m/s":
        return distance / time
    
    @impunity
    def regular_conversion():
        altitudes: "ft" = np.arange(0, 1000, 100)
        duration: "mn" = 100
        result = speed(altitudes, duration)
        print(result)  # results in m/s
    
        result_imperial: "ft/mn" = speed(altitudes, duration)
        print(result_imperial)  # results in ft/mn
    
    if __name__ == "__main__":
        regular_conversion()
  • The check fails if units are inconsistent:

    @impunity
    def inconsistent_units():
        temperatures: "K" = np.arange(0, 100, 10)
        duration: "s" = 6000
        return speed(temperatures, duration)
    
    # Warning: "K" is not compatible with "m"
  • Only check for consistency, do not attempt to rewrite the code:

    @impunity(rewrite=False)  # only check for consistency
    def regular_conversion():
        pass
    
    @impunity(rewrite="output.log")  # check code output in an external file
    def regular_conversion():
        pass

Compatibility with type checkers

Types can be used with the Annotated keyword, which carries

from typing import Annotation
import numpy.types as npt

feet_array = Annotated[npt.ndarray[np.float64], "ft"]
altitudes: feet_array = np.arange(0, 1000, 100)

impunity is implemented and typed with Annotated keywords.

Tests

Tests are supported by the unittest package.

Because AST manipulation can be tricky, continuous integration is ensured by Github Actions for:

  • Linux, MacOS and Windows;
  • all versions of Python since 3.8

Why impunity?

We were searching for a pun with physical units. Things converged on im-pun-unit-y.

impunity's People

Contributors

achevrot avatar dependabot[bot] avatar xoolive avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

impunity's Issues

problems with list warnings

In some cases, lists shouldn't raise warnings:

a1: Annotated(list[float], "m")   # should raise a warning
a2: Annotated(list[float], "m") = []  # should raise a warning
a3 = []  # should not raise a warning

x: "m"
a4 = [x]  # should raise a warning

y: "ft"
y, *_ = a4  # does not convert units

Annotated Assignment when the value of the node is iterable

alt_m1: "m" = 1000
alt_m2: "m" = 1000
alt_m3: "m" = 1000
l: "m" = [alt_m1, alt_m2, alt_m3]
self.assertEqual(l[0], 1000)
l2: "ft" = [alt_m1, alt_m2, alt_m3]
self.assertAlmostEqual(l2[0], 3280.84, delta=1e-2)

First test is fine but second one fails : can't multiply sequence by non-int of type 'float'

Would need to change the Annotated Assign node visitor implementation to do so.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.