Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Updated GitHub Actions workflows to use modern actions and UV package manager
- Modernized code formatting (improved consistency and readability)
- Centralized all package metadata in `pyproject.toml` (removed from module docstring)
=- **Updated all docstrings from reStructuredText to Google/NumPy style** (Args/Returns/Raises format)
- **Updated all docstrings from reStructuredText to Google/NumPy style** (Args/Returns/Raises format)
- **Refactored monolithic module into modular structure**: Split `urlpath/__init__.py` (1540 lines) into `_compat.py`, `_utils.py`, `_flavour.py`, and `_url.py` for better maintainability
- **Centralized Python version checking**: Replaced 18 scattered `sys.version_info >= (3, 12)` checks with single `IS_PY312_PLUS` constant in `_compat.py`
- **Added `cleanup_escapes()` helper function**: Eliminated 6 duplicate `.replace("\\x00", "/")` patterns for cleaner code
- **Made WebOb a required test dependency**: Removed conditional imports and test skips to ensure WebOb integration is always tested

### Added
- `.python-version` file for Python version management
Expand All @@ -48,6 +52,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- **Pydocstyle linting** (Ruff "D" rules) to enforce documentation consistency
- **Type annotations for all test functions** (`-> None` return types)
- **Docstrings for magic methods** (`__str__`, `__bytes__`, etc.)
- **Test coverage for constructor canonicalization**: Tests for `SplitResult`, `ParseResult`, `bytes`, and `__fspath__` inputs
- **Test coverage for multi-argument URL construction**: Validates that `URL("base", "child", "../final")` matches chained joinpath semantics

### Removed
- `setup.py` (replaced by `pyproject.toml`)
Expand Down
38 changes: 38 additions & 0 deletions tests/test_url.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
import urllib.parse
from pathlib import PurePosixPath
from typing import Any, cast
from unittest.mock import Mock
Copy link

Copilot AI Oct 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Import Mock from unittest.mock at the top level but use patch from within the test function. For consistency, move the patch import to the top level imports alongside Mock.

Suggested change
from unittest.mock import Mock
from unittest.mock import Mock, patch

Copilot uses AI. Check for mistakes.

import jmespath
import pytest
import webob

Expand Down Expand Up @@ -383,3 +385,39 @@ def test_colon_in_filename() -> None:
assert url.query == "key=value"
assert url.fragment == "frag"
assert str(url) == "http://www.example.com/abc:def.html?key=value#frag"


def test_get_json_with_jmespath_filtering() -> None:
"""Test get_json method with JMESPath query filtering."""
from unittest.mock import patch

url = URL("http://api.example.com/data")

# Mock response with JSON data
mock_response = Mock()
mock_response.json.return_value = {
"users": [
{"name": "Alice", "age": 30},
{"name": "Bob", "age": 25},
],
"total": 2,
}

# Patch requests.get to avoid actual network calls
with patch("requests.get", return_value=mock_response):
# Test without JMESPath filtering
result = url.get_json()
assert result == mock_response.json.return_value

# Test with JMESPath string query
result = url.get_json(keys="users[0].name")
assert result == "Alice"

# Test with compiled JMESPath expression
compiled_expr = jmespath.compile("users[*].age")
result = url.get_json(keys=compiled_expr)
assert result == [30, 25]

# Test with query parameters
result = url.get_json(query={"filter": "active"}, keys="total")
assert result == 2