pywhatwgurl 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. pywhatwgurl-0.1.0/.github/workflows/actions/fetch_wpt_url_test_data/action.yml +46 -0
  2. pywhatwgurl-0.1.0/.github/workflows/docs-check.yml +33 -0
  3. pywhatwgurl-0.1.0/.github/workflows/docs.yml +64 -0
  4. pywhatwgurl-0.1.0/.github/workflows/fetch_test_data.yml +24 -0
  5. pywhatwgurl-0.1.0/.github/workflows/main.yml +73 -0
  6. pywhatwgurl-0.1.0/.github/workflows/package.yml +33 -0
  7. pywhatwgurl-0.1.0/.github/workflows/release.yml +66 -0
  8. pywhatwgurl-0.1.0/.github/workflows/update_wpt_url.yml +131 -0
  9. pywhatwgurl-0.1.0/.gitignore +31 -0
  10. pywhatwgurl-0.1.0/.pre-commit-config.yaml +24 -0
  11. pywhatwgurl-0.1.0/.python-version +1 -0
  12. pywhatwgurl-0.1.0/CHANGELOG.md +25 -0
  13. pywhatwgurl-0.1.0/CONTRIBUTING.md +214 -0
  14. pywhatwgurl-0.1.0/LICENSE +21 -0
  15. pywhatwgurl-0.1.0/PKG-INFO +207 -0
  16. pywhatwgurl-0.1.0/README.md +161 -0
  17. pywhatwgurl-0.1.0/docs/about/changelog.md +50 -0
  18. pywhatwgurl-0.1.0/docs/about/compliance.md +90 -0
  19. pywhatwgurl-0.1.0/docs/about/contributing.md +200 -0
  20. pywhatwgurl-0.1.0/docs/api/exceptions.md +130 -0
  21. pywhatwgurl-0.1.0/docs/api/url.md +157 -0
  22. pywhatwgurl-0.1.0/docs/api/urlsearchparams.md +161 -0
  23. pywhatwgurl-0.1.0/docs/getting-started/installation.md +76 -0
  24. pywhatwgurl-0.1.0/docs/getting-started/quickstart.md +172 -0
  25. pywhatwgurl-0.1.0/docs/guide/migration.md +325 -0
  26. pywhatwgurl-0.1.0/docs/guide/search-params.md +249 -0
  27. pywhatwgurl-0.1.0/docs/guide/url-components.md +227 -0
  28. pywhatwgurl-0.1.0/docs/guide/url-parsing.md +174 -0
  29. pywhatwgurl-0.1.0/docs/index.md +116 -0
  30. pywhatwgurl-0.1.0/mkdocs.yml +107 -0
  31. pywhatwgurl-0.1.0/pyproject.toml +115 -0
  32. pywhatwgurl-0.1.0/pytest.ini +2 -0
  33. pywhatwgurl-0.1.0/pywhatwgurl/__init__.py +43 -0
  34. pywhatwgurl-0.1.0/pywhatwgurl/_version.py +34 -0
  35. pywhatwgurl-0.1.0/pywhatwgurl/encoding.py +189 -0
  36. pywhatwgurl-0.1.0/pywhatwgurl/host.py +321 -0
  37. pywhatwgurl-0.1.0/pywhatwgurl/idna_processor.py +363 -0
  38. pywhatwgurl-0.1.0/pywhatwgurl/interfaces.py +457 -0
  39. pywhatwgurl-0.1.0/pywhatwgurl/parser.py +767 -0
  40. pywhatwgurl-0.1.0/pywhatwgurl/py.typed +0 -0
  41. pywhatwgurl-0.1.0/pywhatwgurl/record.py +50 -0
  42. pywhatwgurl-0.1.0/pywhatwgurl/search_params.py +233 -0
  43. pywhatwgurl-0.1.0/pywhatwgurl/url.py +256 -0
  44. pywhatwgurl-0.1.0/tests/conformance/README.md +39 -0
  45. pywhatwgurl-0.1.0/tests/conformance/WPT_TRACEABILITY.md +132 -0
  46. pywhatwgurl-0.1.0/tests/conformance/conftest.py +5 -0
  47. pywhatwgurl-0.1.0/tests/conformance/test_wpt_idna.py +102 -0
  48. pywhatwgurl-0.1.0/tests/conformance/test_wpt_percent_encoding.py +31 -0
  49. pywhatwgurl-0.1.0/tests/conformance/test_wpt_setters.py +30 -0
  50. pywhatwgurl-0.1.0/tests/conformance/test_wpt_setters_stripping.py +350 -0
  51. pywhatwgurl-0.1.0/tests/conformance/test_wpt_toascii.py +86 -0
  52. pywhatwgurl-0.1.0/tests/conformance/test_wpt_url_searchparams_integration.py +94 -0
  53. pywhatwgurl-0.1.0/tests/conformance/test_wpt_url_statics.py +68 -0
  54. pywhatwgurl-0.1.0/tests/conformance/test_wpt_url_tojson.py +13 -0
  55. pywhatwgurl-0.1.0/tests/conformance/test_wpt_urlsearchparams.py +830 -0
  56. pywhatwgurl-0.1.0/tests/conformance/test_wpt_urltestdata.py +88 -0
  57. pywhatwgurl-0.1.0/tests/conformance/wpt_data.py +104 -0
  58. pywhatwgurl-0.1.0/tests/conftest.py +23 -0
  59. pywhatwgurl-0.1.0/tests/mocks.py +162 -0
  60. pywhatwgurl-0.1.0/tests/unit/test_interfaces.py +93 -0
  61. pywhatwgurl-0.1.0/tests/unit/test_python_api.py +170 -0
  62. pywhatwgurl-0.1.0/tools/wpt_url_test_data.py +343 -0
  63. pywhatwgurl-0.1.0/util/bump_version.py +61 -0
  64. pywhatwgurl-0.1.0/util/wpt_url_test_data.py +343 -0
  65. pywhatwgurl-0.1.0/uv.lock +1772 -0
@@ -0,0 +1,46 @@
1
+ name: 'fetch_wpt_url_test_data'
2
+ description: 'Retrieve WPT URL test suite JSON.'
3
+ inputs:
4
+ dest_dir:
5
+ description: 'Directory (relative to $GITHUB_WORKSPACE) in which to save the sanitized file'
6
+ required: true
7
+ commit:
8
+ description: 'Pinned WPT commit hash to fetch URL resources from'
9
+ required: false
10
+ default: 'efb889eb4c9ca0b4e3ebd8ab308646b7483a8f54'
11
+ runs:
12
+ using: "composite"
13
+ steps:
14
+ - name: Ensure destination directory exists
15
+ shell: bash
16
+ run: |
17
+ mkdir -p "${{ github.workspace }}/${{ inputs.dest_dir }}"
18
+
19
+ - name: Restore cached JSON
20
+ id: cache
21
+ uses: actions/cache@v3
22
+ with:
23
+ path: |
24
+ ${{ github.workspace }}/${{ inputs.dest_dir }}/urltestdata.json
25
+ ${{ github.workspace }}/${{ inputs.dest_dir }}/setters_tests.json
26
+ ${{ github.workspace }}/${{ inputs.dest_dir }}/percent-encoding.json
27
+ ${{ github.workspace }}/${{ inputs.dest_dir }}/toascii.json
28
+ ${{ github.workspace }}/${{ inputs.dest_dir }}/IdnaTestV2.json
29
+ ${{ github.workspace }}/${{ inputs.dest_dir }}/IdnaTestV2-removed.json
30
+ ${{ github.workspace }}/${{ inputs.dest_dir }}/wpt_url_test_data_meta.json
31
+ key: wpt-urltestdata-${{ inputs.commit }}
32
+
33
+ - name: Download JSON if cache miss
34
+ if: steps.cache.outputs.cache-hit != 'true'
35
+ shell: bash
36
+ run: |
37
+ echo "Cache miss! Downloading fresh copy…"
38
+ python3 "${{ github.workspace }}/util/wpt_url_test_data.py" download \
39
+ --dest_dir "${{ github.workspace }}/${{ inputs.dest_dir }}" \
40
+ --commit "${{ inputs.commit }}"
41
+ echo "Download complete."
42
+
43
+ - name: Skip download if cache hit
44
+ if: steps.cache.outputs.cache-hit == 'true'
45
+ shell: bash
46
+ run: echo "Cache hit! Using existing JSON."
@@ -0,0 +1,33 @@
1
+ name: Docstring Coverage
2
+
3
+ on:
4
+ pull_request:
5
+ branches:
6
+ - master
7
+ push:
8
+ branches:
9
+ - master
10
+
11
+ jobs:
12
+ docstring-coverage:
13
+ name: docstring coverage
14
+ runs-on: ubuntu-latest
15
+
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+ with:
19
+ fetch-depth: 0
20
+
21
+ - name: Install uv
22
+ uses: astral-sh/setup-uv@v5
23
+
24
+ - name: Set up Python
25
+ uses: actions/setup-python@v5
26
+ with:
27
+ python-version-file: ".python-version"
28
+
29
+ - name: Install the project (including dev tools)
30
+ run: uv sync --locked --all-extras --dev
31
+
32
+ - name: Check docstring coverage (interrogate)
33
+ run: uv run interrogate pywhatwgurl/
@@ -0,0 +1,64 @@
1
+ name: Deploy Documentation
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - master
7
+ pull_request:
8
+ branches:
9
+ - master
10
+ workflow_dispatch:
11
+
12
+ permissions:
13
+ contents: read
14
+ pages: write
15
+ id-token: write
16
+
17
+ concurrency:
18
+ group: "pages"
19
+ cancel-in-progress: false
20
+
21
+ jobs:
22
+ build:
23
+ runs-on: ubuntu-latest
24
+ steps:
25
+ - name: Checkout repository
26
+ uses: actions/checkout@v4
27
+ with:
28
+ fetch-depth: 0
29
+
30
+ - name: Set up Python
31
+ uses: actions/setup-python@v5
32
+ with:
33
+ python-version: "3.12"
34
+
35
+ - name: Install uv
36
+ uses: astral-sh/setup-uv@v4
37
+ with:
38
+ version: "latest"
39
+
40
+ - name: Install dependencies
41
+ run: uv sync --group docs
42
+
43
+ - name: Build documentation
44
+ run: uv run mkdocs build --strict
45
+
46
+ - name: Create .nojekyll
47
+ run: touch site/.nojekyll
48
+
49
+ - name: Upload artifact
50
+ uses: actions/upload-pages-artifact@v3
51
+ with:
52
+ path: site
53
+
54
+ deploy:
55
+ if: github.event_name == 'push' && github.ref == 'refs/heads/master'
56
+ needs: build
57
+ runs-on: ubuntu-latest
58
+ environment:
59
+ name: github-pages
60
+ url: ${{ steps.deployment.outputs.page_url }}
61
+ steps:
62
+ - name: Deploy to GitHub Pages
63
+ id: deployment
64
+ uses: actions/deploy-pages@v4
@@ -0,0 +1,24 @@
1
+ name: Fetch WPT URL Test Data
2
+
3
+ env:
4
+ WPT_URL_COMMIT: efb889eb4c9ca0b4e3ebd8ab308646b7483a8f54
5
+ WPT_TEST_DATA_PATH: tests/conformance/data
6
+
7
+ on:
8
+ workflow_dispatch:
9
+ schedule:
10
+ - cron: '0 0 * * *' # Runs every day at midnight UTC
11
+
12
+ jobs:
13
+ fetch-wpt-url-test-data:
14
+ name: Fetch fixtures
15
+ runs-on: ubuntu-latest
16
+ steps:
17
+ - name: Checkout repository
18
+ uses: actions/checkout@v3
19
+
20
+ - name: Fetch WPT URL test suite JSON
21
+ uses: ./.github/workflows/actions/fetch_wpt_url_test_data
22
+ with:
23
+ commit: ${{ env.WPT_URL_COMMIT }}
24
+ dest_dir: ${{ env.WPT_TEST_DATA_PATH }}
@@ -0,0 +1,73 @@
1
+ name: CI
2
+
3
+ env:
4
+ SOURCE_ROOT: pywhatwgurl
5
+ WPT_URL_COMMIT: efb889eb4c9ca0b4e3ebd8ab308646b7483a8f54
6
+ WPT_TEST_DATA_PATH: tests/conformance/data
7
+
8
+ on:
9
+ pull_request:
10
+ branches:
11
+ - master
12
+ push:
13
+ branches:
14
+ - master
15
+
16
+ jobs:
17
+ lint:
18
+ name: lint
19
+ runs-on: ubuntu-latest
20
+
21
+ steps:
22
+ - uses: actions/checkout@v4
23
+ with:
24
+ fetch-depth: 0
25
+
26
+ - name: Install uv
27
+ uses: astral-sh/setup-uv@v5
28
+
29
+ - name: Set up Python
30
+ uses: actions/setup-python@v5
31
+ with:
32
+ python-version-file: ".python-version"
33
+
34
+ - name: Install the project (including dev tools)
35
+ run: uv sync --locked --all-extras --dev
36
+
37
+ - name: Run Ruff
38
+ run: uv run ruff check "${{ env.SOURCE_ROOT }}"
39
+
40
+ - name: Run mypy
41
+ run: uv run mypy "${{ env.SOURCE_ROOT }}"
42
+
43
+ - name: Run pip-audit
44
+ run: |
45
+ uv export --no-dev --no-hashes --no-emit-project -o /tmp/requirements.txt
46
+ uv run pip-audit --disable-pip --no-deps -r /tmp/requirements.txt
47
+
48
+ test:
49
+ name: test
50
+ runs-on: ubuntu-latest
51
+ strategy:
52
+ matrix:
53
+ python-version: ["3.10", "3.11", "3.12", "3.13"]
54
+
55
+ steps:
56
+ - uses: actions/checkout@v4
57
+ with:
58
+ fetch-depth: 0
59
+
60
+ - name: Install uv
61
+ uses: astral-sh/setup-uv@v5
62
+
63
+ - name: Fetch WPT URL resources
64
+ uses: ./.github/workflows/actions/fetch_wpt_url_test_data
65
+ with:
66
+ commit: ${{ env.WPT_URL_COMMIT }}
67
+ dest_dir: ${{ env.WPT_TEST_DATA_PATH }}
68
+
69
+ - name: Install the project
70
+ run: uv sync --locked --all-extras --dev
71
+
72
+ - name: Run tests
73
+ run: uv run pytest
@@ -0,0 +1,33 @@
1
+ name: Package
2
+
3
+ on:
4
+ pull_request:
5
+ push:
6
+ branches:
7
+ - master
8
+ workflow_dispatch:
9
+
10
+ jobs:
11
+ build:
12
+ runs-on: ubuntu-latest
13
+ steps:
14
+ - uses: actions/checkout@v4
15
+ with:
16
+ fetch-depth: 0
17
+ - name: Install uv
18
+ uses: astral-sh/setup-uv@v5
19
+ with:
20
+ version: "latest"
21
+ enable-cache: true
22
+ - name: Build package
23
+ run: uv build
24
+ - uses: actions/upload-artifact@v4
25
+ with:
26
+ name: dist
27
+ path: dist/
28
+
29
+ - name: Publish package
30
+ if: github.event_name == 'push' && github.ref == 'refs/heads/master'
31
+ run: uv publish --publish-url "$UV_PUBLISH_URL"
32
+ env:
33
+ UV_PUBLISH_URL: https://${{ secrets.GEMFURY_PUSH_TOKEN }}@push.fury.io/pywhatwgurl/
@@ -0,0 +1,66 @@
1
+ name: Release
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ inputs:
6
+ bump_rule:
7
+ description: 'Version Bump Rule'
8
+ required: true
9
+ default: 'patch'
10
+ type: choice
11
+ options:
12
+ - patch
13
+ - minor
14
+ - major
15
+
16
+ jobs:
17
+ release:
18
+ runs-on: ubuntu-latest
19
+ permissions:
20
+ contents: write
21
+ id-token: write
22
+ environment:
23
+ name: pypi
24
+ url: https://pypi.org/project/pywhatwgurl/
25
+ steps:
26
+ - uses: actions/checkout@v4
27
+ with:
28
+ fetch-depth: 0
29
+
30
+ - name: Configure Git
31
+ run: |
32
+ git config user.name "github-actions[bot]"
33
+ git config user.email "github-actions[bot]@users.noreply.github.com"
34
+
35
+ - name: Calculate Next Version
36
+ id: version
37
+ run: python util/bump_version.py ${{ inputs.bump_rule }}
38
+
39
+ - name: Create and Push Tag
40
+ run: |
41
+ git tag ${{ steps.version.outputs.new_tag }}
42
+ git push origin ${{ steps.version.outputs.new_tag }}
43
+
44
+ - name: Install uv
45
+ uses: astral-sh/setup-uv@v5
46
+ with:
47
+ version: "latest"
48
+ enable-cache: true
49
+
50
+ - name: Build package
51
+ run: uv build
52
+
53
+ - name: Generate SBOM
54
+ run: |
55
+ uv export --no-dev --no-hashes --format=requirements-txt > requirements.txt
56
+ uv run cyclonedx-py requirements requirements.txt --output-format json --output-file sbom.json
57
+
58
+ - name: Publish to PyPI
59
+ uses: pypa/gh-action-pypi-publish@release/v1
60
+
61
+ - name: Create GitHub Release
62
+ uses: softprops/action-gh-release@v2
63
+ with:
64
+ tag_name: ${{ steps.version.outputs.new_tag }}
65
+ generate_release_notes: true
66
+ files: sbom.json
@@ -0,0 +1,131 @@
1
+ name: Bump WPT URL Pin
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ schedule:
6
+ - cron: "0 3 * * 1" # Mondays at 03:00 UTC
7
+
8
+ permissions:
9
+ contents: write
10
+ pull-requests: write
11
+
12
+ jobs:
13
+ update-wpt-url:
14
+ runs-on: ubuntu-latest
15
+
16
+ steps:
17
+ - name: Checkout repository
18
+ uses: actions/checkout@v4
19
+
20
+ - name: Set up Python
21
+ uses: actions/setup-python@v5
22
+ with:
23
+ python-version: "3.x"
24
+
25
+ - name: Get pinned WPT commit
26
+ id: current
27
+ shell: bash
28
+ run: |
29
+ CURRENT=$(python - <<'PY'
30
+ import pathlib, re, sys
31
+ text = pathlib.Path("util/wpt_url_test_data.py").read_text()
32
+ m = re.search(r'DEFAULT_WPT_COMMIT = "([0-9a-f]+)"', text)
33
+ if not m:
34
+ sys.exit("Could not find DEFAULT_WPT_COMMIT")
35
+ print(m.group(1))
36
+ PY
37
+ )
38
+ echo "commit=${CURRENT}" >> "$GITHUB_OUTPUT"
39
+
40
+ - name: Get latest WPT url commit
41
+ id: latest
42
+ shell: bash
43
+ run: |
44
+ LATEST=$(python - <<'PY'
45
+ import json
46
+ import os
47
+ import urllib.request
48
+
49
+ token = os.getenv("GITHUB_TOKEN")
50
+ headers = {"User-Agent": "pywhatwgurl-ci"}
51
+ if token:
52
+ headers["Authorization"] = f"Bearer {token}"
53
+
54
+ req = urllib.request.Request(
55
+ "https://api.github.com/repos/web-platform-tests/wpt/commits?path=url&per_page=1",
56
+ headers=headers,
57
+ )
58
+ with urllib.request.urlopen(req) as resp:
59
+ data = json.load(resp)
60
+ print(data[0]["sha"])
61
+ PY
62
+ )
63
+ echo "commit=${LATEST}" >> "$GITHUB_OUTPUT"
64
+
65
+ - name: Stop if already up to date
66
+ if: steps.latest.outputs.commit == steps.current.outputs.commit
67
+ run: |
68
+ echo "Pinned commit matches latest (${{ steps.latest.outputs.commit }}). Nothing to do."
69
+ exit 0
70
+
71
+ - name: Update pinned commit hashes
72
+ if: steps.latest.outputs.commit != steps.current.outputs.commit
73
+ shell: bash
74
+ run: |
75
+ TARGET="${{ steps.latest.outputs.commit }}"
76
+ python - <<'PY'
77
+ import pathlib
78
+ import re
79
+ import sys
80
+
81
+ target = "${{ steps.latest.outputs.commit }}"
82
+ def replace_yaml_scalar_key(key: str, text: str) -> str:
83
+ pattern = rf"^(\s*){re.escape(key)}\s*:\s*([0-9a-f]+)\s*$"
84
+ new_text, count = re.subn(
85
+ pattern,
86
+ lambda m: f"{m.group(1)}{key}: {target}",
87
+ text,
88
+ flags=re.MULTILINE,
89
+ )
90
+ if count == 0:
91
+ raise RuntimeError(f"Failed to update {key}")
92
+ return new_text
93
+
94
+ updates = [
95
+ ".github/workflows/fetch_test_data.yml",
96
+ ".github/workflows/main.yml",
97
+ ]
98
+ for path in updates:
99
+ p = pathlib.Path(path)
100
+ p.write_text(replace_yaml_scalar_key("WPT_URL_COMMIT", p.read_text()))
101
+
102
+ action_path = pathlib.Path(".github/workflows/actions/fetch_wpt_url_test_data/action.yml")
103
+ action_text = action_path.read_text()
104
+ def action_repl(m: re.Match[str]) -> str:
105
+ return f"{m.group(1)}'{target}'"
106
+ new_action, count = re.subn(r"(default: )'[^']+'", action_repl, action_text)
107
+ if count == 0:
108
+ raise RuntimeError("Failed to update action default commit")
109
+ action_path.write_text(new_action)
110
+
111
+ util_path = pathlib.Path("util/wpt_url_test_data.py")
112
+ util_text = util_path.read_text()
113
+ def util_repl(m: re.Match[str]) -> str:
114
+ return f'{m.group(1)}{target}{m.group(3)}'
115
+ new_util, count = re.subn(r'(DEFAULT_WPT_COMMIT = ")([0-9a-f]+)(")', util_repl, util_text)
116
+ if count == 0:
117
+ raise RuntimeError("Failed to update util DEFAULT_WPT_COMMIT")
118
+ util_path.write_text(new_util)
119
+ PY
120
+
121
+ - name: Create pull request
122
+ if: steps.latest.outputs.commit != steps.current.outputs.commit
123
+ uses: peter-evans/create-pull-request@v6
124
+ with:
125
+ token: ${{ secrets.WORKFLOW_PAT || github.token }}
126
+ commit-message: "chore: bump WPT URL tests to ${{ steps.latest.outputs.commit }}"
127
+ title: "chore: bump WPT URL tests to ${{ steps.latest.outputs.commit }}"
128
+ branch: "ci/update-wpt-url"
129
+ delete-branch: true
130
+ body: |
131
+ - Update pinned WPT URL commit to `${{ steps.latest.outputs.commit }}`
@@ -0,0 +1,31 @@
1
+ # Python-generated files
2
+ __pycache__/
3
+ *.py[oc]
4
+ build/
5
+ dist/
6
+ wheels/
7
+ *.egg-info
8
+
9
+ # Virtual environments
10
+ .venv
11
+
12
+ # VS Code configuration
13
+ .vscode/
14
+ *.code-workspace
15
+
16
+ # Downloaded WPT URL test data
17
+ tests/conformance/data/
18
+
19
+ # Local caches (do not commit)
20
+ .cache/
21
+ .cache/tests/wpt/
22
+ .uv-cache/
23
+
24
+ # Generated version file
25
+ pywhatwgurl/_version.py
26
+
27
+ # MkDocs build output
28
+ site/
29
+
30
+ # Agent files
31
+ AGENTS.md
@@ -0,0 +1,24 @@
1
+ repos:
2
+ - repo: local
3
+ hooks:
4
+ - id: ruff
5
+ name: Run ruff check with fix
6
+ entry: uv run ruff check --fix
7
+ language: system # Assumes `uv` is installed and available in the system PATH
8
+ types: [python]
9
+ files: \.py$
10
+
11
+ - id: mypy
12
+ name: Run mypy type checking
13
+ entry: uv run mypy pywhatwgurl
14
+ language: system
15
+ types: [python]
16
+ files: ^pywhatwgurl/
17
+ pass_filenames: false
18
+
19
+ - id: pip-audit
20
+ name: Run pip-audit (dependency vulnerability scan)
21
+ entry: bash -c 'uv export --no-dev --no-hashes --no-emit-project -o /tmp/requirements.txt && uv run pip-audit --disable-pip --no-deps -r /tmp/requirements.txt'
22
+ language: system
23
+ always_run: true
24
+ pass_filenames: false
@@ -0,0 +1 @@
1
+ 3.10
@@ -0,0 +1,25 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.1.0] - 2026-03-03
11
+
12
+ ### Added
13
+ - Initial public release of `pywhatwgurl`.
14
+ - Full `URL` and `URLSearchParams` API implementation per the WHATWG URL Standard.
15
+ - 100% WHATWG URL Standard conformance for core URL parsing (validated against [Web Platform Tests](https://github.com/web-platform-tests/wpt/tree/master/url)).
16
+ - Pure Python, fully type-annotated (`py.typed`), zero compiled dependencies.
17
+ - Comprehensive documentation with API reference, user guide, and migration notes.
18
+ - CI pipeline with linting (ruff), type checking (mypy), and security scanning (pip-audit).
19
+ - Automated weekly WPT test data updates via GitHub Actions.
20
+ - SBOM generation (CycloneDX) attached to every GitHub release.
21
+
22
+ ### Known Limitations
23
+ - **IDNA Conformance**: IDNA tests are marked as expected failures (`xfail`). The Python `idna` library follows stricter RFC 5891/5892 rules than the WHATWG URL Standard's lenient UTS46 processing.
24
+ - Real-world domains generally work correctly; failures are primarily with obscure edge cases not covered by the stricter RFCs.
25
+ - No Python WHATWG-compliant IDNA implementation currently exists.