69 lines
2.2 KiB
Python
69 lines
2.2 KiB
Python
class export:
|
|
"""Decorator to export a public API in a given package.
|
|
|
|
Example usage:
|
|
|
|
```python
|
|
@export(package="keras_tuner", path="keras_tuner.applications.HyperResNet")
|
|
class HyperResNet:
|
|
...
|
|
```
|
|
|
|
You can also pass a list of paths as `path`, to make
|
|
the same symbol visible under various aliases:
|
|
|
|
```python
|
|
@export(
|
|
package="keras_tuner",
|
|
path=[
|
|
"keras_tuner.applications.HyperResNet",
|
|
"keras_tuner.applications.resnet.HyperResNet",
|
|
])
|
|
class HyperResNet:
|
|
...
|
|
```
|
|
|
|
**Note:** All export packages must start with the package name.
|
|
Yes, that is redundant, but that is a helpful sanity check.
|
|
The expectation is that each package will customize
|
|
`export_api` to provide a default value for `package`,
|
|
which will serve to validate all `path` values
|
|
and avoid users inadvertendly ending up with non-exported
|
|
symbols due to a bad path (e.g. `path="applications.HyperResNet"`
|
|
instead of `path="keras_tuner.applications.HyperResNet"`).
|
|
"""
|
|
|
|
def __init__(self, package, path):
|
|
if isinstance(path, str):
|
|
export_paths = [path]
|
|
elif isinstance(path, list):
|
|
export_paths = path
|
|
else:
|
|
raise ValueError(
|
|
f"Invalid type for `path` argument: "
|
|
f"Received '{path}' "
|
|
f"of type {type(path)}"
|
|
)
|
|
|
|
for p in export_paths:
|
|
if not p.startswith(package + "."):
|
|
raise ValueError(
|
|
f"All `export_path` values should start with '{package}.'. "
|
|
f"Received: path={path}"
|
|
)
|
|
|
|
self.package = package
|
|
self.path = path
|
|
|
|
def __call__(self, symbol):
|
|
if hasattr(symbol, "_api_export_path") and symbol._api_export_symbol_id == id(
|
|
symbol
|
|
):
|
|
raise ValueError(
|
|
f"Symbol {symbol} is already exported as '{symbol._api_export_path}'. "
|
|
f"Cannot also export it to '{self.path}'."
|
|
)
|
|
symbol._api_export_path = self.path
|
|
symbol._api_export_symbol_id = id(symbol)
|
|
return symbol
|