Skip to content

A library of decorators to communicate, monitor, debug and enforce behavior

License

Notifications You must be signed in to change notification settings

MultifokalHirn/ornaments

Repository files navigation

ornaments

Maturity badge - level 1 Tests Coverage GitHub last commit

`ornaments` helps to *future-proofly* document the intent of one's `python` code.

It aims to do so through meaningful @decorator functions that help other developers understand, (re-)use, and debug your code.


Contents

Overview

Why decorators?

A @decorator 'talks about' other code in a way that is understandable for both the human reader as well as the interpreter. By being meaningful to both, @decorator based documentation can bypass the (all to common) disconnect between documentation and code.

Scope

ornaments provides functionality for adding various

  • value/type checks (as well limiters for input/execution duration) during runtime
  • context-dependend logging functionalities (i.e. execution time)
  • testable meta information (i.e. deprecation warnings)

Usage

from ornaments.invariants import only_called_once

@only_called_once(scope="session", enforce=True)
def only_once_callable_function() -> None:
    return None

# -----

only_once_callable_function()
>>> None

# This should raise an error
only_once_callable_function()
>>> Traceback (most recent call last):
    File "<input>", line 1, in <module>
      only_once_callable_function()
    File "./ornaments/src/ornaments/invariants/only_called_once.py", line 45, in wrapper
      raise CalledTooOftenError(msg)
    ornaments._exceptions.CalledTooOftenError: Function only_once_callable_function has already been called in session. call_scope=(4522676512, <function only_once_callable_function at 0x10d929120>)

But what if I want to use the same function in different contexts? 🤔

from ornaments.invariants import only_called_once

def my_reusable_function() -> None:
    return None

@only_called_once(scope="session", enforce=True)
def only_once_callable_function() -> None:
    return my_reusable_function()

# -----

my_reusable_function()
>>> None

my_reusable_function()
>>> None

only_once_callable_function()
>>> None

# This should raise an error
only_once_callable_function()
>>> Traceback (most recent call last):
    File "<input>", line 1, in <module>
      only_once_callable_function()
    File "./ornaments/src/ornaments/invariants/only_called_once.py", line 45, in wrapper
      raise CalledTooOftenError(msg)
      ...

🚀

Goal Structure

ornaments
├── helpers
│   ├── catch_all_exceptions.py
│   ├── normalized_exceptions.py
│   └── retry.py
├── invariants
│   ├── conditional_execution.py
│   └── only_called_once.py
├── limits
│   ├── call_limit.py
│   └── execution_time_limit.py
├── logging
│   ├── log_calls.py
│   ├── log_execution_time.py
│   ├── log_parameters.py
│   ├── log_return.py
│   └── log_value.py
├── markers
│   ├── stable.py
│   ├── wobbly.py
│   └── deprecated.py
├── monitoring
│   ├── monitored_attribute.py
│   └── monitored_calls.py
├── runtime_checks
│   ├── checked_return_type.py
│   └── parameter_validation.py
└── safety
    └── fallback_function.py

Development

See CONTRIBUTING.md for information on how to setup and contribute to this project.

asciicast

Addendum

License


           .::=+=--++=::.
       .-+++*-+++ =*+*=++=-:
     :+#+-=:-.:+--+++=.=+:=**=.
   .+#==::--+#*-...:=%%+-:**==*=
  .@%=*=+:*#*.       .#@#-==-==-*.
  #@--+=-##::          %@#=:=:+::=
 -@@:==+:%+-.          =@=:++=:: -.
 *@@:-==:%*-.          =@*+=+-+-.-.
 :@@:.-==+@%-          %@===+==: =.
  #@-++-=--#%=       :%%----=:. :=
   #@=.:-:+++++==:--++=.::=++..:+
   :*%#*=:*+: -==:#%#*.==+::..--
   ::-+**=++-:=--.*%%%==--.:::.
        :--:==-:--:--:-:::::
            . . :  : ...

Author - MultifokalHirn

Releases

No releases published

Packages

No packages published