Skip to main content

Establish a general function description protocol, which can realize a comprehensive description of the input, output and side effects of an target function through an Python object. Provide a unified abstraction for parameter checking, interface generation and other functions in applications such as oneFace.

Project description

funcdesc

Establish a general function description protocol, which can realize a comprehensive description of the input, output and side effects of an target function through an Python object. Provide a unified abstraction for parameter checking, interface generation and other functions in applications such as oneFace.

Build Status codecov Install with PyPi MIT license

Features

  • Parse function to get a description object.
  • Mark function's inputs and outputs.
  • Mark function's side effects.
  • Generate checker(guard) for function.
    • Check inputs and outputs's type.
    • Check inputs and outputs's range.
    • Check side-effect.
  • Serialization & Deserialization of the description.
    • Convert description object to JSON string.
    • Parse JSON string to get description object.
  • Utility functions for edit function's signature.
  • Function guard can be used for checking inputs, outputs and side effects.
  • Convert description object to pydantic models.
  • Support docstring.
    • Update description object using docstring.
    • TODO Parse docstring to get description object.
    • TODO Convert description object to docstring.

Concept

"Function description" is a Python object that contains descriptive information about a Python function, such as input parameters, output values, and side effects of the function. The description of the inputs and outputs includes their types, range of values, and default values.

The Description can be generated by parsing a function annotated with type annotations and decorated with the mark decorator, or it can be manually created. After obtaining the Description, we can use it to generate a Guard object to check the types, ranges, or side effects of the inputs and outputs of the function at runtime. Additionally, the information in the Description can be used by downstream tools, such as oneFace, to automatically generate interfaces, including CLI, GUI, and WebUI

concept

Demo

Create description object

Parse a normal type hinted function:

# test.py
from funcdesc import parse_func

def add(a: int, b: int = 0) -> int:
    return a + b

desc = parse_func(add)
print(desc)
$ python test.py
<Description
        inputs=[<Value type=<class 'int'> range=None default=NotDef>, <Value type=<class 'int'> range=None default=0>]
        outputs=[<Value type=<class 'int'> range=None default=NotDef>]
        side_effects=[]
>

Mark inputs and outputs

funcdesc provides two ways to annotate inputs and outputs: 1) using decorators, and 2) using the "Val" object in type hints. For example:

from funcdesc import mark_input, mark_output

@mark_input(0, type=int, range=[0, 10])
@mark_input(1, type=int, range=[0, 10])
@mark_output(0, type=int, range=[0, 20])
def add(a, b) -> int:
    return a + b

Is same to:

from funcdesc import Val

def add(a: Val[int, [0, 10]], b: Val[int, [0, 10]]) -> Val[int, [0, 20]]:
    return a + b

Create function guard

The make_guard decorator can convert a marked function into a Guard object. You can call the Guard just like the original function, and it will check the inputs, outputs, and side effects of the function based on the marked information. For example:

from funcdesc import mark_input, mark_output, make_guard

@make_guard
@mark_input('a', range=[0, 10])
@mark_input('b', range=[0, 10])
@mark_output(0, name="sum", range=[0, 20])
def add(a: int, b: int) -> int:
    return a + b

print(add(5, 5))  # will print "10"
print(add(20, 20))  # will raise an CheckError
$ python tmp/test.py
10
Traceback (most recent call last):
  File ".\tmp\test2.py", line 11, in <module>
    print(add(20, 20))  # will raise an CheckError
  File "C:\Users\Nangu\Desktop\funcdesc\funcdesc\guard.py", line 46, in __call__
    self._check_inputs(pass_in, errors)
  File "C:\Users\Nangu\Desktop\funcdesc\funcdesc\guard.py", line 58, in _check_inputs
    raise CheckError(errors)
funcdesc.guard.CheckError: [ValueError('Value 20 is not in a valid range([0, 10]).'), ValueError('Value 20 is not in a valid range([0, 10]).')]

Builtin types

funcdesc provides some built-in types to facilitate the use of the guard.

Builtin Value types

OneOf and SubSet.

from funcdesc import mark_input, make_guard
from funcdesc.types import SubSet, OneOf


member_list = ["Tom", "Jerry", "Jack"]
food_list = ["apple", "dumpling", "noodles", "banana"]


@make_guard
@mark_input(0, type=OneOf, range=member_list)
@mark_input(1, type=SubSet, range=food_list)
def eat(person, foods):
    print(f"{person} eats {' '.join(foods)}")


eat("Tom", ["apple", "dumpling"])
eat("Jack", ["banana", "noodles"])
eat("Jared", ["apple"])  # "Jared" not in member_list, will raise exception
eat("Tom", ["fish"])  # "fish" not in foods_list, will raise exception

InputPath and OutputPath

from funcdesc.types import InputPath, OutputPath
from funcdesc import make_guard


@make_guard
def copy_file(in_path: InputPath, out_path: OutputPath):
    with open(in_path) as fi, open(out_path, 'w') as fo:
        fo.write(fi.read())


copy_file("file_exist", "another_file")
copy_file("file_not_exist", "another_file")  # will raise exception

Change function's signature

funcdesc also provides some utility functions for modifying function signature, in order to annotate functions with variable-length parameter types.

Change the parameters signature:

import inspect
from funcdesc.mark import sign_parameters

@sign_parameters("a", ("b", int), ("c", int, 10))
def f(*args) -> int:
    return sum(args)

# The signature of `f` is changed
sig = inspect.signature(f)
assert len(sig.parameters) == 3
assert sig.parameters["a"].annotation is inspect._empty
assert sig.parameters["b"].annotation is int
assert sig.parameters["c"].default == 10

Change the return signature:

import inspect
from funcdesc.mark import sign_return

@sign_return(str)
def f(a: int):
    return str(a)

# The signature of `f` is changed
sig = inspect.signature(f)
assert sig.return_annotation is str

Copy the signature of a function to another function:

import inspect
from funcdesc.mark import copy_signature

def f(a: int) -> str:
    return str(a)

@copy_signature(f)
def g(b):
    return str(b)

# The signature of `g` is copied from `f`
sig = inspect.signature(g)
assert sig.parameters["a"].annotation is int
assert sig.return_annotation is str

Generate a Signature object from Description object:

from funcdesc import parse_func

def f(a: int) -> str:
    return str(a)

desc = parse_func(f)
sig = desc.compose_signature()
print(sig) # will print: (a: int) -> str

Related projects

  • oneFace: Generating interfaces(CLI, Qt GUI, Dash web app) from a Python function or a command program.

Project details


Download files

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

Source Distribution

funcdesc-0.2.1.tar.gz (18.2 kB view details)

Uploaded Source

Built Distribution

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

funcdesc-0.2.1-py3-none-any.whl (19.7 kB view details)

Uploaded Python 3

File details

Details for the file funcdesc-0.2.1.tar.gz.

File metadata

  • Download URL: funcdesc-0.2.1.tar.gz
  • Upload date:
  • Size: 18.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.7

File hashes

Hashes for funcdesc-0.2.1.tar.gz
Algorithm Hash digest
SHA256 6330ce8a33f1cd6bc387df2d707a0f91c3a08ad05dcbda002cf5cc7440474435
MD5 f6d7a68be786bc095ef7b7639d84667b
BLAKE2b-256 67c12fe5bc5194a8659f4433c11682fe9c16acf83cc0a155d165ae3a029ee148

See more details on using hashes here.

File details

Details for the file funcdesc-0.2.1-py3-none-any.whl.

File metadata

  • Download URL: funcdesc-0.2.1-py3-none-any.whl
  • Upload date:
  • Size: 19.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.7

File hashes

Hashes for funcdesc-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 64f5b49e686562e69d02940bf2d0db96c9d831a0af3b1ef6c32c582cc641bc05
MD5 7063cf98c92be5a4827d05f46dc1ab17
BLAKE2b-256 39c06ca2fa289d9dd890af713ee6721af530a4464f9d6746cb18bfe17d52e113

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page