Ctrl K
ComunidadGuías…

pyproject.toml

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
[tool.uv]
no-build-package = ["growwapi"]

constraint-dependencies = ["plotly==6.9.0"]
# certifi stays on the newest release growwapi 1.5.0 accepts (certifi<2026).
# A uv override to the patched 2026 bundle does not apply to
# `pip install --require-hashes -r requirements.lock`. The resulting advisory
# is time-limited in supply-chain/pip-audit-allowlist.yml.

# Kotak v3 runtime and release baseline both follow the pinned v3.0.9
# commit in brokers.lock. Freshness compares that release, not default-branch HEAD.
build-constraint-dependencies = [
    "packaging==26.3",
    "setuptools==84.1.0",
    "wheel==0.48.0",
]
no-build-isolation-package = ["kotakneoapi", "upstox-python-sdk"]

[tool.uv.workspace]
members = [
    "packages/core/core",
    "packages/core/data",
    "packages/core/historical",
    "packages/core/indicators",
    "packages/core/ticks",
    "packages/services/engine",
    "packages/services/screener",
    "packages/services/backtest",
    "packages/services/ai",
    "packages/services/ditto",
    "packages/services/automation",
    "packages/services/journal",
    "packages/integrations/gateway",
    "packages/integrations/webhooks",
]

# Dev/test toolchain — installed by `uv sync` (the default `dev` group) so the
# test runner is reproducible from the lockfile rather than ambient on PATH
# (audit BT-05). CI parallelism + randomisation plugins are picked up via their
# entry points when present (see [tool.pytest.ini_options] note below).
[dependency-groups]
dev = [
    "pytest==9.2.0",
    "pytest-asyncio==1.4.1",
    "pytest-xdist==3.8.0",
    "pytest-randomly==5.0.0",
    "pytest-timeout==2.4.0",    # CI runs `pytest --timeout=60 --timeout-method=thread`
                             # (test.yml / nightly); the plugin must be in the synced env
    "pyfakefs==6.2.0",          # baselines §4.4 disk-full migration test (HI24)
    "ruff==0.17.3",              # lint gate — CI runs `uv run ruff check` (test.yml), so it
                             # must be in the synced env, not merely on PATH
]

[tool.uv.sources]
upstox-python-sdk = { git = "https://github.com/upstox/upstox-python.git", rev = "d88a12ef5738a4c8d71f3b88eb7b79a359277c9d" }

kotakneoapi = { git = "https://github.com/Kotak-Neo/kotak-neo-python.git", rev = "0ba71b7f7c295652d4c3ea2b5ce5a88849db18a3" }
flinttrade-ai = { workspace = true }
flinttrade-automation = { workspace = true }
flinttrade-backtest = { workspace = true }
flinttrade-core = { workspace = true }
flinttrade-data = { workspace = true }
flinttrade-ditto = { workspace = true }
flinttrade-engine = { workspace = true }
flinttrade-gateway = { workspace = true }
flinttrade-historical = { workspace = true }
flinttrade-indicators = { workspace = true }
flinttrade-journal = { workspace = true }
flinttrade-screener = { workspace = true }
flinttrade-ticks = { workspace = true }
flinttrade-webhooks = { workspace = true }

# ----------------------------------------------------------------------------
# Pytest configuration
# ----------------------------------------------------------------------------
# Three custom markers are registered for the staged-test-execution model
# (unit on every commit, integration on PR, slow nightly). --strict-markers
# fails CI if any test uses an unregistered marker -- catches typos before
# they go unnoticed.
#
# Existing tests are NOT yet marked. Default behaviour is unchanged: an
# untagged test simply runs in every job. As tests get touched, prefer to
# tag them; CI selection clauses can then be tightened over time.
#
# pytest-xdist + pytest-randomly are picked up automatically when installed
# (they add their own opts via entry points). Local devs can run without
# them; CI installs them and uses -n auto for parallelism.
# ----------------------------------------------------------------------------
[tool.pytest.ini_options]
testpaths = ["tests"]
# Keep package-local tests.* namespaces distinct from shared tests.mocks,
# including when a focused or sharded run does not collect the root tests.
consider_namespace_packages = true
asyncio_mode = "auto"
addopts = [
    "--import-mode=importlib",
    "--strict-markers",
    "-ra",
]
markers = [
    "unit: fast, isolated unit test (default; runs on every commit)",
    "integration: touches DB or mocked external services (PR gate)",
    "slow: long-running test >1s (nightly or via --run-slow)",
]
filterwarnings = [
    # huggingface_hub still calls its own deprecated `hf_xet.download_files()`
    # internally — out of our control, will go away on upstream release.
    "ignore:hf_xet.download_files.*:DeprecationWarning:huggingface_hub.*",
]

[tool.ruff]
# `target-version` is the OLDEST interpreter the code must still run on, not the
# one we develop against. flint.toml [requirements] sets python_requires
# ">=3.14" (python_target "3.14"), so py314 matches the floor. Bump this only
# when the flint.toml floor moves.
target-version = "py314"
line-length = 120

[tool.ruff.lint]
# Baseline: ruff 0.16 widened its default rule set, so the pre-0.16 defaults are
# pinned explicitly. A future ruff release that widens its defaults again cannot
# silently change this gate.
select = ["E4", "E7", "E9", "F"]

# Modern families adopted 2026-07-30 and measured on ruff 0.16.0 (the version the
# dev group resolves to). Listed one family per line, explicitly,
# rather than dropping `select` and inheriting whatever a future ruff decides is
# a default — the gate is intentional and dated, not implicit. Every family here
# is GREEN across packages/*/*/src/; anything that could not reach zero is
# either pinned in `ignore` below with its count, or listed in the deferred
# adoption list at the bottom of this section.
extend-select = [
    "I",     # isort — deterministic import blocks
    "UP",    # pyupgrade — no outdated ways of writing modern Python
    "B",     # flake8-bugbear — real bug classes, not style
    "C4",    # flake8-comprehensions
    "RET",   # flake8-return
    "RSE",   # flake8-raise
    "PIE",   # flake8-pie — misc anti-patterns
    "PERF",  # perflint
    "FURB",  # refurb — modernisation beyond pyupgrade
    "ASYNC", # flake8-async — blocking calls inside async def
    "LOG",   # flake8-logging — logger misuse
    "G",     # flake8-logging-format
    "ISC",   # flake8-implicit-str-concat — catches the missing-comma bug
    "Q",     # flake8-quotes
    "TID",   # flake8-tidy-imports — no `from ..parent` across package layers
    "SLOT",  # flake8-slots
    "INT",   # flake8-gettext
    "EXE",   # flake8-executable — shebang/permission mismatches
    "FA",    # flake8-future-annotations
    "NPY",   # NumPy-specific rules
    "YTT",   # flake8-2020 — sys.version misuse
]

ignore = [
    # ---- Rules inside adopted families that are NOT yet green (2026-07-30) ----
    # Each line is a live debt marker: the count is the violation count at
    # adoption time. Fixing one and deleting its line is always an improvement.
    "UP035",  # 59 — `typing.Callable` → `collections.abc`. ruff's fix is UNSAFE
              #      (it can break re-exports), so it is not auto-appliable.
    "UP040",  # 7  — PEP 695 `type X = ...` aliases; needs per-alias review.
    "UP042",  # 7  — `str, Enum` → `StrEnum`; changes `__str__`/format output,
              #      which some serialised payloads depend on. Needs review.
    "UP047",  # 2  — PEP 695 generic functions.
    "B904",   # 18 — `raise ... from err` inside except.
    "B905",   # 63 — `zip(strict=...)`. Turning strictness on can raise where
              #      today it truncates, so it is a behaviour decision per site.
    "B007",   # 5  — unused loop control variable.
    "B027",   # 3  — empty method in ABC without @abstractmethod.
    "RET504", # 17 — unnecessary assignment before return (ruff fix is unsafe;
              #      the named temporaries are often deliberate for debugging).
    "PERF401",# 43 — manual list comprehension.
    "PERF403",# 3  — manual dict comprehension.
    "ASYNC109",# 9 — own `timeout` parameter instead of `asyncio.timeout`; these
              #      are public signatures, so changing them is an API break.
    "NPY002",  # 2 — legacy `np.random`; the new Generator API draws a different
              #      stream, so switching changes reproducible test fixtures.
    # PERF101 is NOT deferred debt — it is banned. Its fix is classified "safe"
    # but is not: applying it to the single site it flagged in this repo
    # (IndMoneyAdapter._symbol_keys, which iterates a set while adding aliases to
    # it) deleted a load-bearing `list()` cast and turned three passing
    # test_indmoney_adapter tests into `RuntimeError: Set changed size during
    # iteration`. `list(x)` in a `for` header is the standard guard for
    # mutate-while-iterating, and ruff cannot tell that from a redundant copy —
    # so leaving the rule on means the next `ruff check --fix` silently
    # reintroduces the same bug. Verified 2026-07-30.
    "PERF101",
]

# ---- Deferred adoption list (measured 2026-07-30, ruff 0.16.0) ----------------
# Marginal cost of adding each family ON TOP of the set adopted above, measured
# over packages/*/*/src/ with `ruff check --extend-select <family> --statistics`.
# NOT enabled, because enabling them would put the only Python quality gate
# permanently red — and a red gate gets ignored, then stops gating anything.
# Work a family down, then move it into `extend-select` above and delete its
# line here.
#
#   D    4205  (D413 2597, D102 767, D107 397, D401 110, D105 85, D205 44, …)
#   TRY  3622  (TRY003 2990, TRY400 223, TRY301 218, TRY004 100, TRY300 70, …)
#   EM   3010  (EM101 2126, EM102 884 — exception message as a bare literal)
#   PL   1883  (PLR2004 538, PLR0913 342, PLC0415 261, PLR0917 209, PLR0912 171, …)
#   ANN  1626  (ANN401 1572 — `Any` in signatures)
#   RUF  1583  (RUF100 1240 — see the noqa note below; RUF002 217, RUF003 44, …)
#   COM  1538  (COM812 missing-trailing-comma — formatter territory)
#   BLE   456  (BLE001 blind-except)
#   TC    394  (TC002 308, TC003 51, TC001 32 — needs runtime-import review)
#   C90   333  (C901 complex-structure)
#   FBT   254  (FBT003 106, FBT001 92, FBT002 56 — public API signatures)
#   S     204  (S101 61, S110 49, S608 46, S311 23, S105 7, …)
#   SIM   173  (SIM105 77, SIM108 33, SIM102 26, SIM114 14, SIM117 11, …)
#   ARG   155  (ARG002 137, ARG001 18)
#   SLF   119  (private-member-access — mostly deliberate, intra-package)
#   N     104  (N806 36, N818 34, N803 26 — many mirror broker API field names)
#   PTH    74  (os.path → pathlib; every fix is manual, no safe autofix exists)
#   ERA    74  (commented-out code)
#   DTZ    62  (naive datetimes; IST market-clock semantics must be preserved,
#               so a blanket `tz=` insert is a correctness risk, not a cleanup)
#   PYI    55  (PYI034 27, PYI036 22 — a stub-file family firing on .py)
#   T20    35  (print in library code)
#   PD 6, ICN 4, A 0, INP 0, DJ 0
#
# NOTE on RUF100 (1240): packages/*/*/src/ already carries 1376 `# noqa`
# directives, and 1240 of them name a rule that is NOT selected — 740 for
# PLC0415 and 390 for BLE001 alone. Those suppressions were written by authors
# who expected those families to be on. They are inert today: enabling PL/BLE
# would make 1130 existing noqa comments meaningful rather than adding 1130 new
# violations, which makes those two families much cheaper to adopt than their
# headline numbers suggest.
#
# The two test trees are excluded from every count above; their debt is
# enumerated in [tool.ruff.lint.per-file-ignores] below.

[tool.ruff.lint.per-file-ignores]
# The lint path was widened on 2026-07-30 to cover the test trees, which had
# never been linted at all under the CI invocation. The test trees are now gated
# on the E4/E7/E9/F baseline (the F821/F401 import-NameError class), but the
# newly adopted modern families still have measured debt there:
#   tests/                46 violations (41 safely autofixable)
#   packages/*/*/tests/  964 violations (844 safely autofixable, 524 of them
#                        I001 import sorting alone)
# Every rule below is listed individually rather than by family prefix, so a
# test-owning change can clear one and delete its line. `ruff check --fix` over
# the test trees clears roughly 88% of this in one pass.
"tests/**/*.py" = [
    "ASYNC110", "B006", "B009", "B011", "B017", "B018", "C408", "C420",
    "FURB110", "FURB157", "FURB167", "FURB171", "I001", "ISC004", "LOG001",
    "PERF102", "PIE807", "PIE808", "PIE810", "Q000", "Q003", "RET501",
    "RET503", "RSE102", "SLOT000", "UP012", "UP017", "UP022", "UP037", "UP041",
]
"packages/*/*/tests/**/*.py" = [
    "ASYNC110", "B006", "B009", "B011", "B017", "B018", "C408", "C420",
    "FURB110", "FURB157", "FURB167", "FURB171", "I001", "ISC004", "LOG001",
    "PERF102", "PIE807", "PIE808", "PIE810", "Q000", "Q003", "RET501",
    "RET503", "RSE102", "SLOT000", "UP012", "UP017", "UP022", "UP037", "UP041",
]
# The script test tree matches neither glob above, so widening the lint path
# picked it up for the first time. Its only debt is three expected-message
# assertions that each build ONE long string across several lines inside a
# single-element list. That is the exact shape ISC004 exists to flag, because a
# missing comma looks identical - but here the concatenation is deliberate, and
# splitting the assertions to prove it would cost more clarity than it buys.
"scripts/__tests__/**/*.py" = ["ISC004"]  # 3 — deliberate multi-line expected messages

# Two modules deliberately import BELOW module-level `sys.path` manipulation, so
# their whole import section is one long `# noqa: E402` block hand-organised into
# commented sections. isort cannot express that: its fix reflows the block, which
# strands every section comment against the wrong group and drops the per-line
# `# noqa: E402` from any statement it has to split — turning one clean file into
# eleven new E402 violations. Correctness is unaffected either way, so the
# hand-ordering wins and I001 is off for these two files only.
"packages/core/core/src/flinttrade_core/app.py" = ["I001"]
"packages/services/backtest/src/flinttrade_backtest/strategies/__init__.py" = ["I001"]

# The PyO3 crate's Python shim is outside every `src/` tree, so widening the
# lint path to `packages/` picked it up for the first time. One outstanding
# violation, kept visible rather than silently excluded from the path:
"packages/core/ticks/python/tick_engine/__init__.py" = [
    "I001",  # 1 — a two-name reorder inside the single `from tick_engine.tick_engine
             #     import (...)` block. `ruff check --fix` clears it; it belongs to
             #     a ticks-owning change, not to the lint-config change.
]

[tool.ruff.lint.isort]
# The repo writes `from x import a, b as c` on one line. isort's DEFAULT is to
# force every aliased member onto a statement of its own, which turns one line
# into three and churns files for no readability gain. Keep the existing style.
combine-as-imports = true

# Pin first-party classification to the workspace distributions so the same
# import sorts identically no matter which package's src/ root ruff resolves.
known-first-party = [
    "flinttrade_ai",
    "flinttrade_automation",
    "flinttrade_backtest",
    "flinttrade_core",
    "flinttrade_data",
    "flinttrade_ditto",
    "flinttrade_engine",
    "flinttrade_gateway",
    "flinttrade_historical",
    "flinttrade_indicators",
    "flinttrade_journal",
    "flinttrade_screener",
    "flinttrade_ticks",
    "flinttrade_webhooks",
]