Metadata-Version: 2.3
Name: lazy-helper
Version: 0.1.0
Summary: Helper functions to make lazy imports easier in Python
Author-email: jamie.cheng.chang@gmail.com
Requires-Dist: typer ; extra == 'cli'
Requires-Python: >=3.10
Provides-Extra: cli
Description-Content-Type: text/markdown

# lazy-helper
Helper functions to make lazy imports easier in Python

## Motivation
Lazy imports are useful for:

- Improving startup speed.
- Simplifying packages with optional dependencies.
- Typing imports that don't need to be loaded at run time.

There are a few mechanisms in Python for lazy imports right now. All of them have some compromise. 

There is currently a [proposal](https://peps.python.org/pep-0810/) in the works but it'll take a while to come to Python if at all. (It probably will! Maybe in 3.15)

This package provides an opinionated approach to lazy loading, focusing on ease of use and minimising the biggest downside of no typing.

## Installation
```shell
uv add lazy-helper
```

The cli is helpful for typing but can be kept as a dev dependency:
```shell
uv add --dev 'lazy-helper[cli]'
```

## Usage

### Defining the imports
First create a module to group all your lazy imports. I like to call mine `lazy.py` but it's really up to you.

In your module, first create a lazy loader object. As a convention you're expected to assign it to `__lazy__`:
```py
from lazy_helper import Lazy


__lazy__ = Lazy()
```

Now define your lazy imports:
```py
__lazy__("typing")  # same as `import typing`
__lazy__("typing", "TypedDict")  # same as `from typing import TypedDict`
__lazy__("typing", as_="tp")  # `import typing as tp`
__lazy__("typing", "TypedDict", as_="TD")  # `from typing import TypedDict as TD`

```

Finally expose lazy imports at the module level:

```py
__getattr__ = __lazy__.__getattr__
__dir__ = __lazy__.__dir__
__all__ = __lazy__.__all__
```

### Using the imports
Now if when you need to use any of the imports, you must import the module but not the attributes in the module. 

```py
from . import lazy
from .lazy import TD  # Wrong ❌, this will eagerly import TD.
```

Now in attributes of lazy will only be loaded when we use it:

```py
lazy.TD  # will load the typing dynamically
```

### Generating the stubs
Remember ot install the cli as a dev dependency:
```shell
uv add --dev 'lazy-helper[cli]'
```

Then run `lazy-stubgen` passing in any of the files that contain the `__lazy__` objects. 

```shell
lazy-stubgen examples/lazy.py
```

You will see a `lazy.pyi` file, which contains what the imports would look like.
```py
import typing
from typing import TypedDict
import typing as tp
from typing import TypedDict as TD

__all__ = [
    "typing",
    "TypedDict",
    "tp",
    "TD",
]
```

The stubs will also allow type checkers like `mypy` and `pyright` to maintain typing information.
