lixinger-python 0.1.2__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.
- lixinger_python-0.1.2/.claude/settings.local.json +56 -0
- lixinger_python-0.1.2/.env.example +21 -0
- lixinger_python-0.1.2/.github/copilot-instructions.md +13 -0
- lixinger_python-0.1.2/.github/workflows/README.md +141 -0
- lixinger_python-0.1.2/.github/workflows/pr-checks.yml +189 -0
- lixinger_python-0.1.2/.gitignore +25 -0
- lixinger_python-0.1.2/.pre-commit-config.yaml +110 -0
- lixinger_python-0.1.2/.python-version +1 -0
- lixinger_python-0.1.2/.ruff.toml +121 -0
- lixinger_python-0.1.2/ADD_NEW_API_QUICK.md +150 -0
- lixinger_python-0.1.2/AGENTS.md +331 -0
- lixinger_python-0.1.2/CHANGELOG.md +48 -0
- lixinger_python-0.1.2/CLAUDE.md +256 -0
- lixinger_python-0.1.2/DOCS.md +334 -0
- lixinger_python-0.1.2/LICENSE +21 -0
- lixinger_python-0.1.2/MANIFEST.in +9 -0
- lixinger_python-0.1.2/PKG-INFO +171 -0
- lixinger_python-0.1.2/PUBLISHING.md +246 -0
- lixinger_python-0.1.2/README.md +145 -0
- lixinger_python-0.1.2/SETUP.md +273 -0
- lixinger_python-0.1.2/codecov.yml +104 -0
- lixinger_python-0.1.2/docs/api/client.md +7 -0
- lixinger_python-0.1.2/docs/api/company/announcement.md +36 -0
- lixinger_python-0.1.2/docs/api/company/candlestick.md +100 -0
- lixinger_python-0.1.2/docs/api/company/company.md +90 -0
- lixinger_python-0.1.2/docs/api/company/dividend.md +36 -0
- lixinger_python-0.1.2/docs/api/company/equity_change.md +132 -0
- lixinger_python-0.1.2/docs/api/company/fs/non_financial.md +37 -0
- lixinger_python-0.1.2/docs/api/company/fundamental.md +93 -0
- lixinger_python-0.1.2/docs/api/company/indices.md +34 -0
- lixinger_python-0.1.2/docs/api/company/profile.md +91 -0
- lixinger_python-0.1.2/docs/api/fund/announcement.md +36 -0
- lixinger_python-0.1.2/docs/api/fund/asset_combination.md +36 -0
- lixinger_python-0.1.2/docs/api/fund/asset_industry_combination.md +36 -0
- lixinger_python-0.1.2/docs/api/fund/candlestick.md +37 -0
- lixinger_python-0.1.2/docs/api/fund/fund.md +34 -0
- lixinger_python-0.1.2/docs/api/fund/profile.md +34 -0
- lixinger_python-0.1.2/docs/api/fund/shareholdings.md +36 -0
- lixinger_python-0.1.2/docs/api/index/candlestick.md +37 -0
- lixinger_python-0.1.2/docs/api/index/constituent_weightings.md +36 -0
- lixinger_python-0.1.2/docs/api/index/constituents.md +35 -0
- lixinger_python-0.1.2/docs/api/index/drawdown.md +38 -0
- lixinger_python-0.1.2/docs/api/index/fundamental.md +37 -0
- lixinger_python-0.1.2/docs/api/index/index.md +34 -0
- lixinger_python-0.1.2/docs/api/index/tracking_fund.md +34 -0
- lixinger_python-0.1.2/docs/api/overview.md +142 -0
- lixinger_python-0.1.2/docs/development/code-style.md +5 -0
- lixinger_python-0.1.2/docs/development/contributing.md +5 -0
- lixinger_python-0.1.2/docs/development/testing.md +5 -0
- lixinger_python-0.1.2/docs/examples/company.md +24 -0
- lixinger_python-0.1.2/docs/examples/fund.md +5 -0
- lixinger_python-0.1.2/docs/examples/index.md +5 -0
- lixinger_python-0.1.2/docs/getting-started/configuration.md +362 -0
- lixinger_python-0.1.2/docs/getting-started/installation.md +138 -0
- lixinger_python-0.1.2/docs/getting-started/quickstart.md +256 -0
- lixinger_python-0.1.2/docs/index.md +109 -0
- lixinger_python-0.1.2/examples/company_example.py +39 -0
- lixinger_python-0.1.2/examples/company_profile_example.py +32 -0
- lixinger_python-0.1.2/fund_response.json +1 -0
- lixinger_python-0.1.2/lixinger/__init__.py +79 -0
- lixinger_python-0.1.2/lixinger/api/__init__.py +0 -0
- lixinger_python-0.1.2/lixinger/api/base.py +94 -0
- lixinger_python-0.1.2/lixinger/api/cn/__init__.py +0 -0
- lixinger_python-0.1.2/lixinger/api/cn/company/__init__.py +34 -0
- lixinger_python-0.1.2/lixinger/api/cn/company/announcement.py +74 -0
- lixinger_python-0.1.2/lixinger/api/cn/company/candlestick.py +76 -0
- lixinger_python-0.1.2/lixinger/api/cn/company/company.py +88 -0
- lixinger_python-0.1.2/lixinger/api/cn/company/dividend.py +67 -0
- lixinger_python-0.1.2/lixinger/api/cn/company/equity_change.py +84 -0
- lixinger_python-0.1.2/lixinger/api/cn/company/fs/__init__.py +5 -0
- lixinger_python-0.1.2/lixinger/api/cn/company/fs/non_financial.py +77 -0
- lixinger_python-0.1.2/lixinger/api/cn/company/fundamental.py +228 -0
- lixinger_python-0.1.2/lixinger/api/cn/company/indices.py +52 -0
- lixinger_python-0.1.2/lixinger/api/cn/company/namespace.py +66 -0
- lixinger_python-0.1.2/lixinger/api/cn/company/profile.py +66 -0
- lixinger_python-0.1.2/lixinger/api/cn/fund/__init__.py +35 -0
- lixinger_python-0.1.2/lixinger/api/cn/fund/announcement.py +89 -0
- lixinger_python-0.1.2/lixinger/api/cn/fund/asset_combination.py +82 -0
- lixinger_python-0.1.2/lixinger/api/cn/fund/asset_industry_combination.py +93 -0
- lixinger_python-0.1.2/lixinger/api/cn/fund/candlestick.py +84 -0
- lixinger_python-0.1.2/lixinger/api/cn/fund/fund.py +70 -0
- lixinger_python-0.1.2/lixinger/api/cn/fund/profile.py +60 -0
- lixinger_python-0.1.2/lixinger/api/cn/fund/shareholdings.py +86 -0
- lixinger_python-0.1.2/lixinger/api/cn/index/__init__.py +32 -0
- lixinger_python-0.1.2/lixinger/api/cn/index/candlestick.py +86 -0
- lixinger_python-0.1.2/lixinger/api/cn/index/constituent_weightings.py +71 -0
- lixinger_python-0.1.2/lixinger/api/cn/index/constituents.py +71 -0
- lixinger_python-0.1.2/lixinger/api/cn/index/drawdown.py +87 -0
- lixinger_python-0.1.2/lixinger/api/cn/index/fundamental.py +87 -0
- lixinger_python-0.1.2/lixinger/api/cn/index/index.py +69 -0
- lixinger_python-0.1.2/lixinger/api/cn/index/tracking_fund.py +71 -0
- lixinger_python-0.1.2/lixinger/client.py +184 -0
- lixinger_python-0.1.2/lixinger/config.py +72 -0
- lixinger_python-0.1.2/lixinger/exceptions.py +22 -0
- lixinger_python-0.1.2/lixinger/models/__init__.py +5 -0
- lixinger_python-0.1.2/lixinger/models/cn/__init__.py +1 -0
- lixinger_python-0.1.2/lixinger/models/cn/company/__init__.py +20 -0
- lixinger_python-0.1.2/lixinger/models/cn/company/announcement.py +20 -0
- lixinger_python-0.1.2/lixinger/models/cn/company/candlestick.py +24 -0
- lixinger_python-0.1.2/lixinger/models/cn/company/company.py +33 -0
- lixinger_python-0.1.2/lixinger/models/cn/company/dividend.py +25 -0
- lixinger_python-0.1.2/lixinger/models/cn/company/equity_change.py +26 -0
- lixinger_python-0.1.2/lixinger/models/cn/company/fs/__init__.py +5 -0
- lixinger_python-0.1.2/lixinger/models/cn/company/fs/non_financial.py +20 -0
- lixinger_python-0.1.2/lixinger/models/cn/company/fundamental.py +16 -0
- lixinger_python-0.1.2/lixinger/models/cn/company/indices.py +17 -0
- lixinger_python-0.1.2/lixinger/models/cn/fund/__init__.py +19 -0
- lixinger_python-0.1.2/lixinger/models/cn/fund/announcement.py +21 -0
- lixinger_python-0.1.2/lixinger/models/cn/fund/asset_combination.py +40 -0
- lixinger_python-0.1.2/lixinger/models/cn/fund/asset_industry_combination.py +24 -0
- lixinger_python-0.1.2/lixinger/models/cn/fund/candlestick.py +23 -0
- lixinger_python-0.1.2/lixinger/models/cn/fund/fund.py +23 -0
- lixinger_python-0.1.2/lixinger/models/cn/fund/profile.py +28 -0
- lixinger_python-0.1.2/lixinger/models/cn/fund/shareholdings.py +21 -0
- lixinger_python-0.1.2/lixinger/models/cn/index/__init__.py +19 -0
- lixinger_python-0.1.2/lixinger/models/cn/index/candlestick.py +22 -0
- lixinger_python-0.1.2/lixinger/models/cn/index/constituent_weightings.py +16 -0
- lixinger_python-0.1.2/lixinger/models/cn/index/constituents.py +17 -0
- lixinger_python-0.1.2/lixinger/models/cn/index/drawdown.py +16 -0
- lixinger_python-0.1.2/lixinger/models/cn/index/fundamental.py +16 -0
- lixinger_python-0.1.2/lixinger/models/cn/index/index.py +24 -0
- lixinger_python-0.1.2/lixinger/models/cn/index/tracking_fund.py +19 -0
- lixinger_python-0.1.2/lixinger/py.typed +0 -0
- lixinger_python-0.1.2/lixinger/utils/__init__.py +0 -0
- lixinger_python-0.1.2/lixinger/utils/api.py +15 -0
- lixinger_python-0.1.2/lixinger/utils/dataframe.py +57 -0
- lixinger_python-0.1.2/lixinger/utils/dict.py +22 -0
- lixinger_python-0.1.2/lixinger/utils/rate_limiter.py +35 -0
- lixinger_python-0.1.2/lixinger/utils/retry.py +31 -0
- lixinger_python-0.1.2/mkdocs.yml +149 -0
- lixinger_python-0.1.2/mypy.ini +5 -0
- lixinger_python-0.1.2/pyproject.toml +129 -0
- lixinger_python-0.1.2/scripts/explore_api.py +118 -0
- lixinger_python-0.1.2/scripts/generate_docs.py +492 -0
- lixinger_python-0.1.2/scripts/publish.sh +56 -0
- lixinger_python-0.1.2/tests/api/cn/company/test_announcement.py +77 -0
- lixinger_python-0.1.2/tests/api/cn/company/test_dividend.py +57 -0
- lixinger_python-0.1.2/tests/conftest.py +12 -0
- lixinger_python-0.1.2/tests/test_candlestick.py +121 -0
- lixinger_python-0.1.2/tests/test_client.py +46 -0
- lixinger_python-0.1.2/tests/test_cn_index_candlestick.py +116 -0
- lixinger_python-0.1.2/tests/test_cn_index_constituent_weightings.py +62 -0
- lixinger_python-0.1.2/tests/test_company.py +73 -0
- lixinger_python-0.1.2/tests/test_company_profile.py +77 -0
- lixinger_python-0.1.2/tests/test_equity_change.py +114 -0
- lixinger_python-0.1.2/tests/test_fund.py +78 -0
- lixinger_python-0.1.2/tests/test_fund_announcement.py +91 -0
- lixinger_python-0.1.2/tests/test_fund_asset_combination.py +150 -0
- lixinger_python-0.1.2/tests/test_fund_asset_industry_combination.py +75 -0
- lixinger_python-0.1.2/tests/test_fund_candlestick.py +81 -0
- lixinger_python-0.1.2/tests/test_fund_profile.py +89 -0
- lixinger_python-0.1.2/tests/test_fund_shareholdings.py +89 -0
- lixinger_python-0.1.2/tests/test_fundamental.py +82 -0
- lixinger_python-0.1.2/tests/test_index.py +80 -0
- lixinger_python-0.1.2/tests/test_index_constituents.py +90 -0
- lixinger_python-0.1.2/tests/test_index_drawdown.py +53 -0
- lixinger_python-0.1.2/tests/test_index_fundamental.py +99 -0
- lixinger_python-0.1.2/tests/test_indices.py +59 -0
- lixinger_python-0.1.2/tests/test_integration.py +634 -0
- lixinger_python-0.1.2/tests/test_non_financial_statements.py +110 -0
- lixinger_python-0.1.2/tests/test_tracking_fund.py +85 -0
- lixinger_python-0.1.2/uv.lock +1863 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"permissions": {
|
|
3
|
+
"allow": [
|
|
4
|
+
"Bash(tree -L 3 -I \".venv|venv|__pycache__|*.pyc\")",
|
|
5
|
+
"Bash(find . -type d -not -path ./.venv/* -not -path ./.git/*)",
|
|
6
|
+
"Bash(uv --version)",
|
|
7
|
+
"WebFetch(domain:www.lixinger.com)",
|
|
8
|
+
"Bash(uv add python-dotenv)",
|
|
9
|
+
"Bash(python -c \"from lixinger.config import get_config_from_env; print\\(''Config module loads successfully''\\)\")",
|
|
10
|
+
"Bash(python -c \"from lixinger import LixingerClient; print\\(''LixingerClient imports successfully''\\)\")",
|
|
11
|
+
"Bash(ls -la .env*)",
|
|
12
|
+
"Bash(python -c \"\nimport sys\nsys.path.insert\\(0, ''.''\\)\n\n# Test that api_key parameter doesn''t exist\nfrom lixinger.client import LixingerClient\nimport inspect\n\nsig = inspect.signature\\(LixingerClient.__init__\\)\nparams = list\\(sig.parameters.keys\\(\\)\\)\nprint\\(''LixingerClient.__init__ parameters:'', params\\)\nprint\\(\\)\nprint\\(''✓ api_key parameter removed!'' if ''api_key'' not in params else ''✗ api_key still exists!''\\)\nprint\\(''✓ Only keyword-only parameters remain''\\)\n\")",
|
|
13
|
+
"Bash(uv add --dev pre-commit)",
|
|
14
|
+
"Bash(uv pip install -e .)",
|
|
15
|
+
"Bash(python -c \"import lixinger; print\\(''✓ lixinger imports successfully''\\)\")",
|
|
16
|
+
"Bash(python -c \"from lixinger import LixingerClient; print\\(''✓ LixingerClient imports successfully''\\)\")",
|
|
17
|
+
"Bash(python -c \"import yaml; yaml.safe_load\\(open\\(''codecov.yml''\\)\\)\")",
|
|
18
|
+
"Bash(python3 -c \"\nimport yaml\n\nwith open\\(''codecov.yml'', ''r''\\) as f:\n config = yaml.safe_load\\(f\\)\n\nprint\\(''✅ Codecov Configuration Validation\\\\n''\\)\nprint\\(f''Project Coverage Target: {config[\"\"coverage\"\"][\"\"status\"\"][\"\"project\"\"][\"\"default\"\"][\"\"target\"\"]}''\\)\nprint\\(f''Project Threshold: {config[\"\"coverage\"\"][\"\"status\"\"][\"\"project\"\"][\"\"default\"\"][\"\"threshold\"\"]}''\\)\nprint\\(f''Patch Coverage Target: {config[\"\"coverage\"\"][\"\"status\"\"][\"\"patch\"\"][\"\"default\"\"][\"\"target\"\"]}''\\)\nprint\\(f''Patch Threshold: {config[\"\"coverage\"\"][\"\"status\"\"][\"\"patch\"\"][\"\"default\"\"][\"\"threshold\"\"]}''\\)\nprint\\(f''\\\\nFlags Configured: {list\\(config[\"\"flags\"\"].keys\\(\\)\\)}''\\)\nprint\\(f''Components: {len\\(config[\"\"component_management\"\"][\"\"individual_components\"\"]\\)} defined''\\)\nprint\\(f''GitHub Annotations: {config[\"\"github_checks\"\"][\"\"annotations\"\"]}''\\)\nprint\\(f''\\\\n✅ All fields are valid!''\\)\n\")",
|
|
19
|
+
"Bash(curl --data-binary @codecov.yml https://codecov.io/validate)",
|
|
20
|
+
"WebFetch(domain:docs.codecov.com)",
|
|
21
|
+
"WebSearch",
|
|
22
|
+
"Bash(python3 -c \"import yaml; yaml.safe_load\\(open\\(''''codecov.yml''''\\)\\)\")",
|
|
23
|
+
"Bash(ls -1 codecov.yml docs/CODECOV*.md)",
|
|
24
|
+
"Bash(curl -s --data-binary @codecov.yml https://codecov.io/validate)",
|
|
25
|
+
"Bash(uv run ruff check /Users/JianGuo/Documents/CursorProject/lixinger-python/AGENTS.md)",
|
|
26
|
+
"Bash(ls -la /Users/JianGuo/Documents/CursorProject/lixinger-python/*.md)",
|
|
27
|
+
"Bash(tree /Users/JianGuo/Documents/CursorProject/lixinger-python/lixinger/api -L 3)",
|
|
28
|
+
"Bash(tree /Users/JianGuo/Documents/CursorProject/lixinger-python/lixinger/models -L 3)",
|
|
29
|
+
"Bash(uv run pytest tests/ -m \"not integration\" -v)",
|
|
30
|
+
"Bash(uv run ruff check lixinger/)",
|
|
31
|
+
"Bash(uv run mypy lixinger/)",
|
|
32
|
+
"Bash(uv run pytest tests/ -m \"not integration\" --tb=short)",
|
|
33
|
+
"Bash(tree /Users/JianGuo/Documents/CursorProject/lixinger-python/lixinger -L 4 -I __pycache__)",
|
|
34
|
+
"Bash(uv run ruff check .)",
|
|
35
|
+
"Bash(find /Users/JianGuo/Documents/CursorProject/lixinger-python/examples -name *.py)",
|
|
36
|
+
"Bash(tree /Users/JianGuo/Documents/CursorProject/lixinger-python/lixinger -L 4 -I '__pycache__|*.pyc' --dirsfirst)",
|
|
37
|
+
"Bash(uv run pytest tests/ -m \"not integration\" --tb=short -q)",
|
|
38
|
+
"Bash(uv run pytest tests/ -m \"not integration\" -q)",
|
|
39
|
+
"Bash(uv add:*)",
|
|
40
|
+
"Bash(uv run python:*)",
|
|
41
|
+
"Bash(uv run mkdocs build:*)",
|
|
42
|
+
"Bash(git check-ignore:*)",
|
|
43
|
+
"Bash(uv run pytest:*)",
|
|
44
|
+
"Bash(uv run ruff check:*)",
|
|
45
|
+
"Bash(uv run ruff format:*)",
|
|
46
|
+
"Bash(lsof:*)",
|
|
47
|
+
"Bash(xargs kill:*)",
|
|
48
|
+
"Bash(chmod +x scripts/publish.sh)",
|
|
49
|
+
"Bash(chmod +x scripts/check_before_publish.py)",
|
|
50
|
+
"Bash(uv run twine check dist/*)",
|
|
51
|
+
"Bash(unzip -l dist/lixinger_python-0.1.0-py3-none-any.whl | head -30)",
|
|
52
|
+
"Bash(find lixinger -type f -name \"*.py\" -exec grep -l \"^import pandera as pa\" {} \\\\;)",
|
|
53
|
+
"Bash(find lixinger -type f -name \"*.py\" -exec sed -i '' 's/^import pandera as pa$/import pandera.pandas as pa/' {} \\\\;)"
|
|
54
|
+
]
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Lixinger API Configuration
|
|
2
|
+
# Copy this file to .env and fill in your actual values
|
|
3
|
+
|
|
4
|
+
# Your Lixinger API key (required)
|
|
5
|
+
# Get your API key from: https://www.lixinger.com/open/api
|
|
6
|
+
LIXINGER_API_KEY=your_api_key_here
|
|
7
|
+
|
|
8
|
+
# Optional: Custom API base URL (defaults to https://open.lixinger.com/api)
|
|
9
|
+
# LIXINGER_BASE_URL=https://open.lixinger.com/api
|
|
10
|
+
|
|
11
|
+
# Optional: Request timeout in seconds (defaults to 30.0)
|
|
12
|
+
# LIXINGER_TIMEOUT=30.0
|
|
13
|
+
|
|
14
|
+
# Optional: Maximum number of retry attempts (defaults to 3)
|
|
15
|
+
# LIXINGER_MAX_RETRIES=3
|
|
16
|
+
|
|
17
|
+
# Optional: Proxy URL (supports SOCKS)
|
|
18
|
+
# LIXINGER_PROXY=socks5://localhost:1080
|
|
19
|
+
|
|
20
|
+
# Optional: Maximum requests per minute (defaults to 1000)
|
|
21
|
+
# LIXINGER_MAX_REQUESTS_PER_MINUTE=1000
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
When performing a code review:
|
|
2
|
+
|
|
3
|
+
1. Respond in English
|
|
4
|
+
2. If the PR is adding new API, review the request param and response param is strictly aligning with the API doc provided in PR description.
|
|
5
|
+
|
|
6
|
+
**Checklist:**
|
|
7
|
+
- [ ] All parameter names match API docs exactly
|
|
8
|
+
- [ ] All parameter types match API docs exactly
|
|
9
|
+
- [ ] All response fields match API docs exactly
|
|
10
|
+
- [ ] Optional parameters are correctly marked
|
|
11
|
+
- [ ] Default values match API docs (if specified)
|
|
12
|
+
- [ ] Constraints are validated (enums, ranges, etc.)
|
|
13
|
+
- [ ] Documentation links included in docstrings
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# GitHub Actions Workflows
|
|
2
|
+
|
|
3
|
+
This directory contains CI/CD workflows for the lixinger-python project.
|
|
4
|
+
|
|
5
|
+
## Workflows
|
|
6
|
+
|
|
7
|
+
### PR Checks (`pr-checks.yml`)
|
|
8
|
+
|
|
9
|
+
Runs on every pull request and push to main branches.
|
|
10
|
+
|
|
11
|
+
**Required Checks (PR Gate):**
|
|
12
|
+
|
|
13
|
+
1. **Lint Check**
|
|
14
|
+
- Ruff linter (`ruff check .`)
|
|
15
|
+
- Ruff formatter (`ruff format --check .`)
|
|
16
|
+
- Mypy type checker (`mypy lixinger/`)
|
|
17
|
+
|
|
18
|
+
2. **Test Suite**
|
|
19
|
+
- Unit tests only (integration tests excluded)
|
|
20
|
+
- Runs with `pytest -m "not integration"`
|
|
21
|
+
- Generates coverage report
|
|
22
|
+
- Uploads to Codecov
|
|
23
|
+
|
|
24
|
+
3. **Compilation Check**
|
|
25
|
+
- Python compilation (`py_compile`)
|
|
26
|
+
- Import validation
|
|
27
|
+
- Ensures package can be imported
|
|
28
|
+
|
|
29
|
+
**Optional Check:**
|
|
30
|
+
|
|
31
|
+
4. **Integration Tests**
|
|
32
|
+
- Only runs if `LIXINGER_API_KEY` secret is available
|
|
33
|
+
- Skipped for external PRs (normal behavior)
|
|
34
|
+
- Tests with real API (non-blocking)
|
|
35
|
+
|
|
36
|
+
## Setup
|
|
37
|
+
|
|
38
|
+
### Required Secrets
|
|
39
|
+
|
|
40
|
+
No secrets required for basic PR checks (lint, test, compile).
|
|
41
|
+
|
|
42
|
+
### Optional Secrets
|
|
43
|
+
|
|
44
|
+
- `LIXINGER_API_KEY` - For integration tests (optional, only for internal PRs)
|
|
45
|
+
|
|
46
|
+
To add secrets:
|
|
47
|
+
1. Go to repository Settings → Secrets and variables → Actions
|
|
48
|
+
2. Add `LIXINGER_API_KEY` with your API key
|
|
49
|
+
|
|
50
|
+
## Branch Protection Rules
|
|
51
|
+
|
|
52
|
+
Recommended settings for main/master branch:
|
|
53
|
+
|
|
54
|
+
1. Require status checks to pass before merging:
|
|
55
|
+
- [x] Lint (Ruff & Mypy)
|
|
56
|
+
- [x] Test Suite
|
|
57
|
+
- [x] Compilation Check
|
|
58
|
+
- [x] All Checks Passed
|
|
59
|
+
|
|
60
|
+
2. Optional (not required):
|
|
61
|
+
- [ ] Integration Tests (Optional)
|
|
62
|
+
|
|
63
|
+
3. Other recommended settings:
|
|
64
|
+
- [x] Require branches to be up to date before merging
|
|
65
|
+
- [x] Require conversation resolution before merging
|
|
66
|
+
- [ ] Require signed commits (optional)
|
|
67
|
+
|
|
68
|
+
## Local Testing
|
|
69
|
+
|
|
70
|
+
Run the same checks locally before pushing:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
# Lint checks
|
|
74
|
+
uv run ruff check .
|
|
75
|
+
uv run ruff format --check .
|
|
76
|
+
uv run mypy lixinger/
|
|
77
|
+
|
|
78
|
+
# Unit tests
|
|
79
|
+
uv run pytest tests/ -m "not integration" -v
|
|
80
|
+
|
|
81
|
+
# Compilation check
|
|
82
|
+
python -m py_compile lixinger/**/*.py
|
|
83
|
+
uv run python -c "import lixinger"
|
|
84
|
+
|
|
85
|
+
# Integration tests (optional, requires API key)
|
|
86
|
+
uv run pytest tests/test_integration.py -v
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Troubleshooting
|
|
90
|
+
|
|
91
|
+
### "Ruff check failed"
|
|
92
|
+
- Run `uv run ruff check . --fix` to auto-fix issues
|
|
93
|
+
- Run `uv run ruff format .` to format code
|
|
94
|
+
|
|
95
|
+
### "Mypy type check failed"
|
|
96
|
+
- Fix type hints in the reported files
|
|
97
|
+
- Ensure all functions have proper type annotations
|
|
98
|
+
|
|
99
|
+
### "Tests failed"
|
|
100
|
+
- Run `uv run pytest tests/ -v` locally to see details
|
|
101
|
+
- Make sure `.env` is not committed (only `.env.example`)
|
|
102
|
+
- Check that mocks match expected structure
|
|
103
|
+
|
|
104
|
+
### "Compilation failed"
|
|
105
|
+
- Check for syntax errors in Python files
|
|
106
|
+
- Ensure all imports are correct
|
|
107
|
+
|
|
108
|
+
### "Integration tests skipped"
|
|
109
|
+
- Normal for external PRs (no API key available)
|
|
110
|
+
- Internal PRs need `LIXINGER_API_KEY` secret configured
|
|
111
|
+
|
|
112
|
+
## CI/CD Best Practices
|
|
113
|
+
|
|
114
|
+
1. **Fast Feedback**
|
|
115
|
+
- Lint checks run first (fastest)
|
|
116
|
+
- Tests run in parallel with compilation
|
|
117
|
+
- Integration tests are optional (non-blocking)
|
|
118
|
+
|
|
119
|
+
2. **Resource Efficiency**
|
|
120
|
+
- Uses uv caching for faster installs
|
|
121
|
+
- Only runs integration tests when necessary
|
|
122
|
+
- Parallel job execution
|
|
123
|
+
|
|
124
|
+
3. **Security**
|
|
125
|
+
- API keys stored as secrets
|
|
126
|
+
- External PRs cannot access secrets
|
|
127
|
+
- Integration tests continue on error
|
|
128
|
+
|
|
129
|
+
4. **Developer Experience**
|
|
130
|
+
- Clear job names
|
|
131
|
+
- Helpful error messages
|
|
132
|
+
- Same commands work locally
|
|
133
|
+
|
|
134
|
+
## Adding New Checks
|
|
135
|
+
|
|
136
|
+
To add a new check to the PR gate:
|
|
137
|
+
|
|
138
|
+
1. Add a new job in `pr-checks.yml`
|
|
139
|
+
2. Add the job name to `needs:` in the `all-checks` job
|
|
140
|
+
3. Update branch protection rules to require the new check
|
|
141
|
+
4. Document the check in this README
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
name: PR Checks
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
push:
|
|
8
|
+
branches:
|
|
9
|
+
- main
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
lint:
|
|
13
|
+
name: Lint (Ruff & Mypy)
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
steps:
|
|
16
|
+
- name: Checkout code
|
|
17
|
+
uses: actions/checkout@v4
|
|
18
|
+
|
|
19
|
+
- name: Install uv
|
|
20
|
+
uses: astral-sh/setup-uv@v4
|
|
21
|
+
with:
|
|
22
|
+
enable-cache: true
|
|
23
|
+
|
|
24
|
+
- name: Set up Python
|
|
25
|
+
uses: actions/setup-python@v5
|
|
26
|
+
with:
|
|
27
|
+
python-version-file: ".python-version"
|
|
28
|
+
|
|
29
|
+
- name: Install dependencies
|
|
30
|
+
run: |
|
|
31
|
+
uv sync --all-groups
|
|
32
|
+
uv pip install -e .
|
|
33
|
+
|
|
34
|
+
- name: Run Ruff linter
|
|
35
|
+
run: uv run ruff check .
|
|
36
|
+
|
|
37
|
+
- name: Run Ruff formatter check
|
|
38
|
+
run: uv run ruff format --check .
|
|
39
|
+
|
|
40
|
+
- name: Run Mypy type checker
|
|
41
|
+
run: uv run mypy lixinger/
|
|
42
|
+
|
|
43
|
+
test:
|
|
44
|
+
name: Test Suite
|
|
45
|
+
runs-on: ubuntu-latest
|
|
46
|
+
strategy:
|
|
47
|
+
matrix:
|
|
48
|
+
python-version: ["3.13"]
|
|
49
|
+
steps:
|
|
50
|
+
- name: Checkout code
|
|
51
|
+
uses: actions/checkout@v4
|
|
52
|
+
|
|
53
|
+
- name: Install uv
|
|
54
|
+
uses: astral-sh/setup-uv@v4
|
|
55
|
+
with:
|
|
56
|
+
enable-cache: true
|
|
57
|
+
|
|
58
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
59
|
+
uses: actions/setup-python@v5
|
|
60
|
+
with:
|
|
61
|
+
python-version: ${{ matrix.python-version }}
|
|
62
|
+
|
|
63
|
+
- name: Install dependencies
|
|
64
|
+
run: |
|
|
65
|
+
uv sync --all-groups
|
|
66
|
+
uv pip install -e .
|
|
67
|
+
|
|
68
|
+
- name: Run unit tests (exclude integration tests)
|
|
69
|
+
env:
|
|
70
|
+
LIXINGER_API_KEY: ${{ secrets.LIXINGER_API_KEY }}
|
|
71
|
+
run: uv run pytest -m "not integration" -v --cov=lixinger --cov-report=xml --cov-report=term --cov-branch --junitxml=junit.xml -o junit_family=legacy -s
|
|
72
|
+
|
|
73
|
+
- name: Upload coverage reports to Codecov
|
|
74
|
+
uses: codecov/codecov-action@v5
|
|
75
|
+
with:
|
|
76
|
+
token: ${{ secrets.CODECOV_TOKEN }}
|
|
77
|
+
flags: unit
|
|
78
|
+
files: ./coverage.xml
|
|
79
|
+
fail_ci_if_error: false
|
|
80
|
+
verbose: true
|
|
81
|
+
|
|
82
|
+
- name: Upload test results to Codecov
|
|
83
|
+
if: ${{ !cancelled() }}
|
|
84
|
+
uses: codecov/codecov-action@v5
|
|
85
|
+
with:
|
|
86
|
+
token: ${{ secrets.CODECOV_TOKEN }}
|
|
87
|
+
report_type: test_results
|
|
88
|
+
fail_ci_if_error: false
|
|
89
|
+
compile:
|
|
90
|
+
name: Compilation Check
|
|
91
|
+
runs-on: ubuntu-latest
|
|
92
|
+
steps:
|
|
93
|
+
- name: Checkout code
|
|
94
|
+
uses: actions/checkout@v4
|
|
95
|
+
|
|
96
|
+
- name: Install uv
|
|
97
|
+
uses: astral-sh/setup-uv@v4
|
|
98
|
+
with:
|
|
99
|
+
enable-cache: true
|
|
100
|
+
|
|
101
|
+
- name: Set up Python
|
|
102
|
+
uses: actions/setup-python@v5
|
|
103
|
+
with:
|
|
104
|
+
python-version-file: ".python-version"
|
|
105
|
+
|
|
106
|
+
- name: Install dependencies
|
|
107
|
+
run: uv sync
|
|
108
|
+
|
|
109
|
+
- name: Check Python compilation
|
|
110
|
+
run: |
|
|
111
|
+
python -m py_compile lixinger/**/*.py
|
|
112
|
+
echo "✓ All Python files compile successfully"
|
|
113
|
+
|
|
114
|
+
- name: Check imports
|
|
115
|
+
run: |
|
|
116
|
+
uv run python -c "import lixinger; print('✓ Package imports successfully')"
|
|
117
|
+
uv run python -c "from lixinger import LixingerClient; print('✓ LixingerClient imports successfully')"
|
|
118
|
+
|
|
119
|
+
integration-test:
|
|
120
|
+
name: Integration Tests (Optional)
|
|
121
|
+
runs-on: ubuntu-latest
|
|
122
|
+
# Only run if API key secret is available
|
|
123
|
+
if: github.event_name == 'push' || github.repository == github.event.pull_request.head.repo.full_name
|
|
124
|
+
steps:
|
|
125
|
+
- name: Checkout code
|
|
126
|
+
uses: actions/checkout@v4
|
|
127
|
+
|
|
128
|
+
- name: Install uv
|
|
129
|
+
uses: astral-sh/setup-uv@v4
|
|
130
|
+
with:
|
|
131
|
+
enable-cache: true
|
|
132
|
+
|
|
133
|
+
- name: Set up Python
|
|
134
|
+
uses: actions/setup-python@v5
|
|
135
|
+
with:
|
|
136
|
+
python-version-file: ".python-version"
|
|
137
|
+
|
|
138
|
+
- name: Install dependencies
|
|
139
|
+
run: |
|
|
140
|
+
uv sync --all-groups
|
|
141
|
+
uv pip install -e .
|
|
142
|
+
|
|
143
|
+
- name: Run integration tests
|
|
144
|
+
id: integration_tests
|
|
145
|
+
env:
|
|
146
|
+
LIXINGER_API_KEY: ${{ secrets.LIXINGER_API_KEY }}
|
|
147
|
+
run: |
|
|
148
|
+
if [ -n "$LIXINGER_API_KEY" ]; then
|
|
149
|
+
echo "Running integration tests with real API..."
|
|
150
|
+
uv run pytest tests/test_integration.py -v --cov=lixinger --cov-report=xml --cov-branch -s
|
|
151
|
+
echo "ran=true" >> $GITHUB_OUTPUT
|
|
152
|
+
else
|
|
153
|
+
echo "⚠️ Skipping integration tests (no API key available)"
|
|
154
|
+
echo "This is normal for external PRs"
|
|
155
|
+
echo "ran=false" >> $GITHUB_OUTPUT
|
|
156
|
+
fi
|
|
157
|
+
continue-on-error: true
|
|
158
|
+
|
|
159
|
+
- name: Upload integration coverage to Codecov
|
|
160
|
+
if: steps.integration_tests.outputs.ran == 'true'
|
|
161
|
+
uses: codecov/codecov-action@v5
|
|
162
|
+
with:
|
|
163
|
+
token: ${{ secrets.CODECOV_TOKEN }}
|
|
164
|
+
flags: integration
|
|
165
|
+
files: ./coverage.xml
|
|
166
|
+
fail_ci_if_error: false
|
|
167
|
+
verbose: true
|
|
168
|
+
|
|
169
|
+
all-checks:
|
|
170
|
+
name: All Checks Passed
|
|
171
|
+
runs-on: ubuntu-latest
|
|
172
|
+
needs: [lint, test, compile]
|
|
173
|
+
if: always()
|
|
174
|
+
steps:
|
|
175
|
+
- name: Check all job status
|
|
176
|
+
run: |
|
|
177
|
+
if [ "${{ needs.lint.result }}" != "success" ]; then
|
|
178
|
+
echo "❌ Lint checks failed"
|
|
179
|
+
exit 1
|
|
180
|
+
fi
|
|
181
|
+
if [ "${{ needs.test.result }}" != "success" ]; then
|
|
182
|
+
echo "❌ Tests failed"
|
|
183
|
+
exit 1
|
|
184
|
+
fi
|
|
185
|
+
if [ "${{ needs.compile.result }}" != "success" ]; then
|
|
186
|
+
echo "❌ Compilation checks failed"
|
|
187
|
+
exit 1
|
|
188
|
+
fi
|
|
189
|
+
echo "✅ All required checks passed!"
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Python-generated files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[oc]
|
|
4
|
+
build/
|
|
5
|
+
dist/
|
|
6
|
+
wheels/
|
|
7
|
+
*.egg-info
|
|
8
|
+
*.egg
|
|
9
|
+
.env
|
|
10
|
+
|
|
11
|
+
# PyPI credentials
|
|
12
|
+
.pypirc
|
|
13
|
+
|
|
14
|
+
# Virtual environments
|
|
15
|
+
.venv
|
|
16
|
+
.mypy_cache/
|
|
17
|
+
.pytest_cache/
|
|
18
|
+
.ruff_cache/
|
|
19
|
+
__pycache__/
|
|
20
|
+
.coverage
|
|
21
|
+
coverage.xml
|
|
22
|
+
junit.xml
|
|
23
|
+
|
|
24
|
+
# MkDocs generated site
|
|
25
|
+
site/
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# Pre-commit hooks configuration
|
|
2
|
+
# See https://pre-commit.com for more information
|
|
3
|
+
|
|
4
|
+
default_install_hook_types: [pre-commit, commit-msg]
|
|
5
|
+
default_stages: [pre-commit]
|
|
6
|
+
|
|
7
|
+
repos:
|
|
8
|
+
# Ruff - Fast Python linter and formatter
|
|
9
|
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
10
|
+
rev: v0.11.10
|
|
11
|
+
hooks:
|
|
12
|
+
# Run the linter
|
|
13
|
+
- id: ruff
|
|
14
|
+
args: [--fix]
|
|
15
|
+
name: Ruff linter (auto-fix)
|
|
16
|
+
# Run the formatter
|
|
17
|
+
- id: ruff-format
|
|
18
|
+
name: Ruff formatter
|
|
19
|
+
|
|
20
|
+
# Mypy - Static type checker
|
|
21
|
+
- repo: https://github.com/pre-commit/mirrors-mypy
|
|
22
|
+
rev: v1.15.0
|
|
23
|
+
hooks:
|
|
24
|
+
- id: mypy
|
|
25
|
+
name: Mypy type checker
|
|
26
|
+
additional_dependencies:
|
|
27
|
+
- types-python-dateutil
|
|
28
|
+
- pydantic>=2.0.0
|
|
29
|
+
args: [--config-file=pyproject.toml]
|
|
30
|
+
files: ^lixinger/
|
|
31
|
+
|
|
32
|
+
# Pytest - Run fast unit tests only (not integration tests)
|
|
33
|
+
- repo: local
|
|
34
|
+
hooks:
|
|
35
|
+
- id: pytest-fast
|
|
36
|
+
name: Pytest (unit tests only)
|
|
37
|
+
entry: uv run pytest
|
|
38
|
+
args: [tests/, -m, "not integration", --tb=short, -q]
|
|
39
|
+
language: system
|
|
40
|
+
pass_filenames: false
|
|
41
|
+
always_run: true
|
|
42
|
+
stages: [pre-commit]
|
|
43
|
+
|
|
44
|
+
# Standard pre-commit hooks
|
|
45
|
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
46
|
+
rev: v5.0.0
|
|
47
|
+
hooks:
|
|
48
|
+
# Check for files that would conflict in case-insensitive filesystems
|
|
49
|
+
- id: check-case-conflict
|
|
50
|
+
name: Check case conflicts
|
|
51
|
+
|
|
52
|
+
# Check for merge conflicts
|
|
53
|
+
- id: check-merge-conflict
|
|
54
|
+
name: Check merge conflicts
|
|
55
|
+
|
|
56
|
+
# Check YAML files
|
|
57
|
+
- id: check-yaml
|
|
58
|
+
name: Check YAML syntax
|
|
59
|
+
|
|
60
|
+
# Check TOML files
|
|
61
|
+
- id: check-toml
|
|
62
|
+
name: Check TOML syntax
|
|
63
|
+
|
|
64
|
+
# Check JSON files
|
|
65
|
+
- id: check-json
|
|
66
|
+
name: Check JSON syntax
|
|
67
|
+
|
|
68
|
+
# Ensure files end with newline
|
|
69
|
+
- id: end-of-file-fixer
|
|
70
|
+
name: Fix end of files
|
|
71
|
+
exclude: \.lock$
|
|
72
|
+
|
|
73
|
+
# Trim trailing whitespace
|
|
74
|
+
- id: trailing-whitespace
|
|
75
|
+
name: Trim trailing whitespace
|
|
76
|
+
exclude: \.lock$
|
|
77
|
+
|
|
78
|
+
# Check for debug statements
|
|
79
|
+
- id: debug-statements
|
|
80
|
+
name: Check debug statements
|
|
81
|
+
|
|
82
|
+
# Check for private key files
|
|
83
|
+
- id: detect-private-key
|
|
84
|
+
name: Detect private keys
|
|
85
|
+
|
|
86
|
+
# Check for large files
|
|
87
|
+
- id: check-added-large-files
|
|
88
|
+
name: Check large files
|
|
89
|
+
args: [--maxkb=500]
|
|
90
|
+
|
|
91
|
+
# dotenv-linter - Check .env files
|
|
92
|
+
- repo: https://github.com/wemake-services/dotenv-linter
|
|
93
|
+
rev: 0.7.0
|
|
94
|
+
hooks:
|
|
95
|
+
- id: dotenv-linter
|
|
96
|
+
name: Lint .env files
|
|
97
|
+
files: ^\.env\.example$
|
|
98
|
+
|
|
99
|
+
# CI configuration - disable some checks in CI
|
|
100
|
+
ci:
|
|
101
|
+
autofix_commit_msg: |
|
|
102
|
+
[pre-commit.ci] auto fixes from pre-commit.com hooks
|
|
103
|
+
|
|
104
|
+
for more information, see https://pre-commit.ci
|
|
105
|
+
autofix_prs: true
|
|
106
|
+
autoupdate_branch: ""
|
|
107
|
+
autoupdate_commit_msg: "[pre-commit.ci] pre-commit autoupdate"
|
|
108
|
+
autoupdate_schedule: weekly
|
|
109
|
+
skip: [pytest-fast] # Skip pytest in pre-commit.ci (run in GitHub Actions)
|
|
110
|
+
submodules: false
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.13
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
line-length = 120
|
|
2
|
+
|
|
3
|
+
[format]
|
|
4
|
+
quote-style = "double"
|
|
5
|
+
indent-style = "space"
|
|
6
|
+
skip-magic-trailing-comma = false
|
|
7
|
+
|
|
8
|
+
[lint]
|
|
9
|
+
preview = false
|
|
10
|
+
select = [
|
|
11
|
+
# Pyflakes (F) - catch common errors
|
|
12
|
+
"F",
|
|
13
|
+
# Pycodestyle (E, W) - PEP 8 style guide
|
|
14
|
+
"E",
|
|
15
|
+
"W",
|
|
16
|
+
# isort (I) - import sorting
|
|
17
|
+
"I",
|
|
18
|
+
# pep8-naming (N) - naming conventions
|
|
19
|
+
"N",
|
|
20
|
+
# pydocstyle (D) - docstring conventions
|
|
21
|
+
"D",
|
|
22
|
+
# pyupgrade (UP) - upgrade syntax for newer Python versions
|
|
23
|
+
"UP",
|
|
24
|
+
# flake8-bugbear (B) - find bugs and design problems
|
|
25
|
+
"B",
|
|
26
|
+
# flake8-comprehensions (C4) - better comprehensions
|
|
27
|
+
"C4",
|
|
28
|
+
# flake8-pie (PIE) - remove code smells
|
|
29
|
+
"PIE",
|
|
30
|
+
# flake8-return (RET) - return statement best practices
|
|
31
|
+
"RET",
|
|
32
|
+
# flake8-simplify (SIM) - simplify code
|
|
33
|
+
"SIM",
|
|
34
|
+
# flake8-unused-arguments (ARG) - unused arguments
|
|
35
|
+
"ARG",
|
|
36
|
+
# flake8-use-pathlib (PTH) - use pathlib
|
|
37
|
+
"PTH",
|
|
38
|
+
# eradicate (ERA) - commented-out code
|
|
39
|
+
"ERA",
|
|
40
|
+
# pandas-vet (PD) - pandas best practices
|
|
41
|
+
"PD",
|
|
42
|
+
# pygrep-hooks (PGH) - additional checks
|
|
43
|
+
"PGH",
|
|
44
|
+
# Pylint (PL) - additional checks
|
|
45
|
+
"PL",
|
|
46
|
+
# tryceratops (TRY) - exception handling
|
|
47
|
+
"TRY",
|
|
48
|
+
# flake8-type-checking (TCH) - type checking imports
|
|
49
|
+
"TCH",
|
|
50
|
+
# flake8-future-annotations (FA) - future annotations
|
|
51
|
+
"FA",
|
|
52
|
+
]
|
|
53
|
+
|
|
54
|
+
ignore = [
|
|
55
|
+
# Allow non-abstract empty methods in base classes
|
|
56
|
+
"B027",
|
|
57
|
+
# Allow boolean positional values in function calls
|
|
58
|
+
"FBT",
|
|
59
|
+
# Ignore specific pydocstyle errors
|
|
60
|
+
"D100", # Missing docstring in public module
|
|
61
|
+
"D101", # Missing docstring in public class
|
|
62
|
+
"D102", # Missing docstring in public method
|
|
63
|
+
"D103", # Missing docstring in public function
|
|
64
|
+
"D104", # Missing docstring in public package
|
|
65
|
+
"D105", # Missing docstring in magic method
|
|
66
|
+
"D107", # Missing docstring in __init__
|
|
67
|
+
# Allow relative imports
|
|
68
|
+
"TID252",
|
|
69
|
+
# Allow print statements (useful for debugging)
|
|
70
|
+
"T201",
|
|
71
|
+
# Allow assert statements in tests
|
|
72
|
+
"S101",
|
|
73
|
+
# Allow magic numbers
|
|
74
|
+
"PLR2004",
|
|
75
|
+
# Allow long lines in URLs/imports
|
|
76
|
+
"E501",
|
|
77
|
+
# Allow unused variables in comprehensions
|
|
78
|
+
"F841",
|
|
79
|
+
# Allow try-except-pass
|
|
80
|
+
"S110",
|
|
81
|
+
"B904",
|
|
82
|
+
"TRY003",
|
|
83
|
+
"TRY201",
|
|
84
|
+
"PGH003",
|
|
85
|
+
"ARG001",
|
|
86
|
+
"TRY300",
|
|
87
|
+
"PD901",
|
|
88
|
+
"D404",
|
|
89
|
+
"D415",
|
|
90
|
+
"D400",
|
|
91
|
+
"PLR0915"
|
|
92
|
+
]
|
|
93
|
+
|
|
94
|
+
[lint.per-file-ignores]
|
|
95
|
+
# Tests can have longer lines, unused imports, and assertions
|
|
96
|
+
"tests/**/*.py" = [
|
|
97
|
+
"E501", # Line too long
|
|
98
|
+
"F401", # Unused imports
|
|
99
|
+
"S101", # Use of assert
|
|
100
|
+
"ARG", # Unused arguments
|
|
101
|
+
"PLR2004", # Magic numbers
|
|
102
|
+
]
|
|
103
|
+
"data_provider/**/*.py" = [
|
|
104
|
+
"ERA001", # Remove commented-out code
|
|
105
|
+
]
|
|
106
|
+
# Allow unused imports in __init__.py files
|
|
107
|
+
"**/__init__.py" = [
|
|
108
|
+
"F401", # Unused imports
|
|
109
|
+
]
|
|
110
|
+
# Allow Flask app patterns
|
|
111
|
+
"app.py" = [
|
|
112
|
+
"F401", # Unused imports (Flask decorators)
|
|
113
|
+
]
|
|
114
|
+
|
|
115
|
+
[lint.isort]
|
|
116
|
+
known-first-party = ["analyzer", "core", "data_provider"]
|
|
117
|
+
force-sort-within-sections = true
|
|
118
|
+
split-on-trailing-comma = true
|
|
119
|
+
|
|
120
|
+
[lint.mccabe]
|
|
121
|
+
max-complexity = 10
|