{"slug": "whats-fixed-and-improved-in-pycharm-2026-2", "title": "What’s Fixed and Improved in PyCharm 2026.2", "summary": "JetBrains released PyCharm 2026.2 with 263 fixes and improvements, focusing on Python code insight, type inference, and SQLAlchemy 2.0 support. The update resolves long-standing false positives in SQLAlchemy, improves control-flow narrowing, and fixes type inference for iterable unpacking and augmented assignments.", "body_md": "[Releases](/pycharm/category/releases/)\n\n# What’s Fixed and Improved in PyCharm 2026.2\n\nAcross the PyCharm 2026.2 release line, we shipped[ 263 fixes and improvements](https://youtrack.jetbrains.com/issues?q=%23py%20type:%20bug%20%23resolved%20Planned%20for:%202026.2,%20%7B2026.2%20*%7D,%202026.2.1%20visible%20to:%20%7BAll%20Users%7D). Many improve Python code insight directly, with more precise type inference, fewer false positives, smarter completion and imports, and more reliable refactoring. Here are some of the smaller changes you’re likely to notice in everyday Python development.\n\n## SQLAlchemy 2.0 support\n\nSQLAlchemy has been a long-standing source of false positives – enough that several duplicate tickets have accumulated over the years. This release resolves a batch of them for the 2.0 style.\n\nString forward-references inside `Mapped[...]`\n\nresolve correctly:\n\n```\nposts: Mapped[list[\"Post\"]] = relationship(back_populates=\"author\")\n\n# \"Post\" now resolves to the model class\n```\n\nPyCharm also correctly infers the mapped type returned by `Session.get()`\n\n, instead of treating the result as the model class itself:\n\n```\nreport = session.get(Report, report_id)\n\nreveal_type(report)  # was: type[Report] | None   now: Report | None\n```\n\nModern `hybrid_property`\n\nsetters written as `@name.inplace.setter`\n\nare recognized, so assigning to the property no longer produces a warning. Model class attributes defined via mixins are picked up again, too, clearing the old *unexpected argument* reports on model constructors.\n\n([PY-78816](https://youtrack.jetbrains.com/issue/PY-78816),[ PY-65142](https://youtrack.jetbrains.com/issue/PY-65142),[ PY-59732](https://youtrack.jetbrains.com/issue/PY-59732),[ PY-51906](https://youtrack.jetbrains.com/issue/PY-51906),[ PY-28762](https://youtrack.jetbrains.com/issue/PY-28762))\n\n## Code insight and type inference\n\n### Control-flow narrowing and “unreachable code”\n\nSeveral false *This code is unreachable* reports and instances of lost narrowing across loops have been fixed. The common issue: flow analysis either gave up or over-eagerly narrowed to `Never `\n\nin branches it should have kept alive.\n\n`isinstance`\n\non a numeric union no longer kills the `else`\n\nbranch:\n\n``` php\ndef foo(y: int | float) -> None:\n\n    if isinstance(y, float):\n\n        pass\n\n    else:\n\n        print(y)  # was flagged unreachable, y inferred as Never\n```\n\nNarrowing also survives a `while`\n\nloop, so re-narrowing an optional attribute inside the loop body no longer reports a bogus *has no attribute* error.\n\n([PY-83206](https://youtrack.jetbrains.com/issue/PY-83206),[ PY-83354](https://youtrack.jetbrains.com/issue/PY-83354),[ PY-88265](https://youtrack.jetbrains.com/issue/PY-88265))\n\n### Strings inside type annotations\n\nA string used as metadata inside `Annotated[...]`\n\n– a Pydantic discriminator field name, for instance – is no longer parsed as a forward reference and flagged as unresolved.\n\n### Iterable unpacking and star expressions\n\nPyCharm’s analysis of tuple and star unpacking could lose type information and fall back to `Any`\n\n. Unpacking a starred value into a tuple lost its element types, `*`\n\n-expansion collapsed to `Any`\n\n, and several genuine errors went unreported. Starred expressions preserve their element types:\n\n``` php\ndef a() -> tuple[int, int]:\n\n    return 2, 3\n\ndef b() -> tuple[int, int, int]:\n\n    return (1, *a())  # no more bogus \"Expected tuple[int, int, int]\"\n```\n\n([PY-12592](https://youtrack.jetbrains.com/issue/PY-12592),[ PY-27205](https://youtrack.jetbrains.com/issue/PY-27205),[ PY-43585](https://youtrack.jetbrains.com/issue/PY-43585),[ PY-90219](https://youtrack.jetbrains.com/issue/PY-90219))\n\n### Augmented assignment\n\nA cluster of false positives came from augmented assignments being misanalyzed. A simple `/=`\n\non an `int`\n\nproduced the wrong type:\n\n```\nfoo = 5\n\nfoo /= 2\n\nreveal_type(foo)  # was: int   now: float | int\n```\n\n([PY-80622](https://youtrack.jetbrains.com/issue/PY-80622))\n\n`Self`\n\nand constructor return types\n\n`Self`\n\nbinds correctly through `classmethod`\n\nparameters typed as `type[Self]`\n\n:\n\n``` php\nclass A:\n\n    @classmethod\n\n    def bar(cls, y: type[Self]) -> Self: ...\n\nx = A.bar(A)      # was a spurious \"Expected type[A], got type[A]\"\n\nreveal_type(x)    # was: Any   now: A\n```\n\nConstruction also respects `__new__`\n\n, `__init__`\n\n, and metaclass `__call__`\n\n. When `__new__`\n\nreturns something other than an instance, that’s the constructed type – even when an `__init__`\n\nis present. The same fix covers explicitly parameterized calls like `MyClass[int]()`\n\nand `__new__`\n\nassigned as a class attribute.\n\n([PY-89296](https://youtrack.jetbrains.com/issue/PY-89296),[ PY-77611](https://youtrack.jetbrains.com/issue/PY-77611),[ PY-88644](https://youtrack.jetbrains.com/issue/PY-88644),[ PY-89571](https://youtrack.jetbrains.com/issue/PY-89571))\n\n### Enum members: Literal types for `.value`\n\nand `.name`\n\nReading an enum member’s `.value`\n\nor `.name`\n\nyields a precise `Literal`\n\ninstead of a widened `str`\n\nor `int`\n\n, so assignments to `Literal[...]`\n\ntarget type-check. This matches `mypy`\n\n’s inference:\n\n``` python\nfrom enum import Enum\n\nfrom typing import Literal\n\nclass E(Enum):\n\n    a = \"a\"\n\nb: Literal[\"a\"] = E.a.value   # was: Expected 'Literal[\"a\"]', got 'str'\n\nn: Literal[\"a\"] = E.a.name    # .name is a Literal too\n```\n\n### Parameter types inferred from decorators\n\nWhen a decorator constrains the callable it accepts, the decorated function’s parameters are inferred from that constraint instead of falling back to `Any`\n\n:\n\n``` python\nfrom typing import Callable\n\ndef d(fn: Callable[[int], str]): ...\n\n@d\n\ndef f(a):\n\n    reveal_type(a)   # was: Any   now: int\n```\n\n([PY-79204](https://youtrack.jetbrains.com/issue/PY-79204))\n\n### Also fixed\n\n- Keyword arguments in a class header are validated against the base class’s\n`__init_subclass__`\n\nsignature, and offered in completion ([PY-79173](https://youtrack.jetbrains.com/issue/PY-79173)). - An ellipsis in a\n`Callable`\n\nused as a PEP 695 type-parameter bound no longer reports a bogus*Invalid type expression*([PY-83570](https://youtrack.jetbrains.com/issue/PY-83570)). - Type-checker findings are split into granular suppression codes rather than a single\n`PyTypeChecker`\n\nid, and`# noinspection`\n\ndirectives accept a simplified name form.`PyTypeChecker`\n\nstill works as a blanket ignore ([PY-90265](https://youtrack.jetbrains.com/issue/PY-90265)).\n\n## Completion and auto-import\n\n### Smarter auto-import\n\nAuto-import is now noticeably less noisy. Previously, if a module was already imported, PyCharm would offer to add a second, redundant import instead of qualifying through the one you already had. The quick-fix – and the completion popup – prefer to reuse the existing import.\n\nGiven `pkg/src.py`\n\ncontaining `MyClass`\n\n, and a file that already imports the module, *Alt*+*Enter* produces this:\n\n``` python\nfrom pkg import src  # no longer flagged as unused\n\nsrc.MyClass\n```\n\ninstead of adding `from pkg.src import MyClass`\n\n. The same reuse logic applies to plain `import pkg.src`\n\n, and to the auto-import completion on a second *Ctrl*+*Space*.\n\nNested classes can be auto-imported too, which is something PyCharm didn’t previously support:\n\n```\n# mod.py\n\nclass Outer:\n\n    class Inner:\n\n        pass\n\n# main.py – Alt+Enter on Inner now offers \"Import Outer from mod\"\n\nfrom mod import Outer\n\nvalue = Outer.Inner()\n```\n\n([PY-87970](https://youtrack.jetbrains.com/issue/PY-87970),[ PY-87971](https://youtrack.jetbrains.com/issue/PY-87971),[ PY-87972](https://youtrack.jetbrains.com/issue/PY-87972),[ PY-88009](https://youtrack.jetbrains.com/issue/PY-88009),[ PY-88016](https://youtrack.jetbrains.com/issue/PY-88016))\n\n### Completion for `unittest.mock.patch()`\n\ntargets\n\nPatching by string target previously offered no code assistance, so dotted paths had to be entered manually. The string argument to `mock.patch(...)`\n\ngets code completion for modules, classes, and their attributes, and it no longer suggests the invalid `as`\n\nkeyword mid-path:\n\n``` python\nfrom unittest import mock\n\n# sample.py defines: class Foo: my_attr = 42\n\nwith mock.patch(\"sample.Foo.my_attr\", 14):\n\n    ...\n\n# completion now offers `sample`, `Foo`, and `my_attr`\n```\n\n([PY-89189](https://youtrack.jetbrains.com/issue/PY-89189),[ PY-89191](https://youtrack.jetbrains.com/issue/PY-89191),[ PY-89192](https://youtrack.jetbrains.com/issue/PY-89192))\n\n### Typed signatures when overriding built-in methods\n\nCompleting an override of a dunder or built-in method fills in the full annotated signature – and auto-imports the types it needs – instead of bare parameters:\n\n``` python\nfrom types import TracebackType\n\nclass A:\n\n    def __exit__(self, exc_type: type[BaseException] | None,\n\n                 exc_val: BaseException | None,\n\n                 exc_tb: TracebackType | None): ...\n\n# was: def __exit__(self, exc_type, exc_val, exc_tb):\n```\n\n([PY-79218](https://youtrack.jetbrains.com/issue/PY-79218))\n\n## Editor and inspections\n\n### Type inlay hints\n\nInferred type arguments are shown inline at the call site, so you can see what a generic resolved to without hovering over it:\n\n``` python\nclass A[T]:\n\n    def __init__(self, t: T): ...\n\nA[int](1)     # [int] shown as an inlay hint\n```\n\nType names rendered inside inlay hints – return types and solved arguments alike – are also clickable, so you can jump straight to a type’s definition from the hint.\n\n`f-string`\n\nformat-spec validation\n\nPyCharm already validated the `str.format()`\n\nmini-language. Those checks apply to `f-strings`\n\ntoo, and PyCharm flags formatting a type that doesn’t implement `__format__`\n\n:\n\n```\ndata = 1\n\nf\"{data:.2f}\"   # ok\n\nf\"{data:.2q}\"   # now flagged: unsupported format spec\n\nclass A: ...\n\nf\"{A():d}\"      # now flagged: A doesn't support the 'd' format\n```\n\n## Refactoring\n\nThe *Rename* refactoring also updates references to a module when the module itself is renamed. Previously, the renaming left importing sites pointing at the old name:\n\n``` python\n# rename provider/provider_module.py → some_module.py\n\nfrom ..provider import provider_module  # this reference is updated too\n```\n\n([PY-53274](https://youtrack.jetbrains.com/issue/PY-53274))\n\nThe *Refactor | Field action* is now *Attribute*, and the documentation says “instance attributes” to match Python terminology ([PY-85828](https://youtrack.jetbrains.com/issue/PY-85828)).\n\n## Conclusion\n\nTaken together, these changes make PyCharm’s understanding of Python more precise and predictable: fewer false positives, better type inference, smarter completion, and less time spent working around cases where the IDE gets valid code wrong.\n\nMany of these improvements started with real-world examples reported by users. If PyCharm still misunderstands a typing pattern, framework API, or other valid Python code in your project, let us know in YouTrack – a small reproducer can help us turn that friction into the next fix.\n\nTry [PyCharm 2026.2](https://www.jetbrains.com/pycharm/) and let us know which improvements make the biggest difference for your workflow.\n\nThank you for using PyCharm!\n\n#### Subscribe to PyCharm Blog updates", "url": "https://wpnews.pro/news/whats-fixed-and-improved-in-pycharm-2026-2", "canonical_source": "https://blog.jetbrains.com/pycharm/2026/08/what-s-fixed-and-improved-in-pycharm-2026-2/", "published_at": "2026-08-19 13:54:13+00:00", "updated_at": "2026-08-19 14:10:57.863218+00:00", "lang": "en", "topics": ["developer-tools"], "entities": ["JetBrains", "PyCharm", "SQLAlchemy"], "alternates": {"html": "https://wpnews.pro/news/whats-fixed-and-improved-in-pycharm-2026-2", "markdown": "https://wpnews.pro/news/whats-fixed-and-improved-in-pycharm-2026-2.md", "text": "https://wpnews.pro/news/whats-fixed-and-improved-in-pycharm-2026-2.txt", "jsonld": "https://wpnews.pro/news/whats-fixed-and-improved-in-pycharm-2026-2.jsonld"}}