Skip to content

Commit

Permalink
fix: Copy dependencies with subdirectories and all_files=True (#88)
Browse files Browse the repository at this point in the history
  • Loading branch information
gadenbuie authored May 10, 2024
1 parent a3a9825 commit 75e1b8c
Show file tree
Hide file tree
Showing 8 changed files with 28 additions and 11 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ All notable changes to htmltools for Python will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [UNRELEASED]

* The `HTMLDependency.copy()` method can now correctly copy folders in depenendencies that both include directories and have `all_files=True`. (#87)

## [0.5.1] 2023-12-18

* `Tag` objects can now be used as context managers, as in `with tags.div():`. When used this way, then inside the `with` block, `sys.displayhook` is replaced with a function which adds items as children to the `Tag`. This is meant to be used with Shiny Express, Quarto, or Jupyter. (#76)
Expand Down
18 changes: 9 additions & 9 deletions htmltools/_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,7 @@ class Tagifiable(Protocol):
returns a `TagList`, the children of the `TagList` must also be tagified.
"""

def tagify(self) -> "TagList | Tag | MetadataNode | str":
...
def tagify(self) -> "TagList | Tag | MetadataNode | str": ...


@runtime_checkable
Expand All @@ -148,8 +147,7 @@ def __call__(
*args: TagChild | TagAttrs,
_add_ws: TagAttrValue = ...,
**kwargs: TagAttrValue,
) -> "Tag":
...
) -> "Tag": ...


@runtime_checkable
Expand All @@ -158,8 +156,7 @@ class ReprHtml(Protocol):
Objects with a `_repr_html_()` method.
"""

def _repr_html_(self) -> str:
...
def _repr_html_(self) -> str: ...


# =============================================================================
Expand Down Expand Up @@ -1609,7 +1606,7 @@ def copy_to(self, path: str, include_version: bool = True) -> None:
# Verify they all exist
for f in src_files:
src_file = os.path.join(paths["source"], f)
if not os.path.isfile(src_file):
if not os.path.exists(src_file):
raise Exception(
f"Failed to copy HTML dependency {self.name}-{str(self.version)} "
+ f"because {src_file} doesn't exist."
Expand All @@ -1626,7 +1623,10 @@ def copy_to(self, path: str, include_version: bool = True) -> None:
src_file = os.path.join(paths["source"], f)
target_file = os.path.join(target_dir, f)
os.makedirs(os.path.dirname(target_file), exist_ok=True)
shutil.copy2(src_file, target_file)
if os.path.isfile(src_file):
shutil.copy2(src_file, target_file)
elif os.path.isdir(src_file):
shutil.copytree(src_file, target_file)

def _validate_dicts(self, ld: Iterable[object], req_attr: list[str]) -> None:
for d in ld:
Expand Down Expand Up @@ -1740,7 +1740,7 @@ def _tag_show(
import IPython # pyright: ignore[reportUnknownVariableType]

ipy = ( # pyright: ignore[reportUnknownVariableType]
IPython.get_ipython() # pyright: ignore[reportUnknownMemberType]
IPython.get_ipython() # pyright: ignore[reportUnknownMemberType, reportPrivateImportUsage]
)
renderer = "ipython" if ipy else "browser"
except ImportError:
Expand Down
1 change: 1 addition & 0 deletions htmltools/_jsx.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
that's an issue for HTML() and <script> tags, so using normal HTML tags inside JSX
components may become unsupported in a future version (see #26 and #28)
"""

from __future__ import annotations

import copy
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ version = {attr = "htmltools.__version__"}
htmltools = ["py.typed"]

[tool.flake8]
ignore = "E203, E302, E402, E501, F403, F405, W503"
ignore = "E203, E302, E402, E501, E704, F403, F405, W503"
extend-exclude = "docs, .venv, venv, typings, e2e, build"

[tool.isort]
Expand Down
File renamed without changes.
File renamed without changes.
12 changes: 12 additions & 0 deletions tests/test_deps.py
Original file line number Diff line number Diff line change
Expand Up @@ -354,3 +354,15 @@ def test_copy_to():
dep4.copy_to(tmpdir4)
assert (Path(tmpdir4) / "w-1.0" / "testdep.css").exists()
assert (Path(tmpdir4) / "w-1.0" / "testdep.js").exists()

with tempfile.TemporaryDirectory() as tmpdir5:
path_testdep_nested = Path(__file__).parent / "assets" / "testdep-nested"
dep5 = HTMLDependency(
"w",
"1.0",
source={"subdir": str(path_testdep_nested)},
all_files=True,
)
dep5.copy_to(tmpdir5)
assert (Path(tmpdir5) / "w-1.0" / "css" / "my-styles.css").exists()
assert (Path(tmpdir5) / "w-1.0" / "js" / "my-js.js").exists()
2 changes: 1 addition & 1 deletion tests/test_tags.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ def test_basic_tag_api():
assert "style" not in x4.attrs.keys()
try:
x4.add_style("color: red")
assert False, "Expected ValueError for missing semicolon"
raise AssertionError("Expected ValueError for missing semicolon")
except ValueError as e:
assert "must end with a semicolon" in str(e)

Expand Down

0 comments on commit 75e1b8c

Please sign in to comment.