From 3d74b82d5d1efdcc0561d56f64a73988eb00b1ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20D=C3=B6rrer?= Date: Sun, 14 Jan 2024 21:51:14 +0100 Subject: [PATCH 1/4] update actions - added preperations for docs --- .github/workflows/publish.yml | 2 +- .github/workflows/pytest.yml | 2 +- .github/workflows/testbuild.yml | 2 +- docs/__main__.py | 49 ++++++++++++ docs/jinja2_pdoc/dark-mode/README.md | 9 +++ docs/jinja2_pdoc/dark-mode/index.html.jinja2 | 3 + docs/jinja2_pdoc/dark-mode/module.html.jinja2 | 5 ++ .../dark-mode/syntax-highlighting.css | 80 +++++++++++++++++++ docs/jinja2_pdoc/dark-mode/theme.css | 20 +++++ jinja2_pdoc/extension.py | 6 +- poetry.lock | 16 +++- pyproject.toml | 3 + tox.ini | 12 +-- 13 files changed, 196 insertions(+), 13 deletions(-) create mode 100644 docs/__main__.py create mode 100644 docs/jinja2_pdoc/dark-mode/README.md create mode 100644 docs/jinja2_pdoc/dark-mode/index.html.jinja2 create mode 100644 docs/jinja2_pdoc/dark-mode/module.html.jinja2 create mode 100644 docs/jinja2_pdoc/dark-mode/syntax-highlighting.css create mode 100644 docs/jinja2_pdoc/dark-mode/theme.css diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 7b0ad0f..9d25365 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -17,7 +17,7 @@ jobs: run: | python -m pip install --upgrade pip pip install poetry - poetry install --no-root + poetry install --only-root - name: Build and publish env: POETRY_PYPI_TOKEN_PYPI: ${{ secrets.PYPI_TOKEN }} diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index cffd8c1..e5b6b41 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -29,7 +29,7 @@ jobs: run: | python -m pip install --upgrade pip pip install poetry - poetry install --with dev + poetry install --only dev - name: Test with pytest run: | poetry run pytest diff --git a/.github/workflows/testbuild.yml b/.github/workflows/testbuild.yml index 919eeae..1cae0bf 100644 --- a/.github/workflows/testbuild.yml +++ b/.github/workflows/testbuild.yml @@ -17,7 +17,7 @@ jobs: run: | python -m pip install --upgrade pip pip install poetry - poetry install --no-root + poetry install --only-root - name: Build and publish env: POETRY_PYPI_TOKEN_TESTPYPI: ${{ secrets.TESTPYPI_TOKEN }} diff --git a/docs/__main__.py b/docs/__main__.py new file mode 100644 index 0000000..b81892a --- /dev/null +++ b/docs/__main__.py @@ -0,0 +1,49 @@ +import sys + +import click +from pathlibutil import Path + + +@click.group() +def cli(): + pass + + +@cli.command() +@click.argument("root", type=click.Path(file_okay=False)) +def erase(root: str) -> None: + """remove a directry tree""" + + self = Path(sys.argv[0]).parent + root = Path(root).resolve() + + if self == root: + raise click.UsageError("Invalid value for ROOT: cannot delete itself") + + try: + root.delete(recursive=True, missing_ok=True) + except Exception: + sys.exit(1) + + +@cli.command() +@click.argument("src", type=click.Path(exists=True, file_okay=False)) +@click.argument("dst", type=click.Path(file_okay=False)) +@click.option( + "-u", "--unignore", is_flag=True, help="remove gitignore files in destination" +) +def copy(src: str, dst: str, unignore=True) -> None: + """copy directory from src to dst and remove any gitignore files""" + + try: + dest = Path(src).copy(dst) + except Exception: + sys.exit(1) + + if unignore: + for file in dest.rglob(".gitignore"): + file.unlink() + + +if __name__ == "__main__": + cli() diff --git a/docs/jinja2_pdoc/dark-mode/README.md b/docs/jinja2_pdoc/dark-mode/README.md new file mode 100644 index 0000000..2915aab --- /dev/null +++ b/docs/jinja2_pdoc/dark-mode/README.md @@ -0,0 +1,9 @@ +# 🌒 pdoc dark mode + +[**Demo**](https://pdoc.dev/docs/dark-mode/demo.html) + +This is an example showing how to style pdoc in dark mode using custom stylesheets. +pdoc defines all colors as CSS variables, so we only need to adjust pdoc's color scheme (`theme.css`) +and pygments' syntax highlighting theme (`syntax-highlighting.css`). + +Run `cd examples/dark-mode && pdoc -t . pdoc` to see it in action! diff --git a/docs/jinja2_pdoc/dark-mode/index.html.jinja2 b/docs/jinja2_pdoc/dark-mode/index.html.jinja2 new file mode 100644 index 0000000..981d21b --- /dev/null +++ b/docs/jinja2_pdoc/dark-mode/index.html.jinja2 @@ -0,0 +1,3 @@ +{% set root_module_name = "jinja2_pdoc" %} + +{% extends "default/index.html.jinja2" %} \ No newline at end of file diff --git a/docs/jinja2_pdoc/dark-mode/module.html.jinja2 b/docs/jinja2_pdoc/dark-mode/module.html.jinja2 new file mode 100644 index 0000000..607a946 --- /dev/null +++ b/docs/jinja2_pdoc/dark-mode/module.html.jinja2 @@ -0,0 +1,5 @@ +{% extends "default/module.html.jinja2"%} + +{% block module_list_link %} + +{% endblock %} \ No newline at end of file diff --git a/docs/jinja2_pdoc/dark-mode/syntax-highlighting.css b/docs/jinja2_pdoc/dark-mode/syntax-highlighting.css new file mode 100644 index 0000000..b0a7fe3 --- /dev/null +++ b/docs/jinja2_pdoc/dark-mode/syntax-highlighting.css @@ -0,0 +1,80 @@ +/* monokai color scheme, see pdoc/template/README.md */ +pre { line-height: 125%; } +span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 20px; } +.pdoc-code .hll { background-color: #49483e } +.pdoc-code { background: #272822; color: #f8f8f2 } +.pdoc-code .c { color: #75715e } /* Comment */ +.pdoc-code .err { color: #960050; background-color: #1e0010 } /* Error */ +.pdoc-code .esc { color: #f8f8f2 } /* Escape */ +.pdoc-code .g { color: #f8f8f2 } /* Generic */ +.pdoc-code .k { color: #66d9ef } /* Keyword */ +.pdoc-code .l { color: #ae81ff } /* Literal */ +.pdoc-code .n { color: #f8f8f2 } /* Name */ +.pdoc-code .o { color: #f92672 } /* Operator */ +.pdoc-code .x { color: #f8f8f2 } /* Other */ +.pdoc-code .p { color: #f8f8f2 } /* Punctuation */ +.pdoc-code .ch { color: #75715e } /* Comment.Hashbang */ +.pdoc-code .cm { color: #75715e } /* Comment.Multiline */ +.pdoc-code .cp { color: #75715e } /* Comment.Preproc */ +.pdoc-code .cpf { color: #75715e } /* Comment.PreprocFile */ +.pdoc-code .c1 { color: #75715e } /* Comment.Single */ +.pdoc-code .cs { color: #75715e } /* Comment.Special */ +.pdoc-code .gd { color: #f92672 } /* Generic.Deleted */ +.pdoc-code .ge { color: #f8f8f2; font-style: italic } /* Generic.Emph */ +.pdoc-code .gr { color: #f8f8f2 } /* Generic.Error */ +.pdoc-code .gh { color: #f8f8f2 } /* Generic.Heading */ +.pdoc-code .gi { color: #a6e22e } /* Generic.Inserted */ +.pdoc-code .go { color: #66d9ef } /* Generic.Output */ +.pdoc-code .gp { color: #f92672; font-weight: bold } /* Generic.Prompt */ +.pdoc-code .gs { color: #f8f8f2; font-weight: bold } /* Generic.Strong */ +.pdoc-code .gu { color: #75715e } /* Generic.Subheading */ +.pdoc-code .gt { color: #f8f8f2 } /* Generic.Traceback */ +.pdoc-code .kc { color: #66d9ef } /* Keyword.Constant */ +.pdoc-code .kd { color: #66d9ef } /* Keyword.Declaration */ +.pdoc-code .kn { color: #f92672 } /* Keyword.Namespace */ +.pdoc-code .kp { color: #66d9ef } /* Keyword.Pseudo */ +.pdoc-code .kr { color: #66d9ef } /* Keyword.Reserved */ +.pdoc-code .kt { color: #66d9ef } /* Keyword.Type */ +.pdoc-code .ld { color: #e6db74 } /* Literal.Date */ +.pdoc-code .m { color: #ae81ff } /* Literal.Number */ +.pdoc-code .s { color: #e6db74 } /* Literal.String */ +.pdoc-code .na { color: #a6e22e } /* Name.Attribute */ +.pdoc-code .nb { color: #f8f8f2 } /* Name.Builtin */ +.pdoc-code .nc { color: #a6e22e } /* Name.Class */ +.pdoc-code .no { color: #66d9ef } /* Name.Constant */ +.pdoc-code .nd { color: #a6e22e } /* Name.Decorator */ +.pdoc-code .ni { color: #f8f8f2 } /* Name.Entity */ +.pdoc-code .ne { color: #a6e22e } /* Name.Exception */ +.pdoc-code .nf { color: #a6e22e } /* Name.Function */ +.pdoc-code .nl { color: #f8f8f2 } /* Name.Label */ +.pdoc-code .nn { color: #f8f8f2 } /* Name.Namespace */ +.pdoc-code .nx { color: #a6e22e } /* Name.Other */ +.pdoc-code .py { color: #f8f8f2 } /* Name.Property */ +.pdoc-code .nt { color: #f92672 } /* Name.Tag */ +.pdoc-code .nv { color: #f8f8f2 } /* Name.Variable */ +.pdoc-code .ow { color: #f92672 } /* Operator.Word */ +.pdoc-code .w { color: #f8f8f2 } /* Text.Whitespace */ +.pdoc-code .mb { color: #ae81ff } /* Literal.Number.Bin */ +.pdoc-code .mf { color: #ae81ff } /* Literal.Number.Float */ +.pdoc-code .mh { color: #ae81ff } /* Literal.Number.Hex */ +.pdoc-code .mi { color: #ae81ff } /* Literal.Number.Integer */ +.pdoc-code .mo { color: #ae81ff } /* Literal.Number.Oct */ +.pdoc-code .sa { color: #e6db74 } /* Literal.String.Affix */ +.pdoc-code .sb { color: #e6db74 } /* Literal.String.Backtick */ +.pdoc-code .sc { color: #e6db74 } /* Literal.String.Char */ +.pdoc-code .dl { color: #e6db74 } /* Literal.String.Delimiter */ +.pdoc-code .sd { color: #e6db74 } /* Literal.String.Doc */ +.pdoc-code .s2 { color: #e6db74 } /* Literal.String.Double */ +.pdoc-code .se { color: #ae81ff } /* Literal.String.Escape */ +.pdoc-code .sh { color: #e6db74 } /* Literal.String.Heredoc */ +.pdoc-code .si { color: #e6db74 } /* Literal.String.Interpol */ +.pdoc-code .sx { color: #e6db74 } /* Literal.String.Other */ +.pdoc-code .sr { color: #e6db74 } /* Literal.String.Regex */ +.pdoc-code .s1 { color: #e6db74 } /* Literal.String.Single */ +.pdoc-code .ss { color: #e6db74 } /* Literal.String.Symbol */ +.pdoc-code .bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */ +.pdoc-code .fm { color: #a6e22e } /* Name.Function.Magic */ +.pdoc-code .vc { color: #f8f8f2 } /* Name.Variable.Class */ +.pdoc-code .vg { color: #f8f8f2 } /* Name.Variable.Global */ +.pdoc-code .vi { color: #f8f8f2 } /* Name.Variable.Instance */ +.pdoc-code .vm { color: #f8f8f2 } /* Name.Variable.Magic */ diff --git a/docs/jinja2_pdoc/dark-mode/theme.css b/docs/jinja2_pdoc/dark-mode/theme.css new file mode 100644 index 0000000..1dfe7c4 --- /dev/null +++ b/docs/jinja2_pdoc/dark-mode/theme.css @@ -0,0 +1,20 @@ +:root { + --pdoc-background: #212529; +} + +.pdoc { + --text: #f7f7f7; + --muted: #9d9d9d; + --link: #58a6ff; + --link-hover: #3989ff; + --code: #333; + --active: #555; + + --accent: #343434; + --accent2: #555; + + --nav-hover: rgba(0, 0, 0, 0.1); + --name: #77C1FF; + --def: #0cdd0c; + --annotation: #00c037; +} diff --git a/jinja2_pdoc/extension.py b/jinja2_pdoc/extension.py index 24c2476..65c081c 100644 --- a/jinja2_pdoc/extension.py +++ b/jinja2_pdoc/extension.py @@ -1,11 +1,9 @@ -import textwrap from functools import lru_cache -from pathlib import Path -from typing import Any, Dict +from typing import Dict import jinja2 -from jinja2_pdoc.wrapper import PdocStr, Module +from jinja2_pdoc.wrapper import Module, PdocStr class Jinja2Pdoc(jinja2.ext.Extension): diff --git a/poetry.lock b/poetry.lock index c462187..8ecaa2b 100644 --- a/poetry.lock +++ b/poetry.lock @@ -293,6 +293,20 @@ files = [ {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, ] +[[package]] +name = "pathlibutil" +version = "0.1.5" +description = "inherits from pathlib.Path with methods for hashing, copying, deleting and more" +optional = false +python-versions = ">=3.8.1,<3.13" +files = [ + {file = "pathlibutil-0.1.5-py3-none-any.whl", hash = "sha256:59928bd44e29ce408a469563fbd9d3a903b59b8150b845e3e5f7a62d79ed868b"}, + {file = "pathlibutil-0.1.5.tar.gz", hash = "sha256:43c20825536251ec98e7ea73f9bae3c6225a15ceb8d50fcca4354ad247079453"}, +] + +[package.extras] +7z = ["py7zr (>=0.20.2,<0.21.0)"] + [[package]] name = "pdoc" version = "14.3.0" @@ -528,4 +542,4 @@ test = ["pytest (>=6.0.0)", "setuptools (>=65)"] [metadata] lock-version = "2.0" python-versions = ">=3.8.1,<3.13" -content-hash = "b3f44606f90d3898e04722037fbdfc7095e3e3586f62adccfce47e397d3ee227" +content-hash = "6b7b463c5f87de8be271ea19405fe2036303ea7a075af6d28950641599c8ed0f" diff --git a/pyproject.toml b/pyproject.toml index 1455da2..2427892 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -45,6 +45,9 @@ pytest-random-order = "^1.1.0" pytest-cov = "^4.1.0" tox = "^4.11.4" +[tool.poetry.group.doc.dependencies] +pathlibutil = "^0.1.5" + [build-system] requires = ["poetry-core"] build-backend = "poetry.core.masonry.api" diff --git a/tox.ini b/tox.ini index dfb6a8b..5a3d747 100644 --- a/tox.ini +++ b/tox.ini @@ -36,17 +36,18 @@ deps = click coverage black + pathlibutil commands = - # python -m docs erase {env:DOCPATH} + python -m docs erase {env:DOCPATH} coverage erase black {env:PACKAGE} [testenv:pdoc] -skip_install = true +skip_install = false deps = pdoc commands = - pdoc --no-show-source -t docs\dark-mode -o {env:DOCPATH} {env:PACKAGE} jinaj2_pdoc, jinja2, pdoc + pdoc --no-show-source -t docs\dark-mode -o {env:DOCPATH} {env:PACKAGE} jinaj2_pdoc depends = pdoc: clean @@ -56,10 +57,11 @@ deps = click coverage flake8 + pathlibutil commands = flake8 --max-line-length 88 {env:PACKAGE} - coverage report --fail-under 100 --show-missing + coverage report --fail-under 99 --show-missing python -m docs erase {env:GHPAGE} python -m docs copy {env:DOCPATH} {env:GHPAGE} --unignore depends = - release: pdoc,py38,py39,py310,py311,py312,py311-7z + release: pdoc,py38,py39,py310,py311,py312 From adf5f14f7b1668aa956a23913ba55400cb162922 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20D=C3=B6rrer?= Date: Sun, 14 Jan 2024 22:38:34 +0100 Subject: [PATCH 2/4] create docs with pdoc --- .gitignore | 1 + README.md | 7 +++++-- docs/{jinja2_pdoc => }/dark-mode/README.md | 0 docs/{jinja2_pdoc => }/dark-mode/index.html.jinja2 | 0 docs/{jinja2_pdoc => }/dark-mode/module.html.jinja2 | 0 .../dark-mode/syntax-highlighting.css | 0 docs/{jinja2_pdoc => }/dark-mode/theme.css | 0 jinja2_pdoc/__init__.py | 4 ++++ jinja2_pdoc/extension.py | 10 +++++++--- tox.ini | 7 ++++--- 10 files changed, 21 insertions(+), 8 deletions(-) rename docs/{jinja2_pdoc => }/dark-mode/README.md (100%) rename docs/{jinja2_pdoc => }/dark-mode/index.html.jinja2 (100%) rename docs/{jinja2_pdoc => }/dark-mode/module.html.jinja2 (100%) rename docs/{jinja2_pdoc => }/dark-mode/syntax-highlighting.css (100%) rename docs/{jinja2_pdoc => }/dark-mode/theme.css (100%) diff --git a/.gitignore b/.gitignore index a93118a..22f6721 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .vscode +docs/jinja2_pdoc # Byte-compiled / optimized / DLL files __pycache__/ diff --git a/README.md b/README.md index d9e5aa0..c6375b1 100644 --- a/README.md +++ b/README.md @@ -120,7 +120,8 @@ Options: python code to render a template directly from a string -```python +````python + from jinja2_pdoc import jinja2, Jinja2Pdoc env = jinja2.Environment(extensions=[Jinja2Pdoc]) @@ -145,13 +146,14 @@ code = env.from_string(textwrap.dedent(s)).render() Path("example.md").write_text(code) -``` +```` ### Result output of the [code](#library) above ````markdown + # jinja2-pdoc embedd python code directly from pathlib using a jinja2 extension based on pdoc @@ -179,4 +181,5 @@ def open(self, mode='r', buffering=-1, encoding=None, encoding = io.text_encoding(encoding) return io.open(self, mode, buffering, encoding, errors, newline) ``` + ```` diff --git a/docs/jinja2_pdoc/dark-mode/README.md b/docs/dark-mode/README.md similarity index 100% rename from docs/jinja2_pdoc/dark-mode/README.md rename to docs/dark-mode/README.md diff --git a/docs/jinja2_pdoc/dark-mode/index.html.jinja2 b/docs/dark-mode/index.html.jinja2 similarity index 100% rename from docs/jinja2_pdoc/dark-mode/index.html.jinja2 rename to docs/dark-mode/index.html.jinja2 diff --git a/docs/jinja2_pdoc/dark-mode/module.html.jinja2 b/docs/dark-mode/module.html.jinja2 similarity index 100% rename from docs/jinja2_pdoc/dark-mode/module.html.jinja2 rename to docs/dark-mode/module.html.jinja2 diff --git a/docs/jinja2_pdoc/dark-mode/syntax-highlighting.css b/docs/dark-mode/syntax-highlighting.css similarity index 100% rename from docs/jinja2_pdoc/dark-mode/syntax-highlighting.css rename to docs/dark-mode/syntax-highlighting.css diff --git a/docs/jinja2_pdoc/dark-mode/theme.css b/docs/dark-mode/theme.css similarity index 100% rename from docs/jinja2_pdoc/dark-mode/theme.css rename to docs/dark-mode/theme.css diff --git a/jinja2_pdoc/__init__.py b/jinja2_pdoc/__init__.py index fd79af2..a936b92 100644 --- a/jinja2_pdoc/__init__.py +++ b/jinja2_pdoc/__init__.py @@ -1,3 +1,7 @@ +""" +.. include:: ../README.md +""" + import jinja2 import pdoc diff --git a/jinja2_pdoc/extension.py b/jinja2_pdoc/extension.py index 65c081c..fb4c41e 100644 --- a/jinja2_pdoc/extension.py +++ b/jinja2_pdoc/extension.py @@ -7,13 +7,17 @@ class Jinja2Pdoc(jinja2.ext.Extension): + """ + extension to include source code directly from python modules into + jinja2 templates with `{% pdoc module:object:pdoc_attr.str_attr %}` + """ + tags = {"pdoc"} def parse(self, parser: jinja2.parser.Parser) -> jinja2.nodes.Node: """ - replace a `{{ pdoc module:name:__attr__ }}` with the source code from a - the python module. `__attr__` is optional and defaults to `source`, see - `pdoc.doc.Functions` which attributes are available. + parse the arguments following the tag `pdoc` and return a node with the + formatted source code or docstring. """ lineno = next(parser.stream).lineno diff --git a/tox.ini b/tox.ini index 5a3d747..055f8a9 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = clean,py38,py39,py310,py311,py312,report +envlist = clean,pdoc,py38,py39,py310,py311,py312,report [testenv] skip_install = false @@ -43,11 +43,12 @@ commands = black {env:PACKAGE} [testenv:pdoc] -skip_install = false +skip_install = true deps = pdoc + autopep8 commands = - pdoc --no-show-source -t docs\dark-mode -o {env:DOCPATH} {env:PACKAGE} jinaj2_pdoc + pdoc --no-show-source -t docs\dark-mode -o {env:DOCPATH} {env:PACKAGE} depends = pdoc: clean From 86d6b87a0e119f1293417dbd17de59c0a23a9b05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20D=C3=B6rrer?= Date: Sun, 21 Jan 2024 17:03:04 +0100 Subject: [PATCH 3/4] bugfix file check --- jinja2_pdoc/cli.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jinja2_pdoc/cli.py b/jinja2_pdoc/cli.py index 678b1b0..e25f493 100644 --- a/jinja2_pdoc/cli.py +++ b/jinja2_pdoc/cli.py @@ -24,14 +24,14 @@ def load_files( if `force` is True, all files are proessed. """ - for file in files: + for file in map(lambda x: x.with_suffix(""), files): if not root: out = out_dir.joinpath(file.name) else: out = out_dir.joinpath(file.relative_to(root)) if not out.is_file() or force: - yield (file.read_text(), out.with_suffix("")) + yield (file.read_text(), out) click.echo(f"rendering.. {out}") else: click.echo(f"skip....... {out}") From c89f920322492f7dfe8234a7637cb6cf3527116a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20D=C3=B6rrer?= Date: Sun, 21 Jan 2024 19:08:28 +0100 Subject: [PATCH 4/4] catch and print exeptions --- jinja2_pdoc/cli.py | 81 ++++++++++++++++++++++++++++------------------ pyproject.toml | 1 + tests/test_cli.py | 42 +----------------------- 3 files changed, 52 insertions(+), 72 deletions(-) diff --git a/jinja2_pdoc/cli.py b/jinja2_pdoc/cli.py index e25f493..cdf7074 100644 --- a/jinja2_pdoc/cli.py +++ b/jinja2_pdoc/cli.py @@ -1,5 +1,5 @@ from pathlib import Path -from typing import Generator, Iterable, Tuple +from typing import Tuple import click @@ -16,27 +16,27 @@ def eof_newline(content: str, eof: str = "\n") -> str: return content + eof -def load_files( - files: Iterable[Path], out_dir: Path, force: bool, root: Path = None -) -> Generator[Tuple[str, Path], None, None]: +def search_files(file: str, pattern: str = "*.jinja2") -> Tuple[Path, Path]: """ - iterates over files and yield `(content, out_file)` if its not existing. + Search for files with a pattern in a directory or a single file. - if `force` is True, all files are proessed. + Return tuples of template file and output file name """ - for file in map(lambda x: x.with_suffix(""), files): - if not root: - out = out_dir.joinpath(file.name) - else: - out = out_dir.joinpath(file.relative_to(root)) + root = Path(file) - if not out.is_file() or force: - yield (file.read_text(), out) - click.echo(f"rendering.. {out}") - else: - click.echo(f"skip....... {out}") + if root.is_file(): + if root.suffix != Path(pattern).suffix: + raise ValueError(f"file suffix {root.suffix} does not match {pattern}") + + files = [ + root, + ] + root = root.parent else: - click.echo("\n......done") + files = root.rglob(pattern) + + for file in files: + yield (file, file.relative_to(root).with_suffix("")) @click.command() @@ -73,22 +73,41 @@ def main( env = jinja2.Environment(extensions=[Jinja2Pdoc]) - input = Path(input).resolve() - output = Path(output).resolve() + output = Path(output) - if input.is_file(): - files = [ - input, - ] - root = None - else: - files = input.rglob(pattern) - root = input + def echo(tag, file, out): + if isinstance(tag, BaseException): + out = str(tag)[:48] + tag = type(tag).__name__ + color = "red" + else: + out = str(out.resolve())[-48:] + + if tag == "skip": + color = "yellow" + else: + color = "green" + + tag = click.style(f"{tag[:16]:<16}", fg=color) - for content, file in load_files(files, output, force, root): - code = env.from_string(content).render() - file.parent.mkdir(parents=True, exist_ok=True) - file.write_text(eof_newline(code, newline)) + click.echo(f"{tag} {str(file)[-48:]:.<48} {out}") + + for template, file in search_files(input, pattern): + out = output.joinpath(file) + + if out.is_file() and not force: + echo("skip", template, out) + continue + + try: + content = template.read_text() + code = env.from_string(content).render() + out.parent.mkdir(parents=True, exist_ok=True) + out.write_text(eof_newline(code, newline)) + except BaseException as e: + echo(e, template, out) + else: + echo("rendered", template, out) if __name__ == "__main__": diff --git a/pyproject.toml b/pyproject.toml index 2427892..24b4815 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -58,6 +58,7 @@ testpaths = "tests" addopts = [ "--random-order", "--color=yes", + "-s", # "--cov=jinja2_pdoc", # "--cov-report=term-missing:skip-covered", # "--cov-append", diff --git a/tests/test_cli.py b/tests/test_cli.py index c4a3dbd..c22b480 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -2,7 +2,7 @@ from click.testing import CliRunner -from jinja2_pdoc.cli import eof_newline, load_files, main +from jinja2_pdoc.cli import eof_newline, main, search_files def test_eof_newline(): @@ -12,46 +12,6 @@ def test_eof_newline(): assert eof_newline("test", "\n") == "test\n" -def test_load_files(tmp_path: Path): - for content, out in load_files( - [ - Path(__file__), - ], - tmp_path, - force=True, - root=None, - ): - assert "test_load_files" in content - assert out.parent == tmp_path - - -def test_load_files_folder(tmp_path: Path): - files = [ - "examples/example1.md.jinja2", - "examples/ex2/example2.md.jinja2", - "examples/example.md", - ] - - for file in map(lambda x: tmp_path.joinpath(x), files): - file.parent.mkdir(parents=True, exist_ok=True) - file.write_text(file.stem) - - input = tmp_path.joinpath("examples").rglob("*.jinja2") - - for _, out in load_files(input, tmp_path, force=True, root=tmp_path): - file = out.relative_to(tmp_path) - assert out.is_absolute() - assert file.as_posix() + ".jinja2" in files - - input = tmp_path.joinpath("examples").rglob("*.jinja2") - - for content, out in load_files(input, tmp_path, force=True, root=None): - file = out.relative_to(tmp_path) - assert out.is_absolute() - assert file.parent == Path(".") - assert content == file.name - - def test_cli_folder(tmp_path): runner = CliRunner() result = runner.invoke(