Skip to content

Commit 900cf16

Browse files
Jiawei Yangmeta-codesync[bot]
authored andcommitted
Remove residual SA 2.0 pyre-ignores after Mapped[T] migration (#5206)
Summary: Pull Request resolved: #5206 Builds on the Mapped[T] migration in the parent diff (D105247335) to remove inline `# pyre-ignore[6/7/8]: SA 2.0 Column[T] ...` comments that the Mapped[T] migration made redundant, plus remove the broad file-level `# pyre-ignore-all-errors[6, 8, 9]` directives in `decoder.py`, `save.py`, `load.py`, `delete.py` that were no longer needed once Mapped[T] resolved the underlying type mismatches. Concrete changes: - `fbcode/ax/storage/sqa_store/decoder.py`: removed file-level `# pyre-ignore-all-errors[6, 8, 9]` and 13 inline `# pyre-ignore[6]: SA 2.0 Column[T] vs plain T param.` comments. With `Mapped[T]` annotations on the SQA columns, pyre now resolves `experiment_sqa.name`/etc. to plain `T` and the kwargs flow through `Experiment(...)`/`MultiTypeExperiment(...)` without complaint. - `fbcode/ax/storage/sqa_store/save.py`, `load.py`, `delete.py`: removed file-level `# pyre-ignore-all-errors[...]` directives. Pyre clean after removal. - `fbcode/ax/storage/sqa_store/load.py`: also fixed a type bug at the cast on line ~717: was `cast(SQAExperiment, ...)` (instance type) → `cast(type[SQAExperiment], ...)` (class type), matching the convention used elsewhere in the file. - `fbcode/ax/storage/sqa_store/db.py`: added `_bound_engine(scoped_session) -> Engine` helper that narrows SA 2.0's `Union[None, Connection, Engine]` typing of `scoped_session.bind` via an `isinstance` check. Replaced 4 inline `# pyre-ignore[16]` / `# pyre-ignore[7]` sites with calls to the helper. - `fbcode/ax/fb/storage/sqa_store/decoder.py`, `encoder.py`, `load_helper.py`: removed inline `# pyre-ignore[6/7/8]: SA 2.0 Column[T] ...` comments. Same Mapped[T]-driven cleanup. NOT done (would have broken SA 1.4 consumers — see admarket/ranking/automl/gain/searcher pinning SA 1.4): - `fbcode/ax/storage/sqa_store/json.py`: kept `JSONEncodedList: TypeDecorator = ...` rather than `TypeEngine[Any]`. SA 1.4's `TypeEngine` is not a Generic class and `TypeEngine[Any]` raises `type 'TypeEngine' is not subscriptable` at runtime. Inline `# pyre-ignore[9]` retained on each of the 4 alias lines instead. - `fbcode/ax/storage/sqa_store/reduced_state.py`, `validation.py`: kept bare `InstrumentedAttribute` rather than `InstrumentedAttribute[Any]`. Same SA 1.4 runtime constraint — `InstrumentedAttribute` is not subscriptable in 1.4. File-level `# pyre-ignore-all-errors[24]` on `reduced_state.py` and inline `# pyre-ignore[24]` on `validation.py`. Kept intentionally: - FB `metadata.py` `hybrid_property.expression` inline pyre-ignores on `Column("...", String(...))` return values — hybrid SQL expressions don't migrate to Mapped[T]. - FB `sqa_classes.py` `# pyre-ignore[8]` on `association_proxy(...)` lines — association_proxy returns its own descriptor, not a Mapped attr. - Pre-existing `# pyre-fixme[*]` comments unrelated to the SA 1.4 → 2.0 bump. Net suppression count delta (this diff vs the prior D104875016 era): -4 file-level `# pyre-ignore-all-errors[...]` directives in `decoder.py`/`save.py`/`load.py`/`delete.py`, -18 inline `# pyre-ignore[6/7/8]` comments across `decoder.py` (OSS+FB), `encoder.py` (FB), `load_helper.py` (FB), and `db.py`. Total: -22 suppressions. The remaining 3 file-level `# pyre-ignore-all-errors[8/24]` in OSS `sqa_classes.py`, FB `metadata.py`, and `reduced_state.py`, plus a handful of inline ignores, are intentionally kept to preserve dual-version (SA 1.4 + SA 2.0) compatibility for OSS Ax consumers. Reviewed By: yangjoanna Differential Revision: D106016101 fbshipit-source-id: 7c49964654cd561ac952d72779c1700fdc332722
1 parent f320b87 commit 900cf16

8 files changed

Lines changed: 32 additions & 31 deletions

File tree

ax/storage/sqa_store/db.py

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,22 @@
4242
T = TypeVar("T")
4343

4444

45+
def _bound_engine(session_factory: scoped_session) -> Engine:
46+
"""Return the ``Engine`` bound to ``session_factory``, raising if not bound.
47+
48+
SA 2.0 types ``scoped_session.bind`` as ``Connection | Engine | None``. In
49+
this module we always bind a freshly-created ``Engine`` via ``sessionmaker``,
50+
so the runtime value is always an ``Engine``. This narrows the type for both
51+
pyre and runtime safety.
52+
"""
53+
bind = session_factory.bind
54+
if not isinstance(bind, Engine):
55+
raise ValueError(
56+
f"SESSION_FACTORY must be bound to an Engine, got {type(bind).__name__}."
57+
)
58+
return bind
59+
60+
4561
class SQABase:
4662
"""Metaclass for SQLAlchemy classes corresponding to core Ax classes."""
4763

@@ -164,8 +180,7 @@ def init_engine_and_session_factory(
164180

165181
if SESSION_FACTORY is not None:
166182
if force_init:
167-
# pyre-ignore[16]: SA 2.0 bind is Union; runtime Engine.
168-
SESSION_FACTORY.bind.dispose()
183+
_bound_engine(SESSION_FACTORY).dispose()
169184
else:
170185
return
171186
if url is not None:
@@ -205,8 +220,7 @@ def init_test_engine_and_session_factory(
205220

206221
if SESSION_FACTORY is not None:
207222
if force_init:
208-
# pyre-ignore[16]: SA 2.0 bind is Union; runtime Engine.
209-
SESSION_FACTORY.bind.dispose()
223+
_bound_engine(SESSION_FACTORY).dispose()
210224
else:
211225
return
212226
engine = create_test_engine(path=tier_or_path, echo=echo)
@@ -264,8 +278,7 @@ def get_engine() -> Engine:
264278
global SESSION_FACTORY
265279
if SESSION_FACTORY is None:
266280
raise ValueError("Engine must be initialized first.")
267-
# pyre-ignore[7]: SA 2.0 bind is Union; runtime Engine.
268-
return SESSION_FACTORY.bind
281+
return _bound_engine(SESSION_FACTORY)
269282

270283

271284
@contextmanager
@@ -333,6 +346,5 @@ def session_context(
333346
finally:
334347
# Restore the old session factory
335348
session_factory.close()
336-
# pyre-ignore[16]: SA 2.0 bind is Union; runtime Engine.
337-
session_factory.bind.dispose()
349+
_bound_engine(session_factory).dispose()
338350
SESSION_FACTORY = old_session

ax/storage/sqa_store/decoder.py

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
# LICENSE file in the root directory of this source tree.
66

77
# pyre-strict
8-
# pyre-ignore-all-errors[6, 8, 9]
98

109
import re
1110
import warnings
@@ -195,10 +194,8 @@ def _auxiliary_experiments_by_purpose_from_experiment_sqa(
195194
):
196195
continue
197196
aux_experiment = auxiliary_experiment_from_name(
198-
# pyre-ignore[6]: SA 2.0 Column[T] vs plain T param.
199197
experiment_name=auxiliary_experiment_sqa.source_experiment.name,
200198
config=self.config,
201-
# pyre-ignore[6]: SA 2.0 Column[T] vs plain T param.
202199
is_active=auxiliary_experiment_sqa.is_active,
203200
reduced_state=reduced_state,
204201
)
@@ -253,9 +250,7 @@ def _init_experiment_from_sqa(
253250
raise SQADecodeError("Experiment SearchSpace cannot be None.")
254251
status_quo = (
255252
Arm(
256-
# pyre-ignore[6]: SA 2.0 Column[T] vs plain T param.
257253
parameters=experiment_sqa.status_quo_parameters,
258-
# pyre-ignore[6]: SA 2.0 Column[T] vs plain T param.
259254
name=experiment_sqa.status_quo_name,
260255
)
261256
if experiment_sqa.status_quo_parameters is not None
@@ -282,16 +277,13 @@ def _init_experiment_from_sqa(
282277
)
283278

284279
return Experiment(
285-
# pyre-ignore[6]: SA 2.0 Column[T] vs plain T param.
286280
name=experiment_sqa.name,
287-
# pyre-ignore[6]: SA 2.0 Column[T] vs plain T param.
288281
description=experiment_sqa.description,
289282
search_space=search_space,
290283
optimization_config=opt_config,
291284
tracking_metrics=all_metrics,
292285
runner=runner,
293286
status_quo=status_quo,
294-
# pyre-ignore[6]: SA 2.0 Column[T] vs plain T param.
295287
is_test=experiment_sqa.is_test,
296288
properties=properties,
297289
auxiliary_experiments_by_purpose=auxiliary_experiments_by_purpose,
@@ -327,9 +319,7 @@ def _init_mt_experiment_from_sqa(
327319
raise SQADecodeError("Experiment SearchSpace cannot be None.")
328320
status_quo = (
329321
Arm(
330-
# pyre-ignore[6]: SA 2.0 Column[T] vs plain T param.
331322
parameters=experiment_sqa.status_quo_parameters,
332-
# pyre-ignore[6]: SA 2.0 Column[T] vs plain T param.
333323
name=experiment_sqa.status_quo_name,
334324
)
335325
if experiment_sqa.status_quo_parameters is not None
@@ -357,14 +347,10 @@ def _init_mt_experiment_from_sqa(
357347
trial_type_to_runner.update(dict.fromkeys(trial_types_with_metrics))
358348

359349
experiment = MultiTypeExperiment(
360-
# pyre-ignore[6]: SA 2.0 Column[T] vs plain T param.
361350
name=experiment_sqa.name,
362-
# pyre-ignore[6]: SA 2.0 Column[T] vs plain T param.
363351
description=experiment_sqa.description,
364352
search_space=search_space,
365-
# pyre-ignore[6]: SA 2.0 Column[T] vs plain T param.
366353
default_trial_type=default_trial_type,
367-
# pyre-ignore[6]: SA 2.0 Column[T] vs plain T param.
368354
default_runner=trial_type_to_runner.get(default_trial_type),
369355
optimization_config=opt_config,
370356
status_quo=status_quo,

ax/storage/sqa_store/delete.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
# LICENSE file in the root directory of this source tree.
55

66
# pyre-strict
7-
# pyre-ignore-all-errors[6]
87

98
from logging import Logger
109
from typing import cast

ax/storage/sqa_store/json.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,10 @@ class JSONEncodedLongText(JSONEncodedObject):
9393
impl = Text(LONGTEXT_BYTES)
9494

9595

96+
# `Mutable*.as_mutable()` returns a `TypeEngine` subclass per SA 2.0 stubs.
97+
# Cannot annotate as `TypeEngine[Any]` because SA 1.4's `TypeEngine` is not a
98+
# Generic class (`type 'TypeEngine' is not subscriptable` at runtime under 1.4).
99+
# Keep `TypeDecorator` and suppress the SA 2.0 type-stub mismatch on each line.
96100
# pyre-ignore[9]: SA 2.0 typed as_mutable returns TypeEngine; runtime TypeDecorator.
97101
JSONEncodedList: TypeDecorator = MutableList.as_mutable(JSONEncodedObject)
98102
# pyre-ignore[9]: SA 2.0 typed as_mutable returns TypeEngine; runtime TypeDecorator.

ax/storage/sqa_store/load.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
# LICENSE file in the root directory of this source tree.
66

77
# pyre-strict
8-
# pyre-ignore-all-errors[6, 8]
98

109
import logging
1110
from collections.abc import Mapping
@@ -715,8 +714,8 @@ def load_analysis_cards_by_experiment_name(
715714
analysis_card_sqa_class.children
716715
)
717716

718-
exp_sqa_class: SQAExperiment = cast(
719-
SQAExperiment, decoder.config.class_to_sqa_class[Experiment]
717+
exp_sqa_class = cast(
718+
type[SQAExperiment], decoder.config.class_to_sqa_class[Experiment]
720719
)
721720

722721
with session_scope() as session:

ax/storage/sqa_store/reduced_state.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,17 @@
66

77
# pyre-strict
88
# pyre-ignore-all-errors[24]
9+
#
10+
# SA 2.0 requires a type param on InstrumentedAttribute, but SA 1.4
11+
# InstrumentedAttribute is not subscriptable at runtime (`type is not a generic
12+
# class`), so we keep the bare form to preserve dual-version compatibility.
913

1014

1115
from ax.storage.sqa_store.sqa_classes import SQAGeneratorRun, SQATrial
1216
from sqlalchemy.orm import defaultload, strategy_options
1317
from sqlalchemy.orm.attributes import InstrumentedAttribute
1418

1519

16-
# pyre-fixme[9]: `GR_LARGE_MODEL_ATTRS` is declared as `List[InstrumentedAttribute]`
17-
# but SQLAlchemy class attributes are typed as `Column` in stubs; they are
18-
# `InstrumentedAttribute` instances at runtime.
1920
GR_LARGE_MODEL_ATTRS: list[InstrumentedAttribute] = [
2021
SQAGeneratorRun.model_kwargs,
2122
SQAGeneratorRun.bridge_kwargs,

ax/storage/sqa_store/save.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
# LICENSE file in the root directory of this source tree.
66

77
# pyre-strict
8-
# pyre-ignore-all-errors[6, 8, 9]
98

109
import os
1110
from collections.abc import Callable, Generator, Sequence

ax/storage/sqa_store/validation.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@
3434

3535

3636
def listens_for_multiple(
37-
# pyre-ignore[24]: SA 2.0 requires a type param on InstrumentedAttribute.
37+
# pyre-ignore[24]: SA 2.0 requires a type param; SA 1.4 InstrumentedAttribute
38+
# is not subscriptable at runtime, so we keep the bare form.
3839
targets: list[InstrumentedAttribute],
3940
identifier: str,
4041
*args: Any,

0 commit comments

Comments
 (0)