ruff-sync 0.0.1.dev2__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 (40) hide show
  1. ruff_sync-0.0.1.dev2/.agents/TESTING.md +113 -0
  2. ruff_sync-0.0.1.dev2/.agents/workflows/add-test-case.md +38 -0
  3. ruff_sync-0.0.1.dev2/.github/dependabot.yml +9 -0
  4. ruff_sync-0.0.1.dev2/.github/workflows/ci.yaml +90 -0
  5. ruff_sync-0.0.1.dev2/.github/workflows/complexity.yaml +59 -0
  6. ruff_sync-0.0.1.dev2/.gitignore +182 -0
  7. ruff_sync-0.0.1.dev2/.pre-commit-config.yaml +39 -0
  8. ruff_sync-0.0.1.dev2/AGENTS.md +188 -0
  9. ruff_sync-0.0.1.dev2/LICENSE.md +22 -0
  10. ruff_sync-0.0.1.dev2/PKG-INFO +207 -0
  11. ruff_sync-0.0.1.dev2/README.md +195 -0
  12. ruff_sync-0.0.1.dev2/codecov.yml +9 -0
  13. ruff_sync-0.0.1.dev2/pyproject.toml +153 -0
  14. ruff_sync-0.0.1.dev2/ruff_sync.py +301 -0
  15. ruff_sync-0.0.1.dev2/scripts/dogfood.sh +46 -0
  16. ruff_sync-0.0.1.dev2/tasks.py +90 -0
  17. ruff_sync-0.0.1.dev2/tests/__init__.py +0 -0
  18. ruff_sync-0.0.1.dev2/tests/lifecycle_tomls/no_changes_final.toml +46 -0
  19. ruff_sync-0.0.1.dev2/tests/lifecycle_tomls/no_changes_initial.toml +46 -0
  20. ruff_sync-0.0.1.dev2/tests/lifecycle_tomls/no_changes_upstream.toml +16 -0
  21. ruff_sync-0.0.1.dev2/tests/lifecycle_tomls/no_dotted_keys_final.toml +46 -0
  22. ruff_sync-0.0.1.dev2/tests/lifecycle_tomls/no_dotted_keys_initial.toml +46 -0
  23. ruff_sync-0.0.1.dev2/tests/lifecycle_tomls/no_dotted_keys_upstream.toml +7 -0
  24. ruff_sync-0.0.1.dev2/tests/lifecycle_tomls/no_ruff_cfg_final.toml +39 -0
  25. ruff_sync-0.0.1.dev2/tests/lifecycle_tomls/no_ruff_cfg_initial.toml +27 -0
  26. ruff_sync-0.0.1.dev2/tests/lifecycle_tomls/no_ruff_cfg_upstream.toml +15 -0
  27. ruff_sync-0.0.1.dev2/tests/lifecycle_tomls/standard_final.toml +45 -0
  28. ruff_sync-0.0.1.dev2/tests/lifecycle_tomls/standard_initial.toml +46 -0
  29. ruff_sync-0.0.1.dev2/tests/lifecycle_tomls/standard_upstream.toml +15 -0
  30. ruff_sync-0.0.1.dev2/tests/ruff.toml +31 -0
  31. ruff_sync-0.0.1.dev2/tests/test_basic.py +443 -0
  32. ruff_sync-0.0.1.dev2/tests/test_corner_cases.py +77 -0
  33. ruff_sync-0.0.1.dev2/tests/test_e2e.py +109 -0
  34. ruff_sync-0.0.1.dev2/tests/test_project.py +66 -0
  35. ruff_sync-0.0.1.dev2/tests/test_toml_operations.py +35 -0
  36. ruff_sync-0.0.1.dev2/tests/test_whitespace.py +105 -0
  37. ruff_sync-0.0.1.dev2/tests/w_ruff_sync_cfg/pyproject.toml +51 -0
  38. ruff_sync-0.0.1.dev2/tests/wo_ruff_cfg/pyproject.toml +38 -0
  39. ruff_sync-0.0.1.dev2/tests/wo_ruff_sync_cfg/pyproject.toml +46 -0
  40. ruff_sync-0.0.1.dev2/uv.lock +1188 -0
@@ -0,0 +1,113 @@
1
+ # Testing Standards for ruff-sync
2
+
3
+ This document defines the mandatory testing standards and patterns for the `ruff-sync` project. AI agents MUST follow these guidelines when adding or modifying tests.
4
+
5
+ ## 1. Core Principles
6
+
7
+ - **Every Fix Needs a Test**: Any bug fix must include a reproduction test that fails without the fix and passes with it.
8
+ - **No Side Effects**: Tests must be isolated and not touch the actual filesystem or make real network calls.
9
+ - **Semantic + Structural Assertions**: When testing TOML merges, always verify **both**:
10
+ 1. **Structural/Whitespace**: The file "looks" correct (comments and spacing are preserved).
11
+ 2. **Semantic**: The actual data in the merged result matches the expected values.
12
+ - **DRY with Fixtures and Parameterization**: Avoid code duplication. Use fixtures for common setups and `@pytest.mark.parametrize` for matrix testing.
13
+
14
+ ## 2. Tooling and Environment
15
+
16
+ - **Execution**: Always run tests using `poetry run pytest -vv`.
17
+ - **Async Tests**: We use `pytest-asyncio` in **strict mode**.
18
+ - Always decorate async tests with `@pytest.mark.asyncio`.
19
+ - **HTTP Mocking**: Use [respx](https://github.com/lundberg/respx) for all network interactions.
20
+ - **FS Mocking**: Use [pyfakefs](https://jmcgeheeiv.github.io/pyfakefs/) for file-based tests.
21
+
22
+ ## 3. Best Practices and Patterns
23
+
24
+ ### 3.1 Use Pytest Fixtures
25
+ Avoid re-defining common TOML strings or setup logic in every test function. Use fixtures to provide consistent test data.
26
+
27
+ ```python
28
+ @pytest.fixture
29
+ def sample_ruff_config() -> str:
30
+ return """[tool.ruff]
31
+ target-version = "py310"
32
+ lint.select = ["F", "E"]
33
+ """
34
+ ```
35
+
36
+ ### 3.2 Parameterization
37
+ Use `@pytest.mark.parametrize` to test the same logic against multiple scenarios. Use `pytest.param(..., id="case_name")` to ensure test reports are readable.
38
+
39
+ ```python
40
+ @pytest.mark.parametrize(
41
+ "source, upstream, expected_keys",
42
+ [
43
+ pytest.param("[tool.ruff]\nselect=[]", "select=['F']", {"select"}, id="simple-add"),
44
+ pytest.param("[tool.ruff]\nignore=['E']", "ignore=['W']", {"ignore"}, id="simple-merge"),
45
+ ]
46
+ )
47
+ def test_merge_scenarios(source, upstream, expected_keys):
48
+ # ... test logic ...
49
+ ```
50
+
51
+ ## 4. Handling TOML and `tomlkit`
52
+
53
+ `tomlkit` is central to this project but its dynamic type system can be tricky for mypy.
54
+
55
+ ### The "Proxy" Problem
56
+ `tomlkit` often returns "proxy" objects (like dotted keys) that don't always behave like standard dicts.
57
+ - **Assertion Pattern**: To satisfy mypy when indexing into a parsed document in tests, use the `cast(Any, ...)` pattern:
58
+ ```python
59
+ from typing import Any, cast
60
+ import tomlkit
61
+
62
+ doc = tomlkit.parse(content)
63
+ # Cast the document or table to Any before deep indexing
64
+ ruff_cfg = cast(Any, doc)["tool"]["ruff"]
65
+ assert ruff_cfg["target-version"] == "py310"
66
+ ```
67
+ - **Comparison**: Use `list()` or `.unwrap()` if you need to compare `tomlkit` arrays/objects to standard Python types.
68
+
69
+ ## 4. Lifecycle TOML Fixtures
70
+
71
+ For end-to-end (E2E) testing of the sync/merge logic, use the "Lifecycle" pattern.
72
+
73
+ ### Fixture Triples
74
+ Each test case consists of three files in `tests/lifecycle_tomls/`:
75
+ 1. `<case_name>_initial.toml`: The starting project state.
76
+ 2. `<case_name>_upstream.toml`: The remote ruff config to sync from.
77
+ 3. `<case_name>_final.toml`: The expected result after merge.
78
+
79
+ ### Scaffolding New Cases
80
+ Use the provided Invoke task to create a new case from a template:
81
+ ```bash
82
+ poetry run invoke new-case --name <case_name> --description "Description of the edge case"
83
+ ```
84
+
85
+ ## 5. Standard Assertions for Merges
86
+
87
+ When testing `merge_ruff_toml`, your test body should look like this:
88
+
89
+ ```python
90
+ def test_my_edge_case():
91
+ source_s = "..."
92
+ upstream_s = "..."
93
+
94
+ source_doc = tomlkit.parse(source_s)
95
+ upstream_ruff = cast(Any, tomlkit.parse(upstream_s))["tool"]["ruff"]
96
+
97
+ merged_doc = ruff_sync.merge_ruff_toml(source_doc, upstream_ruff)
98
+ merged_s = merged_doc.as_string()
99
+
100
+ # 1. Structural check (e.g., check for comment preservation)
101
+ assert "# Important comment" in merged_s
102
+
103
+ # 2. Semantic check (the "Source of Truth")
104
+ merged_data = tomlkit.parse(merged_s)
105
+ ruff = cast(Any, merged_data)["tool"]["ruff"]
106
+ assert ruff["lint"]["select"] == ["F", "E"]
107
+ ```
108
+
109
+ ## 6. Code Coverage
110
+
111
+ We target **high coverage** for `ruff_sync.py`.
112
+ - Run coverage locally: `poetry run coverage run -m pytest -vv && poetry run coverage report`
113
+ - New features MUST include unit tests in `tests/test_basic.py` or specialized files like `tests/test_whitespace.py` if they involve formatting logic.
@@ -0,0 +1,38 @@
1
+ ---
2
+ description: How to add a new lifecycle TOML test case for ruff-sync
3
+ ---
4
+
5
+ Follow these steps to add a new end-to-end (E2E) test case for `ruff-sync` to test a specific sync or merge scenario.
6
+
7
+ ### 1. Identify the Edge Case or Bug
8
+ - Clearly define the "Initial" state (local `pyproject.toml`) and the "Upstream" state (remote `pyproject.toml`).
9
+ - Define the "Final" expected state after the sync.
10
+
11
+ ### 2. Scaffold the Fixture
12
+ // turbo
13
+ 1. Run the `new-case` task to generate the file triple:
14
+ ```bash
15
+ poetry run invoke new-case --name <case_name> --description "Description of the test case"
16
+ ```
17
+ *Replace `<case_name>` with a simple name (e.g., `dotted_keys`). This creates files in `tests/lifecycle_tomls/`.*
18
+
19
+ ### 3. Edit the Fixtures
20
+ 1. Edit `tests/lifecycle_tomls/<case_name>_initial.toml` with the local starting state.
21
+ 2. Edit `tests/lifecycle_tomls/<case_name>_upstream.toml` with the remote config (must contain a `[tool.ruff]` section).
22
+ 3. Edit `tests/lifecycle_tomls/<case_name>_final.toml` with the expected result of the merge.
23
+
24
+ ### 4. Run the E2E Test Suite
25
+ // turbo
26
+ 1. Execute the tests to ensure the new case is picked up:
27
+ ```bash
28
+ poetry run pytest -vv tests/test_e2e.py
29
+ ```
30
+ *The E2E suite automatically discovers all file triples in the `lifecycle_tomls/` directory.*
31
+
32
+ ### 5. Validate Formatting and Types
33
+ // turbo
34
+ 1. Ensure the new TOML files don't break any project rules:
35
+ ```bash
36
+ poetry run invoke lint --check
37
+ poetry run invoke types
38
+ ```
@@ -0,0 +1,9 @@
1
+ # Please see the documentation for all configuration options:
2
+ # https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
3
+
4
+ version: 2
5
+ updates:
6
+ - package-ecosystem: "pip" # Documentation: For package managers such as pipenv and poetry, you need to use the pip YAML value.
7
+ directory: "/" # Location of package manifests
8
+ schedule:
9
+ interval: daily
@@ -0,0 +1,90 @@
1
+ name: ci
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+ pull_request:
8
+ schedule:
9
+ - cron: "0 */6 * * *"
10
+
11
+ jobs:
12
+ static-analysis:
13
+ strategy:
14
+ matrix:
15
+ task: ["lint", "fmt", "type-check"]
16
+ fail-fast: false
17
+ runs-on: ubuntu-latest
18
+
19
+ steps:
20
+ - name: Checkout
21
+ uses: actions/checkout@v4
22
+
23
+ - name: Install uv
24
+ uses: astral-sh/setup-uv@v5
25
+
26
+ - name: Set up Python
27
+ run: uv python install 3.10
28
+
29
+ - name: Install dependencies
30
+ run: uv sync --group dev --frozen
31
+
32
+ - run: uv run invoke ${{ matrix.task }} --check
33
+
34
+ tests:
35
+ strategy:
36
+ matrix:
37
+ python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
38
+
39
+ runs-on: ubuntu-latest
40
+
41
+ steps:
42
+ - name: Checkout
43
+ uses: actions/checkout@v4
44
+
45
+ - name: Install uv
46
+ uses: astral-sh/setup-uv@v5
47
+
48
+ - name: Set up Python ${{ matrix.python-version }}
49
+ run: uv python install ${{ matrix.python-version }}
50
+
51
+ - name: Install dependencies
52
+ run: uv sync --group dev --frozen
53
+
54
+ - name: Run tests
55
+ run: uv run coverage run -m pytest -vv
56
+
57
+ - name: Generate coverage report
58
+ run: uv run coverage xml
59
+
60
+ - name: Upload coverage reports to Codecov
61
+ uses: codecov/codecov-action@v4.0.1
62
+ with:
63
+ token: ${{ secrets.CODECOV_TOKEN }}
64
+ slug: Kilo59/ruff-sync
65
+
66
+ publish:
67
+ name: Build and publish to PyPI
68
+ if: github.event_name == 'push' && github.ref == 'refs/heads/main'
69
+ needs: [static-analysis, tests]
70
+ runs-on: ubuntu-latest
71
+ permissions:
72
+ # This permission is required for trusted publishing
73
+ id-token: write
74
+ # This permission is required to read the repository content
75
+ contents: read
76
+ steps:
77
+ - name: Checkout
78
+ uses: actions/checkout@v4
79
+
80
+ - name: Install uv
81
+ uses: astral-sh/setup-uv@v5
82
+
83
+ - name: Set up Python
84
+ run: uv python install 3.10
85
+
86
+ - name: Build package
87
+ run: uv build
88
+
89
+ - name: Publish package
90
+ run: uv publish
@@ -0,0 +1,59 @@
1
+ name: complexity
2
+
3
+ on:
4
+ pull_request:
5
+
6
+ jobs:
7
+ evaluate-complexity:
8
+ name: wily check
9
+ runs-on: ubuntu-latest
10
+ permissions:
11
+ pull-requests: write
12
+
13
+ steps:
14
+ - name: Checkout repository
15
+ uses: actions/checkout@v2
16
+ with:
17
+ fetch-depth: 0
18
+ ref: ${{ github.event.pull_request.head.ref }}
19
+ - name: Set up Python
20
+ uses: actions/setup-python@v2
21
+ with:
22
+ python-version: 3.9
23
+ - name: Install Wily
24
+ run: pip install 'wily>=1.25.0'
25
+ - name: Build cache and diff
26
+ id: wily
27
+ run: |
28
+ wily build ruff_sync.py tasks.py tests/
29
+ DIFF=$(wily diff ruff_sync.py tasks.py tests/ --no-detail -r origin/${{ github.event.pull_request.base.ref }})
30
+ echo "$DIFF"
31
+
32
+ # Build multine output
33
+ DIFF="${DIFF//'%'/'%25'}"
34
+ DIFF="${DIFF//$'\n'/'%0A'}"
35
+ DIFF="${DIFF//$'\r'/'%0D'}"
36
+ echo "::set-output name=diff::$DIFF"
37
+ - name: Find current PR
38
+ uses: jwalton/gh-find-current-pr@v1
39
+ id: findPr
40
+ - name: Add Wily PR Comment
41
+ uses: marocchino/sticky-pull-request-comment@v2
42
+ if: steps.findPr.outputs.number && steps.wily.outputs.diff != ''
43
+ with:
44
+ recreate: true
45
+ number: ${{ steps.findPr.outputs.number }}
46
+ message: |
47
+ ```
48
+ ${{ steps.wily.outputs.diff }}
49
+ ```
50
+ - name: Add Wily PR Comment
51
+ uses: marocchino/sticky-pull-request-comment@v2
52
+ if: steps.findPr.outputs.number && steps.wily.outputs.diff == ''
53
+ with:
54
+ recreate: true
55
+ number: ${{ steps.findPr.outputs.number }}
56
+ message: |
57
+ ```
58
+ Wily: No changes in complexity detected.
59
+ ```
@@ -0,0 +1,182 @@
1
+ # Generated by Cargo
2
+ # will have compiled files and executables
3
+ /target/
4
+
5
+ # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
6
+ # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
7
+ Cargo.lock
8
+
9
+ # These are backup files generated by rustfmt
10
+ **/*.rs.bk
11
+
12
+ # Python
13
+
14
+ # Byte-compiled / optimized / DLL files
15
+ __pycache__/
16
+ *.py[cod]
17
+ *$py.class
18
+
19
+ # C extensions
20
+ *.so
21
+
22
+ # Distribution / packaging
23
+ .Python
24
+ build/
25
+ develop-eggs/
26
+ dist/
27
+ downloads/
28
+ eggs/
29
+ .eggs/
30
+ lib/
31
+ lib64/
32
+ parts/
33
+ sdist/
34
+ var/
35
+ wheels/
36
+ share/python-wheels/
37
+ *.egg-info/
38
+ .installed.cfg
39
+ *.egg
40
+ MANIFEST
41
+
42
+ # PyInstaller
43
+ # Usually these files are written by a python script from a template
44
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
45
+ *.manifest
46
+ *.spec
47
+
48
+ # Installer logs
49
+ pip-log.txt
50
+ pip-delete-this-directory.txt
51
+
52
+ # Unit test / coverage reports
53
+ htmlcov/
54
+ .tox/
55
+ .nox/
56
+ .coverage
57
+ .coverage.*
58
+ .cache
59
+ nosetests.xml
60
+ coverage.xml
61
+ *.cover
62
+ *.py,cover
63
+ .hypothesis/
64
+ .pytest_cache/
65
+ cover/
66
+
67
+ # Translations
68
+ *.mo
69
+ *.pot
70
+
71
+ # Django stuff:
72
+ *.log
73
+ local_settings.py
74
+ db.sqlite3
75
+ db.sqlite3-journal
76
+
77
+ # Flask stuff:
78
+ instance/
79
+ .webassets-cache
80
+
81
+ # Scrapy stuff:
82
+ .scrapy
83
+
84
+ # Sphinx documentation
85
+ docs/_build/
86
+
87
+ # PyBuilder
88
+ .pybuilder/
89
+ target/
90
+
91
+ # Jupyter Notebook
92
+ .ipynb_checkpoints
93
+
94
+ # IPython
95
+ profile_default/
96
+ ipython_config.py
97
+
98
+ # pyenv
99
+ # For a library or package, you might want to ignore these files since the code is
100
+ # intended to run in multiple environments; otherwise, check them in:
101
+ # .python-version
102
+
103
+ # pipenv
104
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
105
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
106
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
107
+ # install all needed dependencies.
108
+ #Pipfile.lock
109
+
110
+ # poetry
111
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
112
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
113
+ # commonly ignored for libraries.
114
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
115
+ #poetry.lock
116
+
117
+ # pdm
118
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
119
+ #pdm.lock
120
+ # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
121
+ # in version control.
122
+ # https://pdm.fming.dev/#use-with-ide
123
+ .pdm.toml
124
+
125
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
126
+ __pypackages__/
127
+
128
+ # Celery stuff
129
+ celerybeat-schedule
130
+ celerybeat.pid
131
+
132
+ # SageMath parsed files
133
+ *.sage.py
134
+
135
+ # Environments
136
+ .env
137
+ .venv
138
+ env/
139
+ venv/
140
+ ENV/
141
+ env.bak/
142
+ venv.bak/
143
+
144
+ # Spyder project settings
145
+ .spyderproject
146
+ .spyproject
147
+
148
+ # Rope project settings
149
+ .ropeproject
150
+
151
+ # mkdocs documentation
152
+ /site
153
+
154
+ # mypy
155
+ .mypy_cache/
156
+ .dmypy.json
157
+ dmypy.json
158
+
159
+ # Pyre type checker
160
+ .pyre/
161
+
162
+ # pytype static type analyzer
163
+ .pytype/
164
+
165
+ # Cython debug symbols
166
+ cython_debug/
167
+
168
+ # Agent-generated log files
169
+ logs/
170
+
171
+ # IDEs
172
+
173
+ # PyCharm
174
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
175
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
176
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
177
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
178
+ .idea/
179
+
180
+ # VSCode
181
+ .vscode
182
+ .DS_Store
@@ -0,0 +1,39 @@
1
+ repos:
2
+ - repo: https://github.com/pre-commit/pre-commit-hooks
3
+ rev: v6.0.0
4
+ hooks:
5
+ - id: check-ast
6
+ - id: check-json
7
+ - id: check-yaml
8
+ args: ["--unsafe"]
9
+ - id: end-of-file-fixer
10
+ - id: trailing-whitespace
11
+ - id: no-commit-to-branch
12
+ args: [--branch, develop, --branch, main]
13
+ - repo: https://github.com/astral-sh/ruff-pre-commit
14
+ rev: "v0.15.5"
15
+ hooks:
16
+ - id: ruff-check
17
+ args: ["--fix"]
18
+ - id: ruff-format
19
+ - repo: https://github.com/pre-commit/mirrors-prettier
20
+ rev: v4.0.0-alpha.8
21
+ hooks:
22
+ - id: prettier
23
+ types_or: [yaml, json]
24
+ - repo: https://github.com/rhysd/actionlint
25
+ rev: v1.7.11
26
+ hooks:
27
+ - id: actionlint
28
+ exclude: .github/workflows/complexity.yaml
29
+ # https://pre-commit.ci/
30
+ ci:
31
+ autofix_commit_msg: |
32
+ [pre-commit.ci] auto fixes from pre-commit.com hooks
33
+
34
+ for more information, see https://pre-commit.ci
35
+ autofix_prs: true
36
+ autoupdate_branch: "main"
37
+ autoupdate_commit_msg: "[pre-commit.ci] pre-commit autoupdate"
38
+ autoupdate_schedule: weekly
39
+ submodules: false