accessor-stubs


Nameaccessor-stubs JSON
Version 0.0.1 PyPI version JSON
download
home_pageNone
Summarystubgen for xarray and pandas accessors
upload_time2024-05-29 16:42:51
maintainerNone
docs_urlNone
authorNone
requires_python>=3.9
license?
keywords accessors pandas xarray
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # accessor_stubs

This package addresses a problem that's bothered me for a while a now. The pandas
and xarray packages both discourage subclassing their datastructures, and recommend instead to
use composition or [accessor methods](https://docs.xarray.dev/en/stable/internals/extending-xarray.html).

I really wanted to use accessor methods to add my domain specific functionality to the
xarray ecosystem, but I really really like having IDE autocomplete that works. Unfortunately the dynamic nature of accessor methods makes them incompatible with the current [language server static analysis methods](https://github.com/microsoft/pylance-release/discussions/4564).

To solve this autocomplete problem, I've created this package to create xarray type-stubs
on the fly that follow [PEP 561](https://peps.python.org/pep-0561/#partial-stub-packages). By
using the `register_dataarray_accessor()` and `register_dataset_accessor()` methods from
this package instead of xarray, your accessors will be registered with `accessor_stubs` as well as
`xarray`. Then, when you call `accessor_stubs.stubgen()`, new xarray type-stubs will be generated that
have your accessor methods listed as properties in `DataArray` and `Dataset` type stubs.

This package tracks the version of xarray that is installed and will regenerate type stubs if you
upgrade or downgrade your xarray version.

Right now, only xarray is supported, but maybe I'll add pandas in the future...

## Usage

In your python module/package, register your accessor using accessor_stubs as:

```python
# accessor.py
import xarray as xr
from accessor_stubs import register_dataset_accessor

@register_dataset_accessor("sneaky")
class SneakyAccessor:
    def __init__(self, xarray_obj):
        self._obj = xarray_obj
        self._sneaky_msg = None

    @property
    def sneak(self):
        """Return a sneaky message"""
        if self._sneaky_msg is None:
            self._sneaky_msg = "👟"
        return self._sneaky_msg

```

In the top level **init**.py module of your package from where all your accessors are initialized,
run the `stubgen()` method in accessor_stubs. This will run mypy stubgen on the xarray dataset.py
and dataarray.py files in your xarray installation, then add your registered accessors to the
stub files. It's very important that you run `stubgen()` after all your accessors have been registered.

```python
# __init__.py
import accessor # the module where my accessor is created and registered
from accessor_stubs import stubgen
stubgen()

```

Now after you import your package, new xarray stubs will be generated with your accessors, and your
IDE should be able to recognize your accessors as properties of the xarray datastructure classes:

![vscode_screenshot](./doc/vscode_screenshot.png)

The generated `dataset.pyi` type-stub looks something like this:

```python
from accessor import SneakyAccessor
import datetime
import numpy as np
import pandas as pd
...

class Dataset(DataWithCoords, DatasetAggregations, DatasetArithmetic, Mapping[Hashable, 'DataArray']):
    sneaky: SneakyAccessor
    def __init__(self, data_vars: DataVars | None = None, coords: Mapping[Any, Any] | None = None, attrs: Mapping[Any, Any] | None = None) -> None: ...
    def __eq__(self, other: DsCompatible) -> Self: ...
    @classmethod
    def load_store(cls, store, decoder: Incomplete | None = None) -> Self: ...
    @property
    def variables(self) -> Frozen[Hashable, Variable]: ...
    ...
```

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "accessor-stubs",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.9",
    "maintainer_email": null,
    "keywords": "accessors, pandas, xarray",
    "author": null,
    "author_email": "Constantine Karos <ckaros@outlook.com>",
    "download_url": null,
    "platform": null,
    "description": "# accessor_stubs\n\nThis package addresses a problem that's bothered me for a while a now. The pandas\nand xarray packages both discourage subclassing their datastructures, and recommend instead to\nuse composition or [accessor methods](https://docs.xarray.dev/en/stable/internals/extending-xarray.html).\n\nI really wanted to use accessor methods to add my domain specific functionality to the\nxarray ecosystem, but I really really like having IDE autocomplete that works. Unfortunately the dynamic nature of accessor methods makes them incompatible with the current [language server static analysis methods](https://github.com/microsoft/pylance-release/discussions/4564).\n\nTo solve this autocomplete problem, I've created this package to create xarray type-stubs\non the fly that follow [PEP 561](https://peps.python.org/pep-0561/#partial-stub-packages). By\nusing the `register_dataarray_accessor()` and `register_dataset_accessor()` methods from\nthis package instead of xarray, your accessors will be registered with `accessor_stubs` as well as\n`xarray`. Then, when you call `accessor_stubs.stubgen()`, new xarray type-stubs will be generated that\nhave your accessor methods listed as properties in `DataArray` and `Dataset` type stubs.\n\nThis package tracks the version of xarray that is installed and will regenerate type stubs if you\nupgrade or downgrade your xarray version.\n\nRight now, only xarray is supported, but maybe I'll add pandas in the future...\n\n## Usage\n\nIn your python module/package, register your accessor using accessor_stubs as:\n\n```python\n# accessor.py\nimport xarray as xr\nfrom accessor_stubs import register_dataset_accessor\n\n@register_dataset_accessor(\"sneaky\")\nclass SneakyAccessor:\n    def __init__(self, xarray_obj):\n        self._obj = xarray_obj\n        self._sneaky_msg = None\n\n    @property\n    def sneak(self):\n        \"\"\"Return a sneaky message\"\"\"\n        if self._sneaky_msg is None:\n            self._sneaky_msg = \"\ud83d\udc5f\"\n        return self._sneaky_msg\n\n```\n\nIn the top level **init**.py module of your package from where all your accessors are initialized,\nrun the `stubgen()` method in accessor_stubs. This will run mypy stubgen on the xarray dataset.py\nand dataarray.py files in your xarray installation, then add your registered accessors to the\nstub files. It's very important that you run `stubgen()` after all your accessors have been registered.\n\n```python\n# __init__.py\nimport accessor # the module where my accessor is created and registered\nfrom accessor_stubs import stubgen\nstubgen()\n\n```\n\nNow after you import your package, new xarray stubs will be generated with your accessors, and your\nIDE should be able to recognize your accessors as properties of the xarray datastructure classes:\n\n![vscode_screenshot](./doc/vscode_screenshot.png)\n\nThe generated `dataset.pyi` type-stub looks something like this:\n\n```python\nfrom accessor import SneakyAccessor\nimport datetime\nimport numpy as np\nimport pandas as pd\n...\n\nclass Dataset(DataWithCoords, DatasetAggregations, DatasetArithmetic, Mapping[Hashable, 'DataArray']):\n    sneaky: SneakyAccessor\n    def __init__(self, data_vars: DataVars | None = None, coords: Mapping[Any, Any] | None = None, attrs: Mapping[Any, Any] | None = None) -> None: ...\n    def __eq__(self, other: DsCompatible) -> Self: ...\n    @classmethod\n    def load_store(cls, store, decoder: Incomplete | None = None) -> Self: ...\n    @property\n    def variables(self) -> Frozen[Hashable, Variable]: ...\n    ...\n```\n",
    "bugtrack_url": null,
    "license": "?",
    "summary": "stubgen for xarray and pandas accessors",
    "version": "0.0.1",
    "project_urls": null,
    "split_keywords": [
        "accessors",
        " pandas",
        " xarray"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "d8f4b89dcd3a9cc12642073683c7fb882cbd8b9e0354cc7c3622b917b681aa1d",
                "md5": "660c46625bc7f62846e661ddedd71848",
                "sha256": "bc42947450735695fb9fd7d67af7145ada8a16fab76af6428e2c55285bd60c52"
            },
            "downloads": -1,
            "filename": "accessor_stubs-0.0.1-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "660c46625bc7f62846e661ddedd71848",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.9",
            "size": 6353,
            "upload_time": "2024-05-29T16:42:51",
            "upload_time_iso_8601": "2024-05-29T16:42:51.007631Z",
            "url": "https://files.pythonhosted.org/packages/d8/f4/b89dcd3a9cc12642073683c7fb882cbd8b9e0354cc7c3622b917b681aa1d/accessor_stubs-0.0.1-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-05-29 16:42:51",
    "github": false,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "lcname": "accessor-stubs"
}
        
Elapsed time: 0.25031s