Skip to content

fix deprecated - false negative on usage of deprecated class #5170 - #5175

Open
asukaminato0721 wants to merge 11 commits into
facebook:mainfrom
asukaminato0721:5170
Open

asukaminato0721 wants to merge 11 commits into
facebook:mainfrom
asukaminato0721:5170

Conversation

@asukaminato0721

Copy link
Copy Markdown
Collaborator

Summary

Fixes #5170

add deprecated class support.

  • I am a human, and I fully understand the code I am submitting.

Test Plan

add teset

@meta-cla meta-cla Bot added the cla signed label Oct 9, 2026
@github-actions github-actions Bot added the size/m label Oct 9, 2026
@meta-codesync

meta-codesync Bot commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

This pull request has been imported. If you are a Meta employee, you can view this in D124324453. (Because this pull request was imported automatically, there will not be any future comments.)

@github-actions

This comment has been minimized.

@github-actions github-actions Bot added size/m and removed size/m labels Oct 9, 2026
@github-actions

This comment has been minimized.

@github-actions github-actions Bot added size/l and removed size/m labels Oct 9, 2026
@github-actions

This comment has been minimized.

@connernilsen

Copy link
Copy Markdown
Contributor

Hey @asukaminato0721, thanks for picking this up! It looks like there are some CI errors right now. I think we may need to add a filter to skip these errors on typeshed, since it looks like they're showing up in the scrut tests.

@github-actions

This comment has been minimized.

@connernilsen
connernilsen self-requested a review October 13, 2026 21:55

@connernilsen connernilsen left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for fixing the test! I have a few more requests. Sorry, my previous comment was a little misguided on how to fix the test

Comment thread pyrefly/lib/alt/answers_solver.rs Outdated
Comment thread test/errors.md
Comment thread test/errors.md Outdated
Comment thread pyrefly/lib/alt/expr.rs
@asukaminato0721
asukaminato0721 force-pushed the 5170 branch 2 times, most recently from c885903 to 4c4a4a6 Compare October 14, 2026 14:02
@github-actions github-actions Bot added size/xl and removed size/l labels Oct 14, 2026
@github-actions

This comment has been minimized.

@connernilsen connernilsen left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a few more requests :)

Comment thread pyrefly/lib/alt/expr.rs Outdated
Comment on lines +1247 to +1253
if let Type::ClassDef(cls) = ty
&& cls.module_path() == self.module().path()
&& let Some(class_idx) = self.bindings().enclosing_class(range)
&& let BindingClass::ClassDef(binding) = self.bindings().get(class_idx)
&& binding.def_index == cls.index()
{
// References inside the defining class are part of its implementation.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This logic only records exemptions for this error inside the class body, but bases, decorators, and type params are outside of the body, so they'll error on the class definition.

Can we add tests to make sure this doesn't happen, and if it does, fix it?

Example:

@deprecated("x")
class Old(Base["Old"]): ...

class Old[T: "Old"]: ...

Comment thread pyrefly/lib/binding/binding.rs Outdated
pub def_index: ClassDefIndex,
pub parent: NestingContext,
pub is_protocol: bool,
pub deprecation: Option<Deprecation>,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: can we change this to an Option<Box<Deprecation>> instead? This should bring it down from 13 words to 11

Comment thread pyrefly/lib/test/calls.rs
instance = OldClass() # E: Use NewClass instead
instance.method()
alias = OldClass # E: `OldClass` is deprecated
alias() # E: `OldClass` is deprecated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alias is already flagged on the previous line. Is this intended? I think this is reasonable, but what about

(x := OldClass) # might warn twice

class X:
  def foo(self) -> OldClass:
     ...

X().foo() # this would likely warn

I think we'd at least want to guard against the walrus case, but whether or not we want to handle all of them is up to you

Comment thread pyrefly/lib/test/calls.rs
"#,
);

testcase!(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be worth adding these tests:

(note, test_deprecated_class_and_init might have a second error)

  testcase!(
      test_deprecated_class_header_and_nested,
      r#"
  from warnings import deprecated

  class Base[T]: ...

  @deprecated("x")
  class Old(Base["Old"]):  # no error: the class's own header
      class Inner:
          def f(self) -> "Old": ...  # no error: nested inside Old

  @deprecated("x")
  class Bounded[T: "Bounded"]: ...  # no error: its own type parameter bound
      "#,
  );

  testcase!(
      test_deprecated_class_annotation_forms,
      r#"
  from warnings import deprecated

  @deprecated("x")
  class Old: ...

  def f(a: Old | None, b: type[Old], c: object) -> None:  # E: `Old` is deprecated  # E: `Old` is deprecated
      if isinstance(c, Old):  # E: `Old` is deprecated
          pass
      try:
          pass
      except Exception as e:
          pass
      "#,
  );

  testcase!(
      test_deprecated_class_and_init,
      r#"
  from warnings import deprecated

  @deprecated("class")
  class Old:
      @deprecated("init")
      def __init__(self) -> None: ...

  Old()  # E: `Old` is deprecated  
      "#,
  );

  testcase!(
      test_deprecated_class_qualified_decorator,
      r#"
  import typing_extensions
  import dataclasses, enum, typing

  @typing_extensions.deprecated("x")
  class A: ...

  @typing_extensions.deprecated("x")
  @dataclasses.dataclass
  class D:
      x: int

  @typing_extensions.deprecated("x")
  class E(enum.Enum):
      X = 1

  @typing_extensions.deprecated("x")
  class P(typing.Protocol): ...

  A()  # E: `A` is deprecated
  D(1)  # E: `D` is deprecated
  E.X  # E: `E` is deprecated
  def g(p: P) -> None: ...  # E: `P` is deprecated
      "#,
  );

@github-actions

Copy link
Copy Markdown

Diff from mypy_primer, showing the effect of this PR on open source code:

============================================================
SUMMARY
============================================================
Total: +100 new errors, -2 fixed errors
By preset: +100/-0 (default), +100/-0 (strict)

Projects with changes (17):
  openlibrary: +1 -0
  mitmproxy: +6 -0
  scipy-stubs: +5 -0
  spark: +3 -0
  scikit-learn: +29 -0
  scikit-build-core: +1 -0
  manticore: +2 -0
  mongo-python-driver: +2 -0
  strawberry: +3 -0
  Tanjun: +5 -0
  static-frame: +3 -0
  mypy: +28 -2
  meson: +1 -0
  pyodide: +2 -0
  parso: +2 -0
  pydantic: +4 -0
  PyGithub: +3 -0
============================================================

FULL DIFF DETAILS
------------------------------------------------------------

openlibrary (https://github.com/internetarchive/openlibrary)
+ ERROR openlibrary/tests/fastapi/test_account_loans.py:123:31-64: `openlibrary.plugins.upstream.account.account_loans_json` is deprecated [deprecated]

mitmproxy (https://github.com/mitmproxy/mitmproxy)
+ ERROR docs/src/examples/contrib/check_ssl_pinning.py:57:14-42: `OpenSSL.crypto.X509Extension` is deprecated [deprecated]
+ ERROR examples/contrib/check_ssl_pinning.py:57:14-42: `OpenSSL.crypto.X509Extension` is deprecated [deprecated]
+ ERROR mitmproxy/contentviews/__init__.py:168:32-36: `mitmproxy.contentviews.base.View` is deprecated [deprecated]
+ ERROR mitmproxy/contentviews/_compat.py:60:37-41: `mitmproxy.contentviews.base.View` is deprecated [deprecated]
+ ERROR mitmproxy/contentviews/_compat.py:73:18-22: `mitmproxy.contentviews.base.View` is deprecated [deprecated]
+ ERROR test/mitmproxy/contentviews/test__compat.py:10:20-24: `mitmproxy.contentviews.base.View` is deprecated [deprecated]

scipy-stubs (https://github.com/scipy/scipy-stubs)
+ ERROR scipy-stubs/interpolate/interpolate.pyi:51:16-37: `scipy.interpolate._interpolate.interp2d` is deprecated [deprecated]
+ ERROR scipy-stubs/io/arff/arffread.pyi:16:22-31: `ArffError` is deprecated [deprecated]
+ ERROR scipy-stubs/io/matlab/mio5.pyi:24:22-34: `MatlabObject` is deprecated [deprecated]
+ ERROR scipy-stubs/optimize/minpack.pyi:40:6-20: `OptimizeResult` is deprecated [deprecated]
+ ERROR tests/interpolate/test_interpolate.pyi:97:22-30: `scipy.interpolate._interpolate.interp2d` is deprecated [deprecated]

spark (https://github.com/apache/spark)
+ ERROR python/pyspark/cloudpickle/cloudpickle.py:1249:21-44: `abc.abstractclassmethod` is deprecated [deprecated]
+ ERROR python/pyspark/cloudpickle/cloudpickle.py:1250:21-45: `abc.abstractstaticmethod` is deprecated [deprecated]
+ ERROR python/pyspark/cloudpickle/cloudpickle.py:1251:21-41: `abc.abstractproperty` is deprecated [deprecated]

scikit-learn (https://github.com/scikit-learn/scikit-learn)
+ ERROR sklearn/linear_model/tests/test_common.py:191:9-35: `sklearn.linear_model._passive_aggressive.PassiveAggressiveRegressor` is deprecated [deprecated]
+ ERROR sklearn/linear_model/tests/test_common.py:231:10-37: `sklearn.linear_model._passive_aggressive.PassiveAggressiveClassifier` is deprecated [deprecated]
+ ERROR sklearn/linear_model/tests/test_passive_aggressive.py:93:11-38: `sklearn.linear_model._passive_aggressive.PassiveAggressiveClassifier` is deprecated [deprecated]
+ ERROR sklearn/linear_model/tests/test_passive_aggressive.py:117:11-38: `sklearn.linear_model._passive_aggressive.PassiveAggressiveClassifier` is deprecated [deprecated]
+ ERROR sklearn/linear_model/tests/test_passive_aggressive.py:132:11-38: `sklearn.linear_model._passive_aggressive.PassiveAggressiveClassifier` is deprecated [deprecated]
+ ERROR sklearn/linear_model/tests/test_passive_aggressive.py:151:12-39: `sklearn.linear_model._passive_aggressive.PassiveAggressiveClassifier` is deprecated [deprecated]
+ ERROR sklearn/linear_model/tests/test_passive_aggressive.py:162:11-38: `sklearn.linear_model._passive_aggressive.PassiveAggressiveClassifier` is deprecated [deprecated]
+ ERROR sklearn/linear_model/tests/test_passive_aggressive.py:173:11-38: `sklearn.linear_model._passive_aggressive.PassiveAggressiveClassifier` is deprecated [deprecated]
+ ERROR sklearn/linear_model/tests/test_passive_aggressive.py:180:11-38: `sklearn.linear_model._passive_aggressive.PassiveAggressiveClassifier` is deprecated [deprecated]
+ ERROR sklearn/linear_model/tests/test_passive_aggressive.py:193:11-38: `sklearn.linear_model._passive_aggressive.PassiveAggressiveClassifier` is deprecated [deprecated]
+ ERROR sklearn/linear_model/tests/test_passive_aggressive.py:202:11-38: `sklearn.linear_model._passive_aggressive.PassiveAggressiveClassifier` is deprecated [deprecated]
+ ERROR sklearn/linear_model/tests/test_passive_aggressive.py:206:20-47: `sklearn.linear_model._passive_aggressive.PassiveAggressiveClassifier` is deprecated [deprecated]
+ ERROR sklearn/linear_model/tests/test_passive_aggressive.py:209:20-47: `sklearn.linear_model._passive_aggressive.PassiveAggressiveClassifier` is deprecated [deprecated]
+ ERROR sklearn/linear_model/tests/test_passive_aggressive.py:225:11-38: `sklearn.linear_model._passive_aggressive.PassiveAggressiveClassifier` is deprecated [deprecated]
+ ERROR sklearn/linear_model/tests/test_passive_aggressive.py:239:11-37: `sklearn.linear_model._passive_aggressive.PassiveAggressiveRegressor` is deprecated [deprecated]
+ ERROR sklearn/linear_model/tests/test_passive_aggressive.py:264:11-37: `sklearn.linear_model._passive_aggressive.PassiveAggressiveRegressor` is deprecated [deprecated]
+ ERROR sklearn/linear_model/tests/test_passive_aggressive.py:288:12-38: `sklearn.linear_model._passive_aggressive.PassiveAggressiveRegressor` is deprecated [deprecated]
+ ERROR sklearn/linear_model/tests/test_passive_aggressive.py:296:11-37: `sklearn.linear_model._passive_aggressive.PassiveAggressiveRegressor` is deprecated [deprecated]
+ ERROR sklearn/linear_model/tests/test_passive_aggressive.py:303:19-46: `sklearn.linear_model._passive_aggressive.PassiveAggressiveClassifier` is deprecated [deprecated]
+ ERROR sklearn/linear_model/tests/test_passive_aggressive.py:303:48-74: `sklearn.linear_model._passive_aggressive.PassiveAggressiveRegressor` is deprecated [deprecated]
+ ERROR sklearn/linear_model/tests/test_passive_aggressive.py:318:10-37: `sklearn.linear_model._passive_aggressive.PassiveAggressiveClassifier` is deprecated [deprecated]
+ ERROR sklearn/linear_model/tests/test_passive_aggressive.py:334:10-36: `sklearn.linear_model._passive_aggressive.PassiveAggressiveRegressor` is deprecated [deprecated]
+ ERROR sklearn/utils/_test_common/instance_generator.py:402:5-32: `sklearn.linear_model._passive_aggressive.PassiveAggressiveClassifier` is deprecated [deprecated]
+ ERROR sklearn/utils/_test_common/instance_generator.py:403:5-31: `sklearn.linear_model._passive_aggressive.PassiveAggressiveRegressor` is deprecated [deprecated]
+ ERROR sklearn/utils/tests/test_deprecation.py:40:18-28: `MockClass1` is deprecated [deprecated]
+ ERROR sklearn/utils/tests/test_deprecation.py:63:9-19: `MockClass1` is deprecated [deprecated]
+ ERROR sklearn/utils/tests/test_deprecation.py:71:9-19: `MockClass6` is deprecated [deprecated]
+ ERROR sklearn/utils/tests/test_deprecation.py:80:27-37: `MockClass1` is deprecated [deprecated]
+ ERROR sklearn/utils/tests/test_deprecation.py:98:27-36: `test_deprecated_class_signature.MockClass` is deprecated [deprecated]

scikit-build-core (https://github.com/scikit-build/scikit-build-core)
+ ERROR src/scikit_build_core/_compat/importlib/metadata.py:29:31-47: `importlib.metadata.SelectableGroups` is deprecated [deprecated]

manticore (https://github.com/trailofbits/manticore)
+ ERROR tests/wasm/json2mc.py:8:38-55: `argparse.FileType` is deprecated [deprecated]
+ ERROR tests/wasm_sym/json2smc.py:8:38-55: `argparse.FileType` is deprecated [deprecated]

mongo-python-driver (https://github.com/mongodb/mongo-python-driver)
+ ERROR bson/codec_options.py:65:6-26: `abc.abstractproperty` is deprecated [deprecated]
+ ERROR bson/codec_options.py:84:6-26: `abc.abstractproperty` is deprecated [deprecated]

strawberry (https://github.com/strawberry-graphql/strawberry)
+ ERROR strawberry/utils/typing.py:231:61-70: `ast.Index` is deprecated [deprecated]
+ ERROR strawberry/utils/typing.py:249:61-70: `ast.Index` is deprecated [deprecated]
+ ERROR strawberry/utils/typing.py:275:61-70: `ast.Index` is deprecated [deprecated]

Tanjun (https://github.com/FasterSpeeding/Tanjun)
+ ERROR tanjun/context/autocomplete.py:56:27-46: `alluka._context.BasicContext` is deprecated [deprecated]
+ ERROR tanjun/context/base.py:47:19-38: `alluka._context.BasicContext` is deprecated [deprecated]
+ ERROR tanjun/injecting.py:74:22-47: `alluka._self_injecting.AsyncSelfInjecting` is deprecated [deprecated]
+ ERROR tanjun/injecting.py:104:10-35: `alluka._self_injecting.AsyncSelfInjecting` is deprecated [deprecated]
+ ERROR tanjun/injecting.py:105:16-41: `alluka._self_injecting.AsyncSelfInjecting` is deprecated [deprecated]

static-frame (https://github.com/static-frame/static-frame)
+ ERROR static_frame/core/type_clinic.py:1753:28-36: `numpy._typing._nbit_base.NBitBase` is deprecated [deprecated]
+ ERROR static_frame/test/unit/test_type_clinic.py:41:1-9: `numpy._typing._nbit_base.NBitBase` is deprecated [deprecated]
+ ERROR static_frame/test/unit/test_type_clinic.py:42:9-17: `numpy._typing._nbit_base.NBitBase` is deprecated [deprecated]

mypy (https://github.com/python/mypy)
+ ERROR mypy/typeshed/stdlib/argparse.pyi:33:49-57: `FileType` is deprecated [deprecated]
+ ERROR mypy/typeshed/stdlib/argparse.pyi:411:41-49: `FileType` is deprecated [deprecated]
+ ERROR mypy/typeshed/stdlib/argparse.pyi:469:45-53: `FileType` is deprecated [deprecated]
- ERROR mypy/typeshed/stdlib/ast.pyi:1223:96-116: Unused `# type: ignore` comment [unused-type-ignore]
+ ERROR mypy/typeshed/stdlib/ast.pyi:1222:16-21: `slice` is deprecated [deprecated]
+ ERROR mypy/typeshed/stdlib/ast.pyi:1226:13-18: `slice` is deprecated [deprecated]
+ ERROR mypy/typeshed/stdlib/ast.pyi:2168:36-44: `ExtSlice` is deprecated [deprecated]
+ ERROR mypy/typeshed/stdlib/ast.pyi:2169:33-38: `Index` is deprecated [deprecated]
+ ERROR mypy/typeshed/stdlib/ast.pyi:2170:33-38: `Suite` is deprecated [deprecated]
+ ERROR mypy/typeshed/stdlib/ast.pyi:2171:35-42: `AugLoad` is deprecated [deprecated]
+ ERROR mypy/typeshed/stdlib/ast.pyi:2172:36-44: `AugStore` is deprecated [deprecated]
+ ERROR mypy/typeshed/stdlib/ast.pyi:2173:33-38: `Param` is deprecated [deprecated]
+ ERROR mypy/typeshed/stdlib/asyncio/events.pyi:769:40-60: `mypy.typeshed.stdlib.asyncio.unix_events.AbstractChildWatcher` is deprecated [deprecated]
+ ERROR mypy/typeshed/stdlib/asyncio/events.pyi:772:46-66: `mypy.typeshed.stdlib.asyncio.unix_events.AbstractChildWatcher` is deprecated [deprecated]
+ ERROR mypy/typeshed/stdlib/asyncio/events.pyi:801:32-52: `mypy.typeshed.stdlib.asyncio.unix_events.AbstractChildWatcher` is deprecated [deprecated]
+ ERROR mypy/typeshed/stdlib/asyncio/events.pyi:803:36-56: `mypy.typeshed.stdlib.asyncio.unix_events.AbstractChildWatcher` is deprecated [deprecated]
+ ERROR mypy/typeshed/stdlib/asyncio/unix_events.pyi:99:36-56: `AbstractChildWatcher` is deprecated [deprecated]
+ ERROR mypy/typeshed/stdlib/asyncio/unix_events.pyi:105:36-52: `BaseChildWatcher` is deprecated [deprecated]
+ ERROR mypy/typeshed/stdlib/asyncio/unix_events.pyi:116:36-52: `BaseChildWatcher` is deprecated [deprecated]
+ ERROR mypy/typeshed/stdlib/asyncio/unix_events.pyi:176:48-68: `AbstractChildWatcher` is deprecated [deprecated]
+ ERROR mypy/typeshed/stdlib/asyncio/unix_events.pyi:178:54-74: `AbstractChildWatcher` is deprecated [deprecated]
+ ERROR mypy/typeshed/stdlib/asyncio/unix_events.pyi:196:41-61: `AbstractChildWatcher` is deprecated [deprecated]
+ ERROR mypy/typeshed/stdlib/asyncio/unix_events.pyi:210:40-60: `AbstractChildWatcher` is deprecated [deprecated]
+ ERROR mypy/typeshed/stdlib/asyncio/unix_events.pyi:225:37-57: `AbstractChildWatcher` is deprecated [deprecated]
+ ERROR mypy/typeshed/stdlib/distutils/cygwinccompiler.pyi:19:29-41: `setuptools._distutils.version.LooseVersion` is deprecated [deprecated]
- ERROR mypy/typeshed/stdlib/importlib/abc.pyi:62:108-130: Unused `# type: ignore` comment [unused-type-ignore]
+ ERROR mypy/typeshed/stdlib/importlib/abc.pyi:96:50-64: `ResourceLoader` is deprecated [deprecated]
+ ERROR mypy/typeshed/stdlib/importlib/resources/_common.pyi:36:59-73: `importlib.resources.abc.ResourceReader` is deprecated [deprecated]
+ ERROR mypy/typeshed/stdlib/importlib/resources/abc.pyi:56:32-46: `ResourceReader` is deprecated [deprecated]
+ ERROR mypy/typeshed/stdlib/urllib/request.pyi:390:26-35: `URLopener` is deprecated [deprecated]

meson (https://github.com/mesonbuild/meson)
+ ERROR mesonbuild/linkers/linkers.py:139:6-26: `abc.abstractproperty` is deprecated [deprecated]

pyodide (https://github.com/pyodide/pyodide)
+ ERROR src/tests/test_python.py:159:18-30: `setuptools._distutils.version.LooseVersion` is deprecated [deprecated]
+ ERROR src/tests/test_python.py:160:25-37: `setuptools._distutils.version.LooseVersion` is deprecated [deprecated]

parso (https://github.com/davidhalter/parso)
+ ERROR parso/tree.py:131:6-22: `abc.abstractproperty` is deprecated [deprecated]
+ ERROR parso/tree.py:140:6-22: `abc.abstractproperty` is deprecated [deprecated]

pydantic (https://github.com/pydantic/pydantic)
+ ERROR pydantic/deprecated/json.py:57:5-10: `pydantic.color.Color` is deprecated [deprecated]
+ ERROR pydantic/v1/_hypothesis_plugin.py:105:5-25: `pydantic.color.Color` is deprecated [deprecated]
+ ERROR pydantic/v1/_hypothesis_plugin.py:126:13-39: `pydantic.types.PaymentCardNumber` is deprecated [deprecated]
+ ERROR pydantic/v1/_hypothesis_plugin.py:139:5-31: `pydantic.types.PaymentCardNumber` is deprecated [deprecated]

PyGithub (https://github.com/PyGithub/PyGithub)
+ ERROR github/MainClass.py:198:19-36: `github.AppAuthentication.AppAuthentication` is deprecated [deprecated]
+ ERROR github/Requester.py:287:17-34: `github.AppAuthentication.AppAuthentication` is deprecated [deprecated]
+ ERROR tests/Authentication.py:97:24-48: `github.AppAuthentication.AppAuthentication` is deprecated [deprecated]

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

deprecated - false negative on usage of deprecated class

3 participants