Skip to content
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
5f6fae2
feat: :sparkles: Move over relevant code from sprout and cdp
joelostblom Feb 23, 2026
6f0ef5d
feat: :sparkles: Add Https type and class validator
joelostblom Feb 24, 2026
f943218
feat: :sparkles: Implement resolve_uri
joelostblom Feb 24, 2026
a89633d
refactor: ♻️ Use case/match for readabilty
joelostblom Feb 24, 2026
8072033
refactor: ♻️ Make variable names more precise
joelostblom Feb 24, 2026
7763097
fix: 🐛 Remove unnused import
joelostblom Feb 24, 2026
c375a30
fix: 🐛 Fix mypy errors
joelostblom Feb 24, 2026
26ad174
chore: 🔧 Fix typing
joelostblom Feb 24, 2026
662c3d6
fix: 🐛 Remove old tmp code
joelostblom Feb 24, 2026
fd70520
fix: 🐛 Remove unused import
joelostblom Feb 24, 2026
b7ad9a0
fix: 🐛 Pass vulture checks
joelostblom Feb 24, 2026
df338f3
test: ✅ Comment code to be updated in separate PR to pass tests
joelostblom Feb 24, 2026
0044b9c
fix: 🐛 Remove check datapacakge from this PR
joelostblom Feb 24, 2026
05fbaa8
fix: 🐛 Create type alias
joelostblom Feb 25, 2026
5aae406
fix: 🐛 Ignore line in mypy instead of changing logic
joelostblom Feb 25, 2026
ae6c6eb
refactor: ♻️ Change pydantic classes to custom dataclass
joelostblom Feb 26, 2026
f88fb14
fix: 🐛 Name parameters more precisely
joelostblom Feb 26, 2026
4b632fd
fix: 🐛 Remove explicit file exist check
joelostblom Feb 26, 2026
95b9c69
refactor: ♻️ Reduce cases
joelostblom Feb 27, 2026
4005455
refactor: ♻️ Name variables more precisely
joelostblom Feb 27, 2026
78da642
docs: 📝 Clarify what source can be
joelostblom Feb 27, 2026
c1bcb3f
fix: 🐛 Avoid changes to read_properties in this PR
joelostblom Feb 27, 2026
2b5aeea
Revert "fix: 🐛 Avoid changes to read_properties in this PR"
joelostblom Feb 27, 2026
43a974e
feat: ✨ Check types
joelostblom Feb 27, 2026
39a8c76
fix: 🐛 Remove redundant parsin of gh uri
joelostblom Feb 27, 2026
3c091bf
feat: ✨ Improve naming
joelostblom Feb 27, 2026
030789e
feat: ✨ Add read_prop skeleton
joelostblom Feb 27, 2026
fd8c748
refactor: ♻️ Revert to less precise name until we have discussed more
joelostblom Mar 2, 2026
0b5d5d6
Merge branch 'main' into feat/resolve-uri
joelostblom Mar 2, 2026
6a12807
test: ✅ Update test to match new docstring
joelostblom Mar 2, 2026
7d1b019
fix: 🐛 Restore local file reading behavior to not break former test
joelostblom Mar 2, 2026
a5cc597
refactor: ♻️ Rename test function to match refactor
joelostblom Mar 2, 2026
d2fb845
chore: 🔧 Ignore mypy on lines to be fixed in read_prop PR
joelostblom Mar 2, 2026
f5a206c
test: ✅ Add internal tests for _parse_uri
joelostblom Mar 2, 2026
115b19e
build: 🔨 uv update
joelostblom Mar 2, 2026
779f627
Potential fix for code scanning alert no. 14: Incomplete URL substrin…
joelostblom Mar 2, 2026
539af8e
Apply suggestions from code review
joelostblom Mar 2, 2026
19a145e
test: ✅ Parameterize github tests for clarity
joelostblom Mar 2, 2026
64696a1
docs: 📝 Reformat docstring to fit width
joelostblom Mar 2, 2026
d53e619
test: ✅ Update help message constant
joelostblom Mar 2, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions src/seedcase_flower/cli.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
"""Functions for the exposed CLI."""

from pathlib import Path
from typing import Any, Optional
from typing import Optional

from cyclopts import App, Parameter, config

# from seedcase_flower.config import Config as FlowerConfig
from seedcase_flower.internals import BuildStyle, _read_properties, _resolve_uri
from seedcase_flower.internals import BuildStyle, _resolve_uri

app = App(
help="Flower generates human-readable documentation from Data Packages.",
Expand Down Expand Up @@ -47,8 +47,8 @@ def build(
output_dir: The directory to save the generated files in.
verbose: If True, prints additional information to the console.
"""
path: Path = _resolve_uri(uri)
properties: dict[str, Any] = _read_properties(path)
properties = _resolve_uri(uri)
# properties = _read_properties(path)

# One item per section, rendered from template.
# Internally uses Jinja2 to render templates with metadata, which
Expand Down
74 changes: 68 additions & 6 deletions src/seedcase_flower/internals.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,27 @@
import json
from enum import Enum
from pathlib import Path
from typing import Any
from typing import Annotated, Any
from urllib import parse

from pydantic import AnyUrl, FileUrl, TypeAdapter, UrlConstraints

_AnnotatedHttps = Annotated[AnyUrl, UrlConstraints(allowed_schemes=["https"])]
_adapter = TypeAdapter(_AnnotatedHttps)


class HttpsUrl(str):
"""Type and class with validation for https URLs."""

@classmethod
def __get_pydantic_core_schema__(cls, source, handler): # type: ignore[no-untyped-def]
"""Initialize adapter core schema."""
return _adapter.core_schema

def __new__(cls, value: str): # type: ignore[no-untyped-def]
"""Setup validation."""
validated = _adapter.validate_python(value)
return str.__new__(cls, validated)


class BuildStyle(Enum):
Expand All @@ -14,11 +34,53 @@ class BuildStyle(Enum):
quarto_resource_tables = "quarto_resource_tables"


# Output maybe str? Path?
# Use `match` inside for strictness on URI types? Or use a library for URI parsing?
# TODO Extend to parse strings and return either URL or Path
def _resolve_uri(uri: str) -> Path:
return Path(uri)
type HttpsUrl_or_FileUrl = HttpsUrl | FileUrl


def _resolve_uri(uri_or_path: str) -> HttpsUrl_or_FileUrl:
split_uri = parse.urlsplit(uri_or_path)
match split_uri.scheme:
case "":
return _check_path(uri_or_path)
case "file":
return _check_file_uri(split_uri)
case "https":
return _check_https_uri(split_uri)
case "gh" | "github":
return _check_github_uri(split_uri)
case _:
raise ValueError(
"The URI must be either a path to an existing file/folder "
"or have one of the following URI prefixes: "
"`file:`, `https:`, `gh:`, `github:`"
)


def _check_path(uri_or_path: str) -> FileUrl:
path = Path(uri_or_path).resolve()
if path.is_dir():
path = path / "datapackage.json"
if not path.exists():
raise OSError(f"{path} does not exist.")
return FileUrl(path.as_uri())


def _check_file_uri(split_uri: parse.SplitResult) -> FileUrl:
return FileUrl(split_uri.geturl())


def _check_https_uri(split_uri: parse.SplitResult) -> HttpsUrl:
return HttpsUrl(split_uri.geturl())


def _check_github_uri(split_uri: parse.SplitResult) -> HttpsUrl:
return HttpsUrl(
split_uri._replace(
scheme="https",
netloc="raw.githubusercontent.com",
path=f"/{split_uri.path}/refs/heads/main/datapackage.json",
).geturl()
)


# TODO Extend to also read properties from URLs
Expand Down
3 changes: 3 additions & 0 deletions tools/vulture-allowlist.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,6 @@
_check_jsonpath # unused method (src/seedcase_flower/section.py:83)
quarto_resource_tables # unused variable (src/seedcase_flower/internals.py:14)
cls # unused variable (src/seedcase_flower/section.py:85)
target # unused variable (src/seedcase_flower/.venv/lib/python3.12/site-packages/_virtualenv.py:50)
handler # unused variable (src/seedcase_flower/internals.py:20)
source # unused variable (src/seedcase_flower/internals.py:20)
24 changes: 12 additions & 12 deletions uv.lock

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

Loading