> built 2026-10-20 18:35 UTC from 1831bc2 (master) · py2http 0.1.78. Details: build_info.json

# index.html.md

<!-- generated by epythet -->

[Documentation here](https://i2mint.github.io/py2http/)

# py2http

Dispatching Python functions as http services.

You have some python objects and want to get an “equivalent” http service from them…

## Usage

Run a basic HTTP service from a list of functions.

```python
from py2http.service import run_app

# Define or import functions
def add(a, b):
    return a + b

def multiply(a, b):
    return a * b

class Divider:
    def __init__(self, dividend):
        self.dividend = dividend
    
    def divide(self, divisor):
        return self.dividend / divisor

divider_from_ten = Divider(10)

# Make a list of functions or instance methods
func_list = [add, multiply, divider_from_ten.divide]

# Create an HTTP server
run_app(func_list, publish_openapi=True, publish_swagger=True)
```

The HTTP server will listen on port 3030 by default.

Given we asked for those options, you can:

* access the OpenAPI specification of the http-service at http://localhost:3030/openapi
* access the swagger docs and fiddle of the http-service at http://localhost:3030/swagger
* actually use the http-service’s routes, for example:

```python
# Test the server in a separate process
import requests

url = 'http://localhost:3030/add'
add_args = {'a': 20, 'b': 22}
requests.post(url, json=add_args).json()
# should return 42
```

## Configuration

`run_app` accept many configuration values to customize the handling of HTTP requests and responses. Configuration documentation is listed in the file `config.yaml`.

## Method transformation

Expose class methods by flattening the init -> method call process.

```python
from py2http import run_app
from py2http.decorators import mk_flat

class Adder:
    def __init__(self, a):
        self.a = a

    def add(self, b):
        return self.a + b

add = mk_flat(Adder, Adder.add, func_name='add')

func_list = [add]

run_app(func_list)
```

## Input mapping

By default, the server will only accept JSON requests and parse the values from the request body as keyword arguments. You can define custom input mappers to perform extra handling on the JSON body or directly on the HTTP library request object, such as default injection or type mapping.

```python
from numpy import array
import soundfile
from py2http.decorators import handle_json_req

from my_service.data import fetch_user_data

@handle_json_req  # extracts the JSON body and passes it to the input mapper as a dict
def array_input_mapper(input_kwargs):
    return {'arr': array(input_kwargs.get('arr', [])),
            'scalar': input_kwargs.get('scalar', 1)}

@handle_multipart_req  # extracts a multipart body and passes it as a dict
def sound_file_input_mapper(input_kwargs):
    file_input = input_kwargs['file_upload']
    filename = file_input.filename
    file_bytes = BytesIO(file_input.file)
    wf, sr = soundfile.read(file_bytes)
    return dict(input_kwargs, wf=wf, sr=sr, filename=filename)

def custom_header_input_mapper(req):  # takes a raw aiohttp request
    user = req.headers.get('User', '')
    return {'user': user}


def array_multiplier(arr, scalar):
    return arr * scalar

def save_audio(wf, sr, filename, storage_path='/audio'):
    target = os.path.join(storage_path, filename)
    soundfile.write(target, wf, sr)

def get_user_data(user):
    return fetch_user_data(user)

array_multiplier.input_mapper = array_input_mapper
save_audio.input_mapper = sound_file_input_mapper
get_user_data.input_mapper = custom_header_input_mapper
```

## Output mapping

By default, the server will send the return value of the handler function in an HTTP response in JSON format. You can define custom output mappers to perform extra handling or type conversion.

```python
from io import BytesIO
import soundfile

from py2http.decorators import send_json_resp, send_html_resp

from my_service.data import fetch_blog

@send_json_resp  # sends a JSON response
def array_output_mapper(output, input_kwargs):
    return {'array_value': output['array_value'].tolist()}

@send_html_resp  # sends an HTML response
def mk_html_list(output, input_kwargs):
    tag = input_kwargs.get('tag', 'p')
    item_list = output.split('\n')
    result = [f'<{tag}>{item}</{tag}>' for item in item_list]
    return ''.join(result)

def return_wav(output, input_kwargs):
    wf, sr = output
    wf_bytes = BytesIO()
    soundfile.write(wf_bytes, wf, sr)
    binary_result = wf_bytes.read()
    return web.Response(body=binary_result, content_type='application/octet-stream')


def array_multiplier(arr, scalar):
    return arr * scalar

def get_blog_posts(page):
    return fetch_blog(page)

def download_audio(filename):
    with open(filename) as fp:
        wf, sr = soundfile.read(fp)
    return wf, sr

array_multipler.output_mapper = array_output_mapper

get_blog_posts.output_mapper = mk_html_list

download_audio.output_mapper = return_wav


```

## Error handling

TODO

## Client generation

Py2http generates an OpenAPI specification for the server before running. You can use this document with any OpenAPI-compatible client tools. To extract the specification, you can generate a server application object before running it.

```python
import json
from py2http import mk_app, run_app

def add(a, b):
    return a + b

func_list = [add]

app = mk_app(func_list)
openapi_spec = app.openapi_spec

with open('~/openapi.json', 'w') as fp:
    json.dump(openapi_spec, fp)

run_app(app, port=3030)
```

## Configuration

Functions that generate an HTTP service, such as `run_app`, accept a number of keyword arguments for configuration. The available configuration arguments are listed below with their defaults.

* `framework=py2http.config.BOTTLE` The HTTP framework to use.
* `input_mapper=py2http.default_configs.default_input_mapper` A function to map an HTTP request to a dict of input arguments.
* `output_mapper=py2http.default_configs.default_output_mapper` A function to map the output of a function to an HTTP response.
* `error_handler=py2http.default_configs.default_error_handler` A function to map an exception to an HTTP response.
* `header_inputs={}` A dict of object properties in JSON schema format describing keys that should be excluded from request body definitions. These inputs are expected to be extracted from the request headers in the input mapper.
* `host='localhost'` The hostname the server can be reached at, to include in the OpenAPI specification.
* `port=3030` The TCP port to listen on.
* `http_method='post'` The default HTTP method for exposing functions, if a function does not specify its method.
* `openapi={}` A dict with several configuration options specific to the OpenAPI specification, described below.
* `logger=None` An object that implements a `log` method.
* `app_name='HTTP Service'` The name of the application (Flask only).
* `middleware=[]` A list of middlewares to run (aiohttp only).
* `plugins=[]` A list of plugins to install (bottle only).
* `enable_cors=False` Whether to enable CORS features.
* `cors_allowed_origins='*'` If CORS is enabled, the value to pass in the Access-Control-Allow-Origin header.
* `publish_openapi=False` Whether to add a GET /openapi route to the app that returns the OpenAPI specification.
* `openapi_insecure=False` Whether to skip middlewares and plugins for the /openapi route (disabling any authentication).
* `publish_swagger=False` Whether to add a GET route to the app that returns a Swagger HTML interface.
* `swagger_url='/swagger'` The URL of the swagger route.
* `swagger_title='Swagger'` The title to display on the Swagger HTML page.
* `ssl_certfile=None` The path to a valid SSL certificate.
* `ssl_keyfile=None` The path to a valid SSL certificate’s key.

OpenAPI configuration:

These values will be put in the OpenAPI specification document. All values are optional.

* `title` The title of the application.
* `version` The version number of the application.
* `auth`: A dict specifying the authentication details to include in the document, to make it easier for clients to automate authentication.
* `auth['auth_type']` Either ‘jwt’ or ‘api_key’.
* `auth['login_details']` A dict describing how a client can log in (for jwt authentication only).
* `auth['login_details']['login_url']` The URL of the login route.
* `auth['login_details']['refresh_url']`: The URL of the refresh route.
* `auth['login_details']['login_inputs']`: A list of strings with the keys expected by the login endpoint.
* `auth['login_details']['refresh_inputs']`: A list of strings with the keys expected by the refresh endpoint.
* `auth['login_details']['outputs']`: A list of strings with the keys returned by the login/refresh endpoints.,

<p class="epythet-aggregates">This documentation as a single file: <a href="py2http.md">py2http.md</a> (Markdown, for agents).</p>


# _autosummary/py2http.auth.html.md

# py2http.auth

Framework-independent credential checks, shared by the aiohttp middleware
(`py2http.middleware`) and the Bottle plugins (`py2http.bottle_plugins`), so that
both refuse the same tokens and keys for the same reasons.

```pycon
>>> bearer_token('Bearer abc'), bearer_token('bearer abc'), bearer_token('Basic abc')
('abc', 'abc', '')
>>> key_matches('k-123', 'k-123'), key_matches('k-12', 'k-123'), key_matches(None, 'k')
(True, False, False)
```

### Functions

| [`bearer_token`](_autosummary/py2http.auth.html.md#py2http.auth.bearer_token)(authorization_header)               | The token of an `Authorization: Bearer <token>` header, or `''`.                                                       |
|---------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------|
| [`decode_jwt`](_autosummary/py2http.auth.html.md#py2http.auth.decode_jwt)(token, secret, \*, algorithms[, ...]) | The claims of `token`, or `CredentialsRejected` with a client-safe reason.                                             |
| [`jwt_algorithms`](_autosummary/py2http.auth.html.md#py2http.auth.jwt_algorithms)(secret, \*[, verify, ...])        | Validate a JWT verification setup, returning the algorithms as a list.                                                 |
| [`jwt_decode_kwargs`](_autosummary/py2http.auth.html.md#py2http.auth.jwt_decode_kwargs)([decode_kwargs])               | Validate extra `jwt.decode` arguments (`audience`, `issuer`, `leeway`...), refusing those the verification setup owns. |
| [`key_matches`](_autosummary/py2http.auth.html.md#py2http.auth.key_matches)(given, expected)                     | Whether the `given` credential equals `expected`, in constant time.                                                    |
| [`required_key`](_autosummary/py2http.auth.html.md#py2http.auth.required_key)(key, \*[, name])                    | `key`, refused when empty: an empty key would let a request with no `Authorization` header through.                    |

### Classes

| [`AuthPlugin`](_autosummary/py2http.auth.html.md#py2http.auth.AuthPlugin)()   | What a plugin must be to guard a Flask app (see `py2http.flask_plugins`): a subclass with a `challenge` (the `WWW-Authenticate` value of a refusal) and an `authenticate` that raises `CredentialsRejected` to refuse a request.   |
|-----------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

### Exceptions

| [`CredentialsRejected`](_autosummary/py2http.auth.html.md#py2http.auth.CredentialsRejected)   | A request's credentials were refused.   |
|------------------------------------------------------------------------|-----------------------------------------|

### *class* py2http.auth.AuthPlugin

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

What a plugin must be to guard a Flask app (see `py2http.flask_plugins`): a
subclass with a `challenge` (the `WWW-Authenticate` value of a refusal) and an
`authenticate` that raises `CredentialsRejected` to refuse a request. It is a
marker class rather than a duck-typed method name, so that a plugin which merely has
some `authenticate` method (returning `False` to refuse, say) can’t be mistaken
for one and let everything through.

#### authenticate(authorization_header, , method, endpoint)

The claims to put on the request, or `None`; `CredentialsRejected` refuses.

### *exception* py2http.auth.CredentialsRejected

Bases: [`Exception`](https://docs.python.org/3/builtins/exceptions.html#Exception)

A request’s credentials were refused. The message is safe to show the client:
it never contains the token, nor anything about the server’s key.

### py2http.auth.bearer_token(authorization_header)

The token of an `Authorization: Bearer <token>` header, or `''`.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

### py2http.auth.decode_jwt(token, secret, , algorithms, verify=True, decode_kwargs=None)

The claims of `token`, or `CredentialsRejected` with a client-safe reason.

With `verify=False` neither the signature nor the claims (`exp`…) are checked.
`decode_kwargs` (`audience`, `issuer`, `leeway`…) go to `jwt.decode`.

* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)

### py2http.auth.jwt_algorithms(secret, , verify=True, algorithms=('HS256',), allow_mixed_algorithm_families=False)

Validate a JWT verification setup, returning the algorithms as a list.

Raises at construction time, rather than accepting forgeries at request time, when:

- `algorithms` is empty, a bare string, or names an unknown or unsigned (`none`)
  algorithm (PyJWT names are case-sensitive);
- `verify` is True and `secret` is empty (an empty HMAC secret lets anyone sign
  tokens), or an HMAC algorithm is asked for with a non-`str`/`bytes` secret;
- `verify` is True and HMAC and public-key algorithms are mixed with one
  `secret` (the classic algorithm-confusion setup), unless
  `allow_mixed_algorithm_families` is True.

```pycon
>>> jwt_algorithms('s3cret')
['HS256']
>>> jwt_algorithms('', algorithms=['HS256'])
Traceback (most recent call last):
  ...
ValueError: secret must be a non-empty key when verify=True
```

* **Return type:**
  [`list`](https://docs.python.org/3/builtins/stdtypes.html#list)

### py2http.auth.jwt_decode_kwargs(decode_kwargs=None)

Validate extra `jwt.decode` arguments (`audience`, `issuer`,
`leeway`…), refusing those the verification setup owns.

```pycon
>>> jwt_decode_kwargs({'audience': 'my-api'})
{'audience': 'my-api'}
>>> jwt_decode_kwargs({'options': {'verify_signature': False}})
Traceback (most recent call last):
  ...
ValueError: decode_kwargs may not set ['options']; use verify= and algorithms=
```

* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)

### py2http.auth.key_matches(given, expected)

Whether the `given` credential equals `expected`, in constant time.

* **Return type:**
  [`bool`](https://docs.python.org/3/builtins/functions.html#bool)

### py2http.auth.required_key(key, , name='api_key')

`key`, refused when empty: an empty key would let a request with no
`Authorization` header through.


# _autosummary/py2http.bottle_plugins.html.md

# py2http.bottle_plugins

Plugins for adding middleware functionality to Bottle apps.

### Classes

| [`ApiKeyAuthPlugin`](_autosummary/py2http.bottle_plugins.html.md#py2http.bottle_plugins.ApiKeyAuthPlugin)(api_key)                | A plugin letting through only requests whose `Authorization` header is exactly `api_key` (compared in constant time; an empty key is refused).   |
|-------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------|
| `CorsPlugin`([origins])                                                                   |                                                                                                                                                  |
| [`JWTPlugin`](_autosummary/py2http.bottle_plugins.html.md#py2http.bottle_plugins.JWTPlugin)([secret, verify, mapper, ...]) | A plugin for validating JWTs and extracting their payloads.                                                                                      |

### *class* py2http.bottle_plugins.ApiKeyAuthPlugin(api_key)

Bases: [`AuthPlugin`](_autosummary/py2http.auth.html.md#py2http.auth.AuthPlugin)

A plugin letting through only requests whose `Authorization` header is
exactly `api_key` (compared in constant time; an empty key is refused).

#### authenticate(authorization_header, , method, endpoint)

`None` (the key sets nothing on the request) if the header is the key,
else `CredentialsRejected`. Framework-independent, like `JWTPlugin`’s.

### *class* py2http.bottle_plugins.JWTPlugin(secret='', verify=True, mapper=None, ignore_methods=None, algorithms=None, , allow_mixed_algorithm_families=False, decode_kwargs=None)

Bases: [`AuthPlugin`](_autosummary/py2http.auth.html.md#py2http.auth.AuthPlugin)

A plugin for validating JWTs and extracting their payloads.

After optionally validating a JWT found in the request header, will assign a dict with the JWT claims
to request.token.

#### authenticate(authorization_header, , method, endpoint)

The claims to put on the request (`None` when there are none to put), or
`CredentialsRejected`. Framework-independent: the Bottle plugin and the Flask
`before_request` hook (`py2http.flask_plugins`) both call it.


# _autosummary/py2http.config.html.md

# py2http.config

The code module provides functions for retrieving configuration values for a
function based on a hierarchy of sources, including function properties,
configuration dictionaries, and default values. The `get_result` function is used to
allow nested configurations by function name, with an example provided in the docstring
for illustration.

The `mk_config` function is used to get a configuration value for a function by checking
the function properties, configuration dictionaries, and default values. It also allows
for specifying the expected type of the output, with options to provide additional
options such as the function name and expected type.

Overall, the module helps manage and retrieve configuration values for functions,
ensuring they are appropriately set and validated based on the function’s requirements.

### Functions

| [`get_result`](_autosummary/py2http.config.html.md#py2http.config.get_result)(configs, func, funcname, key, options)   | this is meant to allow nested configs by function name example:   |
|------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------|
| [`mk_config`](_autosummary/py2http.config.html.md#py2http.config.mk_config)(key, func, configs, defaults, ...)        | Get a config value for a function.                                |

### py2http.config.get_result(configs, func, funcname, key, options)

this is meant to allow nested configs by function name
example:

# TODO: See mk_config use and make an actual doctest for get_result
# >>> def create_something():
# …    pass
# >>> example_configs = {‘http_method’: {
# …    ‘create_something’: ‘post’,
# …    ‘get_something’: ‘get’,
# … }}
# >>> defaults = {‘create_something’: ‘DEFAULTED’}
# >>> get_result(example_configs, create_something, ‘create_something’, ‘http_method’, defaults)
# ‘post’

### py2http.config.mk_config(key, func, configs, defaults, \*\*options)

Get a config value for a function. First checks the properties of the function,
then the configs, then the defaults.

* **Parameters:**
  * **key** – The key to search for
  * **func** – The function associated with the config
  * **configs** – A config dict to search
  * **defaults** – The default configs to fall back on
  * **\*\*options** – Additional options
* **Keyword Arguments:**
  * *funcname*
    The name of the function, if not the same as func._\_name_\_
  * *type*
    The expected type of the output (use Callable for functions)


# _autosummary/py2http.constants.html.md

# py2http.constants

This module provides functionality for dispatching Python functions as HTTP services. It allows users to create a basic HTTP server from a list of functions or instance methods, customize input and output mapping, handle errors, generate client code from an OpenAPI specification, and configure various aspects of the server setup. The module includes features for transforming class methods, mapping input and output data, handling errors, and generating client code. It also supports configuration options for the HTTP framework, input and output mappers, error handlers, openAPI specifications, logging, middleware, plugins, CORS, SSL certificates, and more.

### Module Attributes

| [`WWW_AUTHENTICATE_ENV_VAR`](_autosummary/py2http.constants.html.md#py2http.constants.WWW_AUTHENTICATE_ENV_VAR)   | Environment variable naming the challenge for a 401 a dispatched function raised (`AuthorizationError`); the deployment's auth decides it.   |
|-----------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------|

### py2http.constants.WWW_AUTHENTICATE_ENV_VAR *= 'PY2HTTP_WWW_AUTHENTICATE'*

Environment variable naming the challenge for a 401 a dispatched function raised
(`AuthorizationError`); the deployment’s auth decides it. Default: Bearer.


# _autosummary/py2http.decorators.html.md

# py2http.decorators

Decorator tools for py2http.

### Functions

| [`add_attrs`](_autosummary/py2http.decorators.html.md#py2http.decorators.add_attrs)(\*\*attrs)                           | Makes a function that adds attributes to a function.                        |
|-------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------|
| `base_output_mapper`(output, \*\*inputs)                                                        |                                                                             |
| `binary_output`(func)                                                                           |                                                                             |
| [`ensure_awaitable_return_annot`](_autosummary/py2http.decorators.html.md#py2http.decorators.ensure_awaitable_return_annot)(func)            |                                                                             |
| [`flatten_callables`](_autosummary/py2http.decorators.html.md#py2http.decorators.flatten_callables)(\*callables[, func_name])    | Flatten a pipeline of calls into one function.                              |
| `flatten_methods`(methods[, decorator, ...])                                                    |                                                                             |
| [`handle_binary_req`](_autosummary/py2http.decorators.html.md#py2http.decorators.handle_binary_req)(func, \*[, loads])           | Make an input mapper that decodes a binary (octet-stream) request body.     |
| `handle_form_req`(func)                                                                         |                                                                             |
| `handle_json_req`(func)                                                                         |                                                                             |
| `handle_raw_req`(func)                                                                          |                                                                             |
| `http_delete`(func)                                                                             |                                                                             |
| `http_get`(func)                                                                                |                                                                             |
| `http_post`(func)                                                                               |                                                                             |
| `http_put`(func)                                                                                |                                                                             |
| `ignore_extra_arguments`(func)                                                                  |                                                                             |
| [`inject_methodized_funcs`](_autosummary/py2http.decorators.html.md#py2http.decorators.inject_methodized_funcs)([cls, funcs, ...])     |                                                                             |
| [`methodizer`](_autosummary/py2http.decorators.html.md#py2http.decorators.methodizer)([func, instance_params])            | A decorator to get method versions of functions.                            |
| [`mk_flat`](_autosummary/py2http.decorators.html.md#py2http.decorators.mk_flat)(cls, method, \*[, func_name, ...])     | Flatten a simple cls->instance->method call pipeline into one function.     |
| `mk_handlers`(methods, \*[, decorator, ...])                                                    |                                                                             |
| `mk_input_mapper`(input_map)                                                                    |                                                                             |
| [`params_replacer`](_autosummary/py2http.decorators.html.md#py2http.decorators.params_replacer)(replace, obj)                  | Generator of transformed params.                                            |
| [`replace_with_params`](_autosummary/py2http.decorators.html.md#py2http.decorators.replace_with_params)([target, source, inplace]) | Will return a version of the target type that has params taken from source. |
| `route`(route_name)                                                                             |                                                                             |
| `send_binary_resp`(func)                                                                        |                                                                             |
| `send_html_resp`(func)                                                                          |                                                                             |
| `send_json_resp`(func)                                                                          |                                                                             |
| `send_raw_resp`(func)                                                                           |                                                                             |
| [`unsafe_pickle_loads`](_autosummary/py2http.decorators.html.md#py2http.decorators.unsafe_pickle_loads)(data)                      | Unpickle `data`.                                                            |

### Classes

| `DecoParam`(default, annotation)                                                                    |                                                                                                                                                      |
|-----------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------|
| [`DecoParameter`](_autosummary/py2http.decorators.html.md#py2http.decorators.DecoParameter)(name, kind, \*, default, annotation) | A Parameter object that is meant to be the a parameter of a decorator factory.                                                                       |
| [`Decora`](_autosummary/py2http.decorators.html.md#py2http.decorators.Decora)([func])                                     | A version of Decorator where you can define your subclasses by defininig attributes of the subclass (instead of writing a manual \_\_new_\_ method). |
| [`Decorator`](_autosummary/py2http.decorators.html.md#py2http.decorators.Decorator)([func])                                  | A "transparent" decorator meant to be used to subclass into specialized decorators.                                                                  |
| [`JsonRespEncoder`](_autosummary/py2http.decorators.html.md#py2http.decorators.JsonRespEncoder)(\*[, skipkeys, ensure_ascii, ...]) |                                                                                                                                                      |
| [`Literal`](_autosummary/py2http.decorators.html.md#py2http.decorators.Literal)(val)                                       | An object to indicate that the value should be considered literally                                                                                  |
| [`ParamsSpecifier`](_autosummary/py2http.decorators.html.md#py2http.decorators.ParamsSpecifier)([_annotations, \_names, ...])      | A tool to specify params (that is, lists of inspect.Parameter instances that are used in callable signatures.                                        |
| [`ProposalJsonRespEncoder`](_autosummary/py2http.decorators.html.md#py2http.decorators.ProposalJsonRespEncoder)(\*[, skipkeys, ...])       |                                                                                                                                                      |

### *class* py2http.decorators.DecoParameter(name, kind, , default, annotation)

Bases: [`Parameter`](https://docs.python.org/3/library/inspect.html#inspect.Parameter)

A Parameter object that is meant to be the a parameter of a decorator factory.
Subclassing inspect.Parameter so that it can be distinguished from it if needed.

### *class* py2http.decorators.Decora(func=None, \*\*kwargs)

Bases: [`Decorator`](_autosummary/py2http.decorators.html.md#py2http.decorators.Decorator)

A version of Decorator where you can define your subclasses by defininig attributes
of the subclass (instead of writing a manual \_\_new_\_ method).

Here’s a typical use, as a decorator factory…

```pycon
>>> from py2http.decorators import Decora, ParamsSpecifier
>>>
>>>
>>> class whatevs(ParamsSpecifier):
...     minus = 3
...     times: float
...     repeat: int = 2
>>>
>>> class Deco(Decora):
...     my_params = whatevs()
...
...     def __call__(self, *args, **kwargs):
...         func_result = super().__call__(*args, **kwargs)
...         return func_result[0], [func_result[1] * self.times - self.minus] * self.repeat
>>>
>>> def f(w: float, x: int=0, greet='hi'):
...     return greet, w + x
>>>
>>>
>>>
>>> g = Deco(times=3)(f)
>>> assert g(0) == ('hi', [-3] * 2)
>>> assert g(10) == ('hi', [27] * 2)
>>> assert g(10, x=1, greet='hello') == ('hello', [30, 30])
>>>
>>> g = Deco(f, times=1, minus=2, repeat=3)
>>> assert g(0) == ('hi', [-2, -2, -2])
>>> g = Deco(times=0, minus=3, repeat=1)(f)
>>> assert g(10) == ('hi', [-3])
>>> g = Deco(times=2, minus=0, repeat=1)(f)
>>> assert g(10) == ('hi', [20])
>>> f = lambda x, y=1: x + y
>>> f(10)
11
>>> signature(f)
<Signature (x, y=1)>
>>>
```

More examples (of different forms)

```pycon
>>> class LogCalls(Decora):
...     class DecoParams(ParamsSpecifier):
...         verb: str = 'calling'  # will be taken and included in the __init__
...         decoy = None  # will be taken (but not actually used in __call__)
...
...     def __call__(self, *args, **kwargs):
...         print(f'{self.verb} {self.func.__name__} with {args} and {kwargs}')
...         return super().__call__(*args, **kwargs)
...
>>> ff = LogCalls(f, verb='launching')  # doing it the "decorator way"
>>> assert ff(10) == 11
launching <lambda> with (10,) and {}
>>> signature(ff)
<Signature (x, y=1)>
>>> assert signature(ff) == signature(f)  # asserting same signature as the wrapped f
>>> signature(LogCalls)  # the signature of the decorator itself
<Signature (func=None, *, verb: str = 'calling', decoy=None)>
>>>
>>> ff = LogCalls()(f)  # defaults work when using as factory
>>> signature(ff)
<Signature (x, y=1)>
>>> ff(10)
calling <lambda> with (10,) and {}
11
>>> ff = LogCalls(f)  # defaults work when using as decorator
>>> ff(10)
calling <lambda> with (10,) and {}
11
>>>
>>> LogCalls(f, real_arg=False)  # rejects arguments that weren't "registered" by the __new__
Traceback (most recent call last):
    ...
TypeError: TypeError: __new__() got unexpected keyword arguments: {'real_arg'}
>>>
```

But you can still do it with \_\_new_\_ if you want

```pycon
>>> class ProcessOutput(Decora):
...     def __new__(cls, func=None, *, postproc=None):
...         postproc = postproc or (lambda x: x)
...         return super().__new__(cls, func, postproc=postproc)
...
...     def __call__(self, *args, **kwargs):
...         return self.postproc(super().__call__(*args, **kwargs))
...
>>> fff = ProcessOutput(postproc=str)(f)  # doing it the "decorator factory way"
>>> assert fff(10) == "11"
>>> assert signature(fff)  == signature(f)
>>> signature(ProcessOutput)  # the signature of the decorator itself
<Signature (func=None, *, postproc=None)>
>>>
>>> # Verifying that LogCalls still has the right signature
>>> signature(LogCalls)  # the signature of the decorator itself
<Signature (func=None, *, verb: str = 'calling', decoy=None)>
```

### *class* py2http.decorators.Decorator(func=None, \*\*kwargs)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

A “transparent” decorator meant to be used to subclass into specialized decorators.

The signature of the wrapped function is carried to the \_\_call_\_ of the decorated instance.

To specialize (and do something else than just “transparent” wrapping, you need to subclass
Decorator and define your own `__call__` method. You may assume that

The decorator pattern is a significant reuse tool, and indeed we use them a lot in i2i tooling.
The standard way is to write decorators (and decorator factories) the functional was,
but writing them as classes has introspection (therefore debuggability) advantages.

The approach comes with other kinds of problems though.
One of them is signature transfer (both for the decorator and the decorator factory).
Taken care of here.

Another wish (not really a problem) is to be able to use both `deco(func, params)`
and `deco(params(func))` forms. Also taken care of here.

Another problem is an increased boilerplate in specifying the decorator mechanics.
For example: If you want to have a proper signature (not just \*\*kwargs),
you need to overwrite `__new__` for the sole purpose of specifying the arguments
(names, and optional annotations and defaults).
This problem is not taken care of here, but you can check out `Decora`,
a subclass of Decorator, that does.

```pycon
>>> from py2http.decorators import Decorator
>>> f = lambda x, y=1: x + y  # a function to decorate
>>> f(10)
11
>>> signature(f)
<Signature (x, y=1)>
>>>
>>> class LogCalls(Decorator):
...     def __new__(cls, func=None, *, verb='calling'):
...         return super().__new__(cls, func, verb=verb)
...
...     def __call__(self, *args, **kwargs):
...         print(f'{self.verb} {self.func.__name__} with {args} and {kwargs}')
...         return super().__call__(*args, **kwargs)
...
>>> ff = LogCalls(f, verb='launching')  # doing it the "decorator way"
>>> assert ff(10) == 11
launching <lambda> with (10,) and {}
>>> signature(ff)
<Signature (x, y=1)>
>>> assert signature(ff) == signature(f)  # asserting same signature as the wrapped f
>>> signature(LogCalls)
<Signature (func=None, *, verb='calling')>
>>>
>>> class ProcessOutput(Decorator):
...     def __new__(cls, func=None, *, postproc=None):
...         postproc = postproc or (lambda x: x)
...         return super().__new__(cls, func, postproc=postproc)
...
...     def __call__(self, *args, **kwargs):
...         return self.postproc(super().__call__(*args, **kwargs))
...
>>>
>>>
>>> fff = ProcessOutput(postproc=str)(f)  # doing it the "decorator factory way"
>>> assert fff(10) == "11"
>>> assert signature(fff)  == signature(f)
>>> signature(ProcessOutput)
<Signature (func=None, *, postproc=None)>
>>>
>>> ff = LogCalls()(f)  # defaults work when using as factory
>>> signature(ff)
<Signature (x, y=1)>
>>> ff(10)
calling <lambda> with (10,) and {}
11
>>> ff = LogCalls(f)  # defaults work when using as decorator
>>> ff(10)
calling <lambda> with (10,) and {}
11
>>> # rejects arguments that weren't "registered" by the __new__:
>>> LogCalls(f, real_arg=False)
Traceback (most recent call last):
    ...
TypeError: __new__() got an unexpected keyword argument 'real_arg'
```

### *class* py2http.decorators.JsonRespEncoder(, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, sort_keys=False, indent=None, separators=None, default=None)

Bases: [`JSONEncoder`](https://docs.python.org/3/library/json.html#json.JSONEncoder)

#### default(o)

Implement this method in a subclass such that it returns
a serializable object for `o`, or calls the base implementation
(to raise a `TypeError`).

For example, to support arbitrary iterators, you could
implement default like this:

```default
def default(self, o):
    try:
        iterable = iter(o)
    except TypeError:
        pass
    else:
        return list(iterable)
    # Let the base class default method raise the TypeError
    return super().default(o)
```

### *class* py2http.decorators.Literal(val)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

An object to indicate that the value should be considered literally

### *class* py2http.decorators.ParamsSpecifier(\_annotations=None, \_names='', \_dflt_default=None, \_kind=\_ParameterKind.KEYWORD_ONLY, \*\*name_and_dflts)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

A tool to specify params (that is, lists of inspect.Parameter instances that
are used in callable signatures.

But wait! you may not need this!

Often the cleanest way to make a signature, or list of Parameters is to define an empty function
with that signature, and extract it from there.

See `Decora` for the original intended use of ParamsSpecifier.

```pycon
>>> from inspect import signature, Signature, Parameter
>>> def f(a, b: int, c: float = 0.0, d: str='hi'): ...
>>> sig = signature(f)
>>> sig
<Signature (a, b: int, c: float = 0.0, d: str = 'hi')>
>>> list(sig.parameters.values())
[<Parameter "a">, <Parameter "b: int">, <Parameter "c: float = 0.0">, <Parameter "d: str = 'hi'">]
```

The reason for the existence of ParamsSpecifier was to do some magic around giving class-based
decorators a signature. The reasons of this magic may be outdated soon.

```pycon
>>> from py2http.decorators import ParamsSpecifier
>>> from inspect import Parameter, Signature
>>> KO = Parameter.KEYWORD_ONLY
>>>
>>> class MyParams(ParamsSpecifier):
...     b = 3
...     z: float
...     c: int = 2
...
>>> params = MyParams()()
>>> expected_params = [
...     {'name': 'z', 'kind': KO, 'default': None, 'annotation': float},
...     {'name': 'b', 'kind': KO, 'default': 3},
...     {'name': 'c', 'kind': KO, 'default': 2, 'annotation': int}]
>>> assert params == expected_params
```

See that the params are all valid kwargs to inspect.Parameter, by making a signature from them

```pycon
>>> Signature(Parameter(**p) for p in params)
<Signature (*, z: float = None, b=3, c: int = 2)>
```

Let’s now get another params specifier.

```pycon
>>> get_new_params = MyParams(
...     _annotations=dict(b=int, a=str),
...     _names='a wol',
...     another='here')
>>> params = get_new_params()
>>> expected_params = [
...     {'name': 'z', 'kind': KO, 'default': None, 'annotation': float},
...     {'name': 'b', 'kind': KO, 'default': 3, 'annotation': int},
...     {'name': 'c', 'kind': KO, 'default': 2, 'annotation': int},
...     {'name': 'another', 'kind': KO, 'default': 'here'},
...     {'name': 'a', 'kind': KO, 'default': None, 'annotation': str},
...     {'name': 'wol', 'kind': KO, 'default': None}]
```

One thing to note in the expected_params is the order.
Indeed, the order is not the order that is taken (because couldn’t figure out otherwise)
is as such:

- First the class-level attributes that are annotated, but not given a default
  : (though a blanket \_dflt_default default will be given to them all).
    Here order is not assured.
- Second the reset of the class-level attributes, in the order they were defined.
- Third the instance argument params given by the \_names argument, in the order they were listed.
- Finally the instance argument name_and_dflts params, in the order they were listed.

Remember, all this is meant to provide ways to specify signatures.

```pycon
>>> Signature(Parameter(**p) for p in params)
<Signature (*, z: float = None, b: int = 3, c: int = 2, another='here', a: str = None, wol=None)>
```

Now, not that ParamsSpecifier is the tool for this, but to demo what ParamsSpecifier’s
params are, we’ll give one last example where we take a function, make a ParamsSpecifier
from it, and add a different kind of default

```pycon
>>> def f(a, b: int, c: float = 0.0, d: str='hi'): ...
>>> param_maker = ParamsSpecifier.from_func(f, _dflt_default='a different dflt')
>>> Signature(Parameter(**p) for p in param_maker())
<Signature (*, a='a different dflt', b: int = 'a different dflt', c: float = 0.0, d: str = 'hi')>
```

### *class* py2http.decorators.ProposalJsonRespEncoder(, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, sort_keys=False, indent=None, separators=None, default=None)

Bases: [`JSONEncoder`](https://docs.python.org/3/library/json.html#json.JSONEncoder)

#### default(o)

Implement this method in a subclass such that it returns
a serializable object for `o`, or calls the base implementation
(to raise a `TypeError`).

For example, to support arbitrary iterators, you could
implement default like this:

```default
def default(self, o):
    try:
        iterable = iter(o)
    except TypeError:
        pass
    else:
        return list(iterable)
    # Let the base class default method raise the TypeError
    return super().default(o)
```

### py2http.decorators.add_attrs(\*\*attrs)

Makes a function that adds attributes to a function.

Used in it’s normal context, it looks something like this:

```pycon
>>> @add_attrs(my_special_attr='my special value', another=42)
... def foo(x):
...     return x + 1
>>>
>>> foo(10)  # checking that this great function still works
11
>>> # checking that it now has some extra attributes
>>> foo.my_special_attr
'my special value'
>>> foo.another
42
```

But it can be useful to make attribute adder, and reuse when needed.

```pycon
>>> brand_my_func = add_attrs(author="me")
>>> _ = brand_my_func(foo)  # not capturing the output to show that the change happens in-place
>>> foo.author
'me'
```

### py2http.decorators.ensure_awaitable_return_annot(func)

```pycon
>>> async def foo(x: str) -> int: ...
>>> assert str(signature(foo)) == '(x: str) -> int'
>>> assert str(signature(ensure_awaitable_return_annot(foo))) == '(x: str) -> Awaitable[int]'
>>>
>>> # but if func is not async, don't change anything
>>> def bar(a) -> str: ...
>>> assert str(signature(bar)) == str(signature(ensure_awaitable_return_annot(bar)))  == '(a) -> str'
>>>
>>> # or if the return annotation is already contained in an Awaitable, don't change anything
>>> async def baz() -> Awaitable[float]: ...
>>> assert str(signature(baz)) == str(signature(ensure_awaitable_return_annot(baz))) == '() -> Awaitable[float]'
```

### py2http.decorators.flatten_callables(\*callables, func_name=None)

Flatten a pipeline of calls into one function.

### py2http.decorators.handle_binary_req(func, , loads=None)

Make an input mapper that decodes a binary (octet-stream) request body.

`loads` turns the raw body bytes into the mapping of keyword arguments for
`func`. There is deliberately no default: request bodies used to be
unpickled implicitly, which lets any client run code on the server. Pass a
safe decoder of your own, or `loads=unsafe_pickle_loads` if (and only if)
every client is trusted.

Note that `http2py` clients encode binary request bodies with pickle, so
they only work against endpoints that opted into `unsafe_pickle_loads`.

```pycon
>>> handle_binary_req(lambda x: x)
Traceback (most recent call last):
  ...
TypeError: handle_binary_req needs an explicit loads=... (bytes -> dict of inputs). ...
```

### py2http.decorators.inject_methodized_funcs(cls=None, , funcs=(), instance_params=None, if_method_exists='raise')

* **Parameters:**
  * **cls**
  * **funcs**
  * **instance_params**
  * **if_method_exists**
* **Returns:**

# TODO: Come back to inject_methodized_funcs doctest once inject_methodized_funcs is well written
# >>> from inspect import signature
# >>>
# >>>
# >>> def f(a, b, x):
# …     return x \* (a + b)
# …
# >>> def g(x, y=1):
# …     return x \* y
# …
# >>>
# >>> def h(a, x, c, \*\*kwargs):
# …     return f”{a}-{x}-{c}: {list(kwargs.keys())}”
# …
# >>> @inject_methodized_funcs(funcs=(f, g, h))
# … class C:
# …     def \_\_init_\_(self, x, a=0, bob=True):
# …         self.x = x
# …         self.a = a
# …         self.bob = bob
# …
# >>>
# >>>
# >>> c = C(x=10)
# >>> for m in (‘f’, ‘g’, ‘h’):
# …     print(f”{C._\_name_\_}.{m}{signature(getattr(c, m))}”)
# …
# C.f(b, x)
# C.g(y, x)
# C.h(kwargs, c, x)

### py2http.decorators.methodizer(func=None, , instance_params=())

A decorator to get method versions of functions.

* **Parameters:**
  * **func**
  * **instance_params**
* **Returns:**

```pycon
>>> from py2http.decorators import methodizer
>>>
>>>
>>> def f(a, b, x):
...     return x * (a + b)
...
>>> def g(x, y=1):
...     return x * y
...
>>> methodize = methodizer(instance_params=('x', 'non_existing_attr'))
>>>
>>> class A:
...     def __init__(self, x=0):
...         self.x = x
...
...     f = methodize(f)
...     g = methodize(g)
...
>>>
>>> a = A(x=3)
>>> assert a.f(b=1, a=2) == 9
>>> assert a.g() == 3
>>> assert a.g(y=10) == 30
```

### py2http.decorators.mk_flat(cls, method, , func_name='flat_func', cls_cache_key=None)

Flatten a simple cls->instance->method call pipeline into one function.

That is, a function mk_flat(cls, method) that returns a “flat function” such that

```text
cls(**init_kwargs).method(**method_kwargs) == flat_func(**init_kwargs, **method_kwargs)
```

So, instead of this:

```graphviz
label="NESTED: result = cls(**init_kwargs).method(**method_kwargs)"
cls, init_kwargs -> instance
instance, method, method_kwargs -> result
```

you get a function `flat_func` that you can use like this:

```graphviz
label="FLAT: result = flat_func(**init_kwargs, **method_kwargs)"
flat_func, init_kwargs, method_kwargs -> result
```

* **Parameters:**
  * **cls** – A class
  * **method** – A method of this class
  * **func_name** ([`str`](https://docs.python.org/3/builtins/stdtypes.html#str)) – The name of the function (will be “flat_func” by default)
  * **cls_cache_key** ([`str`](https://docs.python.org/3/builtins/stdtypes.html#str)) – The name of the kwarg used to manage cache. If not None, the
    same instance of `cls` will be used for all the flattened method called with the same
    value for this kwarg.
* **Returns:**

```pycon
>>> class MultiplierClass:
...     def __init__(self, x):
...         self.x = x
...     def multiply(self, y: float = 1) -> float:
...         return self.x * y
...     def subtract(self, z):
...         return self.x - z
...
>>> MultiplierClass(6).multiply(7)
42
>>> MultiplierClass(3.14).multiply()
3.14
>>> MultiplierClass(3).subtract(1)
2
>>> f = mk_flat(MultiplierClass, 'multiply', func_name='my_special_func')
>>> help(f)
Help on function my_special_func in module ...

my_special_func(x, y: float = 1) -> float

>>> f = mk_flat(MultiplierClass, MultiplierClass.subtract)
>>> help(f)
Help on function flat_func in in module ...

flat_func(x, z)
```

### py2http.decorators.params_replacer(replace, obj)

Generator of transformed params.

### py2http.decorators.replace_with_params(target=None, , , source=None, inplace=False)

Will return a version of the target type that has params taken from source.
Both target and source can be of the HasParams type, i.e.

```text
Union[Iterable[Parameter], Mapping[str, Parameter], Signature, Callable]
```

```pycon
>>> def f(a, /, b, *, c=None, **kwargs): ...
...
>>> def g(x, y=1, *args, **kwargs): ...
...
>>> f_sig = signature(f)
>>> f_params_map = f_sig.parameters
>>> f_params = tuple(f_params_map.values())
>>> g_sig = signature(g)
>>> g_params_map = g_sig.parameters
>>> g_params = tuple(g_params_map.values())
>>>
>>> original_f_sig = signature(f)
>>> print(original_f_sig)
(a, /, b, *, c=None, **kwargs)
>>> new_f = replace_with_params(f, source=g)
>>> print(signature(new_f))
(x, y=1, *args, **kwargs)
>>> assert signature(new_f) == signature(g)
>>> # but f remains unchanged (there is inplace=False option though!)
>>> assert signature(f) == original_f_sig
```

### py2http.decorators.unsafe_pickle_loads(data)

Unpickle `data`. UNSAFE on anything a client can send.

Unpickling runs code chosen by whoever produced the bytes, so this must only
be used when every caller of the endpoint is fully trusted (for example, a
service reachable only by your own processes). It exists so that opting into
pickled request bodies is explicit and visible at the call site:

```default
handle_binary_req(func, loads=unsafe_pickle_loads)
```


# _autosummary/py2http.default_configs.html.md

# py2http.default_configs

This module provides default configurations, input mappers, output mappers,
and error handlers for an HTTP service implemented in Python using the py2http
library. It includes functions for handling JSON requests and responses,
as well as mapping errors to appropriate HTTP responses based on different
HTTP frameworks (AIOHTTP, BOTTLE, FLASK).

The module also defines a set of default configuration values for setting up
the HTTP service, such as the application name, framework to use, port number,
error handling strategy, and CORS settings. It provides flexibility to customize
these configurations based on the specific requirements of the project.

Overall, this module serves as a foundational component for building and setting
up an HTTP service in Python using the py2http library.

### Functions

| `aiohttp_error_handler`(error)                                                                |                                                                                                                                                                                                                                                   |
|-----------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `bottle_error_handler`(error)                                                                 |                                                                                                                                                                                                                                                   |
| `bottle_output_mapper`(output, \*\*inputs)                                                    |                                                                                                                                                                                                                                                   |
| `default_error_handler`(error)                                                                |                                                                                                                                                                                                                                                   |
| `default_input_mapper`(\*\*inputs)                                                            |                                                                                                                                                                                                                                                   |
| [`error_status`](_autosummary/py2http.default_configs.html.md#py2http.default_configs.error_status)(error)                          | The HTTP status for an error a handler raised (500 when it is not a client's).                                                                                                                                                                    |
| [`flask_error_handler`](_autosummary/py2http.default_configs.html.md#py2http.default_configs.flask_error_handler)(error)                   | The `(body, status, headers)` a Flask view returns for an error, mapped like the bottle handler (`OPAQUE_ERRORS` hides the text of a 500).                                                                                                        |
| [`flask_json_output_mapper`](_autosummary/py2http.default_configs.html.md#py2http.default_configs.flask_json_output_mapper)(output, \*\*inputs) | The default output mapper of a Flask app: the output as a JSON response.                                                                                                                                                                          |
| `flask_output_mapper`(output, \*\*inputs)                                                     |                                                                                                                                                                                                                                                   |
| [`flask_response_mapper`](_autosummary/py2http.default_configs.html.md#py2http.default_configs.flask_response_mapper)(output_mapper)         | Make a Flask view's response of what an output mapper returns.                                                                                                                                                                                    |
| [`framework_defaults`](_autosummary/py2http.default_configs.html.md#py2http.default_configs.framework_defaults)(framework, \*, ...)       | The error handler and output mapper to use under `framework`: the given ones, except that the defaults (which only know of Bottle and AIOHTTP) are swapped for the framework's own, so that no process-wide state decides how a response is made. |
| [`www_authenticate_challenge`](_autosummary/py2http.default_configs.html.md#py2http.default_configs.www_authenticate_challenge)()                 | The `WWW-Authenticate` value of a 401 a dispatched function raised: the `PY2HTTP_WWW_AUTHENTICATE` environment variable, else `Bearer` (also when the variable holds a line break, which would make every 401 fail to send).                      |

### py2http.default_configs.error_status(error)

The HTTP status for an error a handler raised (500 when it is not a client’s).

```pycon
>>> error_status(AuthorizationError()), error_status(ForbiddenError())
(401, 403)
>>> error_status(InputError()), error_status(KeyError())
(400, 500)
```

* **Return type:**
  [`int`](https://docs.python.org/3/builtins/functions.html#int)

### py2http.default_configs.flask_error_handler(error)

The `(body, status, headers)` a Flask view returns for an error, mapped like
the bottle handler (`OPAQUE_ERRORS` hides the text of a 500).

### py2http.default_configs.flask_json_output_mapper(output, \*\*inputs)

The default output mapper of a Flask app: the output as a JSON response.

### py2http.default_configs.flask_response_mapper(output_mapper)

Make a Flask view’s response of what an output mapper returns.

The `send_*_resp` decorators set Bottle’s `response.content_type` and return
the body (`str` or `bytes`); Flask ignores that and would answer `text/html`.
A mapper that declares a `content_type` and returns a `str`/`bytes` body, or a
`(body, status[, headers])` tuple of one, gets that content type (unless the tuple’s
headers set their own); an `async` mapper is awaited first. Anything else (a
`Response`, a dict) is kept as is.

```pycon
>>> from py2http.decorators import send_raw_resp  # (needs flask)
>>> flask_response_mapper(send_raw_resp(lambda o: o))(b"x").content_type
'text/plain'
```

### py2http.default_configs.framework_defaults(framework, , error_handler, output_mapper)

The error handler and output mapper to use under `framework`: the given ones,
except that the defaults (which only know of Bottle and AIOHTTP) are swapped for
the framework’s own, so that no process-wide state decides how a response is made.

```pycon
>>> framework_defaults(FLASK, error_handler=default_error_handler,
...     output_mapper=default_output_mapper)[0] is flask_error_handler
True
```

### py2http.default_configs.www_authenticate_challenge()

The `WWW-Authenticate` value of a 401 a dispatched function raised: the
`PY2HTTP_WWW_AUTHENTICATE` environment variable, else `Bearer` (also when the
variable holds a line break, which would make every 401 fail to send).

```pycon
>>> os.environ.pop(WWW_AUTHENTICATE_ENV_VAR, None) and None
>>> www_authenticate_challenge()
'Bearer'
```

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)


# _autosummary/py2http.diagnosis.html.md

# py2http.diagnosis

This module is meant to contain diagnosis and validation tools.

### Functions

| `route_collisions`(app)   |    |
|---------------------------|----|


# _autosummary/py2http.flask_plugins.html.md

# py2http.flask_plugins

Flask counterparts of the Bottle plugins: auth as a `before_request` hook, CORS as an
`after_request` hook.

The credential checks are the plugins’ own (`JWTPlugin.authenticate`,
`ApiKeyAuthPlugin.authenticate`, which call `py2http.auth`), so Bottle and Flask
refuse the same requests for the same reasons. A plugin without an `authenticate`
method is a Bottle-only plugin: it is refused with `NotImplementedError` rather than
dropped, because a silently dropped auth plugin would leave its routes open.

### Functions

| [`check_flask_plugins`](_autosummary/py2http.flask_plugins.html.md#py2http.flask_plugins.check_flask_plugins)(plugins)                    | The `plugins` as a list, each known to work under Flask; else `NotImplementedError`.   |
|--------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------|
| [`mk_auth_hook`](_autosummary/py2http.flask_plugins.html.md#py2http.flask_plugins.mk_auth_hook)(plugins, \*, public_views[, cors]) | A `before_request` function running `plugins` (outermost first, as under Bottle).      |
| [`mk_cors_hook`](_autosummary/py2http.flask_plugins.html.md#py2http.flask_plugins.mk_cors_hook)([origins])                         | An `after_request` function adding the CORS headers `CorsPlugin` adds.                 |

### py2http.flask_plugins.check_flask_plugins(plugins)

The `plugins` as a list, each known to work under Flask; else `NotImplementedError`.

```pycon
>>> check_flask_plugins(None)
[]
>>> check_flask_plugins([object()])
Traceback (most recent call last):
  ...
NotImplementedError: The plugin <object object at ...> is Bottle-only...
```

* **Return type:**
  [`list`](https://docs.python.org/3/builtins/stdtypes.html#list)

### py2http.flask_plugins.mk_auth_hook(plugins, , public_views, cors=False)

A `before_request` function running `plugins` (outermost first, as under Bottle).

Everything is guarded except: the `public_views` (the view *functions* themselves,
not endpoint names: a user function named `openapi` must stay guarded); a request that matched no
route (it answers 404/405, as under Bottle, and runs no view); and, with `cors`,
the `OPTIONS` preflight, which Bottle’s CORS plugin answers before any auth runs.
A plugin’s claims go on `request.token`, where the endpoint finds them through
`current_request`.

### py2http.flask_plugins.mk_cors_hook(origins='\*')

An `after_request` function adding the CORS headers `CorsPlugin` adds.

Flask answers the `OPTIONS` preflight itself, so this only adds the headers.


# _autosummary/py2http.html.md

# py2http

This module provides functionality to easily create HTTP services from Python
functions and class methods. It includes features such as method transformation,
input mapping, output mapping, error handling, and client generation.
The module also allows for customization through various configuration options
and provides the ability to generate OpenAPI specifications for the created HTTP
services. Additionally, it includes middleware, plugins, and decorators to enhance
the functionality of the HTTP services.

### Modules

| [`auth`](_autosummary/py2http.auth.html.md#module-py2http.auth)                       | Framework-independent credential checks, shared by the aiohttp middleware (`py2http.middleware`) and the Bottle plugins (`py2http.bottle_plugins`), so that both refuse the same tokens and keys for the same reasons.                                                    |
|-------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [`bottle_plugins`](_autosummary/py2http.bottle_plugins.html.md#module-py2http.bottle_plugins)   | Plugins for adding middleware functionality to Bottle apps.                                                                                                                                                                                                               |
| [`config`](_autosummary/py2http.config.html.md#module-py2http.config)                   | The code module provides functions for retrieving configuration values for a function based on a hierarchy of sources, including function properties, configuration dictionaries, and default values.                                                                     |
| [`constants`](_autosummary/py2http.constants.html.md#module-py2http.constants)             | This module provides functionality for dispatching Python functions as HTTP services.                                                                                                                                                                                     |
| [`decorators`](_autosummary/py2http.decorators.html.md#module-py2http.decorators)           | Decorator tools for py2http.                                                                                                                                                                                                                                              |
| [`default_configs`](_autosummary/py2http.default_configs.html.md#module-py2http.default_configs) | This module provides default configurations, input mappers, output mappers, and error handlers for an HTTP service implemented in Python using the py2http library.                                                                                                       |
| [`diagnosis`](_autosummary/py2http.diagnosis.html.md#module-py2http.diagnosis)             | This module is meant to contain diagnosis and validation tools.                                                                                                                                                                                                           |
| [`flask_plugins`](_autosummary/py2http.flask_plugins.html.md#module-py2http.flask_plugins)     | Flask counterparts of the Bottle plugins: auth as a `before_request` hook, CORS as an `after_request` hook.                                                                                                                                                               |
| [`middleware`](_autosummary/py2http.middleware.html.md#module-py2http.middleware)           | aiohttp middleware that guards every route of an app: `mk_jwt_middleware` (a verified `Authorization: Bearer` JWT) and `mk_superadmin_middleware` (one shared key).                                                                                                       |
| [`obj_dispatch`](_autosummary/py2http.obj_dispatch.html.md#module-py2http.obj_dispatch)       | Dispatching HTTP requests to the attributes of objects, classes and modules.                                                                                                                                                                                              |
| [`openapi_utils`](_autosummary/py2http.openapi_utils.html.md#module-py2http.openapi_utils)     | This module is designed to generate OpenAPI specifications based on Python functions.                                                                                                                                                                                     |
| [`route_utils`](_autosummary/py2http.route_utils.html.md#module-py2http.route_utils)         | This module provides functionality to create handlers for class methods, based on input classes and method names.                                                                                                                                                         |
| [`schema_tools`](_autosummary/py2http.schema_tools.html.md#module-py2http.schema_tools)       | This module provides functions for generating OpenAPI input and output schemas from Python functions, as well as validating input against a schema.                                                                                                                       |
| [`service`](_autosummary/py2http.service.html.md#module-py2http.service)                 | This Python module provides a framework for dispatching Python functions as HTTP services and generating OpenAPI specifications for these services.                                                                                                                       |
| [`sizeof`](_autosummary/py2http.sizeof.html.md#module-py2http.sizeof)                   | Approximate the memory an object holds, without walking more of it than a budget.                                                                                                                                                                                         |
| [`types`](_autosummary/py2http.types.html.md#module-py2http.types)                     | This module defines several type aliases and constants related to function parameters and signatures.                                                                                                                                                                     |
| [`util`](_autosummary/py2http.util.html.md#module-py2http.util)                       | This module contains various utilities including a `lazyprop` descriptor for lazy loading properties, a `CreateProcess` context manager for running functions in parallel processes, a `ModuleFoundIgnore` context manager for ignoring `ModuleNotFoundErrors`, and more. |


# _autosummary/py2http.middleware.html.md

# py2http.middleware

aiohttp middleware that guards every route of an app: `mk_jwt_middleware`
(a verified `Authorization: Bearer` JWT) and `mk_superadmin_middleware` (one
shared key). The checks themselves live in `py2http.auth`, shared with the Bottle
plugins of `py2http.bottle_plugins`.

### Functions

| [`mk_jwt_middleware`](_autosummary/py2http.middleware.html.md#py2http.middleware.mk_jwt_middleware)(secret[, verify, ...])   | Make an aiohttp middleware that requires a valid `Authorization: Bearer` JWT on every request, and puts the decoded claims on `request.token`.   |
|---------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------|
| [`mk_superadmin_middleware`](_autosummary/py2http.middleware.html.md#py2http.middleware.mk_superadmin_middleware)(secret)           | Make an aiohttp middleware that only lets through requests whose `Authorization` header is exactly `secret` (compared in constant time).         |

### py2http.middleware.mk_jwt_middleware(secret, verify=True, , algorithms=('HS256',), public_routes=('ping', 'openapi'), allow_mixed_algorithm_families=False, decode_kwargs=None)

Make an aiohttp middleware that requires a valid `Authorization: Bearer`
JWT on every request, and puts the decoded claims on `request.token`.

* **Parameters:**
  * **secret** – The key tokens are verified with (an HMAC secret for `HS*`
    algorithms, a public key for `RS*`/`ES*`/…).
  * **verify** – If False, signatures and claims (`exp`, …) are NOT checked:
    whatever a token says ends up on `request.token`, and an
    undecodable token only triggers a warning. For development only.
    (Before, PyJWT 2 ignored the legacy option this passed, so
    signatures were still checked even with `verify=False`.)
  * **algorithms** ([`Iterable`](https://docs.python.org/3/library/collections.abc.html#collections.abc.Iterable)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]) – The algorithms a token may be signed with (PyJWT names,
    case-sensitive; `"none"` is refused). Defaults to `("HS256",)`,
    as `py2http.bottle_plugins.JWTPlugin` does.
  * **public_routes** ([`Iterable`](https://docs.python.org/3/library/collections.abc.html#collections.abc.Iterable)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]) – Names of aiohttp routes (`name=` in `add_route`) that
    need no token. Matched on the route name, not the handler’s
    `__name__`, so a handler that happens to be called `ping` is not
    public by accident. Route names are matched in sub-applications
    too, so a sub-app route named `ping` is public as well.
  * **allow_mixed_algorithm_families** ([`bool`](https://docs.python.org/3/builtins/functions.html#bool)) – Accepting an HMAC algorithm and a
    public-key algorithm with one `secret` is the classic
    algorithm-confusion setup (a token “signed” with HS256 using the
    public key as the HMAC secret), so it raises `ValueError` unless
    this is True. The middleware used to accept `["HS256", "RS256"]`;
    pass that list with this flag to restore it.
  * **decode_kwargs** ([`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)) – Extra `jwt.decode` arguments, such as `audience`,
    `issuer` or `leeway` (without them a token carrying an `aud`
    claim is always refused).

### py2http.middleware.mk_superadmin_middleware(secret)

Make an aiohttp middleware that only lets through requests whose
`Authorization` header is exactly `secret` (compared in constant time).
An empty `secret` is refused, since it would let header-less requests through.


# _autosummary/py2http.obj_dispatch.html.md

# py2http.obj_dispatch

Dispatching HTTP requests to the attributes of objects, classes and modules.

A handler whose `endpoint` is not a function names the attributes clients may call
with `attr_names` (see `public_attr` for `'*'`):

- a **module**: its functions are called by name. They are function endpoints like
  any other: no object is kept, so there is no size bound, and a function that mutates
  module globals does so for every client, exactly as a plain function endpoint (or a
  bound method passed into an app spec) would. Authenticate with the auth middleware
  (`mk_jwt_middleware`, `JWTPlugin`), or pass an optional `obj_owner` to refuse
  requests it does not identify;
- an **instance** (one object every client shares): `_instance_endpoint_dispatcher`;
- a **class** (each client creates and uses its own objects):
  `_class_endpoint_dispatcher`.

Instances and classes need an `obj_owner`, a `(request) -> owner` hook reading
`current_request`, and are bounded in size (`py2http.sizeof`), measured after each
call except those to `obj_readers`. A call returning a generator, coroutine or async
generator is measured when it is returned and again when that result finishes.

### Module Attributes

| [`current_request`](_autosummary/py2http.obj_dispatch.html.md#py2http.obj_dispatch.current_request)   | The request being handled (set around every handler call), so per-request hooks such as `obj_owner` can read it without the dispatched function taking it.   |
|--------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [`ObjOwner`](_autosummary/py2http.obj_dispatch.html.md#py2http.obj_dispatch.ObjOwner)          | `(request) -> owner`, a hashable that identifies an *authenticated* client (e.g. a user id from a verified token).                                           |

### Functions

| [`public_attr`](_autosummary/py2http.obj_dispatch.html.md#py2http.obj_dispatch.public_attr)(obj, attr_name)     | The attribute policy `attr_names='*'` stands for: only public methods.    |
|----------------------------------------------------------------------------------|---------------------------------------------------------------------------|
| [`unsafe_any_attr`](_autosummary/py2http.obj_dispatch.html.md#py2http.obj_dispatch.unsafe_any_attr)(obj, attr_name) | Dispatch ANY attribute of the object, including private ones and dunders. |

### Classes

| [`LRUObjStore`](_autosummary/py2http.obj_dispatch.html.md#py2http.obj_dispatch.LRUObjStore)(\*[, max_size, on_evict])   | A mapping that keeps at most `max_size` items, evicting the least recently used one when a new key would exceed it (`on_evict(k, v)` is told).   |
|------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------|
| [`OwnedObjStore`](_autosummary/py2http.obj_dispatch.html.md#py2http.obj_dispatch.OwnedObjStore)(\*[, quota, max_owners])  | Objects kept per owner, with object and byte budgets.                                                                                            |

### *class* py2http.obj_dispatch.LRUObjStore(, max_size=1000, on_evict=None)

Bases: [`MutableMapping`](https://docs.python.org/3/library/collections.abc.html#collections.abc.MutableMapping)

A mapping that keeps at most `max_size` items, evicting the least recently
used one when a new key would exceed it (`on_evict(k, v)` is told).

Used as the default store of objects created through a class endpoint, so that
clients cannot grow server memory without bound by creating objects.

```pycon
>>> s = LRUObjStore(max_size=2)
>>> s['a'], s['b'] = 1, 2
>>> _ = s['a']  # 'a' is now the most recently used
>>> s['c'] = 3
>>> sorted(s)
['a', 'c']
```

#### peek(k, default=None)

`self.get(k, default)`, without making `k` the most recently used.

### py2http.obj_dispatch.ObjOwner

`(request) -> owner`, a hashable that identifies an
*authenticated* client (e.g. a user id from a verified token). `None` and `""`
mean “not identified” and are refused. A client-chosen value (a session cookie the
client mints, an IP) lets one client create owners until others are evicted.

* **Type:**
  `obj_owner` hook

alias of `Callable`[[[`Any`](https://docs.python.org/3/library/typing.html#typing.Any)], [`Any`](https://docs.python.org/3/library/typing.html#typing.Any) | [`None`](https://docs.python.org/3/builtins/constants.html#None)]

### *class* py2http.obj_dispatch.OwnedObjStore(, quota=100, max_owners=1000)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Objects kept per owner, with object and byte budgets. Thread-safe.

- `quota` objects per owner: an owner’s own least recently used object is evicted
  beyond it, never someone else’s;
- `max_owners` owners at once: the least recently active owner’s objects go;
- byte accounting: `record()` the size of an object; `owner_bytes()` and
  `total_bytes` sum what is currently stored.

```pycon
>>> s = OwnedObjStore(quota=2, max_owners=2)
>>> s.put('ann', 'a1', 1); s.put('ann', 'a2', 2); s.put('bob', 'b1', 3)
>>> s.put('ann', 'a3', 4)  # ann's quota: her least recently used object goes
>>> s.get('ann', 'a1') is None, s.get('ann', 'a3'), s.get('bob', 'b1')
(True, 4, 3)
>>> s.get('bob', 'a3') is None  # another owner's id is simply not found
True
>>> s.record('ann', 'a3', 100); s.record('bob', 'b1', 5)
>>> s.owner_bytes('ann'), s.total_bytes
(100, 105)
```

### py2http.obj_dispatch.current_request *: [ContextVar](https://docs.python.org/3/library/contextvars.html#contextvars.ContextVar)* *= <ContextVar name='py2http_current_request' default=None>*

The request being handled (set around every handler call), so per-request hooks such
as `obj_owner` can read it without the dispatched function taking it.

### py2http.obj_dispatch.public_attr(obj, attr_name)

The attribute policy `attr_names='*'` stands for: only public methods.

A name is dispatchable if it does not start with `_` and

- for a module: it is a function that the module defines (or lists in its
  `__all__`), never something it merely imports, nor plain data;
- otherwise: it is a plain Python function, `staticmethod`,
  `classmethod` or `property` defined in the object’s class (or a base
  class), and the instance does not shadow it.

This keeps private helpers, dunders (`__dict__`, `__init__`, …),
per-instance state (`__dict__` entries, `__slots__`, dataclass and
namedtuple fields) and callables merely assigned as class attributes
(`opener = open`) out of reach of HTTP clients.

Note that every public method is exposed, inherited ones included (e.g. a
pydantic model’s `model_dump`). For anything holding secrets, or a mapping
whose mutators should stay private (`MutableMapping` mixins such as
`clear` and `pop` are plain functions), list the names explicitly instead.

```pycon
>>> class A:
...     data = 0
...     opener = open
...     def f(self): ...
...     def _g(self): ...
...     def __init__(self): self.secret = 1
>>> [public_attr(A(), name)
...  for name in ('f', '_g', '__init__', '__dict__', 'secret', 'data', 'opener')]
[True, False, False, False, False, False, False]
```

* **Return type:**
  [`bool`](https://docs.python.org/3/builtins/functions.html#bool)

### py2http.obj_dispatch.unsafe_any_attr(obj, attr_name)

Dispatch ANY attribute of the object, including private ones and dunders.

This was the behaviour of `attr_names='*'` before `public_attr`: it lets a
client read `__dict__`, call `__init__` with arguments of its choosing, and so
on. Use `attr_names=unsafe_any_attr` only when every client is trusted.

* **Return type:**
  [`bool`](https://docs.python.org/3/builtins/functions.html#bool)


# _autosummary/py2http.openapi_utils.html.md

# py2http.openapi_utils

This module is designed to generate OpenAPI specifications based on Python functions.
It includes functions for creating OpenAPI paths, setting authentication details,
and building OpenAPI templates. The `OpenApiExtractor` class can be used to extract
information from an existing OpenAPI document.

The `func_to_openapi_spec` function is particularly useful, as it takes a Python
function as input and generates an OpenAPI path specification, including request
and response schemas.

Overall, this module allows you to define API routes and generate corresponding
OpenAPI specifications directly from your Python functions. It provides a convenient
way to document and expose your functions as HTTP endpoints.

### Functions

| `add_paths_to_spec`(paths_spec, new_paths)                                                |    |
|-------------------------------------------------------------------------------------------|----|
| `func_to_openapi_spec`(func[, exclude_keys, ...])                                         |    |
| `mk_arg_schema`(arg)                                                                      |    |
| `mk_obj_schema`(request_object)                                                           |    |
| `mk_openapi_path`([pathname, method, ...])                                                |    |
| `mk_openapi_template`([config])                                                           |    |
| `openapi_type_mapping`(obj_type)                                                          |    |
| [`set_auth`](_autosummary/py2http.openapi_utils.html.md#py2http.openapi_utils.set_auth)(openapi_spec[, auth_type, ...]) |    |

### Classes

| `OpenApiExtractor`(openapi_spec[, func_to_path])   |    |
|----------------------------------------------------|----|

### py2http.openapi_utils.set_auth(openapi_spec, auth_type='jwt', , login_details=None)

* **Parameters:**
  * **openapi_spec** – An OpenAPI formatted server specification
  * **auth_type** – Either ‘jwt’ or ‘api_key’
  * **login_details** – Optional - {
    ‘login_url’: the login url
    ‘refresh_url’: the refresh url, if applicable
    ‘login_inputs’: a list of strings e.g. [‘account’, ‘email’, ‘password’]
    ‘refresh_inputs’: a list of strings e.g. [‘account’, ‘refresh_token’]
    ‘outputs’: a list of strings e.g. [‘jwt’, ‘refresh_token’]
    }
    “”


# _autosummary/py2http.route_utils.html.md

# py2http.route_utils

This module provides functionality to create handlers for class methods,
based on input classes and method names. It also includes a function to generate a
list of handler functions from a class based on a whitelist of method names.

It uses introspection to dynamically create handlers that instantiate the input class
and call the specified method with the provided arguments. The module supports input
and output transformations for the handlers.

You can use this module to easily convert class methods into standalone functions,
which can be useful for creating HTTP services or APIs based on existing class
functionality.

### Functions

| `create_handler`(input_class, methodname)         |    |
|---------------------------------------------------|----|
| `mk_functions_from_class`(input_class, whitelist) |    |


# _autosummary/py2http.schema_tools.html.md

# py2http.schema_tools

This module provides functions for generating OpenAPI input and output schemas from
Python functions, as well as validating input against a schema.
It also includes a function to create an input mapper based on a transformation
dictionary. The module aims to assist in the generation of API specifications and
input validation for HTTP services built using Python. The functions are designed to
simplify the process of defining API inputs and outputs, and ensuring data integrity
in request handling.

### Functions

| `mk_input_mapper`(transform)                                                            |                                                                              |
|-----------------------------------------------------------------------------------------|------------------------------------------------------------------------------|
| [`mk_input_schema_from_func`](_autosummary/py2http.schema_tools.html.md#py2http.schema_tools.mk_input_schema_from_func)(func[, ...]) | Make the openAPI input schema for a function.                                |
| `mk_output_schema_from_func`(func)                                                      |                                                                              |
| `mk_sub_dict_schema_from_typed_dict`(typed_dict)                                        |                                                                              |
| `mk_sub_list_schema_from_iterable`(iterable_type)                                       |                                                                              |
| [`param_default`](_autosummary/py2http.schema_tools.html.md#py2http.schema_tools.param_default)(param)                   | Return `param.default`, or `Parameter.empty` if it is a placeholder default. |
| `validate_input`(raw_input, schema)                                                     |                                                                              |

### py2http.schema_tools.mk_input_schema_from_func(func, exclude_keys=None, include_func_params=False)

Make the openAPI input schema for a function.

* **Parameters:**
  * **func** – A callable
  * **exclude_keys** – keys to exclude in the schema
  * **include_func_params** – Boolean indicating whether the python Parameter objects should
    also be included (under the field `x-py-param`)
* **Returns:**
  An openAPI input schema dict

```pycon
>>> from py2http.schema_tools import mk_input_schema_from_func
>>> import typing
>>>
>>> def add(a, b: float = 0.0) -> float:
...     '''Adds numbers'''
...     return a + b
...
>>> got = mk_input_schema_from_func(add)
>>> expected = {
...     'type': dict,
...     'properties': {
...         'a': {'type': typing.Any},
...         'b': {'default': 0.0, 'type': float}},
...     'required': ['a']}
>>> assert got == expected, f"\n  expected {expected}\n  got {got}"
>>>
>>>
>>> # TODO: Look into this one: it results in a x default=None (there should be no default)
>>> #       and a type for y (there should be no type, unless by convention)
>>> def mult(x: float, y=1, z: int=1):
...     return (x * y) ** z
...
>>> got = mk_input_schema_from_func(mult)
>>> expected = {
...     'type': dict,
...     'properties': {
...        'x': {'type': float},
...        'y': {'default': 1, 'type': int},
...        'z': {'type': int, 'default': 1}},
...     'required': ['x']}
>>> assert got == expected, f"\n  expected {expected}\n  got {got}"
>>>
>>> # i2's ``NotSet`` sentinel as a default (e.g. in an ``i2.FuncFactory``
>>> # signature) means "no default": the param stays required.
>>> from i2.deco import NotSet
>>> def mult_(x: float = NotSet, y=NotSet, z: int = 1):
...     return (x * y) ** z
>>> mk_input_schema_from_func(mult_) == {
...     'type': dict,
...     'properties': {
...         'x': {'type': float}, 'y': {'type': Any}, 'z': {'type': int, 'default': 1}},
...     'required': ['x', 'y']}
True
```

### py2http.schema_tools.param_default(param)

Return `param.default`, or `Parameter.empty` if it is a placeholder default.

A placeholder default is `i2`’s `NotSet` sentinel or any
`i2.DefaultPlaceholder` (such as the marker `methodize(..., default_from=...)`
puts in a signature). It means “no concrete value here”, not a real default, so
schema builders treat that param as required, with no default (it is not JSON
serializable either).

```pycon
>>> from i2.deco import NotSet
>>> param_default(Parameter('x', Parameter.KEYWORD_ONLY, default=3))
3
>>> param_default(Parameter('x', Parameter.KEYWORD_ONLY, default=NotSet))
<class 'inspect._empty'>
```


# _autosummary/py2http.service.html.md

# py2http.service

This Python module provides a framework for dispatching Python functions as HTTP
services and generating OpenAPI specifications for these services.
It includes functionality for handling input mappers, output mappers, error handling,
configuration, and client generation.

The module defines functions for creating and running web applications that expose
Python functions as API endpoints. It supports various web frameworks like Flask,
Bottle, and aiohttp for running these applications.

Additionally, the module allows for creating multi-service applications by defining
routes per API with a list of handlers for each API. It also supports publishing
OpenAPI specifications and Swagger documentation for the APIs.

Overall, this module offers a comprehensive approach to creating HTTP services from
Python functions, enabling developers to easily expose their functions as remote APIs
with minimal setup.

### Functions

| `func_copy`(func)                                                                                 |                                                                                                                   |
|---------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------|
| `method_not_found`(method_name)                                                                   |                                                                                                                   |
| `mk_aiohttp_app`(funcs, \*\*configs)                                                              |                                                                                                                   |
| [`mk_app`](_autosummary/py2http.service.html.md#py2http.service.mk_app)(app_spec, \*[, app_name, framework, ...]) | Generates an application which exposes web services created from the given python functions to remotely run them. |
| `mk_bottle_app`(funcs, \*\*configs)                                                               |                                                                                                                   |
| [`mk_flask_app`](_autosummary/py2http.service.html.md#py2http.service.mk_flask_app)(funcs, \*\*configs)                 | A Flask app serving `funcs`.                                                                                      |
| [`mk_route`](_autosummary/py2http.service.html.md#py2http.service.mk_route)(func, \*\*configs)                      | Generate a route object and an OpenAPI path specification for a function                                          |
| `mk_routes_and_openapi_specs`(funcs, \*\*configs)                                                 |                                                                                                                   |
| [`run_app`](_autosummary/py2http.service.html.md#py2http.service.run_app)(app_obj, \*[, app_name, framework, ...]) | Run an application which exposes web services created from the given python functions to remotely run them.       |
| [`run_flask`](_autosummary/py2http.service.html.md#py2http.service.run_flask)(app, \*, host, port[, certfile, ...])  | Run a Flask app with Flask's own server (`server` does not apply to it).                                          |

### Classes

| [`SubAppSpec`](_autosummary/py2http.service.html.md#py2http.service.SubAppSpec)   |    |
|---------------------------------------------------------------|----|

### *class* py2http.service.SubAppSpec

Bases: [`TypedDict`](https://docs.python.org/3/library/typing.html#typing.TypedDict)

### py2http.service.mk_app(app_spec, \*, app_name='HTTP Service', framework='bottle', input_mapper=<function default_input_mapper>, output_mapper=<function send_json_resp.<locals>.output_mapper>, error_handler=<function default_error_handler>, header_inputs={}, middleware=[], host='localhost', port=3030, server='gunicorn', http_method='post', openapi={}, logger=None, plugins=[], enable_cors=False, max_request_size=None, cors_allowed_origins='\*', publish_openapi=False, openapi_insecure=False, publish_swagger=False, swagger_url='/swagger', swagger_title='Swagger', ssl_certfile=None, ssl_keyfile=None, \*\*configs)

Generates an application which exposes web services created from the given python
functions to remotely run them.
You can generate a multi-service application defining a route per API or sub
application.

First define a bunch of functions (or handlers) you want to expose as a web service.

```pycon
>>> def foo():
...     return 0
...
>>> def bar():
...     return True
...
```

Let’s make a single-service application. A single API will be generated with an
endpoint per handler, plus an auto-generated enpoints to ping the API.

```pycon
>>> handlers = [foo, bar]
>>> app = mk_app(handlers)
>>> app.get_url('bar')
'/bar'
>>> app.get_url('foo')
'/foo'
>>> app.get_url('ping')
'/ping'
```

You can also automatically generate an endpoint to expose the openapi specification
of your API by activating the flag “publish_openapi”. Publishing the openapi
specification will allow a client application to use the specification object to
build an interface to actually consume the API by wrapping the http layer.

```pycon
>>> app = mk_app(handlers, publish_openapi=True)
>>> app.openapi_spec
{'openapi': '3.0.2', 'info': {'title': 'default', 'version': '0.1'}, 'servers':
[{'url': 'http://localhost:3030'}], 'paths': {'/foo': {'post': {'x-method_name':
'foo', 'description': '', 'requestBody': {'required': True, 'content':
{'application/json': {'schema': {'type': 'object', 'properties': {}}}}},
'responses': {'200': {'description': '', 'content': {'application/json':
{'schema': {}}}}}}}, '/bar': {'post': {'x-method_name': 'bar', 'description': '',
'requestBody': {'required': True, 'content': {'application/json': {'schema':
{'type': 'object', 'properties': {}}}}}, 'responses': {'200': {'description': '',
'content': {'application/json': {'schema': {}}}}}}}}}
>>> app.get_url('openapi')
'/openapi'
```

You can also generate swagger documentation by activating the “publish_swagger”
flag. This will generate a swagger documentation for the API and make it available
at the specified url (by default “/swagger”).

```pycon
>>> app = mk_app(handlers, publish_openapi=True, publish_swagger=True)
```

Let’s use http2py to consume the openapi specification

```pycon
>>> from http2py import HttpClient
>>> api = HttpClient(openapi_spec=app.openapi_spec)
>>> assert(hasattr(api, 'foo'))
>>> assert(hasattr(api, 'bar'))
```

Now, let’s make a multi-service application. You only have to define a route per
API with a list of handlers for each API.

```pycon
>>> handler_spec = {
...     'foo_api': [foo],
...     'bar_api': [bar],
... }
>>> app = mk_app(handler_spec, publish_openapi=True)
>>> app.get_url('/foo_api')
'/foo_api'
>>> app.get_url('/bar_api')
'/bar_api'
```

* **Parameters:**
  * **handler_spec** (*HandlerSpec*) – The handler specification. Can be a list of python to expose,
    or a dict with a list of functions to expose per route in case of a multi-service
    application.
  * **\*\*configs** ([*dict*](https://docs.python.org/3/builtins/stdtypes.html#dict)) – The configuration for the application. See config.yaml for
    configuration documentation.

### py2http.service.mk_flask_app(funcs, \*\*configs)

A Flask app serving `funcs`. The JSON, raw, binary and form input mappers and
the `send_*_resp` output mappers work as under Bottle; `middleware` is a list
of WSGI wrappers.

As under Bottle, `plugins` guards every route (`JWTPlugin`, `ApiKeyAuthPlugin`;
a Bottle-only plugin raises `NotImplementedError`) except `/ping`, and except
`/openapi` when `openapi_insecure`; `enable_cors` adds the CORS headers
(`cors_allowed_origins`) to every response; `publish_swagger` serves the Swagger
UI at `swagger_url`, guarded by `plugins` like any other route. See
`py2http.flask_plugins`.

### py2http.service.mk_route(func, \*\*configs)

Generate a route object and an OpenAPI path specification for a function

* **Parameters:**
  **func** – The function
* **Keyword Arguments:**
  The configuration settings

### py2http.service.run_app(app_obj, \*, app_name='HTTP Service', framework='bottle', input_mapper=<function default_input_mapper>, output_mapper=<function send_json_resp.<locals>.output_mapper>, error_handler=<function default_error_handler>, header_inputs={}, middleware=[], host='localhost', port=3030, server='gunicorn', http_method='post', openapi={}, logger=None, plugins=[], enable_cors=False, max_request_size=None, cors_allowed_origins='\*', publish_openapi=False, openapi_insecure=False, publish_swagger=False, swagger_url='/swagger', swagger_title='Swagger', ssl_certfile=None, ssl_keyfile=None, \*\*configs)

Run an application which exposes web services created from the given python
functions to remotely run them.
You can generate a multi-service application defining a route per api or sub
application.
You can also generate the application first, then run it using this function.

* **Parameters:**
  * **app_obj** ([`Union`](https://docs.python.org/3/library/typing.html#typing.Union)[[`Iterable`](https://docs.python.org/3/library/typing.html#typing.Iterable)[[`Union`](https://docs.python.org/3/library/typing.html#typing.Union)[[`Callable`](https://docs.python.org/3/library/typing.html#typing.Callable), `HandlerWithMappers`]], [`Dict`](https://docs.python.org/3/library/typing.html#typing.Dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Union`](https://docs.python.org/3/library/typing.html#typing.Union)[[`Iterable`](https://docs.python.org/3/library/typing.html#typing.Iterable)[[`Union`](https://docs.python.org/3/library/typing.html#typing.Union)[[`Callable`](https://docs.python.org/3/library/typing.html#typing.Callable), `HandlerWithMappers`]], [`SubAppSpec`](_autosummary/py2http.service.html.md#py2http.service.SubAppSpec)]], [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]) – The handler specification or application object. Can be a list of
    python to expose, or a dict with a list of functions to expose per route in case
    of a multi-service. Can also be a pre-generated application object to run.
  * **\*\*configs** ([*dict*](https://docs.python.org/3/builtins/stdtypes.html#dict)) – The configuration for the application. See
    `py2http.default_configs:default_configs` for defaults and config.yaml for
    configuration documentation.

### py2http.service.run_flask(app, , host, port, certfile=None, keyfile=None, \*\*\_)

Run a Flask app with Flask’s own server (`server` does not apply to it).


# _autosummary/py2http.sizeof.html.md

# py2http.sizeof

Approximate the memory an object holds, without walking more of it than a budget.

`bounded_deep_sizeof` is how py2http bounds the objects clients create or grow
through class and instance endpoints (`py2http.obj_dispatch`).

### Functions

| [`bounded_deep_sizeof`](_autosummary/py2http.sizeof.html.md#py2http.sizeof.bounded_deep_sizeof)(obj[, limit])   | Approximate memory held by `obj` and everything it references (containers, instance `__dict__` and `__slots__`, what a bound method, a `partial` or a function's closure, attributes and defaults hold), counting each object once.   |
|--------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

### py2http.sizeof.bounded_deep_sizeof(obj, limit=None)

Approximate memory held by `obj` and everything it references (containers,
instance `__dict__` and `__slots__`, what a bound method, a `partial` or a
function’s closure, attributes and defaults hold), counting each object once. Stops
as soon as the total exceeds `limit`, so measuring costs at most about `limit`
bytes’ worth of objects. Classes, modules and the code of functions are shared, so
not counted, and neither is what classes and modules hold (class attributes, module
globals), nor caches kept in C (`lru_cache`). Holding a bound method of another
object counts that whole object, as holding the object itself would.

```pycon
>>> small, big = bounded_deep_sizeof([1, 2]), bounded_deep_sizeof(list(range(1000)))
>>> small < big
True
>>> bounded_deep_sizeof(list(range(10**6)), limit=1000) > 1000
True
```

* **Return type:**
  [`int`](https://docs.python.org/3/builtins/functions.html#int)


# _autosummary/py2http.types.html.md

# py2http.types

This module defines several type aliases and constants related to function parameters and signatures.

The `WriteOpResult` TypedDict represents the result of a write operation, with keys for the success status (`ok`), number of items affected (`n`), and identifiers (`ids`) of the affected items.

The `ParameterKind` constant represents the type of a Parameter, specifically `Parameter.POSITIONAL_OR_KEYWORD`.

The `Params` alias is used to represent an Iterable of Parameter objects, while `HasParams` is a union type that can represent various structures that contain Parameter objects, such as Iterable, Mapping, Signature, or Callable.

Additionally, shorthand constants are defined for the different kinds of parameters:

- `PK` for `Parameter.POSITIONAL_OR_KEYWORD`
- `VP` and `VK` for `Parameter.VAR_POSITIONAL` and `Parameter.VAR_KEYWORD` respectively
- `PO` and `KO` for `Parameter.POSITIONAL_ONLY` and `Parameter.KEYWORD_ONLY` respectively
- `var_param_kinds` is a set containing `VP` and `VK` for easy access to variable parameter kinds.

This module provides a convenient way to work with function parameters and signatures in Python.

### Classes

| [`WriteOpResult`](_autosummary/py2http.types.html.md#py2http.types.WriteOpResult)   |    |
|------------------------------------------------------------------|----|

### *class* py2http.types.WriteOpResult

Bases: [`TypedDict`](https://docs.python.org/3/library/typing.html#typing.TypedDict)


# _autosummary/py2http.util.html.md

# py2http.util

This module contains various utilities including a `lazyprop` descriptor for lazy loading properties, a `CreateProcess` context manager for running functions in parallel processes, a `ModuleFoundIgnore` context manager for ignoring `ModuleNotFoundErrors`, and more.

The `lazyprop` descriptor is used to define properties that are computed once and then cached until the instance of the class is destroyed. It is useful for computing properties on-demand but only once.

The `CreateProcess` context manager is used to launch a parallel process and close it on exit. This is helpful when you need to execute tasks concurrently in a separate process.

The `ModuleFoundIgnore` context manager allows you to ignore `ModuleNotFoundError` exceptions in a block of code. This can be useful when importing optional modules that may or may not exist.

The `TypeAsserter` function generates a callable that asserts the expected type of a value based on a given kind. It can be used to validate the types of inputs based on predefined rules.

Overall, this module provides a collection of useful tools for handling lazy property loading, parallel processing, exception handling, type validation, and more.

### Functions

| [`call_with_inputs`](_autosummary/py2http.util.html.md#py2http.util.call_with_inputs)(func[, args, kwargs])   | Call `func(*args, **kwargs)`, passing the entries of `kwargs` that name positional-only parameters of `func` positionally, which JSON (a mapping) can only supply by name (i2mint/py2http#14).   |
|-------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `conditional_logger`([verbose, log_func])                                                 |                                                                                                                                                                                                  |
| [`deprecate`](_autosummary/py2http.util.html.md#py2http.util.deprecate)([func, msg])                   | Decorator to emit a DeprecationWarning when the decorated function is called.                                                                                                                    |
| `if_not_empty`(obj[, if_empty_val])                                                       |                                                                                                                                                                                                  |
| [`obj_to_items_gen`](_autosummary/py2http.util.html.md#py2http.util.obj_to_items_gen)(obj, attrs[, ...])      | Make a generator of (k, v) items extracted from an input object, given an iterable of attributes to extract                                                                                      |
| [`obj_to_path`](_autosummary/py2http.util.html.md#py2http.util.obj_to_path)(obj)                         | Quasi-inverse of obj_to_path: Get a root_obj and attr_path from an object.                                                                                                                       |
| [`path_to_obj`](_autosummary/py2http.util.html.md#py2http.util.path_to_obj)(root_obj, attr_path)         | Get an object from a root object and "attribute path" specification.                                                                                                                             |
| `py_obj_info`(obj)                                                                        |                                                                                                                                                                                                  |
| [`pyparam_to_dict`](_autosummary/py2http.util.html.md#py2http.util.pyparam_to_dict)(param[, kv_trans])       | Get dict from a Parameter object                                                                                                                                                                 |

### Classes

| [`CreateProcess`](_autosummary/py2http.util.html.md#py2http.util.CreateProcess)(proc_func[, process_name, ...])   | A context manager to launch a parallel process and close it on exit.                                 |
|--------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------|
| [`Missing`](_autosummary/py2http.util.html.md#py2http.util.Missing)([val])                                  | A class to use as a value to indicate that something was missing                                     |
| [`ModuleNotFoundIgnore`](_autosummary/py2http.util.html.md#py2http.util.ModuleNotFoundIgnore)()                          | Context manager to ignore ModuleNotFoundErrors.                                                      |
| [`Skip`](_autosummary/py2http.util.html.md#py2http.util.Skip)()                                          | Class to indicate if one should skip an item                                                         |
| [`TypeAsserter`](_autosummary/py2http.util.html.md#py2http.util.TypeAsserter)(types_for_kind[, if_kind_missing]) | Makes a callable that asserts that a value `v` has the expected type(s) that it's kind `k` should be |
| [`lazyprop`](_autosummary/py2http.util.html.md#py2http.util.lazyprop)(func)                                  | A descriptor implementation of lazyprop (cached property).                                           |

### *class* py2http.util.CreateProcess(proc_func, process_name=None, wait_before_entering=2, verbose=False, args=(), \*\*kwargs)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

A context manager to launch a parallel process and close it on exit.

### *class* py2http.util.Missing(val=None)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

A class to use as a value to indicate that something was missing

### *class* py2http.util.ModuleNotFoundIgnore

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Context manager to ignore ModuleNotFoundErrors.

When all goes well, code is executed normally:

```pycon
>>> with ModuleNotFoundIgnore():
...     import os.path  # test when the module exists
...     # The following code is reached and executed
...     print('hi there!')
...     print(str(os.path.join)[:14] + '...')  # code is reached
hi there!
<function join...
```

But if you try to import a module that doesn’t exist on your system,
the block will be skipped from that point onward, silently.

```pycon
>>> with ModuleNotFoundIgnore():
...     import do.i.exist
...     # The following code is NEVER reached or executed
...     print(do.i.exist)
...     t = 0 / 0
```

But if there’s any other kind of error (other than ModuleNotFoundError that is,
the error will be raised normally.

```pycon
>>> with ModuleNotFoundIgnore():
...     t = 0/0
Traceback (most recent call last):
  ...
ZeroDivisionError: division by zero
```

### *class* py2http.util.Skip

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Class to indicate if one should skip an item

### *class* py2http.util.TypeAsserter(types_for_kind, if_kind_missing='ignore')

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Makes a callable that asserts that a value `v` has the expected type(s) that it’s kind `k` should be

```pycon
>>> assert_type = TypeAsserter({'foo': str, 'bar': (Callable, type(None))})
>>> assert_type('bar', lambda x: x)
>>> assert_type('bar', None)
>>> assert_type('foo', 'i am a string')
>>> assert_type('foo', list('i am not a string'))
Traceback (most recent call last):
  ...
AssertionError: Invalid foo type, must be a <class 'str'>, but was a <class 'list'>
```

If a kind wasn’t specified, the default is to ignore

```pycon
>>> assert_type('not_a_kind', 'blah')
>>> assert_type = TypeAsserter({'foo': str, 'bar': (Callable, type(None))})  # nothing happens
```

But you can choose to warn or raise an exception instead

```pycon
>>> assert_type = TypeAsserter({'foo': str, 'bar': list}, if_kind_missing='raise')
>>> assert_type('not_a_kind', 'blah')
Traceback (most recent call last):
    ...
ValueError: Unrecognized kind: not_a_kind. The ones I recognize: ['foo', 'bar']
```

### py2http.util.call_with_inputs(func, args=(), kwargs=None)

Call `func(*args, **kwargs)`, passing the entries of `kwargs` that name
positional-only parameters of `func` positionally, which JSON (a mapping) can
only supply by name (i2mint/py2http#14).

```pycon
>>> call_with_inputs({"a": 1}.__getitem__, kwargs={"key": "a"})
1
>>> d = {}
>>> call_with_inputs(d.__setitem__, kwargs={"key": "k", "value": 2}), d
(None, {'k': 2})
>>> call_with_inputs(lambda x, /, y=0: (x, y), kwargs={"x": 1, "y": 2})
(1, 2)
```

A positional-only argument that is neither required to be given nor given takes its
default; a missing required one is an `InputError` (a client error), not a
`TypeError`. A callable whose signature can’t be read gets `**kwargs` as is.

Python lets a function with `**kwargs` receive a keyword that is also the name of
a positional-only parameter (`Counter.update(iterable=3)`): such an optional
parameter is left in `kwargs`; only required ones are bound by name.

### py2http.util.deprecate(func=None, , msg=None)

Decorator to emit a DeprecationWarning when the decorated function is called.

### *class* py2http.util.lazyprop(func)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

A descriptor implementation of lazyprop (cached property).
Made based on David Beazley’s “Python Cookbook” book and enhanced with boltons.cacheutils ideas.

```pycon
>>> class Test:
...     def __init__(self, a):
...         self.a = a
...     @lazyprop
...     def len(self):
...         print('generating "len"')
...         return len(self.a)
>>> t = Test([0, 1, 2, 3, 4])
>>> t.__dict__
{'a': [0, 1, 2, 3, 4]}
>>> t.len
generating "len"
5
>>> t.__dict__
{'a': [0, 1, 2, 3, 4], 'len': 5}
>>> t.len
5
>>> # But careful when using lazyprop that no one will change the value of a without deleting the property first
>>> t.a = [0, 1, 2]  # if we change a...
>>> t.len  # ... we still get the old cached value of len
5
>>> del t.len  # if we delete the len prop
>>> t.len  # ... then len being recomputed again
generating "len"
3
```

### py2http.util.obj_to_items_gen(obj, attrs, on_missing_attr=<class 'py2http.util.Missing'>, kv_trans=<function <lambda>>)

Make a generator of (k, v) items extracted from an input object, given an iterable of attributes to extract

* **Parameters:**
  * **obj** – A python object
  * **attrs** ([`Iterable`](https://docs.python.org/3/library/typing.html#typing.Iterable)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]) – The iterable of attributes to extract from obj
  * **on_missing_val** – 

    What to do if an attribute is missing:
    - Skip: Skip the item
    - Callable: Call a function with the attribute as an input
    - anything else: Just return that as a value
  * **kv_trans** ([`Optional`](https://docs.python.org/3/library/typing.html#typing.Optional)[[`Callable`](https://docs.python.org/3/library/typing.html#typing.Callable)])
* **Returns:**
  A generator

### py2http.util.obj_to_path(obj)

Quasi-inverse of obj_to_path: Get a root_obj and attr_path from an object.
Obviously, would only be able to work with some types (only by-ref types?).

```pycon
>>> class A:
...     def foo(self, x): ...
...     foo.x = 3
...     class B:
...         def bar(self, x): ...
...
>>> for t in [(A, ('foo',)), (A, ('B',)), (A, ('B', 'bar'))]:
...     print(obj_to_path(path_to_obj(*t)))
...     print(t)
...     print()
(<class 'util.A'>, ('foo',))
(<class 'util.A'>, ('foo',))

<class 'util.A.B'>
(<class 'util.A'>, ('B',))

(<class 'util.A'>, ('B', 'bar'))
(<class 'util.A'>, ('B', 'bar'))
```

# >>> for t in [(A, (‘foo’,)), (A, (‘B’,)), (A, (‘B’, ‘bar’))]:
# …     assert obj_to_path(path_to_obj(\*t)) == t

### py2http.util.path_to_obj(root_obj, attr_path)

Get an object from a root object and “attribute path” specification.

```pycon
>>> class A:
...     def foo(self, x): ...
...     foo.x = 3
...     class B:
...         def bar(self, x): ...
...
>>> obj = path_to_obj(A, ('foo',))
>>> assert callable(obj) and obj.__name__ == 'foo'
>>> path_to_obj(A, ('foo', 'x'))
3
>>> obj = path_to_obj(A, ('B', 'bar'))
>>> assert callable(obj) and obj.__qualname__ == 'A.B.bar'
```

### py2http.util.pyparam_to_dict(param, kv_trans=<function \_pyparam_kv_trans.skip_empties>)

Get dict from a Parameter object

* **Parameters:**
  * **param** – A inspect.Parameter instance
  * **kv_trans** ([`Callable`](https://docs.python.org/3/library/typing.html#typing.Callable)) – A callable that will be called on the (k, v) attribute items of the Parameter instance
* **Returns:**
  A dict extracted from this Parameter

```pycon
>>> from inspect import Parameter, Signature, signature
>>> from functools import partial
>>>
>>> def mult(x: float, /, y=1, *, z: int=1): ...
>>> params_dicts = map(pyparam_to_dict, signature(mult).parameters.values())
>>> # see that we can recover the original signature from these dicts
>>> assert Signature(map(lambda kw: Parameter(**kw), params_dicts)) == signature(mult)
```

Now what about the kv_trans? It’s default is made to return None when a value is equal to
`Parameter.empty` (which is the way the inspect module distinguishes the `None` object from
“it’s just not there”.

But we could provide our own kv_trans, which should be a function taking `(k, v)` pair
(those k and v arg names are imposed!) and returns… well, what ever you want to return
really. But you if return None, the `(k, v)` item will be skipped.

Look here how using `kv_trans=pyparam_to_dict.kv_trans.with_str_kind` does the job
of skipping `Parameter.empty` items, but also cast the `kind` value to a string,
so that it can be jsonizable.

```pycon
>>> params_to_jdict = partial(pyparam_to_dict, kv_trans=pyparam_to_dict.kv_trans.with_str_kind)
>>> got = list(map(params_to_jdict, signature(mult).parameters.values()))
>>> expected = [
...     {'name': 'x', 'kind': 'POSITIONAL_ONLY', 'annotation': float},
...     {'name': 'y', 'kind': 'POSITIONAL_OR_KEYWORD', 'default': 1},
...     {'name': 'z', 'kind': 'KEYWORD_ONLY', 'default': 1, 'annotation': int}]
>>> assert got == expected, f"\n  got={got}\n  expected={expected}"
```


# about-this-build.html.md

<!-- generated by epythet -->

# About this build

This documentation was built on **2026-10-20 18:35 UTC** from commit <a href="https://github.com/i2mint/py2http/commit/1831bc256eea64f10b753cf6c7762b896d0fd01a"><code>1831bc2</code></a> on branch <code>master</code>, for **py2http 0.1.78** (from <code>setup.cfg</code>).

#### WARNING
The documentation and the package may be misaligned:

- The documented version (0.1.78) is ahead of the latest release on PyPI (0.1.77): these docs describe unreleased code.

## Source

|                     |                                                                                                                                                       |
|---------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------|
| Commit              | <a href="https://github.com/i2mint/py2http/commit/1831bc256eea64f10b753cf6c7762b896d0fd01a"><code>1831bc256eea64f10b753cf6c7762b896d0fd01a</code></a> |
| Branch              | <code>master</code>                                                                                                                                   |
| Tags at this commit | <code>0.1.78</code>                                                                                                                                   |
| Working tree        | clean                                                                                                                                                 |
| Remote              | <code>https://github.com/i2mint/py2http</code>                                                                                                        |

## Continuous integration

|              |                                                                                            |
|--------------|--------------------------------------------------------------------------------------------|
| Repository   | <code>i2mint/py2http</code>                                                                |
| Run          | <a href="https://github.com/i2mint/py2http/actions/runs/39475703674">39475703674</a>       |
| Ref          | <code>refs/heads/master</code>                                                             |
| Event commit | <code>f87b5cea7f924cc0169ffd927c521c1a4d09441b</code> (in the history of the built commit) |

## Tools

|          |         |
|----------|---------|
| epythet  | 0.2.22  |
| Sphinx   | 9.1.1   |
| docutils | 0.22.4  |
| Python   | 3.12.15 |

## Configuration as resolved

|               |                                                                   |
|---------------|-------------------------------------------------------------------|
| theme         | <code>auto</code> (Sphinx theme <code>sphinxawesome_theme</code>) |
| accent        | <code>#186a23</code>                                              |
| api_generator | <code>autosummary</code>                                          |
| ignore        | <code>tests/</code>, <code>scrap/</code>, <code>examples/</code>  |
| agent_outputs | <code>true</code>                                                 |
| aggregates    | <code>md</code>                                                   |
| ai_artifacts  | <code>true</code>                                                 |

## Package on PyPI

Latest release: <a href="https://pypi.org/project/py2http/0.1.77/">0.1.77</a>, older than the documented version (0.1.78).

## Reproduce

```bash
git clone https://github.com/i2mint/py2http && cd py2http
git checkout 1831bc256eea64f10b753cf6c7762b896d0fd01a
pip install "epythet==0.2.22"
epythet quickstart . --ignore tests/ scrap/ examples/
```

The same data, for machines: <a href="build_info.json"><code>build_info.json</code></a> (schema version 1).


# api.html.md

# API reference

| [`py2http`](_autosummary/py2http.html.md#module-py2http)   | This module provides functionality to easily create HTTP services from Python functions and class methods.   |
|---------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------|


