Skip to content

Commit

Permalink
feat(bindgen): environment_dispatch supports the function_factory
Browse files Browse the repository at this point in the history
  • Loading branch information
thewtex committed Apr 13, 2023
1 parent e2b2c84 commit a8c47d4
Show file tree
Hide file tree
Showing 14 changed files with 164 additions and 10 deletions.
14 changes: 12 additions & 2 deletions .github/workflows/python-wasm.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ jobs:
working-directory: ./src/python/itkwasm
run: |
python -m pip install --upgrade pip
cd test/test-accelerator
python -m pip install -e "."
cd -
python -m pip install -e ".[test]"
- name: Test with pytest
working-directory: ./src/python/itkwasm
Expand Down Expand Up @@ -48,8 +51,15 @@ jobs:
- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install hatch
python -m pip install hatch pytest
- name: Test compress-stringify wasi
working-directory: ./packages/compress-stringify/python/compress-stringify-wasi
working-directory: ./packages/compress-stringify/python/itkwasm-compress-stringify-wasi
run: |
python -m pip install -e .
pytest
hatch run test
- name: Test compress-stringify
working-directory: ./packages/compress-stringify/python/itkwasm-compress-stringify
run: |
python -m pip install -e .
pytest
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,9 @@ keywords = [

requires-python = ">=3.7"
dependencies = [
"itkwasm >= 1.0b93",
"itkwasm >= 1.0.b93",
"importlib_resources",

]

[tool.hatch.version]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,10 @@ keywords = [

requires-python = ">=3.7"
dependencies = [
"itkwasm >= 1.0b93",
"importlib_resources",
"itkwasm >= 1.0.b93",
"itkwasm-compress-stringify-wasi; sys_platform != \"emscripten\"",
"itkwasm-compress-stringify-emscripten; sys_platform == \"emscripten\"",

]

[tool.hatch.version]
Expand Down
3 changes: 1 addition & 2 deletions src/bindgen/python-resources/template.pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,7 @@ keywords = [

requires-python = ">=3.7"
dependencies = [
"itkwasm >= 1.0b93",
"importlib_resources",
"itkwasm >= 1.0.b93",@bindgenDependencies@
]

[tool.hatch.version]
Expand Down
4 changes: 3 additions & 1 deletion src/bindgen/python.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,9 @@ pip install ${packageName}
function packagePyProjectToml(packageName, packageDir, bindgenPyPackage, options) {
let pyProjectToml = fs.readFileSync(bindgenResource('template.pyproject.toml'), {encoding:'utf8', flag:'r'})
pyProjectToml = pyProjectToml.replaceAll('@bindgenPackageName@', packageName)
let repository = options.repository ?? 'https://github.com/InsightSoftwareConsortium/itk-wasm'
const repository = options.repository ?? 'https://github.com/InsightSoftwareConsortium/itk-wasm'
let bindgenDependencies = packageName.endsWith('wasi') || packageName.endsWith('emscripten') ? '\n "importlib_resources",\n' : `\n "${packageName}-wasi; sys_platform != \\"emscripten\\"",\n "${packageName}-emscripten; sys_platform == \\"emscripten\\"",\n`
pyProjectToml = pyProjectToml.replaceAll('@bindgenDependencies@', bindgenDependencies)
pyProjectToml = pyProjectToml.replaceAll('@bindgenProjectRepository@', repository)
pyProjectToml = pyProjectToml.replaceAll('@bindgenPyPackage@', bindgenPyPackage)
const pyProjectTomlPath = path.join(packageDir, 'pyproject.toml')
Expand Down
3 changes: 2 additions & 1 deletion src/python/itkwasm/itkwasm/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from .float_types import FloatTypes
from .int_types import IntTypes
from .pixel_types import PixelTypes
from .environment_dispatch import environment_dispatch
from .environment_dispatch import environment_dispatch, function_factory

__all__ = [
"InterfaceTypes",
Expand All @@ -40,4 +40,5 @@
"IntTypes",
"PixelTypes",
"environment_dispatch",
"function_factory",
]
67 changes: 66 additions & 1 deletion src/python/itkwasm/itkwasm/environment_dispatch.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,73 @@
from typing import Callable
from typing import Callable, Tuple, Dict, Optional, Set
import sys
import importlib
import sys
if sys.version_info < (3, 10):
from importlib_metadata import entry_points
else:
from importlib.metadata import entry_points

class FunctionFactory:
def __init__(self):
self._registered: Dict[Tuple[str, str], Set[Callable]] = {}
self._priorities: Dict[Callable, int] = {}
self._has_entry_point_lookup: Set[Tuple[str, str]] = set()

def register(self, interface_package: str, func_name: str, func: Callable, priority: int=1)-> None:
key = (interface_package, func_name)
registered = self._registered.get(key, set())
registered.add(func)
self._registered[key] = registered
self._priorities[func] = priority

def lookup(self, interface_package: str, func_name: str) -> Optional[Set[Callable]]:
key = (interface_package, func_name)
if not key in self._has_entry_point_lookup:
discovered_funcs = entry_points(group=f'{interface_package}.{func_name}')
for ep in discovered_funcs:
priority = ep.name.partition('.priority.')[2]
if priority:
priority = int(priority)
else:
priority = 1
func = ep.load()
self.register(interface_package, func_name, func, priority)
self._has_entry_point_lookup.add(key)
return self._registered.get(key, None)

def highest_priority(self, interface_package: str, func_name: str) -> Optional[Callable]:
"""Highest priority registered function with priority > 0."""
registered = self.lookup(interface_package, func_name)
if registered is None:
return None
highest = max(self._registered[(interface_package, func_name)], key=lambda x: self._priorities[x])
if self._priorities[highest] < 1:
return None
return highest

def set_priority(self, func: Callable, priority: int)-> None:
if func not in self._priorities:
raise ValueError(f"Function {func} has not been registered")
self._priorities[func] = priority

def get_priority(self, func: Callable)-> int:
if func not in self._priorities:
raise ValueError(f"Function {func} has not been registered")
return self._priorities[func]

def disable(self, interface_package: str, func_name: str):
"""Set the priorites of all registered functions to -1."""
registered = self.lookup(interface_package, func_name)
for func in registered:
self._priorities[func] = -1

function_factory = FunctionFactory()

def environment_dispatch(interface_package: str, func_name: str) -> Callable:
factory_func = function_factory.highest_priority(interface_package, func_name)
if factory_func is not None:
return factory_func

if sys.platform != "emscripten":
package = f"{interface_package}_wasi"
else:
Expand Down
1 change: 1 addition & 0 deletions src/python/itkwasm/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ dependencies = [
"numpy",
"typing_extensions",
"wasmtime; sys_platform != \"emscripten\"",
"importlib_metadata; python_version < \"3.10\"",
]

[project.urls]
Expand Down
26 changes: 26 additions & 0 deletions src/python/itkwasm/test/test-accelerator/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
[build-system]
requires = ["hatchling", "hatch-vcs"]
build-backend = "hatchling.build"

[project]
name = "test-accelerator"
license = "Apache-2.0"
version = "0.0.1"

requires-python = ">=3.7"
dependencies = [
"itkwasm >= 1.0b82",
]

[tool.hatch.envs.default]
dependencies = [
"pytest",
]

[tool.hatch.envs.default.scripts]
test = "pytest"

[project.entry-points."itkwasm_example_package.example_function"]
"test_accelerator-faster.priority.10" = "test_accelerator.faster_mod:faster"
"test_accelerator-fastest.priority.15" = "test_accelerator.fastest_mod:fastest"
"test_accelerator-slower.priority.-1" = "test_accelerator.slower_mod:slower"
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from .faster_mod import faster
from .fastest_mod import fastest
from .slower_mod import slower
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
def faster():
pass
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
def fastest():
pass
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
def slower():
pass
38 changes: 38 additions & 0 deletions src/python/itkwasm/test/test_function_factory.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import pytest

def test_function_factory():
test_accelerator = pytest.importorskip("test_accelerator")

from itkwasm import function_factory
interface_package = "itkwasm_example_package"
func_name = "example_function"
registered = function_factory.lookup(interface_package, func_name)

from test_accelerator import slower, faster, fastest

highest = function_factory.highest_priority(interface_package, func_name)
assert highest == fastest

function_factory.set_priority(faster, 30)
highest = function_factory.highest_priority(interface_package, func_name)
assert highest == faster

assert function_factory.get_priority(slower) == -1

function_factory.disable(interface_package, func_name)
highest = function_factory.highest_priority(interface_package, func_name)
assert highest == None

def test_environment_dispatch():
test_accelerator = pytest.importorskip("test_accelerator")

from itkwasm import function_factory, environment_dispatch
interface_package = "itkwasm_example_package"
func_name = "example_function"

from test_accelerator import fastest
function_factory.register(interface_package, func_name, fastest, 1)

func = environment_dispatch(interface_package, func_name)
from test_accelerator import fastest
assert func == fastest

0 comments on commit a8c47d4

Please sign in to comment.