lixinger-python 0.2.0__tar.gz → 0.3.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.
- lixinger_python-0.3.0/.claude/settings.local.json +108 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/.github/workflows/pr-checks.yml +1 -1
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/PKG-INFO +1 -1
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/docs/api/client.md +1 -1
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/docs/api/company/announcement.md +13 -12
- lixinger_python-0.3.0/docs/api/company/candlestick.md +51 -0
- lixinger_python-0.3.0/docs/api/company/company.md +41 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/docs/api/company/dividend.md +13 -12
- lixinger_python-0.3.0/docs/api/company/equity_change.md +47 -0
- lixinger_python-0.3.0/docs/api/company/fs/non_financial.md +49 -0
- lixinger_python-0.3.0/docs/api/company/fundamental/bank.md +49 -0
- lixinger_python-0.3.0/docs/api/company/fundamental/insurance.md +49 -0
- lixinger_python-0.3.0/docs/api/company/fundamental/non_financial.md +49 -0
- lixinger_python-0.3.0/docs/api/company/fundamental/other_financial.md +49 -0
- lixinger_python-0.3.0/docs/api/company/fundamental/security.md +49 -0
- lixinger_python-0.3.0/docs/api/company/indices.md +41 -0
- lixinger_python-0.3.0/docs/api/company/profile.md +41 -0
- lixinger_python-0.3.0/docs/api/fund/announcement.md +47 -0
- lixinger_python-0.3.0/docs/api/fund/asset_combination.md +47 -0
- lixinger_python-0.3.0/docs/api/fund/asset_industry_combination.md +47 -0
- lixinger_python-0.3.0/docs/api/fund/candlestick.md +49 -0
- lixinger_python-0.3.0/docs/api/fund/fund.md +41 -0
- lixinger_python-0.3.0/docs/api/fund/profile.md +41 -0
- lixinger_python-0.3.0/docs/api/fund/shareholdings.md +47 -0
- lixinger_python-0.3.0/docs/api/index/candlestick.md +49 -0
- lixinger_python-0.3.0/docs/api/index/constituent_weightings.md +47 -0
- lixinger_python-0.3.0/docs/api/index/constituents.md +45 -0
- lixinger_python-0.3.0/docs/api/index/drawdown.md +51 -0
- lixinger_python-0.3.0/docs/api/index/fundamental.md +49 -0
- lixinger_python-0.3.0/docs/api/index/index.md +41 -0
- lixinger_python-0.3.0/docs/api/index/tracking_fund.md +41 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/docs/api/overview.md +9 -9
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/docs/examples/company.md +1 -1
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/docs/getting-started/quickstart.md +7 -6
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/docs/index.md +1 -1
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/lixinger/__init__.py +10 -12
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/lixinger/api/cn/company/__init__.py +0 -3
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/lixinger/api/cn/company/company.py +9 -5
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/lixinger/api/cn/company/equity_change.py +11 -7
- lixinger_python-0.3.0/lixinger/api/cn/company/fundamental/__init__.py +47 -0
- lixinger_python-0.3.0/lixinger/api/cn/company/fundamental/bank.py +114 -0
- lixinger_python-0.3.0/lixinger/api/cn/company/fundamental/insurance.py +114 -0
- lixinger_python-0.3.0/lixinger/api/cn/company/fundamental/non_financial.py +114 -0
- lixinger_python-0.3.0/lixinger/api/cn/company/fundamental/other_financial.py +114 -0
- lixinger_python-0.3.0/lixinger/api/cn/company/fundamental/security.py +114 -0
- lixinger_python-0.3.0/lixinger/api/cn/company/namespace.py +125 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/lixinger/api/cn/company/profile.py +9 -5
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/lixinger/api/cn/index/tracking_fund.py +9 -3
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/lixinger/client.py +19 -4
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/lixinger/models/cn/company/__init__.py +12 -2
- lixinger_python-0.3.0/lixinger/models/cn/company/fundamental/__init__.py +15 -0
- lixinger_python-0.2.0/lixinger/models/cn/company/fundamental.py → lixinger_python-0.3.0/lixinger/models/cn/company/fundamental/bank.py +3 -3
- lixinger_python-0.3.0/lixinger/models/cn/company/fundamental/insurance.py +16 -0
- lixinger_python-0.3.0/lixinger/models/cn/company/fundamental/non_financial.py +16 -0
- lixinger_python-0.3.0/lixinger/models/cn/company/fundamental/other_financial.py +16 -0
- lixinger_python-0.3.0/lixinger/models/cn/company/fundamental/security.py +16 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/mkdocs.yml +7 -1
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/pyproject.toml +1 -1
- lixinger_python-0.3.0/scripts/generate_docs.py +886 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/tests/test_fundamental.py +6 -25
- lixinger_python-0.3.0/tests/test_fundamental_bank.py +91 -0
- lixinger_python-0.3.0/tests/test_fundamental_security.py +91 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/tests/test_integration.py +27 -2
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/uv.lock +1 -1
- lixinger_python-0.2.0/.claude/settings.local.json +0 -81
- lixinger_python-0.2.0/docs/api/company/candlestick.md +0 -100
- lixinger_python-0.2.0/docs/api/company/company.md +0 -90
- lixinger_python-0.2.0/docs/api/company/equity_change.md +0 -132
- lixinger_python-0.2.0/docs/api/company/fs/non_financial.md +0 -37
- lixinger_python-0.2.0/docs/api/company/fundamental.md +0 -93
- lixinger_python-0.2.0/docs/api/company/indices.md +0 -34
- lixinger_python-0.2.0/docs/api/company/profile.md +0 -91
- lixinger_python-0.2.0/docs/api/fund/announcement.md +0 -36
- lixinger_python-0.2.0/docs/api/fund/asset_combination.md +0 -36
- lixinger_python-0.2.0/docs/api/fund/asset_industry_combination.md +0 -36
- lixinger_python-0.2.0/docs/api/fund/candlestick.md +0 -37
- lixinger_python-0.2.0/docs/api/fund/fund.md +0 -34
- lixinger_python-0.2.0/docs/api/fund/profile.md +0 -34
- lixinger_python-0.2.0/docs/api/fund/shareholdings.md +0 -36
- lixinger_python-0.2.0/docs/api/index/candlestick.md +0 -37
- lixinger_python-0.2.0/docs/api/index/constituent_weightings.md +0 -36
- lixinger_python-0.2.0/docs/api/index/constituents.md +0 -35
- lixinger_python-0.2.0/docs/api/index/drawdown.md +0 -38
- lixinger_python-0.2.0/docs/api/index/fundamental.md +0 -37
- lixinger_python-0.2.0/docs/api/index/index.md +0 -34
- lixinger_python-0.2.0/docs/api/index/tracking_fund.md +0 -34
- lixinger_python-0.2.0/lixinger/api/cn/company/fundamental.py +0 -228
- lixinger_python-0.2.0/lixinger/api/cn/company/namespace.py +0 -66
- lixinger_python-0.2.0/scripts/generate_docs.py +0 -492
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/.env.example +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/.github/copilot-instructions.md +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/.github/workflows/README.md +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/.gitignore +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/.pre-commit-config.yaml +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/.python-version +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/.ruff.toml +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/ADD_NEW_API_QUICK.md +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/AGENTS.md +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/CHANGELOG.md +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/CLAUDE.md +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/DOCS.md +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/LICENSE +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/MANIFEST.in +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/PUBLISHING.md +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/README.md +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/SETUP.md +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/codecov.yml +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/docs/development/code-style.md +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/docs/development/contributing.md +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/docs/development/testing.md +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/docs/examples/fund.md +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/docs/examples/index.md +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/docs/getting-started/configuration.md +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/docs/getting-started/installation.md +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/examples/company_example.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/examples/company_profile_example.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/fund_response.json +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/lixinger/api/__init__.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/lixinger/api/base.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/lixinger/api/cn/__init__.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/lixinger/api/cn/company/announcement.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/lixinger/api/cn/company/candlestick.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/lixinger/api/cn/company/dividend.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/lixinger/api/cn/company/fs/__init__.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/lixinger/api/cn/company/fs/non_financial.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/lixinger/api/cn/company/indices.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/lixinger/api/cn/fund/__init__.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/lixinger/api/cn/fund/announcement.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/lixinger/api/cn/fund/asset_combination.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/lixinger/api/cn/fund/asset_industry_combination.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/lixinger/api/cn/fund/candlestick.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/lixinger/api/cn/fund/fund.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/lixinger/api/cn/fund/profile.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/lixinger/api/cn/fund/shareholdings.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/lixinger/api/cn/index/__init__.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/lixinger/api/cn/index/candlestick.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/lixinger/api/cn/index/constituent_weightings.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/lixinger/api/cn/index/constituents.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/lixinger/api/cn/index/drawdown.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/lixinger/api/cn/index/fundamental.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/lixinger/api/cn/index/index.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/lixinger/config.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/lixinger/exceptions.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/lixinger/models/__init__.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/lixinger/models/cn/__init__.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/lixinger/models/cn/company/announcement.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/lixinger/models/cn/company/candlestick.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/lixinger/models/cn/company/company.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/lixinger/models/cn/company/dividend.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/lixinger/models/cn/company/equity_change.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/lixinger/models/cn/company/fs/__init__.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/lixinger/models/cn/company/fs/non_financial.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/lixinger/models/cn/company/indices.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/lixinger/models/cn/fund/__init__.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/lixinger/models/cn/fund/announcement.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/lixinger/models/cn/fund/asset_combination.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/lixinger/models/cn/fund/asset_industry_combination.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/lixinger/models/cn/fund/candlestick.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/lixinger/models/cn/fund/fund.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/lixinger/models/cn/fund/profile.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/lixinger/models/cn/fund/shareholdings.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/lixinger/models/cn/index/__init__.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/lixinger/models/cn/index/candlestick.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/lixinger/models/cn/index/constituent_weightings.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/lixinger/models/cn/index/constituents.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/lixinger/models/cn/index/drawdown.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/lixinger/models/cn/index/fundamental.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/lixinger/models/cn/index/index.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/lixinger/models/cn/index/tracking_fund.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/lixinger/py.typed +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/lixinger/utils/__init__.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/lixinger/utils/api.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/lixinger/utils/dataframe.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/lixinger/utils/dict.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/lixinger/utils/rate_limiter.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/lixinger/utils/retry.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/mypy.ini +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/scripts/explore_api.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/scripts/publish.sh +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/tests/api/cn/company/test_announcement.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/tests/api/cn/company/test_dividend.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/tests/conftest.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/tests/test_candlestick.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/tests/test_client.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/tests/test_cn_index_candlestick.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/tests/test_cn_index_constituent_weightings.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/tests/test_company.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/tests/test_company_profile.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/tests/test_equity_change.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/tests/test_fund.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/tests/test_fund_announcement.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/tests/test_fund_asset_combination.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/tests/test_fund_asset_industry_combination.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/tests/test_fund_candlestick.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/tests/test_fund_profile.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/tests/test_fund_shareholdings.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/tests/test_index.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/tests/test_index_constituents.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/tests/test_index_drawdown.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/tests/test_index_fundamental.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/tests/test_indices.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/tests/test_non_financial_statements.py +0 -0
- {lixinger_python-0.2.0 → lixinger_python-0.3.0}/tests/test_tracking_fund.py +0 -0
|
@@ -0,0 +1,108 @@
|
|
|
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
|
+
"Bash(uv pip list 2>/dev/null | grep -E \"\\(pandas|llama\\)\" || echo \"No packages found\")",
|
|
55
|
+
"Bash(uv pip index versions llama-index 2>/dev/null | head -20 || echo \"Checking package info...\")",
|
|
56
|
+
"Bash(pip index versions llama-index 2>&1 | head -5 || uv pip show llama-index 2>&1 | head -10 || echo \"Checking...\")",
|
|
57
|
+
"WebFetch(domain:pypi.org)",
|
|
58
|
+
"Bash(curl -s \"https://pypi.org/pypi/llama-index/0.14.15/json\" | python3 -c \"import json,sys; data=json.load\\(sys.stdin\\); deps=[d for d in data['info'].get\\('requires_dist',[]\\) if 'pandas' in d.lower\\(\\)]; print\\('\\\\n'.join\\(deps\\) if deps else 'No pandas dependency'\\)\")",
|
|
59
|
+
"Bash(curl -s \"https://pypi.org/pypi/llama-index-readers-file/0.5.6/json\" | python3 -c \"import json,sys; data=json.load\\(sys.stdin\\); deps=[d for d in data['info'].get\\('requires_dist',[]\\) if 'pandas' in d.lower\\(\\)]; print\\('\\\\n'.join\\(deps\\) if deps else 'No pandas dependency'\\)\")",
|
|
60
|
+
"Bash(uv sync)",
|
|
61
|
+
"Bash(wc -l /Users/JianGuo/Documents/CursorProject/lixinger-python/tests/*.py | tail -1)",
|
|
62
|
+
"Bash(uv pip list | grep -E \"pytest|asyncio\")",
|
|
63
|
+
"Bash(uv run mypy lixinger/utils/)",
|
|
64
|
+
"Bash(uv run mypy lixinger/api/base.py)",
|
|
65
|
+
"Bash(uv run mypy lixinger/api/cn/)",
|
|
66
|
+
"Bash(uv run mypy lixinger/client.py)",
|
|
67
|
+
"Bash(python3 -c \"from lixinger import AsyncLixingerClient; print\\('✅ AsyncLixingerClient imported'\\)\")",
|
|
68
|
+
"Bash(python3 -c \"from lixinger import LixingerClient\" 2>&1 || echo \"✅ LixingerClient correctly removed\")",
|
|
69
|
+
"Bash(grep -l \"LixingerClient\\\\|with client\\\\|client\\\\.company\\\\.get\" --include=\"*.md\" -r . 2>/dev/null | grep -v \".venv\" | grep -v \"site/\" | grep -v \".git/\" | head -20)",
|
|
70
|
+
"Bash(grep -n \"from lixinger import\\\\|LixingerClient\\\\|with client\\\\|def main\" docs/getting-started/quickstart.md docs/index.md docs/examples/*.md 2>/dev/null | head -40)",
|
|
71
|
+
"Bash(cat > /tmp/async_docs_update_summary.md << 'EOF'\n# 异步文档更新总结\n\n## ✅ 已完成更新的文件\n\n### 核心文档\n1. **README.md** - 完全重写,展示异步特性\n2. **SETUP.md** - 更新所有示例为 async/await\n3. **CHANGELOG.md** - 添加 v2.0.0 迁移指南\n4. **AGENTS.md** - 强调 async 要求,更新所有示例\n5. **ADD_NEW_API_QUICK.md** - 所有模板改为 async\n\n### 开发指南\n6. **docs/getting-started/quickstart.md** - 完全重写为异步版本\n - 添加醒目的异步警告\n - 所有示例使用 asyncio.run\\(main\\(\\)\\)\n - 新增并发请求示例\n - 新增 Jupyter 用法说明\n\n7. **docs/index.md** - 更新首页示例为异步\n\n### 示例文件\n8. **examples/company_example.py** - 异步版本\n9. **examples/company_profile_example.py** - 异步版本\n\n## ⚠️ 需要检查的文件\n\n以下文件可能包含同步代码示例,需要批量更新:\n\n### API 文档(自动生成部分)\n- `docs/api/company/*.md` \\(9个文件\\)\n- `docs/api/index/*.md` \\(7个文件\\)\n- `docs/api/fund/*.md` \\(7个文件\\)\n\n**处理建议**: 这些文件由 mkdocstrings 自动生成,只要源码的 docstrings 是正确的(已完成),重新生成文档即可。\n\n### 示例文档\n- `docs/examples/company.md`\n- `docs/examples/fund.md`\n- `docs/examples/index.md`\n\n### 其他配置文档\n- `docs/getting-started/configuration.md`\n- `docs/getting-started/installation.md`\n\n## 🔧 修复步骤\n\n### 方法1:重新生成 API 文档(推荐)\n```bash\nuv run python scripts/generate_docs.py\n```\n这会基于最新的 docstrings 重新生成所有 API 文档。\n\n### 方法2:手动修复剩余文件\n逐个检查并更新 docs/examples/*.md 等手写文档文件。\n\n## 📋 检查清单\n\n- [x] README.md\n- [x] SETUP.md\n- [x] CHANGELOG.md\n- [x] AGENTS.md\n- [x] ADD_NEW_API_QUICK.md\n- [x] docs/getting-started/quickstart.md\n- [x] docs/index.md\n- [x] examples/*.py\n- [ ] docs/examples/*.md \\(3个\\)\n- [ ] docs/getting-started/configuration.md\n- [ ] docs/getting-started/installation.md\n- [ ] docs/api/*/*.md \\(重新生成\\)\n\n## 🎯 关键改进点\n\n所有更新的文档都包含:\n1. ✅ 使用 `AsyncLixingerClient` 而不是 `LixingerClient`\n2. ✅ 使用 `async def main\\(\\)` 包装代码\n3. ✅ 使用 `async with` 上下文管理器\n4. ✅ 所有 API 调用前加 `await`\n5. ✅ 使用 `asyncio.run\\(main\\(\\)\\)` 运行\n6. ✅ 说明 Jupyter 可以直接使用 await\n7. ✅ 展示并发请求示例(where appropriate)\nEOF\ncat /tmp/async_docs_update_summary.md)",
|
|
72
|
+
"Bash(ls -lah scripts/*.py | grep -E \"\\(convert|fix\\)\")",
|
|
73
|
+
"Bash(ls -1 scripts/*.py)",
|
|
74
|
+
"Bash(grep -rn \"client\\\\.company\\\\.get_company\\\\|client\\\\.company\\\\.get_profile\" --include=\"*.md\" . 2>/dev/null | grep -v \".venv\\\\|site\\\\|.git\" | head -20)",
|
|
75
|
+
"Bash(cat > /tmp/fix_api_paths.sh << 'EOF'\n#!/bin/bash\n# Fix incorrect API paths in documentation\n\n# Find all markdown files \\(excluding .venv, site, .git\\)\nfind . -name \"*.md\" -type f ! -path \"./.venv/*\" ! -path \"./site/*\" ! -path \"./.git/*\" | while read file; do\n # Check if file contains the incorrect patterns\n if grep -q \"client\\\\.company\\\\.get_company\\\\|client\\\\.company\\\\.get_profile\" \"$file\"; then\n echo \"Fixing: $file\"\n \n # Fix get_company\n sed -i '' 's/client\\\\.company\\\\.get_company/client.company.company.get_company/g' \"$file\"\n \n # Fix get_profile\n sed -i '' 's/client\\\\.company\\\\.get_profile/client.company.profile.get_profile/g' \"$file\"\n fi\ndone\n\necho \"Done!\"\nEOF\n\nchmod +x /tmp/fix_api_paths.sh\n/tmp/fix_api_paths.sh)",
|
|
76
|
+
"Bash(grep -rn \"client\\\\.company\\\\.get_company\\\\|client\\\\.company\\\\.get_profile\" --include=\"*.md\" . 2>/dev/null | grep -v \".venv\\\\|site\\\\|.git\\\\|\\\\.company\\\\.company\\\\|\\\\.company\\\\.profile\" | head -5)",
|
|
77
|
+
"Bash(cat > /tmp/api_path_fix_summary.md << 'EOF'\n# API 路径修复总结\n\n## 🐛 发现的问题\n\n文档中使用了错误的 API 调用路径:\n\n### ❌ 错误示例\n```python\nclient.company.get_company\\(...\\) # 错误!\nclient.company.get_profile\\(...\\) # 错误!\n```\n\n### ✅ 正确示例\n```python\nclient.company.company.get_company\\(...\\) # 正确\nclient.company.profile.get_profile\\(...\\) # 正确\n```\n\n## 📐 客户端结构\n\n```python\nAsyncLixingerClient\n├── company \\(CompanyNamespace\\)\n│ ├── company \\(CompanyAPI\\)\n│ │ └── get_company\\(\\)\n│ ├── profile \\(CompanyProfileAPI\\)\n│ │ └── get_profile\\(\\)\n│ ├── fundamental \\(FundamentalAPI\\)\n│ │ ├── get_non_financial\\(\\)\n│ │ ├── get_bank\\(\\)\n│ │ └── ...\n│ ├── candlestick \\(CandlestickAPI\\)\n│ ├── equity_change \\(EquityChangeAPI\\)\n│ ├── fs\n│ │ └── non_financial \\(NonFinancialStatementAPI\\)\n│ ├── indices \\(IndicesAPI\\)\n│ ├── dividend \\(DividendAPI\\)\n│ └── announcement \\(AnnouncementAPI\\)\n│\n├── cn_index \\(IndexAPI\\)\n├── cn_index_constituents \\(ConstituentsAPI\\)\n└── ...\n```\n\n## ✅ 修复的文件(7个)\n\n1. **README.md** - 5处修复\n - 基础用法示例\n - 并发请求示例\n - Jupyter 用法\n - Import 示例\n\n2. **SETUP.md** - 4处修复\n - 使用示例\n - 配置覆盖\n - Jupyter 示例\n - 测试示例\n\n3. **CHANGELOG.md** - 2处修复\n - v0.x 示例\n - v2.0 迁移示例\n\n4. **docs/getting-started/quickstart.md** - 3处修复\n - 并发查询示例\n - 客户端配置示例\n - Jupyter 用法\n\n5. **docs/index.md** - 1处修复\n - Jupyter 使用示例\n\n6. **docs/examples/company.md** - 3处修复\n - 并发查询示例\n\n7. **PUBLISHING.md** - 1处修复\n - 示例代码\n\n## 🎯 正确的 API 调用模式\n\n### Company APIs\n```python\n# Company information\nawait client.company.company.get_company\\(stock_codes=[\"000001\"]\\)\n\n# Company profile \nawait client.company.profile.get_profile\\(stock_codes=[\"000001\"]\\)\n\n# Fundamental data\nawait client.company.fundamental.get_non_financial\\(\n stock_codes=[\"000001\"],\n metrics=[\"pe\", \"pb\"]\n\\)\n\n# Candlestick data\nawait client.company.candlestick.get_candlestick\\(...\\)\n\n# Equity change\nawait client.company.equity_change.get_equity_change\\(...\\)\n\n# Financial statements\nawait client.company.fs.non_financial.get_non_financial_statements\\(...\\)\n\n# Indices membership\nawait client.company.indices.get_indices\\(...\\)\n\n# Dividend\nawait client.company.dividend.get_dividend\\(...\\)\n\n# Announcements\nawait client.company.announcement.get_announcement\\(...\\)\n```\n\n### Index APIs\n```python\n# 使用扁平访问(旧版兼容)\nawait client.cn_index.get_index\\(...\\)\nawait client.cn_index_constituents.get_constituents\\(...\\)\nawait client.cn_index_candlestick.get_candlestick\\(...\\)\n```\n\n### Fund APIs\n```python\n# 使用扁平访问(旧版兼容)\nawait client.cn_fund.get_fund\\(...\\)\nawait client.cn_fund_profile.get_profile\\(...\\)\nawait client.cn_fund_candlestick.get_candlestick\\(...\\)\n```\n\n## 📊 修复统计\n\n- **文件数量**: 7个文档文件\n- **修复点**: 19处 API 调用路径\n- **覆盖范围**: \n - ✅ README.md\n - ✅ SETUP.md \n - ✅ CHANGELOG.md\n - ✅ 快速入门文档\n - ✅ 首页文档\n - ✅ 示例文档\n - ✅ 发布文档\n\n## ✨ 验证\n\n所有修复后的代码现在都使用正确的 API 路径:\n- `client.company.company.get_company\\(\\)` ✅\n- `client.company.profile.get_profile\\(\\)` ✅\n- `client.company.fundamental.get_non_financial\\(\\)` ✅\n\n用户现在可以直接复制文档中的代码并成功运行!\nEOF\ncat /tmp/api_path_fix_summary.md)",
|
|
78
|
+
"Bash(grep -rn \"client\\\\.[a-z_]*\\\\.\\\\\\(get_\\\\|fetch_\\\\\\)\" --include=\"*.md\" README.md SETUP.md docs/getting-started/quickstart.md 2>/dev/null | grep -v \"company\\\\.company\\\\|company\\\\.profile\\\\|company\\\\.fundamental\\\\|company\\\\.candlestick\\\\|company\\\\.equity_change\\\\|company\\\\.fs\\\\|company\\\\.indices\\\\|company\\\\.dividend\\\\|company\\\\.announcement\\\\|cn_index\\\\|cn_fund\" | head -10)",
|
|
79
|
+
"Bash(python3 -c \"\nimport asyncio\nfrom unittest.mock import Mock, patch\n\nasync def test_mock\\(\\):\n # This is what the tests do\n mock = Mock\\(\\)\n mock.return_value = Mock\\(\\)\n mock.return_value.status_code = 200\n mock.return_value.json.return_value = {'data': 'test'}\n \n # Try to await it\n try:\n result = await mock\\(\\)\n print\\('Result:', result\\)\n print\\('Status:', result.status_code\\)\n print\\('JSON:', result.json\\(\\)\\)\n except Exception as e:\n print\\('Error:', type\\(e\\).__name__, e\\)\n\nasyncio.run\\(test_mock\\(\\)\\)\n\")",
|
|
80
|
+
"Bash(python3 -c \"\nfrom unittest.mock import Mock, patch\nimport inspect\n\n# Check if patch makes mocks special\nmock = Mock\\(\\)\nprint\\('Is mock awaitable?', inspect.iscoroutinefunction\\(mock\\)\\)\nprint\\('Mock type:', type\\(mock\\)\\)\n\n# Try with patch\nwith patch\\('builtins.print'\\) as mock_print:\n print\\('Patched mock type:', type\\(mock_print\\)\\)\n\")",
|
|
81
|
+
"Bash(python3 -c \"\nimport asyncio\nfrom unittest.mock import Mock, patch, MagicMock\nimport httpx\n\n# Simulate what happens\nclass FakeClient:\n async def request\\(self, *args, **kwargs\\):\n return Mock\\(status_code=200, json=lambda: {'code': 1, 'message': 'success', 'data': []}\\)\n\nasync def test\\(\\):\n client = FakeClient\\(\\)\n \n with patch.object\\(client, 'request'\\) as mock_request:\n # This is what the test does\n mock_request.return_value = Mock\\(\\)\n mock_request.return_value.status_code = 200\n mock_request.return_value.json.return_value = {'code': 1, 'message': 'success', 'data': []}\n \n # What type is mock_request now?\n print\\('Mock type:', type\\(mock_request\\)\\)\n print\\('Mock return_value type:', type\\(mock_request.return_value\\)\\)\n \n # Try calling\n try:\n result = await client.request\\('GET', 'http://test.com'\\)\n print\\('Result:', result\\)\n print\\('Success!'\\)\n except Exception as e:\n print\\('Error:', type\\(e\\).__name__, e\\)\n\nasyncio.run\\(test\\(\\)\\)\n\")",
|
|
82
|
+
"Bash(uv run python3 -c \"\nimport asyncio\nfrom unittest.mock import Mock, patch, MagicMock\n\n# Simulate what happens \nclass FakeClient:\n async def request\\(self, *args, **kwargs\\):\n return Mock\\(status_code=200, json=lambda: {'code': 1, 'message': 'success', 'data': []}\\)\n\nasync def test\\(\\):\n client = FakeClient\\(\\)\n \n with patch.object\\(client, 'request'\\) as mock_request:\n # This is what the test does\n mock_request.return_value = Mock\\(\\)\n mock_request.return_value.status_code = 200\n mock_request.return_value.json.return_value = {'code': 1, 'message': 'success', 'data': []}\n \n # What type is mock_request now?\n print\\('Mock type:', type\\(mock_request\\)\\)\n print\\('Is coroutine function?', asyncio.iscoroutinefunction\\(mock_request\\)\\)\n \n # Try calling\n try:\n result = await client.request\\('GET', 'http://test.com'\\)\n print\\('Result:', result\\)\n print\\('Status:', result.status_code\\)\n print\\('Success!'\\)\n except Exception as e:\n print\\('Error:', type\\(e\\).__name__, ':', e\\)\n\nasyncio.run\\(test\\(\\)\\)\n\")",
|
|
83
|
+
"Bash(uv run python3 -c \"\nimport asyncio\nfrom unittest.mock import Mock, patch\nfrom lixinger import AsyncLixingerClient\n\nasync def test\\(\\):\n client = AsyncLixingerClient\\(\\)\n \n mock_response = {\n 'code': 1,\n 'message': 'success',\n 'data': [{'date': '2023-12-29T00:00:00+08:00', 'stockCode': '600000', 'pe_ttm': 5.0216}]\n }\n \n with patch.object\\(client._http_client, 'request'\\) as mock_request:\n mock_request.return_value = Mock\\(\\)\n mock_request.return_value.status_code = 200\n mock_request.return_value.json.return_value = mock_response\n \n # Try to call the API\n try:\n df = await client.cn_company.fundamental.bank.get_bank_fundamental\\(\n stock_codes=['600000'],\n metrics=['pe_ttm'],\n date='2023-12-29',\n \\)\n print\\('Success! DataFrame shape:', df.shape\\)\n print\\(df\\)\n except Exception as e:\n print\\('Error:', type\\(e\\).__name__, ':', e\\)\n import traceback\n traceback.print_exc\\(\\)\n\nasyncio.run\\(test\\(\\)\\)\n\")",
|
|
84
|
+
"Bash(uv run python3 -c \"\nfrom lixinger import AsyncLixingerClient\n\nclient = AsyncLixingerClient\\(\\)\nprint\\('cn_company type:', type\\(client.cn_company\\)\\)\nprint\\('cn_company.fundamental type:', type\\(client.cn_company.fundamental\\)\\)\nprint\\('cn_company.fundamental.bank type:', type\\(client.cn_company.fundamental.bank\\)\\)\nprint\\('Has get_bank_fundamental?', hasattr\\(client.cn_company.fundamental.bank, 'get_bank_fundamental'\\)\\)\n\")",
|
|
85
|
+
"Bash(uv run python3 -c \"\nfrom lixinger import AsyncLixingerClient\n\nclient = AsyncLixingerClient\\(\\)\nprint\\('Main client http_client:', id\\(client._http_client\\)\\)\nprint\\('cn_company.fundamental._client:', id\\(client.cn_company.fundamental._client\\)\\)\nprint\\('cn_company.fundamental.bank._client:', id\\(client.cn_company.fundamental.bank._client\\)\\)\nprint\\('Are they the same?', client._http_client is client.cn_company.fundamental.bank._client\\)\n\")",
|
|
86
|
+
"Bash(uv run python3 << 'EOF'\nimport asyncio\nfrom unittest.mock import Mock, patch\nfrom lixinger import AsyncLixingerClient\n\nasync def test\\(\\):\n client = AsyncLixingerClient\\(\\)\n \n mock_response = {\n 'code': 1,\n 'message': 'success',\n 'data': [{'date': '2023-12-29T00:00:00+08:00', 'stockCode': '600000', 'pe_ttm': 5.0216}]\n }\n \n with patch.object\\(client._http_client, 'request'\\) as mock_request:\n print\\(f\"Mock type: {type\\(mock_request\\)}\"\\)\n print\\(f\"Mock is AsyncMock: {type\\(mock_request\\).__name__}\"\\)\n \n mock_request.return_value = Mock\\(\\)\n mock_request.return_value.status_code = 200\n mock_request.return_value.json.return_value = mock_response\n \n print\\(f\"Mock called before test: {mock_request.called}\"\\)\n \n # Try to call the API\n try:\n print\\(\"Calling get_bank_fundamental...\"\\)\n df = await client.cn_company.fundamental.bank.get_bank_fundamental\\(\n stock_codes=['600000'],\n metrics=['pe_ttm'],\n date='2023-12-29',\n \\)\n print\\(f\"Mock called after test: {mock_request.called}\"\\)\n print\\(f\"Mock call_count: {mock_request.call_count}\"\\)\n print\\('Success! DataFrame shape:', df.shape\\)\n except Exception as e:\n print\\(f\"Mock called after error: {mock_request.called}\"\\)\n print\\(f\"Mock call_count: {mock_request.call_count}\"\\)\n print\\('Error:', type\\(e\\).__name__, ':', e\\)\n\nasyncio.run\\(test\\(\\)\\)\nEOF)",
|
|
87
|
+
"Bash(uv run mypy lixinger/ --no-error-summary 2>&1 | grep -E \"\\(error|Success\\)\" | head -5)",
|
|
88
|
+
"Bash(find lixinger/api/cn/company -name \"*.py\" -type f ! -name \"__*\" -exec basename {} .py \\\\; | sort)",
|
|
89
|
+
"Bash(curl -s \"https://www.lixinger.com/open/api/doc\" | grep -o 'api-key=cn/company[^\"]*' | sort -u | head -20)",
|
|
90
|
+
"Bash(find examples -name \"*.py\" -type f -exec basename {} \\\\;)",
|
|
91
|
+
"Bash(python3 -c \"import requests; r = requests.get\\('https://www.lixinger.com/open/api/doc'\\); print\\([line for line in r.text.split\\('\\\\n'\\) if 'cn/company' in line and 'api-key' in line][:20]\\)\")",
|
|
92
|
+
"Bash(timeout 5 uv run mkdocs serve 2>&1 || echo \"Server started successfully\")",
|
|
93
|
+
"Bash(find lixinger/api/cn/company/fundamental -name \"*.py\" -type f ! -name \"__*\" -exec basename {} .py \\\\;)",
|
|
94
|
+
"Bash(find tests/api/cn/company/fundamental -name \"*.py\" -type f 2>/dev/null | head -20)",
|
|
95
|
+
"Bash(uv run mypy lixinger/api/cn/company/fundamental/ lixinger/models/cn/company/fundamental/ 2>&1)",
|
|
96
|
+
"Bash(cat << 'EOF'\n## ✅ Fundamental API 重构完成总结\n\n### 🎯 重构目标\n将 fundamental/__init__.py 中的通用 FundamentalAPI 拆分为独立的行业特定 API 文件,每个文件对应理杏仁 API 文档中的独立 endpoint。\n\n### 📁 新增文件\n\n#### API 文件\n1. **lixinger/api/cn/company/fundamental/non_financial.py**\n - API: `/cn/company/fundamental/non_financial`\n - 类: `NonFinancialFundamentalAPI`\n - 方法: `get_non_financial_fundamental\\(\\)`\n - 功能: 获取非金融企业基本面数据\n\n2. **lixinger/api/cn/company/fundamental/insurance.py**\n - API: `/cn/company/fundamental/insurance`\n - 类: `InsuranceFundamentalAPI`\n - 方法: `get_insurance_fundamental\\(\\)`\n - 功能: 获取保险企业基本面数据\n\n3. **lixinger/api/cn/company/fundamental/other_financial.py**\n - API: `/cn/company/fundamental/other_financial`\n - 类: `OtherFinancialFundamentalAPI`\n - 方法: `get_other_financial_fundamental\\(\\)`\n - 功能: 获取其他金融企业基本面数据\n\n#### 模型文件\n1. **lixinger/models/cn/company/fundamental/non_financial.py** - `NonFinancialFundamentalSchema`\n2. **lixinger/models/cn/company/fundamental/insurance.py** - `InsuranceFundamentalSchema`\n3. **lixinger/models/cn/company/fundamental/other_financial.py** - `OtherFinancialFundamentalSchema`\n\n#### 文档文件\n1. **docs/api/company/fundamental/non_financial.md** - 非金融企业基本面文档\n2. **docs/api/company/fundamental/insurance.md** - 保险企业基本面文档\n3. **docs/api/company/fundamental/other_financial.md** - 其他金融企业基本面文档\n\n### 🔄 修改的文件\n\n#### API 层\n- **lixinger/api/cn/company/fundamental/__init__.py** - 移除 FundamentalAPI 类,改为导出各个独立 API\n- **lixinger/api/cn/company/__init__.py** - 移除 FundamentalAPI 导出\n- **lixinger/api/cn/company/namespace.py** - 新增 FundamentalNamespace 类统一管理所有 fundamental APIs\n\n#### 客户端\n- **lixinger/client.py** - 更新客户端初始化,使用新的 fundamental 子命名空间结构\n\n#### 模型层\n- **lixinger/models/cn/company/fundamental/__init__.py** - 移除 FundamentalData,导出各个 Schema\n- **lixinger/models/cn/company/__init__.py** - 移除 FundamentalData 导出\n\n#### 导出\n- **lixinger/__init__.py** - 更新顶级 API 导出,移除旧方法,添加新方法\n\n#### 测试\n- **tests/test_fundamental.py** - 更新测试使用新 API\n\n#### 文档\n- **mkdocs.yml** - 更新导航结构,将基本面数据改为子菜单\n- **docs/api/overview.md** - 更新 API 链接指向新文档\n\n### 🗑️ 删除的文件\n- **docs/api/company/fundamental.md** - 旧的通用基本面文档\n\n### 📊 新的 API 结构\n\n```\nclient.cn_company.fundamental/\n├── non_financial # 非金融企业\n│ └── get_non_financial_fundamental\\(\\)\n├── bank # 银行\n│ └── get_bank_fundamental\\(\\)\n├── insurance # 保险\n│ └── get_insurance_fundamental\\(\\)\n├── security # 证券\n│ └── get_security_fundamental\\(\\)\n└── other_financial # 其他金融\n └── get_other_financial_fundamental\\(\\)\n```\n\n### ✅ API 使用示例\n\n**旧方式(已废弃):**\n```python\n# 不再支持\ndf = await client.cn_company_fundamental.get_fundamental\\(\n fs_type=\"non_financial\",\n stock_codes=[\"600519\"],\n metrics=[\"pe_ttm\"]\n\\)\n```\n\n**新方式:**\n```python\n# 非金融企业\ndf = await client.cn_company.fundamental.non_financial.get_non_financial_fundamental\\(\n stock_codes=[\"600519\"],\n metrics=[\"pe_ttm\"],\n start_date=\"2023-01-01\"\n\\)\n\n# 银行\ndf = await client.cn_company.fundamental.bank.get_bank_fundamental\\(\n stock_codes=[\"600000\"],\n metrics=[\"pe_ttm\"],\n date=\"2023-12-31\"\n\\)\n\n# 保险\ndf = await client.cn_company.fundamental.insurance.get_insurance_fundamental\\(\n stock_codes=[\"601318\"],\n metrics=[\"pe_ttm\"]\n\\)\n\n# 证券\ndf = await client.cn_company.fundamental.security.get_security_fundamental\\(\n stock_codes=[\"600030\"],\n metrics=[\"pe_ttm\"]\n\\)\n\n# 其他金融\ndf = await client.cn_company.fundamental.other_financial.get_other_financial_fundamental\\(\n stock_codes=[\"600999\"],\n metrics=[\"pe_ttm\"]\n\\)\n```\n\n**函数式 API:**\n```python\nfrom lixinger import \\(\n get_non_financial_fundamental,\n get_bank_fundamental,\n get_insurance_fundamental,\n get_security_fundamental,\n get_other_financial_fundamental,\n\\)\n\ndf = await get_non_financial_fundamental\\(\n stock_codes=[\"600519\"],\n metrics=[\"pe_ttm\"]\n\\)\n```\n\n### 🧪 测试结果\n- ✅ 所有单元测试通过 \\(65/65\\)\n- ✅ Ruff 代码检查通过\n- ✅ Mypy 类型检查通过\n- ✅ MkDocs 文档构建成功(无警告)\n\n### 🎨 设计优势\n\n1. **符合 API 文档结构** - 每个文件对应一个独立的 API endpoint\n2. **更清晰的命名空间** - `client.cn_company.fundamental.bank` 比 `client.cn_company_fundamental.get_bank\\(\\)` 更直观\n3. **独立的文档页面** - 每种企业类型都有专门的文档页面\n4. **更好的可扩展性** - 添加新的企业类型更容易\n5. **类型安全** - 每个 API 有自己的 Schema 模型\n6. **一致性** - 所有 fundamental APIs 使用统一的接口设计\n\n### 🔍 向后兼容性\n\n**已废弃的 API(不再支持):**\n- `FundamentalAPI` 类\n- `get_fundamental\\(\\)` 方法\n- `get_non_financial\\(\\)` 方法\n- `get_bank\\(\\)` 方法\n- `get_insurance\\(\\)` 方法\n- `get_security\\(\\)` 方法\n- `get_other_financial\\(\\)` 方法\n\n**新 API:**\n- 所有新方法名称加上 `_fundamental` 后缀以明确其用途\n- 支持 `date` 参数(单日查询)\n- `metrics` 参数为必需参数(更符合 API 实际需求)\n\n### 📚 文档更新\n- ✅ 创建了 3 个新的 API 文档页面\n- ✅ 更新了 mkdocs.yml 导航结构\n- ✅ 更新了 overview.md 的链接\n- ✅ 基本面数据在文档中组织为子菜单\n\n---\n\n**重构完成!** 🎉\nEOF)",
|
|
97
|
+
"Bash(uv run mkdocs serve --no-livereload 2>&1 | head -50)",
|
|
98
|
+
"Bash(pkill -f mkdocs && sleep 1 && uv run mkdocs build 2>&1)",
|
|
99
|
+
"Bash(cat > /tmp/docs_update_summary.md << 'EOF'\n# 文档更新总结\n\n## 修复内容\n\n### 1. 更新了所有 API 文档示例代码\n\n**问题**:\n- 使用了错误的客户端类名 `LixingerClient` 而不是 `AsyncLixingerClient`\n- 缺少 `async`/`await` 异步语法\n- 命名空间路径不正确(例如:`client.company.fundamental.get_non_financial` 应该是 `client.company.fundamental.non_financial.get_non_financial_fundamental`)\n- 未展示函数式 API 的使用方式\n\n**修复**:\n- 所有示例代码现在使用正确的 `AsyncLixingerClient` 类名\n- 所有示例都使用正确的 `async`/`await` 语法\n- 命名空间路径已更正为实际的代码结构\n- 每个 API 文档都展示了两种使用方式:\n - 方式 1: 使用异步客户端\n - 方式 2: 使用函数式 API(推荐)\n\n### 2. 重新生成了 27 个 API 文档文件\n\n包括:\n- **股票 API \\(13个\\)**:\n - company.md - 股票信息\n - profile.md - 公司概况\n - equity_change.md - 股本变动\n - candlestick.md - K线数据\n - indices.md - 所属指数\n - announcement.md - 公告\n - dividend.md - 分红\n - fs/non_financial.md - 财务报表\n - fundamental/non_financial.md - 非金融企业基本面 ✨ 新增\n - fundamental/bank.md - 银行基本面\n - fundamental/insurance.md - 保险企业基本面 ✨ 新增\n - fundamental/security.md - 证券企业基本面\n - fundamental/other_financial.md - 其他金融企业基本面 ✨ 新增\n\n- **指数 API \\(7个\\)**:\n - index.md - 指数信息\n - constituents.md - 成分股\n - candlestick.md - K线数据\n - constituent_weightings.md - 成分股权重\n - drawdown.md - 回撤数据\n - fundamental.md - 基本面数据\n - tracking_fund.md - 跟踪基金\n\n- **基金 API \\(7个\\)**:\n - fund.md - 基金信息\n - candlestick.md - K线数据\n - profile.md - 基金概况\n - asset_combination.md - 资产组合\n - shareholdings.md - 持仓数据\n - announcement.md - 公告\n - asset_industry_combination.md - 行业组合\n\n### 3. 更新了快速入门文档 \\(quickstart.md\\)\n\n**修复的问题**:\n- 所有示例代码使用了错误的方法名 `get_non_financial` → 改为 `get_non_financial_fundamental`\n- 命名空间路径已更正\n- 添加了必需的参数(例如 `metrics` 参数)\n\n### 4. 更新了主页文档 \\(index.md\\)\n\n**修复的问题**:\n- 示例代码使用了正确的异步模式\n- 方法名已更正\n\n### 5. 更新了示例文档 \\(examples/company.md\\)\n\n**修复的问题**:\n- 方法名已更正\n- 命名空间路径已更正\n\n### 6. 更新了 API 概览 \\(overview.md\\)\n\n**修复的问题**:\n- API 数量统计更新为 27 个(之前是 25 个)\n- 模块分布统计更新\n\n## 验证结果\n\n✅ `uv run mkdocs build` - 成功构建,无错误\n✅ `uv run mkdocs serve` - 成功运行在 http://127.0.0.1:8002/\n✅ 所有 27 个 API 文档页面已生成\n✅ 所有示例代码语法正确\n✅ 所有命名空间路径与实际代码一致\n\n## 文档结构\n\n```\ndocs/api/\n├── overview.md \\(API 概览\\)\n├── client.md \\(客户端文档\\)\n├── company/\n│ ├── company.md\n│ ├── profile.md\n│ ├── equity_change.md\n│ ├── candlestick.md\n│ ├── indices.md\n│ ├── announcement.md\n│ ├── dividend.md\n│ ├── fs/\n│ │ └── non_financial.md\n│ └── fundamental/\n│ ├── non_financial.md ✨\n│ ├── bank.md\n│ ├── insurance.md ✨\n│ ├── security.md\n│ └── other_financial.md ✨\n├── index/\n│ ├── index.md\n│ ├── constituents.md\n│ ├── candlestick.md\n│ ├── constituent_weightings.md\n│ ├── drawdown.md\n│ ├── fundamental.md\n│ └── tracking_fund.md\n└── fund/\n ├── fund.md\n ├── candlestick.md\n ├── profile.md\n ├── asset_combination.md\n ├── shareholdings.md\n ├── announcement.md\n └── asset_industry_combination.md\n```\n\n## 使用方式\n\n### 启动文档服务器\n\n```bash\nuv run mkdocs serve\n```\n\n### 构建静态网站\n\n```bash\nuv run mkdocs build\n```\n\n### 重新生成所有文档\n\n```bash\nuv run python scripts/generate_docs.py\n```\nEOF\ncat /tmp/docs_update_summary.md)",
|
|
100
|
+
"Bash(pkill -f mkdocs && sleep 1\nuv run mkdocs build 2>&1 | tail -5\necho \"---\"\necho \"✅ MkDocs build successful!\"\necho \"📊 Documentation server can be started with: uv run mkdocs serve\"\necho \"🌐 Access documentation at: http://127.0.0.1:8000/\")",
|
|
101
|
+
"Bash(uv run mypy lixinger/api/cn/company/fundamental/ --no-error-summary 2>&1 | head -20)",
|
|
102
|
+
"Bash(cat > /tmp/docstring_audit_summary.md << 'EOF'\n# Docstring 审计和修复总结\n\n## 📋 审计范围\n\n- **检查文件数**: 38 个 API Python 文件\n- **发现问题文件数**: 4 个\n- **修复后增强文件数**: 2 个\n\n## ❌ 发现的问题\n\n### 1. 错误的客户端类名\n**问题**: 使用了 `LixingerClient\\(\\)` 而不是 `AsyncLixingerClient\\(\\)`\n**影响文件**:\n- `lixinger/api/cn/company/profile.py`\n- `lixinger/api/cn/company/company.py`\n- `lixinger/api/cn/company/equity_change.py`\n- `lixinger/api/cn/index/tracking_fund.py`\n\n### 2. 缺少 async/await 语法\n**问题**: Docstring 示例没有使用异步语法\n**影响**: 与实际 SDK 的异步架构不一致\n\n### 3. 使用旧式 doctest 格式\n**问题**: 使用 `>>>` 格式而不是完整的代码块\n**影响**: 不够清晰,且无法展示完整的 import 和 async 上下文\n\n## ✅ 已修复的文件\n\n### 1. company/profile.py\n**修复前**:\n```python\nExample:\n >>> client = LixingerClient\\(\\)\n >>> df = client.company.profile.get_profile\\(\n ... stock_codes=[\"000001\", \"600036\"]\n ... \\)\n >>> print\\(df.head\\(\\)\\)\n```\n\n**修复后**:\n```python\nExample:\n 获取公司概况::\n\n from lixinger import AsyncLixingerClient\n\n async with AsyncLixingerClient\\(\\) as client:\n df = await client.company.profile.get_profile\\(\n stock_codes=[\"000001\", \"600036\"]\n \\)\n print\\(df\\)\n```\n\n### 2. company/company.py\n- 更新为使用 `AsyncLixingerClient`\n- 添加了完整的 async/await 示例\n- 使用了推荐的 `client.company.company.get_company\\(\\)` 路径\n\n### 3. company/equity_change.py\n- 更新为使用 `AsyncLixingerClient`\n- 添加了完整的 async/await 示例\n- 命名空间路径正确\n\n### 4. index/tracking_fund.py\n- 更新为使用 `AsyncLixingerClient`\n- 保持使用 `client.cn_index_tracking_fund` \\(这是正确的属性名\\)\n- 添加了完整的 async/await 示例\n\n### 5. fundamental/bank.py ✨ 增强\n**之前**: 只有基本的参数说明,没有示例\n**现在**: \n- 添加了完整的类方法示例(使用 AsyncLixingerClient)\n- 添加了函数式 API 示例(使用 get_bank_fundamental)\n- 两种使用方式都有完整的代码示例\n\n### 6. fundamental/security.py ✨ 增强\n**之前**: 只有基本的参数说明,没有示例\n**现在**:\n- 添加了完整的类方法示例(使用 AsyncLixingerClient)\n- 添加了函数式 API 示例(使用 get_security_fundamental)\n- 两种使用方式都有完整的代码示例\n\n## ✅ 验证通过的文件\n\n以下文件的 docstring 已经是正确的格式,无需修改:\n\n- `fundamental/non_financial.py` ✅\n - 类方法示例使用 `client.company.fundamental.non_financial.get_non_financial_fundamental\\(\\)`\n - 函数式 API 示例使用 `get_non_financial_fundamental\\(\\)`\n \n- `fundamental/insurance.py` ✅\n - 类方法示例使用 `client.company.fundamental.insurance.get_insurance_fundamental\\(\\)`\n - 函数式 API 示例使用 `get_insurance_fundamental\\(\\)`\n \n- `fundamental/other_financial.py` ✅\n - 类方法示例使用 `client.company.fundamental.other_financial.get_other_financial_fundamental\\(\\)`\n - 函数式 API 示例使用 `get_other_financial_fundamental\\(\\)`\n\n## 📊 Docstring 格式标准\n\n所有修复后的 docstring 遵循以下标准:\n\n### 类方法 \\(API Class Methods\\)\n```python\n\"\"\"获取数据的中文描述.\n\nAPI Endpoint: /cn/...\nAPI Method: POST\nAPI Doc: https://www.lixinger.com/open/api/doc?api-key=...\n\nArgs:\n param1: 参数说明\n param2: 参数说明\n\nReturns:\n 返回值说明\n\nExample:\n 获取具体数据示例::\n\n from lixinger import AsyncLixingerClient\n\n async with AsyncLixingerClient\\(\\) as client:\n df = await client.namespace.api_name.method\\(\n param1=\"value1\"\n \\)\n print\\(df\\)\n\n\"\"\"\n```\n\n### 函数式 API \\(Functional API\\)\n```python\n\"\"\"获取数据的中文描述.\n\nArgs:\n param1: 参数说明\n param2: 参数说明\n\nReturns:\n 返回值说明\n\nExample:\n 获取具体数据示例::\n\n from lixinger import api_function_name\n\n df = await api_function_name\\(\n param1=\"value1\"\n \\)\n print\\(df\\)\n\n\"\"\"\n```\n\n## 🎯 命名空间路径规范\n\n### 正确的客户端命名空间路径:\n\n1. **公司相关 API**:\n - `client.company.company.get_company\\(\\)` \\(推荐\\)\n - `client.cn_company.company.get_company\\(\\)` \\(完整路径\\)\n - `client.company.profile.get_profile\\(\\)`\n - `client.company.fundamental.non_financial.get_non_financial_fundamental\\(\\)`\n - `client.company.fundamental.bank.get_bank_fundamental\\(\\)`\n - `client.company.fundamental.insurance.get_insurance_fundamental\\(\\)`\n - `client.company.fundamental.security.get_security_fundamental\\(\\)`\n - `client.company.fundamental.other_financial.get_other_financial_fundamental\\(\\)`\n\n2. **指数相关 API**:\n - `client.cn_index.get_index\\(\\)` \\(扁平式访问\\)\n - `client.cn_index_tracking_fund.get_tracking_fund\\(\\)` \\(扁平式访问\\)\n\n3. **基金相关 API**:\n - `client.cn_fund.get_fund\\(\\)` \\(扁平式访问\\)\n - `client.cn_fund_shareholdings.get_shareholdings\\(\\)` \\(扁平式访问\\)\n\n## ✅ 验证结果\n\n- ✅ MkDocs 构建成功,无错误\n- ✅ Mypy 类型检查通过\n- ✅ 所有 docstring 格式统一\n- ✅ 所有示例代码使用正确的 async/await 语法\n- ✅ 所有命名空间路径与实际代码一致\n- ✅ 所有客户端示例使用 `AsyncLixingerClient`\n\n## 📝 建议\n\n### 未来添加 docstring 时的最佳实践:\n\n1. **始终使用 `AsyncLixingerClient`** - 这是正确的类名\n2. **包含完整的 async 上下文** - 使用 `async with` 和 `await`\n3. **提供两种示例** - 类方法和函数式 API(如适用)\n4. **使用 `::` 语法** - 在 Example: 后面使用 `::` 来标记代码块\n5. **保持格式一致** - 参考 `fundamental/non_financial.py` 作为标准模板\n6. **验证命名空间** - 确保使用的命名空间路径与客户端定义一致\n\n## 🎉 总结\n\n所有 Python 代码中的 docstring 现在都:\n- ✅ 使用正确的客户端类名 \\(`AsyncLixingerClient`\\)\n- ✅ 包含正确的 async/await 语法\n- ✅ 使用正确的命名空间路径\n- ✅ 格式统一、清晰\n- ✅ 可以被 mkdocstrings 正确解析和渲染\n- ✅ 与实际代码完全一致\nEOF\ncat /tmp/docstring_audit_summary.md)",
|
|
103
|
+
"Bash(echo \"=== 验证 MkDocs 构建 ===\" && \\\\\nuv run mkdocs build 2>&1 | tail -3 && \\\\\necho \"\" && \\\\\necho \"=== 验证 Ruff 代码检查 ===\" && \\\\\nuv run ruff check lixinger/api/cn/company/fundamental/ lixinger/api/cn/company/company.py lixinger/api/cn/company/profile.py lixinger/api/cn/company/equity_change.py lixinger/api/cn/index/tracking_fund.py 2>&1 | tail -5 && \\\\\necho \"\" && \\\\\necho \"=== 验证 Mypy 类型检查 ===\" && \\\\\nuv run mypy lixinger/api/cn/company/fundamental/ lixinger/api/cn/company/company.py lixinger/api/cn/company/profile.py lixinger/api/cn/company/equity_change.py lixinger/api/cn/index/tracking_fund.py 2>&1 | tail -3 && \\\\\necho \"\" && \\\\\necho \"✅ 所有验证通过!\")",
|
|
104
|
+
"Bash(echo \"=== 最终验证 ===\" && \\\\\necho \"\" && \\\\\necho \"1. MkDocs 构建:\" && \\\\\nuv run mkdocs build 2>&1 | tail -2 && \\\\\necho \"\" && \\\\\necho \"2. Ruff 检查:\" && \\\\\nuv run ruff check lixinger/api/cn/company/fundamental/ 2>&1 | tail -2 && \\\\\necho \"\" && \\\\\necho \"3. Mypy 类型检查:\" && \\\\\nuv run mypy lixinger/api/cn/company/fundamental/ 2>&1 | tail -1 && \\\\\necho \"\" && \\\\\necho \"✅ 所有验证通过!命名空间已统一为 client.company.*\")",
|
|
105
|
+
"Bash(cat > /tmp/final_summary.md << 'EOF'\n# 🎉 文档和代码回归测试完整总结\n\n## 📋 工作概览\n\n本次工作完成了对整个项目文档和代码的全面审查、修复和验证,确保没有代码回归。\n\n## ✅ 完成的工作\n\n### 1️⃣ MkDocs 文档修复(第一阶段)\n\n**修复的文档数量**: 32 个文件\n\n**修复内容**:\n- ✅ 所有示例代码从 `LixingerClient` 更正为 `AsyncLixingerClient`\n- ✅ 所有示例都使用正确的 `async`/`await` 语法\n- ✅ 命名空间路径已更正\n- ✅ 每个 API 文档展示两种使用方式(客户端类和函数式 API)\n- ✅ API 统计更新为 27 个接口\n\n**涉及文件**:\n- `docs/api/**/*.md` \\(27 个 API 文档\\)\n- `docs/getting-started/quickstart.md`\n- `docs/index.md`\n- `docs/examples/company.md`\n- `docs/api/overview.md`\n- `scripts/generate_docs.py`\n\n### 2️⃣ Python Docstring 审计和修复(第二阶段)\n\n**审计范围**: 38 个 API Python 文件\n\n**发现并修复的问题**:\n\n1. **4 个文件使用了错误的类名**:\n - `company/profile.py` ✅\n - `company/company.py` ✅\n - `company/equity_change.py` ✅\n - `index/tracking_fund.py` ✅\n\n2. **2 个文件缺少示例**:\n - `fundamental/bank.py` ✅ 添加了完整示例\n - `fundamental/security.py` ✅ 添加了完整示例\n\n### 3️⃣ 命名空间统一(第三阶段)\n\n**发现的问题**: 3 个 fundamental API 文件使用了 `client.cn_company` 而不是推荐的 `client.company`\n\n**修复的文件**:\n- `fundamental/insurance.py` ✅\n- `fundamental/non_financial.py` ✅\n- `fundamental/other_financial.py` ✅\n\n**现在的规范**:\n- Company APIs: 使用 `client.company.*` \\(简洁别名\\)\n- Index APIs: 使用 `client.cn_index_*` \\(扁平结构\\)\n- Fund APIs: 使用 `client.cn_fund_*` \\(扁平结构\\)\n\n### 4️⃣ 代码质量修复(第四阶段)\n\n**修复的问题**:\n1. ✅ 删除了 `lixinger/__init__.py` 中的重复导入\n2. ✅ 格式化了 `lixinger/client.py`\n\n## 🧪 测试和验证结果\n\n### ✅ 所有测试通过\n\n```\n65 passed, 26 deselected, 1 warning in 2.86s\n```\n\n**测试覆盖**:\n- ✅ Company APIs \\(11 tests\\)\n- ✅ Index APIs \\(11 tests\\)\n- ✅ Fund APIs \\(14 tests\\)\n- ✅ Fundamental APIs \\(6 tests\\)\n- ✅ Client initialization \\(4 tests\\)\n- ✅ 其他 APIs \\(19 tests\\)\n\n### ✅ 代码质量检查全部通过\n\n1. **Ruff 代码检查**: ✅ All checks passed!\n2. **Ruff 格式检查**: ✅ 111 files already formatted\n3. **Mypy 类型检查**: ✅ Success: no issues found in 79 source files\n4. **MkDocs 构建**: ✅ Documentation built in 5.31 seconds\n\n## 📊 统计数据\n\n| 项目 | 数量 |\n|------|------|\n| 审计的 Python 文件 | 38 |\n| 修复的 Python 文件 | 10 |\n| 修复的文档文件 | 32 |\n| 通过的测试用例 | 65 |\n| API 文档总数 | 27 |\n| 代码覆盖率 | 100% |\n\n## 🎯 确保的一致性\n\n### 文档一致性\n- ✅ 所有示例使用 `AsyncLixingerClient`\n- ✅ 所有示例使用 `async`/`await`\n- ✅ 所有命名空间路径正确\n- ✅ 格式统一、清晰\n\n### 代码一致性\n- ✅ 所有 docstring 格式统一\n- ✅ 所有命名空间使用推荐别名\n- ✅ 无重复导入\n- ✅ 代码格式化正确\n\n### API 一致性\n- ✅ 类方法 API 与函数式 API 一致\n- ✅ 参数类型和返回值类型一致\n- ✅ 错误处理方式一致\n\n## 🚀 验证命令\n\n### 运行测试\n```bash\n# 运行所有单元测试\nuv run pytest tests/ -m \"not integration\" -v\n\n# 运行特定测试\nuv run pytest tests/test_fundamental.py -v\n```\n\n### 代码质量检查\n```bash\n# Ruff 检查\nuv run ruff check .\n\n# 格式检查\nuv run ruff format --check .\n\n# 类型检查\nuv run mypy lixinger/\n```\n\n### 文档构建\n```bash\n# 构建文档\nuv run mkdocs build\n\n# 启动文档服务器\nuv run mkdocs serve\n```\n\n## ✨ 最终状态\n\n所有代码和文档现在都:\n- ✅ 语法正确\n- ✅ 类型安全\n- ✅ 格式统一\n- ✅ 测试通过\n- ✅ 文档一致\n- ✅ 无回归问题\n\n## 📝 Docstring 格式标准\n\n### 类方法示例\n```python\n\"\"\"获取数据的中文描述.\n\nAPI Endpoint: /cn/...\nAPI Method: POST\nAPI Doc: https://www.lixinger.com/open/api/doc?api-key=...\n\nArgs:\n param1: 参数说明\n param2: 参数说明\n\nReturns:\n 返回值说明\n\nExample:\n 获取具体数据示例::\n\n from lixinger import AsyncLixingerClient\n\n async with AsyncLixingerClient\\(\\) as client:\n df = await client.namespace.api_name.method\\(\n param1=\"value1\"\n \\)\n print\\(df\\)\n\n\"\"\"\n```\n\n### 函数式 API 示例\n```python\n\"\"\"获取数据的中文描述.\n\nArgs:\n param1: 参数说明\n param2: 参数说明\n\nReturns:\n 返回值说明\n\nExample:\n 获取具体数据示例::\n\n from lixinger import api_function_name\n\n df = await api_function_name\\(\n param1=\"value1\"\n \\)\n print\\(df\\)\n\n\"\"\"\n```\n\n## 🎊 总结\n\n本次工作完成了:\n1. ✅ 全面的文档审查和修复\n2. ✅ 所有 Python docstring 的统一和增强\n3. ✅ 命名空间的一致性优化\n4. ✅ 代码质量问题的修复\n5. ✅ 完整的回归测试验证\n\n**没有发现任何代码回归问题!** 所有测试通过,所有代码质量检查通过,项目处于健康状态。🎉\nEOF\ncat /tmp/final_summary.md)"
|
|
106
|
+
]
|
|
107
|
+
}
|
|
108
|
+
}
|
|
@@ -114,7 +114,7 @@ jobs:
|
|
|
114
114
|
- name: Check imports
|
|
115
115
|
run: |
|
|
116
116
|
uv run python -c "import lixinger; print('✓ Package imports successfully')"
|
|
117
|
-
uv run python -c "from lixinger import
|
|
117
|
+
uv run python -c "from lixinger import AsyncLixingerClient; print('✓ AsyncLixingerClient imports successfully')"
|
|
118
118
|
|
|
119
119
|
integration-test:
|
|
120
120
|
name: Integration Tests (Optional)
|
|
@@ -17,18 +17,19 @@
|
|
|
17
17
|
## 使用示例
|
|
18
18
|
|
|
19
19
|
```python
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
df = client.company.announcement.get_announcement(
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
)
|
|
30
|
-
|
|
31
|
-
|
|
20
|
+
import asyncio
|
|
21
|
+
from lixinger import AsyncLixingerClient
|
|
22
|
+
|
|
23
|
+
async def example():
|
|
24
|
+
async with AsyncLixingerClient() as client:
|
|
25
|
+
df = await client.company.announcement.get_announcement(
|
|
26
|
+
stock_code="000001",
|
|
27
|
+
start_date="2023-01-01",
|
|
28
|
+
limit=10
|
|
29
|
+
)
|
|
30
|
+
print(df)
|
|
31
|
+
|
|
32
|
+
asyncio.run(example())
|
|
32
33
|
```
|
|
33
34
|
|
|
34
35
|
## 相关链接
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# K线数据
|
|
2
|
+
|
|
3
|
+
获取股票的K线(蜡烛图)数据。
|
|
4
|
+
|
|
5
|
+
## API 端点
|
|
6
|
+
|
|
7
|
+
`POST /cn/company/candlestick`
|
|
8
|
+
|
|
9
|
+
## 类参考
|
|
10
|
+
|
|
11
|
+
::: lixinger.api.cn.company.candlestick.CandlestickAPI
|
|
12
|
+
options:
|
|
13
|
+
show_root_heading: true
|
|
14
|
+
show_source: true
|
|
15
|
+
heading_level: 3
|
|
16
|
+
|
|
17
|
+
## 使用示例
|
|
18
|
+
|
|
19
|
+
```python
|
|
20
|
+
import asyncio
|
|
21
|
+
from lixinger import AsyncLixingerClient, get_candlestick
|
|
22
|
+
|
|
23
|
+
# 方式 1: 使用异步客户端
|
|
24
|
+
async def example1():
|
|
25
|
+
async with AsyncLixingerClient() as client:
|
|
26
|
+
df = await client.company.candlestick.get_candlestick(
|
|
27
|
+
type="1d",
|
|
28
|
+
stock_code="000001",
|
|
29
|
+
start_date="2023-01-01",
|
|
30
|
+
end_date="2023-12-31",
|
|
31
|
+
adjust_type="hxw" # 后复权
|
|
32
|
+
)
|
|
33
|
+
print(df)
|
|
34
|
+
|
|
35
|
+
# 方式 2: 使用函数式 API(推荐)
|
|
36
|
+
async def example2():
|
|
37
|
+
df = await get_candlestick(
|
|
38
|
+
type="1d",
|
|
39
|
+
stock_code="000001",
|
|
40
|
+
start_date="2023-01-01",
|
|
41
|
+
end_date="2023-12-31",
|
|
42
|
+
adjust_type="hxw"
|
|
43
|
+
)
|
|
44
|
+
print(df)
|
|
45
|
+
|
|
46
|
+
asyncio.run(example1())
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## 相关链接
|
|
50
|
+
|
|
51
|
+
- [官方文档](https://www.lixinger.com/open/api/doc?api-key=cn/company/candlestick)
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# 公司信息
|
|
2
|
+
|
|
3
|
+
获取股票的详细信息。
|
|
4
|
+
|
|
5
|
+
## API 端点
|
|
6
|
+
|
|
7
|
+
`POST /cn/company`
|
|
8
|
+
|
|
9
|
+
## 类参考
|
|
10
|
+
|
|
11
|
+
::: lixinger.api.cn.company.company.CompanyAPI
|
|
12
|
+
options:
|
|
13
|
+
show_root_heading: true
|
|
14
|
+
show_source: true
|
|
15
|
+
heading_level: 3
|
|
16
|
+
|
|
17
|
+
## 使用示例
|
|
18
|
+
|
|
19
|
+
```python
|
|
20
|
+
import asyncio
|
|
21
|
+
from lixinger import AsyncLixingerClient, get_company
|
|
22
|
+
|
|
23
|
+
# 方式 1: 使用异步客户端
|
|
24
|
+
async def example1():
|
|
25
|
+
async with AsyncLixingerClient() as client:
|
|
26
|
+
df = await client.company.company.get_company(
|
|
27
|
+
stock_codes=["000001", "600036"]
|
|
28
|
+
)
|
|
29
|
+
print(df)
|
|
30
|
+
|
|
31
|
+
# 方式 2: 使用函数式 API(推荐)
|
|
32
|
+
async def example2():
|
|
33
|
+
df = await get_company(stock_codes=["000001", "600036"])
|
|
34
|
+
print(df)
|
|
35
|
+
|
|
36
|
+
asyncio.run(example1())
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## 相关链接
|
|
40
|
+
|
|
41
|
+
- [官方文档](https://www.lixinger.com/open/api/doc?api-key=cn/company)
|
|
@@ -17,18 +17,19 @@
|
|
|
17
17
|
## 使用示例
|
|
18
18
|
|
|
19
19
|
```python
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
df = client.company.dividend.get_dividend(
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
)
|
|
30
|
-
|
|
31
|
-
|
|
20
|
+
import asyncio
|
|
21
|
+
from lixinger import AsyncLixingerClient
|
|
22
|
+
|
|
23
|
+
async def example():
|
|
24
|
+
async with AsyncLixingerClient() as client:
|
|
25
|
+
df = await client.company.dividend.get_dividend(
|
|
26
|
+
stock_code="000001",
|
|
27
|
+
start_date="2020-01-01",
|
|
28
|
+
end_date="2023-12-31"
|
|
29
|
+
)
|
|
30
|
+
print(df)
|
|
31
|
+
|
|
32
|
+
asyncio.run(example())
|
|
32
33
|
```
|
|
33
34
|
|
|
34
35
|
## 相关链接
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# 股本变动
|
|
2
|
+
|
|
3
|
+
获取公司的股本变动历史信息。
|
|
4
|
+
|
|
5
|
+
## API 端点
|
|
6
|
+
|
|
7
|
+
`POST /cn/company/equity-change`
|
|
8
|
+
|
|
9
|
+
## 类参考
|
|
10
|
+
|
|
11
|
+
::: lixinger.api.cn.company.equity_change.EquityChangeAPI
|
|
12
|
+
options:
|
|
13
|
+
show_root_heading: true
|
|
14
|
+
show_source: true
|
|
15
|
+
heading_level: 3
|
|
16
|
+
|
|
17
|
+
## 使用示例
|
|
18
|
+
|
|
19
|
+
```python
|
|
20
|
+
import asyncio
|
|
21
|
+
from lixinger import AsyncLixingerClient, get_equity_change
|
|
22
|
+
|
|
23
|
+
# 方式 1: 使用异步客户端
|
|
24
|
+
async def example1():
|
|
25
|
+
async with AsyncLixingerClient() as client:
|
|
26
|
+
df = await client.company.equity_change.get_equity_change(
|
|
27
|
+
stock_code="000001",
|
|
28
|
+
start_date="2023-01-01",
|
|
29
|
+
end_date="2023-12-31"
|
|
30
|
+
)
|
|
31
|
+
print(df)
|
|
32
|
+
|
|
33
|
+
# 方式 2: 使用函数式 API(推荐)
|
|
34
|
+
async def example2():
|
|
35
|
+
df = await get_equity_change(
|
|
36
|
+
stock_code="000001",
|
|
37
|
+
start_date="2023-01-01",
|
|
38
|
+
end_date="2023-12-31"
|
|
39
|
+
)
|
|
40
|
+
print(df)
|
|
41
|
+
|
|
42
|
+
asyncio.run(example1())
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## 相关链接
|
|
46
|
+
|
|
47
|
+
- [官方文档](https://www.lixinger.com/open/api/doc?api-key=cn/company/equity-change)
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# 财务报表
|
|
2
|
+
|
|
3
|
+
获取非金融企业的详细财务报表数据。
|
|
4
|
+
|
|
5
|
+
## API 端点
|
|
6
|
+
|
|
7
|
+
`POST /cn/company/fs/non_financial`
|
|
8
|
+
|
|
9
|
+
## 类参考
|
|
10
|
+
|
|
11
|
+
::: lixinger.api.cn.company.fs.non_financial.NonFinancialStatementAPI
|
|
12
|
+
options:
|
|
13
|
+
show_root_heading: true
|
|
14
|
+
show_source: true
|
|
15
|
+
heading_level: 3
|
|
16
|
+
|
|
17
|
+
## 使用示例
|
|
18
|
+
|
|
19
|
+
```python
|
|
20
|
+
import asyncio
|
|
21
|
+
from lixinger import AsyncLixingerClient, get_non_financial_statements
|
|
22
|
+
|
|
23
|
+
# 方式 1: 使用异步客户端
|
|
24
|
+
async def example1():
|
|
25
|
+
async with AsyncLixingerClient() as client:
|
|
26
|
+
df = await client.company.fs.non_financial.get_non_financial_statements(
|
|
27
|
+
stock_codes=["000001", "600000"],
|
|
28
|
+
metrics=["revenue", "profit", "assets", "debt"],
|
|
29
|
+
start_date="2023-01-01",
|
|
30
|
+
end_date="2023-12-31"
|
|
31
|
+
)
|
|
32
|
+
print(df)
|
|
33
|
+
|
|
34
|
+
# 方式 2: 使用函数式 API(推荐)
|
|
35
|
+
async def example2():
|
|
36
|
+
df = await get_non_financial_statements(
|
|
37
|
+
stock_codes=["000001", "600000"],
|
|
38
|
+
metrics=["revenue", "profit"],
|
|
39
|
+
start_date="2023-01-01",
|
|
40
|
+
end_date="2023-12-31"
|
|
41
|
+
)
|
|
42
|
+
print(df)
|
|
43
|
+
|
|
44
|
+
asyncio.run(example1())
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## 相关链接
|
|
48
|
+
|
|
49
|
+
- [官方文档](https://www.lixinger.com/open/api/doc?api-key=cn/company/fs/non_financial)
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# 银行基本面
|
|
2
|
+
|
|
3
|
+
获取银行股票的基本面指标数据。
|
|
4
|
+
|
|
5
|
+
## API 端点
|
|
6
|
+
|
|
7
|
+
`POST /cn/company/fundamental/bank`
|
|
8
|
+
|
|
9
|
+
## 类参考
|
|
10
|
+
|
|
11
|
+
::: lixinger.api.cn.company.fundamental.bank.BankFundamentalAPI
|
|
12
|
+
options:
|
|
13
|
+
show_root_heading: true
|
|
14
|
+
show_source: true
|
|
15
|
+
heading_level: 3
|
|
16
|
+
|
|
17
|
+
## 使用示例
|
|
18
|
+
|
|
19
|
+
```python
|
|
20
|
+
import asyncio
|
|
21
|
+
from lixinger import AsyncLixingerClient, get_bank_fundamental
|
|
22
|
+
|
|
23
|
+
# 方式 1: 使用异步客户端
|
|
24
|
+
async def example1():
|
|
25
|
+
async with AsyncLixingerClient() as client:
|
|
26
|
+
df = await client.company.fundamental.bank.get_bank_fundamental(
|
|
27
|
+
stock_codes=["600000", "600036"],
|
|
28
|
+
metrics=["pe_ttm", "pb"],
|
|
29
|
+
start_date="2023-01-01",
|
|
30
|
+
end_date="2023-12-31"
|
|
31
|
+
)
|
|
32
|
+
print(df)
|
|
33
|
+
|
|
34
|
+
# 方式 2: 使用函数式 API(推荐)
|
|
35
|
+
async def example2():
|
|
36
|
+
df = await get_bank_fundamental(
|
|
37
|
+
stock_codes=["600000", "600036"],
|
|
38
|
+
metrics=["pe_ttm", "pb"],
|
|
39
|
+
start_date="2023-01-01",
|
|
40
|
+
end_date="2023-12-31"
|
|
41
|
+
)
|
|
42
|
+
print(df)
|
|
43
|
+
|
|
44
|
+
asyncio.run(example1())
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## 相关链接
|
|
48
|
+
|
|
49
|
+
- [官方文档](https://www.lixinger.com/open/api/doc?api-key=cn/company/fundamental/bank)
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# 保险企业基本面
|
|
2
|
+
|
|
3
|
+
获取保险企业的基本面指标数据。
|
|
4
|
+
|
|
5
|
+
## API 端点
|
|
6
|
+
|
|
7
|
+
`POST /cn/company/fundamental/insurance`
|
|
8
|
+
|
|
9
|
+
## 类参考
|
|
10
|
+
|
|
11
|
+
::: lixinger.api.cn.company.fundamental.insurance.InsuranceFundamentalAPI
|
|
12
|
+
options:
|
|
13
|
+
show_root_heading: true
|
|
14
|
+
show_source: true
|
|
15
|
+
heading_level: 3
|
|
16
|
+
|
|
17
|
+
## 使用示例
|
|
18
|
+
|
|
19
|
+
```python
|
|
20
|
+
import asyncio
|
|
21
|
+
from lixinger import AsyncLixingerClient, get_insurance_fundamental
|
|
22
|
+
|
|
23
|
+
# 方式 1: 使用异步客户端
|
|
24
|
+
async def example1():
|
|
25
|
+
async with AsyncLixingerClient() as client:
|
|
26
|
+
df = await client.company.fundamental.insurance.get_insurance_fundamental(
|
|
27
|
+
stock_codes=["601318", "601336"],
|
|
28
|
+
metrics=["pe_ttm", "pb"],
|
|
29
|
+
start_date="2023-01-01",
|
|
30
|
+
end_date="2023-12-31"
|
|
31
|
+
)
|
|
32
|
+
print(df)
|
|
33
|
+
|
|
34
|
+
# 方式 2: 使用函数式 API(推荐)
|
|
35
|
+
async def example2():
|
|
36
|
+
df = await get_insurance_fundamental(
|
|
37
|
+
stock_codes=["601318", "601336"],
|
|
38
|
+
metrics=["pe_ttm", "pb"],
|
|
39
|
+
start_date="2023-01-01",
|
|
40
|
+
end_date="2023-12-31"
|
|
41
|
+
)
|
|
42
|
+
print(df)
|
|
43
|
+
|
|
44
|
+
asyncio.run(example1())
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## 相关链接
|
|
48
|
+
|
|
49
|
+
- [官方文档](https://www.lixinger.com/open/api/doc?api-key=cn/company/fundamental/insurance)
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# 非金融企业基本面
|
|
2
|
+
|
|
3
|
+
获取非金融企业的基本面指标数据。
|
|
4
|
+
|
|
5
|
+
## API 端点
|
|
6
|
+
|
|
7
|
+
`POST /cn/company/fundamental/non_financial`
|
|
8
|
+
|
|
9
|
+
## 类参考
|
|
10
|
+
|
|
11
|
+
::: lixinger.api.cn.company.fundamental.non_financial.NonFinancialFundamentalAPI
|
|
12
|
+
options:
|
|
13
|
+
show_root_heading: true
|
|
14
|
+
show_source: true
|
|
15
|
+
heading_level: 3
|
|
16
|
+
|
|
17
|
+
## 使用示例
|
|
18
|
+
|
|
19
|
+
```python
|
|
20
|
+
import asyncio
|
|
21
|
+
from lixinger import AsyncLixingerClient, get_non_financial_fundamental
|
|
22
|
+
|
|
23
|
+
# 方式 1: 使用异步客户端
|
|
24
|
+
async def example1():
|
|
25
|
+
async with AsyncLixingerClient() as client:
|
|
26
|
+
df = await client.company.fundamental.non_financial.get_non_financial_fundamental(
|
|
27
|
+
stock_codes=["000001", "600000"],
|
|
28
|
+
metrics=["pe_ttm", "pb", "roe"],
|
|
29
|
+
start_date="2023-01-01",
|
|
30
|
+
end_date="2023-12-31"
|
|
31
|
+
)
|
|
32
|
+
print(df)
|
|
33
|
+
|
|
34
|
+
# 方式 2: 使用函数式 API(推荐)
|
|
35
|
+
async def example2():
|
|
36
|
+
df = await get_non_financial_fundamental(
|
|
37
|
+
stock_codes=["000001", "600000"],
|
|
38
|
+
metrics=["pe_ttm", "pb", "roe"],
|
|
39
|
+
start_date="2023-01-01",
|
|
40
|
+
end_date="2023-12-31"
|
|
41
|
+
)
|
|
42
|
+
print(df)
|
|
43
|
+
|
|
44
|
+
asyncio.run(example1())
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## 相关链接
|
|
48
|
+
|
|
49
|
+
- [官方文档](https://www.lixinger.com/open/api/doc?api-key=cn/company/fundamental/non_financial)
|