Skip to content

Commit 45f0a99

Browse files
authored
Merge branch 'master' into dependabot/pip/docs/h11-0.16.0
2 parents 85b9a9e + 6cbdea8 commit 45f0a99

20 files changed

+1232
-190
lines changed

.coverage

0 Bytes
Binary file not shown.
Lines changed: 100 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,17 @@
11
name: Json2xml
22

3-
on: [push, pull_request]
3+
on:
4+
push:
5+
branches: [main, master]
6+
paths-ignore:
7+
- 'docs/**'
8+
- '*.md'
9+
- '*.rst'
10+
pull_request:
11+
paths-ignore:
12+
- 'docs/**'
13+
- '*.md'
14+
- '*.rst'
415

516
permissions:
617
contents: read
@@ -12,31 +23,27 @@ concurrency:
1223
cancel-in-progress: true
1324

1425
jobs:
15-
build:
26+
test:
1627
runs-on: ${{ matrix.os }}
1728
strategy:
1829
fail-fast: false
1930
matrix:
2031
python-version: [pypy-3.10, pypy-3.11, '3.10', '3.11', '3.12', '3.13']
21-
tox-python-version: [pypy3.10, pypy3.11, py310, py311, py312, py313]
2232
os: [
2333
ubuntu-latest,
2434
windows-latest,
2535
macos-latest,
2636
]
2737
include:
28-
# Add exact version 3.14.0-alpha.0 for ubuntu-latest only
29-
- python-version: 3.14.0-alpha.7
30-
tox-python-version: py314-full
38+
# Add exact version 3.14.0-beta.1 for ubuntu-latest only
39+
- python-version: 3.14.0-beta.1
3140
os: ubuntu-latest
3241
exclude:
33-
# Exclude other OSes with Python 3.14.0-alpha.0
34-
- python-version: 3.14.0-alpha.7
35-
tox-python-version: py314-full
42+
# Exclude other OSes with Python 3.14.0-beta.1
43+
- python-version: 3.14.0-beta.1
3644
os: windows-latest
37-
- python-version: 3.14.0-alpha.7
45+
- python-version: 3.14.0-beta.1
3846
os: macos-latest
39-
tox-python-version: py314-full
4047

4148
steps:
4249
- uses: actions/checkout@v4
@@ -48,27 +55,101 @@ jobs:
4855
with:
4956
python-version: ${{ matrix.python-version }}
5057
allow-prereleases: true
51-
- name: install uv
52-
uses: astral-sh/setup-uv@v3
58+
59+
- name: Install uv
60+
uses: astral-sh/setup-uv@v6
5361
with:
5462
enable-cache: true
55-
cache-dependency-glob: requirements-dev.txt
63+
cache-dependency-glob: |
64+
requirements*.txt
65+
requirements-dev.in
66+
pyproject.toml
5667
5768
- name: Install dependencies
58-
run: uv pip install --system tox tox-uv
69+
run: |
70+
uv pip install --system -e .
71+
uv pip install --system pytest pytest-xdist pytest-cov
5972
60-
- name: Run tox targets for ${{ matrix.python-version }}
61-
run: tox -e ${{matrix.tox-python-version}}
73+
- name: Create coverage directory
74+
run: mkdir -p coverage/reports
75+
76+
- name: Run tests
77+
run: |
78+
pytest --cov=json2xml --cov-report=xml:coverage/reports/coverage.xml --cov-report=term -xvs tests -n auto
79+
env:
80+
PYTHONPATH: ${{ github.workspace }}
6281

6382
- name: Upload coverage to Codecov
6483
uses: codecov/codecov-action@v5
84+
if: success()
6585
with:
6686
directory: ./coverage/reports/
6787
env_vars: OS,PYTHON
68-
fail_ci_if_error: true
69-
files: ./coverage.xml,./coverage2.xml,!./cache
88+
fail_ci_if_error: false # Don't fail CI if codecov upload fails
89+
files: ./coverage/reports/coverage.xml
7090
flags: unittests
7191
token: ${{ secrets.CODECOV_TOKEN }}
7292
name: codecov-umbrella
7393
verbose: true
94+
env:
95+
OS: ${{ matrix.os }}
96+
PYTHON: ${{ matrix.python-version }}
97+
98+
lint:
99+
runs-on: ubuntu-latest
100+
steps:
101+
- uses: actions/checkout@v4
102+
with:
103+
persist-credentials: false
104+
105+
- name: Set up Python 3.12
106+
uses: actions/[email protected]
107+
with:
108+
python-version: '3.12'
109+
110+
- name: Install uv
111+
uses: astral-sh/setup-uv@v6
112+
with:
113+
enable-cache: true
114+
cache-dependency-glob: |
115+
requirements*.txt
116+
requirements-dev.in
117+
pyproject.toml
118+
119+
- name: Install dependencies
120+
run: |
121+
uv pip install --system -e .
122+
uv pip install --system ruff>=0.3.0
123+
124+
- name: Run ruff
125+
run: ruff check json2xml tests
126+
127+
typecheck:
128+
runs-on: ubuntu-latest
129+
steps:
130+
- uses: actions/checkout@v4
131+
with:
132+
persist-credentials: false
133+
134+
- name: Set up Python 3.12
135+
uses: actions/[email protected]
136+
with:
137+
python-version: '3.12'
138+
139+
- name: Install uv
140+
uses: astral-sh/setup-uv@v6
141+
with:
142+
enable-cache: true
143+
cache-dependency-glob: |
144+
requirements*.txt
145+
requirements-dev.in
146+
pyproject.toml
147+
148+
- name: Install dependencies
149+
run: |
150+
uv pip install --system -e .
151+
uv pip install --system mypy>=1.0.0 types-setuptools
152+
153+
- name: Run mypy
154+
run: mypy json2xml tests
74155

AGENT.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# json2xml AGENT.md
2+
3+
## Build/Test Commands
4+
- Test: `pytest -vv` (all tests) or `pytest tests/test_<name>.py -vv` (single test file)
5+
- Test with coverage: `pytest --cov=json2xml --cov-report=xml:coverage/reports/coverage.xml --cov-report=term -xvs`
6+
- Lint: `ruff check json2xml tests`
7+
- Type check: `mypy json2xml tests`
8+
- Test all Python versions: `tox`
9+
- Clean artifacts: `make clean`
10+
11+
## Architecture
12+
- Main module: `json2xml/` with `json2xml.py` (main converter), `dicttoxml.py` (core conversion), `utils.py` (utilities)
13+
- Core functionality: JSON to XML conversion via `Json2xml` class wrapping `dicttoxml`
14+
- Tests: `tests/` with test files following `test_*.py` pattern
15+
16+
## Code Style (from .cursorrules)
17+
- Always add typing annotations to functions/classes with descriptive docstrings (PEP 257)
18+
- Use pytest (no unittest), all tests in `./tests/` with typing annotations
19+
- Import typing fixtures when TYPE_CHECKING: `CaptureFixture`, `FixtureRequest`, `LogCaptureFixture`, `MonkeyPatch`, `MockerFixture`
20+
- Ruff formatting: line length 119, ignores E501, F403, E701, F401
21+
- Python 3.10+ required, supports up to 3.14
22+
- Dependencies: defusedxml, urllib3, xmltodict, pytest, pytest-cov

Makefile

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,19 +45,27 @@ clean-pyc: ## remove Python file artifacts
4545
find . -name '__pycache__' -exec rm -fr {} +
4646

4747
clean-test: ## remove test and coverage artifacts
48-
rm -fr .tox/
4948
rm -f .coverage
5049
rm -fr htmlcov/
5150
rm -fr .pytest_cache
51+
rm -fr coverage/
5252

53-
lint: ## check style with flake8
54-
flake8 json2xml tests
53+
lint: ## check style with ruff
54+
ruff check json2xml tests
55+
56+
lint-fix: ## automatically fix ruff issues
57+
ruff check --fix json2xml tests
58+
59+
typecheck: ## check types with mypy
60+
mypy json2xml tests
5561

5662
test: ## run tests quickly with the default Python
57-
pytest -vv
63+
pytest --cov=json2xml --cov-report=xml:coverage/reports/coverage.xml --cov-report=term -xvs tests -n auto
64+
65+
test-simple: ## run tests without coverage
66+
pytest -vv tests
5867

59-
test-all: ## run tests on every Python version with tox
60-
tox
68+
check-all: lint typecheck test ## run all checks (lint, typecheck, test)
6169

6270
coverage: ## check code coverage quickly with the default Python
6371
coverage run -m pytest -vv --disable-warnings

README.rst

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -191,17 +191,50 @@ Outputs this:
191191
The methods are simple and easy to use and there are also checks inside of code to exit cleanly
192192
in case any of the input(file, string or API URL) returns invalid JSON.
193193

194-
How to run tests
195-
^^^^^^^^^^^^^^^^
194+
Development
195+
^^^^^^^^^^^
196196

197-
This is provided by pytest, which is straight forward.
197+
This project uses modern Python development practices. Here's how to set up a development environment:
198198

199199
.. code-block:: console
200200
201-
virtualenv venv -p $(which python3.9)
202-
pip install -r requirements-dev.txt
203-
python setup.py install
204-
pytest -vv
201+
# Create and activate virtual environment (using uv - recommended)
202+
uv venv
203+
source .venv/bin/activate # On Windows: .venv\Scripts\activate
204+
205+
# Install dependencies
206+
uv pip install -r requirements-dev.txt
207+
uv pip install -e .
208+
209+
**Running Tests and Checks**
210+
211+
We provide several ways to run tests and quality checks:
212+
213+
Using Make (recommended):
214+
215+
.. code-block:: console
216+
217+
make test # Run tests with coverage
218+
make lint # Run linting with ruff
219+
make typecheck # Run type checking with mypy
220+
make check-all # Run all checks (lint, typecheck, test)
221+
222+
Using the development script:
223+
224+
.. code-block:: console
225+
226+
python dev.py # Run all checks
227+
python dev.py test # Run tests only
228+
python dev.py lint # Run linting only
229+
python dev.py typecheck # Run type checking only
230+
231+
Using tools directly:
232+
233+
.. code-block:: console
234+
235+
pytest --cov=json2xml --cov-report=term -xvs tests -n auto
236+
ruff check json2xml tests
237+
mypy json2xml tests
205238
206239
207240
Help and Support to maintain this project

dev.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
#!/usr/bin/env python3
2+
"""Development script for running tests, linting, and type checking."""
3+
4+
import subprocess
5+
import sys
6+
from pathlib import Path
7+
8+
9+
def run_command(cmd: list[str], description: str) -> bool:
10+
"""Run a command and return True if successful."""
11+
print(f"\n🔍 {description}...")
12+
try:
13+
result = subprocess.run(cmd, check=True, cwd=Path(__file__).parent)
14+
print(f"✅ {description} passed!")
15+
return True
16+
except subprocess.CalledProcessError as e:
17+
print(f"❌ {description} failed with exit code {e.returncode}")
18+
return False
19+
20+
21+
def main() -> None:
22+
"""Run development checks."""
23+
if len(sys.argv) > 1:
24+
command = sys.argv[1]
25+
else:
26+
command = "all"
27+
28+
success = True
29+
30+
if command in ("lint", "all"):
31+
success &= run_command(["ruff", "check", "json2xml", "tests"], "Linting")
32+
33+
if command in ("test", "all"):
34+
success &= run_command([
35+
"pytest", "--cov=json2xml", "--cov-report=term",
36+
"-xvs", "tests", "-n", "auto"
37+
], "Tests")
38+
39+
if command in ("typecheck", "all"):
40+
success &= run_command(["mypy", "json2xml", "tests"], "Type checking")
41+
42+
if command == "help":
43+
print("Usage: python dev.py [command]")
44+
print("Commands:")
45+
print(" all - Run all checks (default)")
46+
print(" lint - Run linting only")
47+
print(" test - Run tests only")
48+
print(" typecheck - Run type checking only")
49+
print(" help - Show this help")
50+
return
51+
52+
if not success:
53+
print(f"\n❌ Some checks failed!")
54+
sys.exit(1)
55+
else:
56+
print(f"\n🎉 All checks passed!")
57+
58+
59+
if __name__ == "__main__":
60+
main()

docs/conf.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,14 @@
1717
# relative to the documentation root, use os.path.abspath to make it
1818
# absolute, like shown here.
1919
#
20+
import datetime
2021
import os
2122
import sys
22-
import datetime
23+
2324
sys.path.insert(0, os.path.abspath('..'))
2425

2526
import json2xml
2627

27-
2828
year = datetime.datetime.now().year
2929

3030
# -- General configuration ---------------------------------------------

docs/requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ sphinxcontrib-serializinghtml==2.0.0
9494
# via sphinx
9595
starlette==0.45.3
9696
# via sphinx-autobuild
97-
tornado==6.4.2
97+
tornado==6.5.1
9898
# via -r requirements.in
9999
typing-extensions==4.12.2
100100
# via

0 commit comments

Comments
 (0)