- example.py: mark the base Example.scope field frozen so the (#7798)

Literal[api]/Literal[python] subclass overrides are covariant
  read-only narrowings. Subclass fields stay writable at runtime.
- method_definition.py, options_chains.py: pydantic 2.14 types
  FieldInfo.annotation as TypeForm[Any] | None, which ty rejects in
  Union[]/Annotated[] and where  is expected; bind it as Any.
  Use FieldInfo.get_default(call_default_factory=True) instead of
  calling the default_factory union directly.
- economy_views.py: read data/obbject_item without None defaults in the
  IMF shipping views. charting always sets obbject_item, and data is
  only popped when present and not None.- finra, jodi, eia: annotate @asynccontextmanager/@contextmanager
  functions with AsyncGenerator/Generator instead of the deprecated
  AsyncIterator/Iterator return types.
- charting: cast the darts forecast dataset to TimeSeries before
  indexing so .all_values resolves instead of hitting ndarray.
- fred, imf, nasdaq, sec, tmx: turn off invalid-attribute-override and
  invalid-mutable-override for models/** only, following the cboe
  precedent. Provider models extend the standard models by narrowing
  query params to Literals or widening fields to Optional, which these
  rules flag by design.

Co-authored-by: dlee-bq <325002271+dlee-bq@users.noreply.github.com>
This commit is contained in:
dlee-bq
2026-10-17 20:50:39 +00:00
committed by GitHub
parent d67b32e2f9
commit 7f04334398
13 changed files with 55 additions and 17 deletions

View File

@@ -18,7 +18,7 @@ QUOTE_TYPES = {str, date}
class Example(BaseModel): class Example(BaseModel):
"""Example model.""" """Example model."""
scope: str scope: str = Field(frozen=True)
model_config = ConfigDict(validate_assignment=True) model_config = ConfigDict(validate_assignment=True)

View File

@@ -791,7 +791,7 @@ class MethodDefinition:
qp_model := MethodDefinition.query_params_model(param.annotation) qp_model := MethodDefinition.query_params_model(param.annotation)
) is not None: ) is not None:
for field_name, field in qp_model.model_fields.items(): for field_name, field in qp_model.model_fields.items():
field_anno = field.annotation field_anno: Any = field.annotation
new_type = MethodDefinition.get_expanded_type( new_type = MethodDefinition.get_expanded_type(
field_name, None, field_anno field_name, None, field_anno
) )
@@ -807,7 +807,7 @@ class MethodDefinition:
if field.is_required(): if field.is_required():
field_default: Any = Parameter.empty field_default: Any = Parameter.empty
elif field.default_factory is not None: elif field.default_factory is not None:
field_default = field.default_factory() field_default = field.get_default(call_default_factory=True)
else: else:
field_default = field.default field_default = field.default
formatted[field_name] = Parameter( formatted[field_name] = Parameter(

View File

@@ -390,7 +390,7 @@ class OptionsChainsData(OptionsChainsProperties):
row_fields: dict[str, Any] = {} row_fields: dict[str, Any] = {}
for field_name, field_info in cls.model_fields.items(): for field_name, field_info in cls.model_fields.items():
annotation = field_info.annotation annotation: Any = field_info.annotation
inner = ( inner = (
get_args(annotation)[0] get_args(annotation)[0]
if get_origin(annotation) is list if get_origin(annotation) is list

View File

@@ -567,9 +567,9 @@ class EconomyViews:
or getattr(kwargs["charting_settings"], "chart_style", "dark") or getattr(kwargs["charting_settings"], "chart_style", "dark")
) )
data = ( data = (
kwargs.pop("data", None) kwargs.pop("data")
if "data" in kwargs and kwargs["data"] is not None if "data" in kwargs and kwargs["data"] is not None
else kwargs.get("obbject_item") else kwargs["obbject_item"]
) )
fig = plot_chokepoint_annual_avg_vessels(data, theme=theme) fig = plot_chokepoint_annual_avg_vessels(data, theme=theme)
fig.update_layout( fig.update_layout(
@@ -601,9 +601,9 @@ class EconomyViews:
raise RuntimeError("Unable to import the required module.") from e raise RuntimeError("Unable to import the required module.") from e
data = ( data = (
kwargs.pop("data", None) kwargs.pop("data")
if "data" in kwargs and kwargs["data"] is not None if "data" in kwargs and kwargs["data"] is not None
else kwargs.get("obbject_item") else kwargs["obbject_item"]
) )
fig = plot_port_info_map(data) fig = plot_port_info_map(data)
fig.update_layout( fig.update_layout(

View File

@@ -11,6 +11,7 @@ from typing import (
Literal, Literal,
TypeVar, TypeVar,
Union, Union,
cast,
) )
from warnings import warn from warnings import warn
@@ -325,7 +326,9 @@ class OpenBBFigure(go.Figure):
if forecast: # pragma: no cover - darts forecast path (darts is an optional dependency) if forecast: # pragma: no cover - darts forecast path (darts is an optional dependency)
components = list(dataset.components[:4]) # ty: ignore[unresolved-attribute] components = list(dataset.components[:4]) # ty: ignore[unresolved-attribute]
values = ( values = (
dataset[components].all_values(copy=False).flatten(order="F") cast("TimeSeries", dataset)[components]
.all_values(copy=False)
.flatten(order="F")
) )
n_components = len(components) n_components = len(components)
n_entries = len(values) // n_components n_entries = len(values) // n_components

View File

@@ -2,7 +2,7 @@
import re import re
import threading import threading
from collections.abc import AsyncIterator from collections.abc import AsyncGenerator
from contextlib import asynccontextmanager from contextlib import asynccontextmanager
from pathlib import Path from pathlib import Path
from typing import Annotated, Any from typing import Annotated, Any
@@ -2062,7 +2062,7 @@ async def render_browser(
@asynccontextmanager @asynccontextmanager
async def lifespan(_app) -> AsyncIterator[None]: async def lifespan(_app) -> AsyncGenerator[None, None]:
"""Warm the proxy cache for the lifetime of the API, cleaning up on shutdown.""" """Warm the proxy cache for the lifetime of the API, cleaning up on shutdown."""
_schedule_warm() _schedule_warm()
try: try:

View File

@@ -1,6 +1,6 @@
"""HTTP transport for the FINRA data services.""" """HTTP transport for the FINRA data services."""
from collections.abc import AsyncIterator, Awaitable, Callable from collections.abc import AsyncGenerator, Awaitable, Callable
from contextlib import asynccontextmanager from contextlib import asynccontextmanager
from typing import Any from typing import Any
@@ -243,7 +243,7 @@ class QueryApiSession:
@asynccontextmanager @asynccontextmanager
async def query_api_session() -> AsyncIterator[QueryApiSession]: async def query_api_session() -> AsyncGenerator[QueryApiSession, None]:
"""Open a session on the public FINRA Query API. """Open a session on the public FINRA Query API.
Yields Yields
@@ -412,7 +412,7 @@ async def _trace_token(session: Any) -> str:
@asynccontextmanager @asynccontextmanager
async def trace_session() -> AsyncIterator[TraceSession]: async def trace_session() -> AsyncGenerator[TraceSession, None]:
"""Open a session on the public TRACE data service. """Open a session on the public TRACE data service.
Yields Yields
@@ -590,7 +590,7 @@ class MarketDataSession:
@asynccontextmanager @asynccontextmanager
async def market_data_session() -> AsyncIterator[MarketDataSession]: async def market_data_session() -> AsyncGenerator[MarketDataSession, None]:
"""Open a seeded session on the FINRA Market Data Center. """Open a seeded session on the FINRA Market Data Center.
Yields Yields

View File

@@ -83,6 +83,13 @@ exclude = ["tests", "integration"]
[tool.ty.rules] [tool.ty.rules]
unresolved-import = "warn" unresolved-import = "warn"
[[tool.ty.overrides]]
include = ["openbb_fred/models/**"]
[tool.ty.overrides.rules]
invalid-attribute-override = "ignore"
invalid-mutable-override = "ignore"
[tool.coverage.run] [tool.coverage.run]
branch = true branch = true
source = ["openbb_fred"] source = ["openbb_fred"]

View File

@@ -110,6 +110,13 @@ exclude = ["tests", "integration", "openbb_imf/utils/generate_cache.py"]
[tool.ty.rules] [tool.ty.rules]
unresolved-import = "ignore" unresolved-import = "ignore"
[[tool.ty.overrides]]
include = ["openbb_imf/models/**"]
[tool.ty.overrides.rules]
invalid-attribute-override = "ignore"
invalid-mutable-override = "ignore"
[tool.pytest.ini_options] [tool.pytest.ini_options]
testpaths = ["tests"] testpaths = ["tests"]
addopts = "-q --strict-markers" addopts = "-q --strict-markers"

View File

@@ -14,7 +14,7 @@ from openbb_jodi.utils.constants import (
if TYPE_CHECKING: if TYPE_CHECKING:
import asyncio # noqa import asyncio # noqa
from collections.abc import Iterator, Mapping # noqa from collections.abc import Generator, Mapping # noqa
from datetime import date as dateType # noqa from datetime import date as dateType # noqa
from pathlib import Path # noqa from pathlib import Path # noqa
from typing import IO # noqa from typing import IO # noqa
@@ -361,7 +361,7 @@ def bump_checked_at(table: str, snapshot: dict) -> dict:
@contextmanager @contextmanager
def open_archive_csv(path: "Path") -> "Iterator": def open_archive_csv(path: "Path") -> "Generator":
"""Open the CSV stream inside a raw source file, unzipping when needed.""" """Open the CSV stream inside a raw source file, unzipping when needed."""
import zipfile import zipfile

View File

@@ -77,6 +77,13 @@ exclude = ["tests", "integration"]
[tool.ty.rules] [tool.ty.rules]
unresolved-import = "ignore" unresolved-import = "ignore"
[[tool.ty.overrides]]
include = ["openbb_nasdaq/models/**"]
[tool.ty.overrides.rules]
invalid-attribute-override = "ignore"
invalid-mutable-override = "ignore"
[tool.pytest.ini_options] [tool.pytest.ini_options]
testpaths = ["tests"] testpaths = ["tests"]
addopts = "-q --strict-markers" addopts = "-q --strict-markers"

View File

@@ -90,6 +90,13 @@ exclude = ["tests", "integration"]
[tool.ty.rules] [tool.ty.rules]
unresolved-import = "ignore" unresolved-import = "ignore"
[[tool.ty.overrides]]
include = ["openbb_sec/models/**"]
[tool.ty.overrides.rules]
invalid-attribute-override = "ignore"
invalid-mutable-override = "ignore"
[tool.pytest.ini_options] [tool.pytest.ini_options]
testpaths = ["tests"] testpaths = ["tests"]
addopts = "-q --strict-markers" addopts = "-q --strict-markers"

View File

@@ -91,6 +91,13 @@ exclude = ["tests", "integration"]
[tool.ty.rules] [tool.ty.rules]
unresolved-import = "warn" unresolved-import = "warn"
[[tool.ty.overrides]]
include = ["openbb_tmx/models/**"]
[tool.ty.overrides.rules]
invalid-attribute-override = "ignore"
invalid-mutable-override = "ignore"
[tool.coverage.report] [tool.coverage.report]
exclude_lines = ["pragma: no cover", "if TYPE_CHECKING:", "raise NotImplementedError", "@overload"] exclude_lines = ["pragma: no cover", "if TYPE_CHECKING:", "raise NotImplementedError", "@overload"]