No project description provided
Project description
adjudicator
Adjudicator (nount): An adjudicator is a person or body that makes formal judgments on a disputed matter. They are the ones who settle disputes or decide who is right in a disagreement. This could be a judge in a courtroom, an arbitrator in a negotiation, or any person or system given the power to make decisions of this type.
Adjudicator is a framework for implementing type-based rule engines largely inspired by the Pants build system. The rule graph consists of nodes which are concrete Python types and edges which are functions that take a set of input types and produce an output type.
Rules are matched on a set of facts, which populate the possible input types of a rule. Deriving a type may require chained execution of rules, which is supported. Global facts may be used to populate a potential input type for all rule executions.
The Adjudicator rule engine is designed to be used in a request-response fashion. A request is a set of facts that
should be used to derive a type. A response is the derived type. The rule engine will execute the rules necessary to
derive the type and return the response. If a rule was already executed with the same inputs, it will not be executed
again. For optimal use of the caching mechanism, all types participating in the rule evaluation should be immutable
and implement a stable hash (e.g. using @dataclass(frozen=True)
and tuple
instead of list
, etc.).
When a mutable type should intentionally participate in the rule evaluation, usually this works automatically because
the hash of a Python object that does not provide a custom __hash__()
implementation or disables its hashing is based
on the object's identity. This means that the hash is stable for the memory allocation of the object, and will not
change if the object is mutated. For types that do not support hashing, support can be enabled explicitly using the
RuleEngine.hashsupport
object.
Table of Contents
Quickstart
The following example shows how to use Adjudicator to implement a simple "Hello World" application. The rule engine
invokes the say_hello()
production rule because a HelloResponse
is requested and a HelloRequest
is provided,
which matches the rule's signature.
from dataclasses import dataclass
from adjudicator import Params, RuleEngine, rule
@dataclass(frozen=True)
class HelloRequest:
name: str
@dataclass(frozen=True)
class HelloResponse:
greeting: str
@rule()
def say_hello(request: HelloRequest) -> HelloResponse:
return HelloResponse(greeting=f"Hello {request.name}!")
engine = RuleEngine()
engine.load_module(__name__)
response = engine.get(HelloResponse, Params(HelloRequest(name="World")))
print(response.greeting)
A more complex example can be found in src/adjudicator/examples/readmesync directory. That script is actually used to keep this README file up to date with the example and the table of contents above. It demonstrates how to use the rule engine to generate a file based on a set of rules, leveraging union memberships and rule result caching.
Installation
Adjudicator is available on PyPI. You need at least Python 3.10.
pip install python-adjudicator
Future Extensions
- Currently the rule graph stores rules as connections between types and rules on edges. A more efficient representation would be the one illustrated above, where types are connected to rules which are connected to types.
- The ability to mark facts as required to be consumed. If such a fact is not consumed during the execution of a request, an error will be raised.
Add-on: ReadmeSync
The python-adjudicator
package includes functionality to keep the content of a README.md
file up to date by
placing inline comments into the file that follow a certain syntax. In fact, the same utility is used to keep this
readme file up to date with the example code and the table of contents.
Synopsis
usage: python -m adjudicator.examples.readmesync [-h] [--preview] [--verbose]
[file]
ReadmeSync is a utility that allows you to place comments into a Markdown file that represent
directives for content to be included in their place. The following types of directives are
supported:
- `<!-- include <path> -->`: Include the contents of the file at the given path. A `code:<lang>`
option can be added to the directive to wrap the content in a code block using the specified
language name (can be empty).
- `<!-- runcmd <command> -->`: Run the given command and include the output in the document. A
`code:<lang>` option can be added to the directive to wrap the output in a code block using
the specified language name (can be empty).
- `<!-- table of contents -->`: Include a table of contents for the document for all Markdown
headers following the directive.
positional arguments:
file [default: README.md]
options:
-h, --help show this help message and exit
--preview, -p run in preview mode
--verbose, -v enable verbose logging
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Hashes for python_adjudicator-0.3.1-py3-none-any.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | c20bd883463f294f61374740a6e01d1be8c6b78078410653e0830f3d827765ed |
|
MD5 | cd75daaa61be915b05833d4c3499a020 |
|
BLAKE2b-256 | a827490c3f821a3bbeb4fa492c0aef4f9db38cb68b311cf393eb98b50f3b30a0 |