Skip to content

Commit

Permalink
Add most_specific_src metadata and export type annotations (#2)
Browse files Browse the repository at this point in the history
* WIP

* WIP
  • Loading branch information
Cariad Eccleston authored Dec 6, 2020
1 parent d9d0eb6 commit b024bbe
Show file tree
Hide file tree
Showing 14 changed files with 235 additions and 99 deletions.
3 changes: 0 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,6 @@ jobs:
- name: Sync dependencies
run: pipenv sync --dev

- name: Lint
run: pipenv run ./lint.sh

- name: Test
run: pipenv run ./test.sh

Expand Down
24 changes: 12 additions & 12 deletions Pipfile.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

76 changes: 44 additions & 32 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ pip3 install dwalk
## CLI usage

```bash
dwalk --filenames FILENAME [FILENAME ...] [--directory DIRECTORY]
dwalk --filenames FILENAME [FILENAME ...] [--directory DIRECTORY] [--include-meta]
```

- `--directory VALUE`: Directory to walk to. The files in this directory will take priority over the files in its parent. Optional, and uses the current working directory by default.
Expand Down Expand Up @@ -65,37 +65,6 @@ dwalk --directory example --filenames foo.yml foo.user.yml
}
```

Pass the optional `--include-meta` flag to see where each value came from:

```json
{
"__dwalk__": {
"accessibility": {
"src": "/Users/cariad/code/dwalk/example/foo.user.yml"
},
"prompts": {
"src": "/Users/cariad/code/dwalk/example/foo.yml"
},
"theme": {
"src": "/Users/cariad/code/dwalk/example/foo.user.yml"
}
},
"accessibility": {
"high-contrast": true
},
"prompts": {
"__dwalk__": {
"accessibility": {
"src": "/Users/cariad/code/dwalk/example/foo.user.yml"
}
},
"accessibility": "user-enabled",
"notifications": "not-asked"
},
"theme": "pink"
}
```

### Merging via directory precedence

Say you have three configuration files:
Expand Down Expand Up @@ -150,6 +119,48 @@ dwalk --directory example/game --filenames foo.yml foo.user.yml
}
```

## Metadata

Metdata can be included in the result by adding the `--include-meta` flag.

This will add `__dwalk__` keys that describe:
- The `src` file whenever a property is merged in.
- The `most_specific_src` that properties were merged in from.

For example:

```json
{
"__dwalk__": {
"__dwalk__": {
"most_specific_src": "/Users/cariad/code/dwalk/example/foo.user.yml"
},
"accessibility": {
"src": "/Users/cariad/code/dwalk/example/foo.user.yml"
},
"prompts": {
"src": "/Users/cariad/code/dwalk/example/foo.yml"
},
"theme": {
"src": "/Users/cariad/code/dwalk/example/foo.user.yml"
}
},
"accessibility": {
"high-contrast": true
},
"prompts": {
"__dwalk__": {
"accessibility": {
"src": "/Users/cariad/code/dwalk/example/foo.user.yml"
}
},
"accessibility": "user-enabled",
"notifications": "not-asked"
},
"theme": "pink"
}
```

## Package

`dwalk` can be imported and used in Python scripts:
Expand All @@ -165,6 +176,7 @@ from logging import basicConfig, getLogger
merged = dwalk(
directory="../dwalk/testing/bottom",
filenames=["dwalk.2.yml", "dwalk.1.yml"],
include_meta=False,
)

print(merged)
Expand Down
3 changes: 0 additions & 3 deletions coverage.sh

This file was deleted.

13 changes: 10 additions & 3 deletions dwalk/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,16 @@ def __init__(self, args: Optional[List[str]] = None) -> None:
action="store_true",
help="print the version",
)
self.arg_parser.add_argument("--filenames", nargs="+")
self.arg_parser.add_argument("--directory")
self.arg_parser.add_argument(
"--filenames",
nargs="+",
help="Files to load in each directory. List from low- to high-precedence.",
)
self.arg_parser.add_argument(
"--directory",
required=False,
help="Highest-precedence directory. Defaults to working directory.",
)
self.arg_parser.add_argument(
"--include-meta",
action="store_true",
Expand All @@ -50,7 +58,6 @@ def execute(self) -> int:
int: Shell return code.
"""
try:

result = dwalk(
filenames=self.args.filenames,
directory=Path(self.args.directory) if self.args.directory else None,
Expand Down
13 changes: 12 additions & 1 deletion dwalk/dwalk.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from yaml import safe_load

from dwalk.directories import directories
from dwalk.merge import merge
from dwalk.merge import merge, set_key


def dwalk(
Expand Down Expand Up @@ -43,6 +43,8 @@ def dwalk(
if isinstance(directory, str):
directory = Path(directory).resolve()

most_specific: Optional[Path] = None

for d in directories(bottom=directory):
logger.debug("Examining directory: %s", d)

Expand All @@ -57,10 +59,19 @@ def dwalk(
from_src=str(path) if include_meta else None,
to_dict=result,
)
if include_meta:
most_specific = path
except FileNotFoundError:
logger.debug("File does not exist: %s", path)
pass
except Exception as ex:
logger.error("Failed to read file: %s (%s)", path, ex)

if include_meta:
set_key(
to_dict=result,
path=["__dwalk__", "__dwalk__", "most_specific_src"],
value=str(most_specific),
)

return result
Empty file added dwalk/py.typed
Empty file.
18 changes: 0 additions & 18 deletions dwalk/test_discover.py

This file was deleted.

41 changes: 41 additions & 0 deletions dwalk/test_dwalk.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
from pathlib import Path
from typing import List

from pytest import mark

from dwalk import dwalk

project_dir = Path(__file__).parent.parent
testing_dir = project_dir.joinpath("testing")
bottom_dir = testing_dir.joinpath("bottom")


def test() -> None:
test_dir = project_dir.joinpath("testing").joinpath("bottom")
actual = dwalk(filenames=["dwalk.2.yml", "dwalk.1.yml"], directory=test_dir)
assert actual == {
"alphabet": {"a": "alpha", "b": "bravo", "c": "charlie", "d": "delta"},
"favourite_colour": "purple",
"is_bottom_1": True,
"is_bottom_2": True,
"is_top_1": True,
"is_top_2": True,
"shopping_list": ["atari", "bismuth", "cookies"],
"side_count": {"hexagon": 6, "pentagon": 5, "square": 4, "triangle": 3},
}


@mark.parametrize(
"directory, filenames, expect",
[
(
bottom_dir,
["dwalk.2.yml", "dwalk.1.yml"],
bottom_dir.joinpath("dwalk.1.yml"),
),
(bottom_dir, ["dwalk.3.yml"], testing_dir.joinpath("dwalk.3.yml")),
],
)
def test_most_specific_src(directory: Path, filenames: List[str], expect: Path) -> None:
actual = dwalk(directory=directory, filenames=filenames, include_meta=True)
assert actual["__dwalk__"]["__dwalk__"]["most_specific_src"] == str(expect)
24 changes: 0 additions & 24 deletions lint.sh

This file was deleted.

7 changes: 5 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from pathlib import Path

from setuptools import find_packages, setup
from setuptools import setup

from dwalk.version import get_version

Expand Down Expand Up @@ -51,7 +51,10 @@
long_description=long_description,
long_description_content_type="text/markdown",
name="dwalk",
packages=find_packages(),
packages=["dwalk"],
package_data={
"dwalk": ["py.typed"],
},
python_requires=">=3.8",
url="https://github.com/cariad/dwalk",
version=version,
Expand Down
32 changes: 31 additions & 1 deletion test.sh
Original file line number Diff line number Diff line change
@@ -1,2 +1,32 @@
#!/bin/bash -e
python -m pytest

echo "Linting YAML..."
yamllint . --strict

echo "Sorting Python import definitions..."
if [[ "${ci:=}" == "true" ]]; then
isort . --check-only --diff
else
isort .
fi

echo "Applying opinionated Python code style..."
if [[ "${ci:=}" == "true" ]]; then
black . --check --diff
else
black .
fi

echo "Checking PEP8 compliance..."
flake8 .

echo "Checking Python types..."
mypy dwalk

echo "Testing..."
coverage run
coverage report -m

if [[ "${ci:=}" != "true" ]]; then
coverage html
fi
2 changes: 2 additions & 0 deletions testing/dwalk.3.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# This property is only in this file:
favourite_sound: jam
Loading

0 comments on commit b024bbe

Please sign in to comment.