dirct


Namedirct JSON
Version 2.0.1 PyPI version JSON
download
home_pagehttps://github.com/abrahammurciano/python-dirct
SummaryA dict that reflects the contents of a directory.
upload_time2024-05-22 09:18:13
maintainerNone
docs_urlNone
authorAbraham Murciano
requires_python>=3.11
licenseGPLv3
keywords
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # dirct
A dict that reflects the contents of a directory.

## Installation

You can install this package with pip.
```sh
$ pip install dirct
```

## Links

[![Documentation](https://img.shields.io/badge/Documentation-C61C3E?style=for-the-badge&logo=Read+the+Docs&logoColor=%23FFFFFF)](https://abrahammurciano.github.io/python-dirct)

[![Source Code - GitHub](https://img.shields.io/badge/Source_Code-GitHub-181717?style=for-the-badge&logo=GitHub&logoColor=%23FFFFFF)](https://github.com/abrahammurciano/python-dirct.git)

[![PyPI - dirct](https://img.shields.io/badge/PyPI-dirct-006DAD?style=for-the-badge&logo=PyPI&logoColor=%23FFD242)](https://pypi.org/project/dirct/)

## Usage

### Basic usage

```python
>>> from dirct import Dirct
>>> d = Dirct("path/to/directory")
>>> from typing import Mapping
>>> isinstance(d, Mapping)
True
```

### Loading files

The directory may contain any number of files and subdirectories. Files ending in `.toml`, `.json`, `.yaml`, and `.yml` are parsed correctly according to their respective formats, and all other files are read as text if it can be decoded or as bytes otherwise.

You can also pass custom loader callables to the `loaders` parameter of the `Dirct` constructor. A loader callable takes the `Path` to a file and returns the value that file represents. The `DEFAULT_LOADERS` constant contains loaders for the aforementioned file formats.

```python
from dirct import Dirct, DEFAULT_PARSERS

def csv_loader(path: Path) -> Sequence[Mapping[str, str]]:
	with path.open() as f:
		return tuple(csv.DictReader(f))

Dirct("path/to/directory", loaders=(csv_loader, *DEFAULT_LOADERS))
```

Loaders are tried in order. If a loader raises an `UnsupportedFileError` then the next loader is tried. If a loader raises any other type of `Exception` it is propagated. If no loader can load a file, then an `UnsupportedFileError` is raised.

### Example directory

Consider the following directory `path/to/directory/` that contains data about a video game.

```
path/to/directory/
├── __self__.toml
├── publisher.toml
├── version
└── levels/
	├── castle.lvl.json
	├── dungeon.lvl.json
	└── forest.lvl.json
```

Creating a `Dirct` with this directory would produce a mapping with the following structure.

```py
>>> d = Dirct("path/to/directory").to_dict()
{
	"name": "Dungeons, Dungeons, and More Dungeons", # From __self__.toml
	"release_date": datetime.date(2021, 1, 1), # From __self__.toml
	"version": "1.0.0",
	"publisher.toml": {
		"name": "Probabilitor the Annoying",
		"founded": 2015
	},
	"levels": {
		"castle.lvl.json": {
			"name": "Castle",
			"enemies": ["goblin", "orc", "ogre"]
		},
		"dungeon.lvl.json": {
			"name": "Dungeon",
			"enemies": ["skeleton", "zombie", "ghost"]
		},
		"forest.lvl.json": {
			"name": "Forest",
			"enemies": ["wolf", "bear", "dragon"]
		}
	}
}
```

### Mapping files to/from keys

Converting between file names and dictionary keys is handled by a `KeyMapper` object, which can be passed to the `key_mapper` argument of the `Dirct` constructor.

#### Exact key mapper (default)

The exact key mapper only recognizes keys that exactly match the file/directory names.

```python
>>> from dirct import ExactKeyMapper
>>> d = Dirct("path/to/directory", key_mapper=ExactKeyMapper())
>>> tuple(d.keys())
('publisher.toml', 'version', 'levels')
>>> d["publisher.toml"] # Gets the contents of publisher.toml
{'name': 'Probabilitor the Annoying', 'founded': 2015}
>>> d["publisher"]
KeyError: 'publisher'
>>> d[".publisher.toml"]
KeyError: '.publisher.toml'
>>> d["publisher.json"]
KeyError: 'publisher.json'
```

#### Basename key mapper

The basename key mapper ignores leading dots and all trailing extensions. If `hidden=False` is passed to the constructor, then leading dots are not ignored.

In case of a name collision when mapping a key to a path, an `AmbiguityError` is raised unless `strict=False` was passed to the constructor, in which case a warning is logged and one of the paths is chosen. (For a given directory's contents, the same path will be chosen consistently.)

```python
>>> d = Dirct("path/to/directory") # Default key mapper
>>> tuple(d.keys())
('publisher', 'version', 'levels')
>>> d["publisher"] # Gets the contents of publisher.toml
{'name': 'Probabilitor the Annoying', 'founded': 2015}
>>> d["publisher.toml"] # Also works
{'name': 'Probabilitor the Annoying', 'founded': 2015}
>>> d[".publisher.foo.json"] # Also works because the leading dot and file extensions are ignored
{'name': 'Probabilitor the Annoying', 'founded': 2015}
```

### `__self__`

A directory may contain a single special file called `__self__.*` with any known extension. The contents of this file are parsed to a dictionary (an `InvalidSelfError` is raised if it can't be parsed as a dictionary) which is then merged with the rest of the directory's contents (explicit files/subdirectories take precedence over `__self__.*`). This allows you to keep some of the keys in a single file and the rest in separate files or subdirectories.

For example, `__self__.toml` may contain the following:

```toml
name = "Dungeons, Dungeons, and More Dungeons"
release_date = 2021-01-01
```

```python
>>> d = Dirct("path/to/directory")
>>> d["name"]
'Dungeons, Dungeons, and More Dungeons'
```

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/abrahammurciano/python-dirct",
    "name": "dirct",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.11",
    "maintainer_email": null,
    "keywords": null,
    "author": "Abraham Murciano",
    "author_email": "abrahammurciano@gmail.com",
    "download_url": "https://files.pythonhosted.org/packages/f6/9e/e5759d073b1dc9b9b005d28a5a15e15ebe8b3d2a28afb2e266d3ad8ebaa3/dirct-2.0.1.tar.gz",
    "platform": null,
    "description": "# dirct\nA dict that reflects the contents of a directory.\n\n## Installation\n\nYou can install this package with pip.\n```sh\n$ pip install dirct\n```\n\n## Links\n\n[![Documentation](https://img.shields.io/badge/Documentation-C61C3E?style=for-the-badge&logo=Read+the+Docs&logoColor=%23FFFFFF)](https://abrahammurciano.github.io/python-dirct)\n\n[![Source Code - GitHub](https://img.shields.io/badge/Source_Code-GitHub-181717?style=for-the-badge&logo=GitHub&logoColor=%23FFFFFF)](https://github.com/abrahammurciano/python-dirct.git)\n\n[![PyPI - dirct](https://img.shields.io/badge/PyPI-dirct-006DAD?style=for-the-badge&logo=PyPI&logoColor=%23FFD242)](https://pypi.org/project/dirct/)\n\n## Usage\n\n### Basic usage\n\n```python\n>>> from dirct import Dirct\n>>> d = Dirct(\"path/to/directory\")\n>>> from typing import Mapping\n>>> isinstance(d, Mapping)\nTrue\n```\n\n### Loading files\n\nThe directory may contain any number of files and subdirectories. Files ending in `.toml`, `.json`, `.yaml`, and `.yml` are parsed correctly according to their respective formats, and all other files are read as text if it can be decoded or as bytes otherwise.\n\nYou can also pass custom loader callables to the `loaders` parameter of the `Dirct` constructor. A loader callable takes the `Path` to a file and returns the value that file represents. The `DEFAULT_LOADERS` constant contains loaders for the aforementioned file formats.\n\n```python\nfrom dirct import Dirct, DEFAULT_PARSERS\n\ndef csv_loader(path: Path) -> Sequence[Mapping[str, str]]:\n\twith path.open() as f:\n\t\treturn tuple(csv.DictReader(f))\n\nDirct(\"path/to/directory\", loaders=(csv_loader, *DEFAULT_LOADERS))\n```\n\nLoaders are tried in order. If a loader raises an `UnsupportedFileError` then the next loader is tried. If a loader raises any other type of `Exception` it is propagated. If no loader can load a file, then an `UnsupportedFileError` is raised.\n\n### Example directory\n\nConsider the following directory `path/to/directory/` that contains data about a video game.\n\n```\npath/to/directory/\n\u251c\u2500\u2500 __self__.toml\n\u251c\u2500\u2500 publisher.toml\n\u251c\u2500\u2500 version\n\u2514\u2500\u2500 levels/\n\t\u251c\u2500\u2500 castle.lvl.json\n\t\u251c\u2500\u2500 dungeon.lvl.json\n\t\u2514\u2500\u2500 forest.lvl.json\n```\n\nCreating a `Dirct` with this directory would produce a mapping with the following structure.\n\n```py\n>>> d = Dirct(\"path/to/directory\").to_dict()\n{\n\t\"name\": \"Dungeons, Dungeons, and More Dungeons\", # From __self__.toml\n\t\"release_date\": datetime.date(2021, 1, 1), # From __self__.toml\n\t\"version\": \"1.0.0\",\n\t\"publisher.toml\": {\n\t\t\"name\": \"Probabilitor the Annoying\",\n\t\t\"founded\": 2015\n\t},\n\t\"levels\": {\n\t\t\"castle.lvl.json\": {\n\t\t\t\"name\": \"Castle\",\n\t\t\t\"enemies\": [\"goblin\", \"orc\", \"ogre\"]\n\t\t},\n\t\t\"dungeon.lvl.json\": {\n\t\t\t\"name\": \"Dungeon\",\n\t\t\t\"enemies\": [\"skeleton\", \"zombie\", \"ghost\"]\n\t\t},\n\t\t\"forest.lvl.json\": {\n\t\t\t\"name\": \"Forest\",\n\t\t\t\"enemies\": [\"wolf\", \"bear\", \"dragon\"]\n\t\t}\n\t}\n}\n```\n\n### Mapping files to/from keys\n\nConverting between file names and dictionary keys is handled by a `KeyMapper` object, which can be passed to the `key_mapper` argument of the `Dirct` constructor.\n\n#### Exact key mapper (default)\n\nThe exact key mapper only recognizes keys that exactly match the file/directory names.\n\n```python\n>>> from dirct import ExactKeyMapper\n>>> d = Dirct(\"path/to/directory\", key_mapper=ExactKeyMapper())\n>>> tuple(d.keys())\n('publisher.toml', 'version', 'levels')\n>>> d[\"publisher.toml\"] # Gets the contents of publisher.toml\n{'name': 'Probabilitor the Annoying', 'founded': 2015}\n>>> d[\"publisher\"]\nKeyError: 'publisher'\n>>> d[\".publisher.toml\"]\nKeyError: '.publisher.toml'\n>>> d[\"publisher.json\"]\nKeyError: 'publisher.json'\n```\n\n#### Basename key mapper\n\nThe basename key mapper ignores leading dots and all trailing extensions. If `hidden=False` is passed to the constructor, then leading dots are not ignored.\n\nIn case of a name collision when mapping a key to a path, an `AmbiguityError` is raised unless `strict=False` was passed to the constructor, in which case a warning is logged and one of the paths is chosen. (For a given directory's contents, the same path will be chosen consistently.)\n\n```python\n>>> d = Dirct(\"path/to/directory\") # Default key mapper\n>>> tuple(d.keys())\n('publisher', 'version', 'levels')\n>>> d[\"publisher\"] # Gets the contents of publisher.toml\n{'name': 'Probabilitor the Annoying', 'founded': 2015}\n>>> d[\"publisher.toml\"] # Also works\n{'name': 'Probabilitor the Annoying', 'founded': 2015}\n>>> d[\".publisher.foo.json\"] # Also works because the leading dot and file extensions are ignored\n{'name': 'Probabilitor the Annoying', 'founded': 2015}\n```\n\n### `__self__`\n\nA directory may contain a single special file called `__self__.*` with any known extension. The contents of this file are parsed to a dictionary (an `InvalidSelfError` is raised if it can't be parsed as a dictionary) which is then merged with the rest of the directory's contents (explicit files/subdirectories take precedence over `__self__.*`). This allows you to keep some of the keys in a single file and the rest in separate files or subdirectories.\n\nFor example, `__self__.toml` may contain the following:\n\n```toml\nname = \"Dungeons, Dungeons, and More Dungeons\"\nrelease_date = 2021-01-01\n```\n\n```python\n>>> d = Dirct(\"path/to/directory\")\n>>> d[\"name\"]\n'Dungeons, Dungeons, and More Dungeons'\n```\n",
    "bugtrack_url": null,
    "license": "GPLv3",
    "summary": "A dict that reflects the contents of a directory.",
    "version": "2.0.1",
    "project_urls": {
        "Documentation": "https://abrahammurciano.github.io/python-dirct/dirct",
        "Homepage": "https://github.com/abrahammurciano/python-dirct",
        "Repository": "https://github.com/abrahammurciano/python-dirct"
    },
    "split_keywords": [],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "873a38793a3f287b30373b16cbeb4d9b2fca5444d48164d8de52bd67a0d4e63d",
                "md5": "f549c397ae7338a55d4f93f773210aa2",
                "sha256": "365d9ef2c3c96f073f2f69fc01f09261f4b6dba02fdea7b1c26414944b7492c6"
            },
            "downloads": -1,
            "filename": "dirct-2.0.1-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "f549c397ae7338a55d4f93f773210aa2",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.11",
            "size": 22377,
            "upload_time": "2024-05-22T09:18:12",
            "upload_time_iso_8601": "2024-05-22T09:18:12.690973Z",
            "url": "https://files.pythonhosted.org/packages/87/3a/38793a3f287b30373b16cbeb4d9b2fca5444d48164d8de52bd67a0d4e63d/dirct-2.0.1-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "f69ee5759d073b1dc9b9b005d28a5a15e15ebe8b3d2a28afb2e266d3ad8ebaa3",
                "md5": "426b08440e835319d28641173abb332d",
                "sha256": "1ea0c4ce158f96402b3817459984b511c5203e89d05a3382d568cf34dab0e49e"
            },
            "downloads": -1,
            "filename": "dirct-2.0.1.tar.gz",
            "has_sig": false,
            "md5_digest": "426b08440e835319d28641173abb332d",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.11",
            "size": 20301,
            "upload_time": "2024-05-22T09:18:13",
            "upload_time_iso_8601": "2024-05-22T09:18:13.711141Z",
            "url": "https://files.pythonhosted.org/packages/f6/9e/e5759d073b1dc9b9b005d28a5a15e15ebe8b3d2a28afb2e266d3ad8ebaa3/dirct-2.0.1.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-05-22 09:18:13",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "abrahammurciano",
    "github_project": "python-dirct",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "dirct"
}
        
Elapsed time: 0.27496s