Skip to main content

Function Registry

Function Registry is a Python library designed to help consolidate functions and their respective versions into a centralized catalog. Whether you’re working on a single project or need a distributable library, Function Registry provides:

  • A ready-to-use FunctionRegistry class.
  • An abstract base class (AbstractFunctionRegistry) for custom implementations.

Installation

Requirements

  • Python 3.8 or higher
  • pip, pipenv, or poetry

Install with pip

pip install function_registry

Install from source

git clone https://github.com/sgg10/function-registry.git
cd function-registry
pip install -e .

Quick Start

Basic Example

Here’s how to get started with the FunctionRegistry class:

from function_registry import FunctionRegistry

# Create a new function catalog
registry = FunctionRegistry()

# Save a function versions
@registry.save_version("add", version=1)
def add(a, b):
    return a + b

@registry.save_version("add", version=2)
def add(*nums):
    return sum(nums)

# Retrieve the saved function versions

print(registry.get_version("add", version=1)["function"](2, 3))  # 5
print(registry.get_version("add", version=2)["function"](2, 3, 4))  # 9

Features and Examples

1. Using sequential or semantic versioning

You can use sequential or semantic versioning for any function, but you must keep the same type of versioning for the same function, otherwise you will get an exception.

Example: you cannot have @registry.save_version(“add”, version=1) and then @registry.save_version(“add”, version=“1.1.0”).

@registry.save_version("add", version=1)
def add(a, b):
    return a + b

@registry.save_version("add", version=2)
def add(*nums):
    return sum(nums)

@registry.save_version("div", version="1.0.0")
def div(a, b):
    return a / b

@registry.save_version("div", version="1.0.1")
def div(a, b):
    try:
        return a / b
    except ZeroDivisionError:
        return "Cannot divide by zero"


print(registry.get_version("add", version=1)["function"](2, 3))  # 5
print(registry.get_version("add", version=2)["function"](2, 3, 4))  # 9
print(registry.get_version("div", version="1.0.0")["function"](10, 2))  # 5.0
print(registry.get_version("div", version="1.0.1")["function"](10, 0))  # "Cannot divide by zero"

2. Using Metadata

Attach custom metadata to functions for advanced search capabilities.

from function_registry import FunctionRegistry

# Create a new function catalog
registry = FunctionRegistry()

@registry.save_version("metadata_func", version=1, metadata={"author": "John Doe"})
def metadata_func():
    return "Metadata Example"

versioned_func = registry.get_version("metadata_func", version=1)
print(versioned_func["metadata"]["author"])  # Output: John Doe

3. Custom version search

You can create a custom search function to filter versions based on custom criteria.

For example, you can search for the latest version of a function that was created by a specific author.

from function_registry import FunctionRegistry
from function_registry.types import FR_VERSION_DICT_TYPE

AUTHOR = "John Doe"

# Create a new function catalog
registry = FunctionRegistry()

@registry.save_version("add", version=1, metadata={"author": "John Doe"})
def add(a, b):
    return a + b

@registry.save_version("add", version=2, metadata={"author": "Jane Doe"})
def add(*nums):
    return sum(nums)

@registry.save_version("add", version=3, metadata={"author": "John Doe"})
def add(*nums):
    print(f"Adding {len(nums)} numbers")
    return sum(nums)

def custom_search(versions: FR_VERSION_DICT_TYPE):
    filtered_versions = {k: v for k, v in versions.items() if v["metadata"]["author"] == AUTHOR}

    return max(filtered_versions.keys(), key=lambda v: v)

latest_version = registry.get_version("add", custom_search_function=custom_search)
print(latest_version["metadata"]["author"])  # Output: John Doe
print(latest_version["metadata"]["version"])  # Output: 3
print(latest_version["function"](2, 3, 4))  # Output: 9

4. Custom Function Registry Implementation

Leverage the AbstractFunctionRegistry base class to build your own registry.

from function_registry import AbstractFunctionRegistry

class CustomRegistry(AbstractFunctionRegistry):
    def __init__(self):
        self._functions = {}

    def save_version(self, function_name, version=None, metadata=None):
        # Custom implementation here
        pass

    def get_version(self, function_name, version=None, custom_search_function=None):
        # Custom implementation here
        pass

    def extend(self):
        # Custom implementation here
        pass

# Example usage
custom_registry = CustomRegistry()

5. Extend Function Registry with other Registries

You can extend the FunctionRegistry class with other registries to combine their functions.

from function_registry import FunctionRegistry

catalog_1 = FunctionRegistry()
catalog_2 = FunctionRegistry()

# Save functions to catalog_1
@catalog_1.save_version("add", version=1)
def add(a, b):
    return a + b

# Save functions to catalog_2
@catalog_2.save_version("sub", version=1)
def sub(a, b):
    return a - b

# Extend catalog_1 with catalog_2
catalog_1.extend(catalog_2)

print(catalog_1.get_version("add", version=1)["function"](2, 3))  # 5
print(catalog_1.get_version("sub", version=1)["function"](5, 3))  # 2

6. Flexible Function Duplication Strategies

Extend registries with strategies like

  • KEEP_EXISTING: Keep the existing function version and ignore the new one.
  • OVERWRITE: Overwrite the existing function version with the new one.
  • RAISE: Raise an exception if a function version already exists.
  • MERGE_WITH_EXISTING_PRIORITY: Merge the existing and new function versions, giving priority to the existing version if one version of the function already exists.
  • MERGE_WITH_NEW_PRIORITY: Merge the existing and new function versions, giving priority to the new version if one version of the function already exists.
from function_registry import FunctionRegistry
from function_registry.enums import EXTEND_DUPLICATED_STRATEGIES

catalog_1 = FunctionRegistry()
catalog_2 = FunctionRegistry()


# Save functions to catalog_1
@catalog_1.save_version("add", version=1)
def add(a, b):
    return a + b


# Save functions to catalog_2
@catalog_2.save_version("add", version=1)
def add(a, b):
    return a + b + 100


# Extend catalog_1 with catalog_2
catalog_1.extend(catalog_2, EXTEND_DUPLICATED_STRATEGIES.OVERWRITE)

# Call the function from catalog_1
print(catalog_1.get_version("add", version=1)["function"](1, 2))  # Output: 103

Testing

To run the unit tests, execute the following command from the project root directory:

python -m unittest discover tests

The test cases ensure the library's robustness by covering:

  • Function version registration.
  • Metadata handling.
  • Custom search functions.
  • Error handling (e.g., duplicate versions, missing versions).

Contributing

All contributions to improve Function Registry are welcome! To contribute, follow these steps:

  1. Fork the repository.
git clone https://github.com/sgg10/function-registry.git
cd function-registry
  1. Create a new branch for your changes:
git checkout -b feature/new-feature
  1. Make changes and test them locally.
  2. Submit a pull request: Open a pull request describing your changes.

For bug reports or feature requests, please visit the issues page.

License

This project is licensed under the MIT License. See the LICENSE file for details.

Metadata

Release files for function-registry 1.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for function-registry 1.0.0
File Size Uploaded
function_registry-1.0.0.tar.gz 12.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for function-registry 1.0.0
File Interpreter ABI Platform
function_registry-1.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 21.2 kB

Release files / function_registry-1.0.0.tar.gz

Download URL function_registry-1.0.0.tar.gz
Size 12.2 kB
Tags Source
SHA-256 checksum
How to use checksums
135f1b28a3802612dda89eb6ebb023b363010c3d92db029b4b1f5bdb70dc58e1
BLAKE2b-256 checksum
How to use checksums
a2cf985903c6cc86e1a84589fc481932802d085073a36dff4c9e7b5486403769
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.0.1 CPython/3.9.18

Release files / function_registry-1.0.0-py3-none-any.whl

Download URL function_registry-1.0.0-py3-none-any.whl
Size 9.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
667d2cd5dd046abfdb10949344eb65f71ffb683234fc95c87c8b5102b9099065
BLAKE2b-256 checksum
How to use checksums
055e42bc1bb7c2e443dc3100301e55eb0cad65c239f704b0e3e682791fd76148
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.0.1 CPython/3.9.18

Release history Release notifications | RSS feed

This release

1.0.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page