Compare commits

..
82 Commits
Author SHA1 Message Date
Dave Halter 3102215478 Move the type parameter syntax tests so that it works for all versions
ci / tests (3.10, ubuntu-24.04, 3.10) (push) Has been cancelled
ci / tests (3.10, ubuntu-24.04, 3.11) (push) Has been cancelled
ci / tests (3.10, ubuntu-24.04, 3.12) (push) Has been cancelled
ci / tests (3.10, ubuntu-24.04, 3.13) (push) Has been cancelled
ci / tests (3.10, ubuntu-24.04, 3.14) (push) Has been cancelled
ci / tests (3.10, windows-2022, 3.10) (push) Has been cancelled
ci / tests (3.10, windows-2022, 3.11) (push) Has been cancelled
ci / tests (3.10, windows-2022, 3.12) (push) Has been cancelled
ci / tests (3.10, windows-2022, 3.13) (push) Has been cancelled
ci / tests (3.10, windows-2022, 3.14) (push) Has been cancelled
ci / tests (3.11, ubuntu-24.04, 3.10) (push) Has been cancelled
ci / tests (3.11, ubuntu-24.04, 3.11) (push) Has been cancelled
ci / tests (3.11, ubuntu-24.04, 3.12) (push) Has been cancelled
ci / tests (3.11, ubuntu-24.04, 3.13) (push) Has been cancelled
ci / tests (3.11, ubuntu-24.04, 3.14) (push) Has been cancelled
ci / tests (3.11, windows-2022, 3.10) (push) Has been cancelled
ci / tests (3.11, windows-2022, 3.11) (push) Has been cancelled
ci / tests (3.11, windows-2022, 3.12) (push) Has been cancelled
ci / tests (3.11, windows-2022, 3.13) (push) Has been cancelled
ci / tests (3.11, windows-2022, 3.14) (push) Has been cancelled
ci / tests (3.12, ubuntu-24.04, 3.10) (push) Has been cancelled
ci / tests (3.12, ubuntu-24.04, 3.11) (push) Has been cancelled
ci / tests (3.12, ubuntu-24.04, 3.12) (push) Has been cancelled
ci / tests (3.12, ubuntu-24.04, 3.13) (push) Has been cancelled
ci / tests (3.12, ubuntu-24.04, 3.14) (push) Has been cancelled
ci / tests (3.12, windows-2022, 3.10) (push) Has been cancelled
ci / tests (3.12, windows-2022, 3.11) (push) Has been cancelled
ci / tests (3.12, windows-2022, 3.12) (push) Has been cancelled
ci / tests (3.12, windows-2022, 3.13) (push) Has been cancelled
ci / tests (3.12, windows-2022, 3.14) (push) Has been cancelled
ci / tests (3.13, ubuntu-24.04, 3.10) (push) Has been cancelled
ci / tests (3.13, ubuntu-24.04, 3.11) (push) Has been cancelled
ci / tests (3.13, ubuntu-24.04, 3.12) (push) Has been cancelled
ci / tests (3.13, ubuntu-24.04, 3.13) (push) Has been cancelled
ci / tests (3.13, ubuntu-24.04, 3.14) (push) Has been cancelled
ci / tests (3.13, windows-2022, 3.10) (push) Has been cancelled
ci / tests (3.13, windows-2022, 3.11) (push) Has been cancelled
ci / tests (3.13, windows-2022, 3.12) (push) Has been cancelled
ci / tests (3.13, windows-2022, 3.13) (push) Has been cancelled
ci / tests (3.13, windows-2022, 3.14) (push) Has been cancelled
ci / tests (3.14, ubuntu-24.04, 3.10) (push) Has been cancelled
ci / tests (3.14, ubuntu-24.04, 3.11) (push) Has been cancelled
ci / tests (3.14, ubuntu-24.04, 3.12) (push) Has been cancelled
ci / tests (3.14, ubuntu-24.04, 3.13) (push) Has been cancelled
ci / tests (3.14, ubuntu-24.04, 3.14) (push) Has been cancelled
ci / tests (3.14, windows-2022, 3.10) (push) Has been cancelled
ci / tests (3.14, windows-2022, 3.11) (push) Has been cancelled
ci / tests (3.14, windows-2022, 3.12) (push) Has been cancelled
ci / tests (3.14, windows-2022, 3.13) (push) Has been cancelled
ci / tests (3.14, windows-2022, 3.14) (push) Has been cancelled
ci / tests (interpreter, ubuntu-24.04, 3.10) (push) Has been cancelled
ci / tests (interpreter, ubuntu-24.04, 3.11) (push) Has been cancelled
ci / tests (interpreter, ubuntu-24.04, 3.12) (push) Has been cancelled
ci / tests (interpreter, ubuntu-24.04, 3.13) (push) Has been cancelled
ci / tests (interpreter, ubuntu-24.04, 3.14) (push) Has been cancelled
ci / tests (interpreter, windows-2022, 3.10) (push) Has been cancelled
ci / tests (interpreter, windows-2022, 3.11) (push) Has been cancelled
ci / tests (interpreter, windows-2022, 3.12) (push) Has been cancelled
ci / tests (interpreter, windows-2022, 3.13) (push) Has been cancelled
ci / tests (interpreter, windows-2022, 3.14) (push) Has been cancelled
ci / code-quality (push) Has been cancelled
ci / coverage (push) Has been cancelled
2026-05-02 01:24:54 +02:00
Dave Halter 1b37f2eb94 Prepare for the 0.20.0 release 2026-05-02 01:14:51 +02:00
Dave Halter 8e4df5cc0e Make sure the new generic syntax does not fail with latest parso 2026-05-02 01:08:27 +02:00
Dave HalterandGitHub 4c9dbcca03 Merge pull request #2098 from davidhalter/updates
Typeshed upgrade
2026-05-01 22:40:26 +00:00
Dave Halter fedb1a5eb0 Fix 3.10 tests in one more case 2026-05-02 00:22:06 +02:00
Dave Halter 87e782f9c8 Fix flake8 2026-05-02 00:13:19 +02:00
Dave Halter cd52d982e1 Fixes to get the tests passing for 3.10 2026-05-02 00:11:16 +02:00
Dave Halter d0b11806d4 Finally make tests work for 3.14 2026-05-01 23:49:36 +02:00
Dave Halter 8520a9958b Implement support for TypeVar inference for __new__ 2026-05-01 22:52:05 +02:00
Dave Halter 55e5f0cb92 Implement new-style unions with TypeVars 2026-05-01 21:01:27 +02:00
Dave Halter 8ba5b67622 Change some more tests for typeshed 2026-05-01 17:07:36 +02:00
Dave Halter d87a4af50f Implement unions with forward references 2026-05-01 16:40:25 +02:00
Dave Halter 01dc123ea1 Allow unions when inferring annotations 2026-05-01 16:33:24 +02:00
Dave Halter 418598d8c1 Implement type[...] 2026-05-01 15:44:26 +02:00
Dave Halter 0702da22f2 Change some tests 2026-05-01 14:43:59 +02:00
Dave Halter b7652708ec Add more tests about newstyle unions 2026-05-01 14:37:46 +02:00
Dave Halter e7d29065bd Change a test about ellipsis slightly 2026-05-01 14:37:35 +02:00
Dave Halter 1820aa9476 Change some tests slightly 2026-05-01 14:30:00 +02:00
Dave Halter 696df90daf Change some tests slightly 2026-05-01 14:14:12 +02:00
Dave Halter f8fb2d1230 Basic support for TypeAlias, fixes #1969 2026-05-01 13:05:22 +02:00
Dave Halter 590ed56c6e Revert a small change to tests 2026-04-30 00:26:29 +02:00
Dave Halter a1d9da0a7f Make sure tuple behaves similar to Tuple, fixes #2040 2026-04-30 00:15:56 +02:00
Dave Halter 4f7dfd14b3 Small improvements to generator/async completions 2026-04-29 23:38:07 +02:00
Dave Halter be993d132e Attempt to improve tuple unpackings 2026-04-29 23:10:31 +02:00
Dave Halter 0d79865a0f Fix __enter__ Self resolving 2026-04-29 18:15:57 +02:00
Dave Halter 3375d48f8c Improve typing_extensions usages 2026-04-29 18:08:59 +02:00
Dave Halter aa72381ed1 Implement Self, fixes #2023, fixes #2068 2026-04-29 17:51:01 +02:00
Dave Halter c30732eb04 Add a tuple[...] test for the future, see #2040 2026-04-29 17:10:02 +02:00
Dave Halter fe0369436e Change a few tests to match new typeshed 2026-04-29 09:30:49 +02:00
Dave Halter 04e5f5b3b8 Change a few tests for new typeshed 2026-04-28 17:14:42 +02:00
Dave Halter 75f1d064d5 Ignore Final/ClassVar if they don't have a generic assignment 2026-04-28 17:05:43 +02:00
Dave Halter 6473ddc28c Implement Final[...] in a way so it doesn't completely fail 2026-04-28 15:49:26 +02:00
Dave Halter b27a7dde18 Fix file path completions 2026-04-28 15:25:25 +02:00
Dave Halter 3365d0763b Implement __new__ signatures, fixes #2073 2026-04-28 02:25:25 +02:00
Dave Halter ff581e8403 Start fixing some of the problems with new typeshed 2026-04-28 01:41:40 +02:00
Dave Halter 2455414d1d Upgrade Typeshed 2026-04-28 01:38:26 +02:00
Dave Halter 38122a7fd3 Fix issues around whitespace after dot completions, fixes #1954
ci / tests (3.10, ubuntu-24.04, 3.10) (push) Has been cancelled
ci / tests (3.10, ubuntu-24.04, 3.11) (push) Has been cancelled
ci / tests (3.10, ubuntu-24.04, 3.12) (push) Has been cancelled
ci / tests (3.10, ubuntu-24.04, 3.13) (push) Has been cancelled
ci / tests (3.10, ubuntu-24.04, 3.14) (push) Has been cancelled
ci / tests (3.10, windows-2022, 3.10) (push) Has been cancelled
ci / tests (3.10, windows-2022, 3.11) (push) Has been cancelled
ci / tests (3.10, windows-2022, 3.12) (push) Has been cancelled
ci / tests (3.10, windows-2022, 3.13) (push) Has been cancelled
ci / tests (3.10, windows-2022, 3.14) (push) Has been cancelled
ci / tests (3.11, ubuntu-24.04, 3.10) (push) Has been cancelled
ci / tests (3.11, ubuntu-24.04, 3.11) (push) Has been cancelled
ci / tests (3.11, ubuntu-24.04, 3.12) (push) Has been cancelled
ci / tests (3.11, ubuntu-24.04, 3.13) (push) Has been cancelled
ci / tests (3.11, ubuntu-24.04, 3.14) (push) Has been cancelled
ci / tests (3.11, windows-2022, 3.10) (push) Has been cancelled
ci / tests (3.11, windows-2022, 3.11) (push) Has been cancelled
ci / tests (3.11, windows-2022, 3.12) (push) Has been cancelled
ci / tests (3.11, windows-2022, 3.13) (push) Has been cancelled
ci / tests (3.11, windows-2022, 3.14) (push) Has been cancelled
ci / tests (3.12, ubuntu-24.04, 3.10) (push) Has been cancelled
ci / tests (3.12, ubuntu-24.04, 3.11) (push) Has been cancelled
ci / tests (3.12, ubuntu-24.04, 3.12) (push) Has been cancelled
ci / tests (3.12, ubuntu-24.04, 3.13) (push) Has been cancelled
ci / tests (3.12, ubuntu-24.04, 3.14) (push) Has been cancelled
ci / tests (3.12, windows-2022, 3.10) (push) Has been cancelled
ci / tests (3.12, windows-2022, 3.11) (push) Has been cancelled
ci / tests (3.12, windows-2022, 3.12) (push) Has been cancelled
ci / tests (3.12, windows-2022, 3.13) (push) Has been cancelled
ci / tests (3.12, windows-2022, 3.14) (push) Has been cancelled
ci / tests (3.13, ubuntu-24.04, 3.10) (push) Has been cancelled
ci / tests (3.13, ubuntu-24.04, 3.11) (push) Has been cancelled
ci / tests (3.13, ubuntu-24.04, 3.12) (push) Has been cancelled
ci / tests (3.13, ubuntu-24.04, 3.13) (push) Has been cancelled
ci / tests (3.13, ubuntu-24.04, 3.14) (push) Has been cancelled
ci / tests (3.13, windows-2022, 3.10) (push) Has been cancelled
ci / tests (3.13, windows-2022, 3.11) (push) Has been cancelled
ci / tests (3.13, windows-2022, 3.12) (push) Has been cancelled
ci / tests (3.13, windows-2022, 3.13) (push) Has been cancelled
ci / tests (3.13, windows-2022, 3.14) (push) Has been cancelled
ci / tests (3.14, ubuntu-24.04, 3.10) (push) Has been cancelled
ci / tests (3.14, ubuntu-24.04, 3.11) (push) Has been cancelled
ci / tests (3.14, ubuntu-24.04, 3.12) (push) Has been cancelled
ci / tests (3.14, ubuntu-24.04, 3.13) (push) Has been cancelled
ci / tests (3.14, ubuntu-24.04, 3.14) (push) Has been cancelled
ci / tests (3.14, windows-2022, 3.10) (push) Has been cancelled
ci / tests (3.14, windows-2022, 3.11) (push) Has been cancelled
ci / tests (3.14, windows-2022, 3.12) (push) Has been cancelled
ci / tests (3.14, windows-2022, 3.13) (push) Has been cancelled
ci / tests (3.14, windows-2022, 3.14) (push) Has been cancelled
ci / tests (interpreter, ubuntu-24.04, 3.10) (push) Has been cancelled
ci / tests (interpreter, ubuntu-24.04, 3.11) (push) Has been cancelled
ci / tests (interpreter, ubuntu-24.04, 3.12) (push) Has been cancelled
ci / tests (interpreter, ubuntu-24.04, 3.13) (push) Has been cancelled
ci / tests (interpreter, ubuntu-24.04, 3.14) (push) Has been cancelled
ci / tests (interpreter, windows-2022, 3.10) (push) Has been cancelled
ci / tests (interpreter, windows-2022, 3.11) (push) Has been cancelled
ci / tests (interpreter, windows-2022, 3.12) (push) Has been cancelled
ci / tests (interpreter, windows-2022, 3.13) (push) Has been cancelled
ci / tests (interpreter, windows-2022, 3.14) (push) Has been cancelled
ci / code-quality (push) Has been cancelled
ci / coverage (push) Has been cancelled
2026-04-27 18:15:45 +02:00
Dave Halter 40c685c52b Fix star import completions, fixes #2087 2026-04-27 16:10:56 +02:00
Dave Halter 83a232e945 Change the CHANGELOG slightly 2026-04-27 16:09:39 +02:00
Dave HalterandGitHub 5bbbc53f19 Merge pull request #2097 from davidhalter/py314
Python 3.14; fixes #2093, fixes #2070, will fix #2064 after release.
2026-04-27 13:52:06 +00:00
Dave Halter 6e17c85a57 Avoid flake8 issues 2026-04-27 15:29:08 +02:00
Dave Halter 44600ea194 Fix union acess for 3.14 2026-04-27 15:21:26 +02:00
Dave Halter 04d45a8e1e Remove a 3, 9 artifact 2026-04-27 14:42:24 +02:00
Dave Halter f1ab9d9539 Remove some 3.8 artifacts 2026-04-27 14:41:58 +02:00
Dave Halter 7bac12c125 Remove some 3.7/3.6 artifacts 2026-04-27 14:35:10 +02:00
Dave Halter d4233732be Format unions with | consistently 2026-04-27 14:24:23 +02:00
Dave Halter 74fb7ff279 Enable tests for 3.14 in CI, fixes #2070 2026-04-27 14:18:17 +02:00
Dave Halter 375dd1bacc Add 3.14 to the supported environments 2026-04-27 14:01:39 +02:00
Dave Halter 94f7e540ff Merge branch 'py314' of https://github.com/frenzymadness/jedi into py314 2026-04-27 12:22:31 +02:00
Dave HalterandGitHub 4cca2ed774 Merge pull request #2095 from davidhalter/typing
Use Zuban instead of Mypy for subsecond type checking and editor integration
2026-04-27 00:05:43 +00:00
Dave Halter f8c8ef8c66 Upgrade all the sphinx dependencies 2026-04-27 01:48:02 +02:00
Dave Halter 5938262227 Avoid 3.8/3.9 in tests 2026-04-27 01:07:39 +02:00
Dave Halter a662298e2f Remove a bit more python3.8/3.9 specific code 2026-04-27 00:42:07 +02:00
Dave Halter 1eddf24a50 Remove Python 3.9 and 3.10 2026-04-27 00:34:17 +02:00
Dave Halter edb5462cf5 Fix an issue with tests 2026-04-26 03:05:30 +02:00
Dave Halter 30b3acf6d3 Change the flake8 version to hopefully fix the version issue in CI 2026-04-26 02:44:39 +02:00
Dave Halter 56e55e9ed5 Upgrade zuban 2026-04-26 02:27:28 +02:00
Lumir Balhar 04737b2637 Fix Python 3.15 compatibility
- Fix getattr_static for Python 3.15 __dict__ GetSetDescriptorType
- Accept abs() parameter name change ('x' → 'number')
- Add Python 3.15 os module constants to test expectations

Fixes instance attribute introspection and stdlib changes in Python 3.15.
2026-04-08 08:19:15 +02:00
Dave Halter 68be64b992 Use forward references because 3.8 is still a bit annoying 2026-03-26 23:31:24 +01:00
Dave Halter 9e582586fa Merge testing and qa extras_require into dev 2026-03-26 23:22:39 +01:00
Dave Halter 9f91506947 Enable --strict and then disable some of the errors 2026-03-26 23:11:19 +01:00
Dave Halter ffe4ae5877 Replace the mypy check with zuban check 2026-03-26 23:02:08 +01:00
Lumir Balhar 9b24443787 Fix Python 3.14 compatibility for typing.Union annotations
In Python 3.14, typing.Union changed its repr from 'typing.Union[X, Y]'
to 'X | Y' (PEP 604), breaking annotation inference.

Changes:
- Use getattr() instead of safe_getattr() for __module__ retrieval
  (getattr_static fails on Union types in Python 3.14)
- Add fallback to typing.get_origin() when regex fails to match
- Normalize Union display back to 'Union[X, Y]' format for consistency
- Update test expectations for invalid annotation edge case in 3.14

Fixes: https://github.com/davidhalter/jedi/issues/2064
2026-03-09 15:39:23 +01:00
Dave Halter 3176c1dcb8 A bit more solid typing for goto_or_help_or_infer 2026-02-16 22:54:32 +01:00
Dave Halter ea09983566 Some small typing improvements for tests 2026-02-16 21:20:27 +01:00
David BrochartandDave Halter 76c1e03f07 Fix typo 2026-02-13 11:01:08 +00:00
Dave Halter 8cbb817b12 Fix a lot of test related typing issues 2026-02-10 19:38:55 +01:00
Dave Halter 6903bc25d5 Remove an outdated script 2026-02-10 19:02:51 +01:00
Dave Halter e7fdbcc834 Fix a few more typing issues 2026-02-04 02:24:41 +01:00
Dave Halter 3ffed76884 Improve a weird typing issue 2026-02-04 01:28:30 +01:00
Dave Halter 30ef824abd Introduce some stricter typing 2026-02-04 01:19:14 +01:00
Dave Halter c7481b3319 Fix a linter issue
ci / tests (3.10, ubuntu-24.04, 3.10) (push) Has been cancelled
ci / tests (3.10, ubuntu-24.04, 3.11) (push) Has been cancelled
ci / tests (3.10, ubuntu-24.04, 3.12) (push) Has been cancelled
ci / tests (3.10, ubuntu-24.04, 3.13) (push) Has been cancelled
ci / tests (3.10, ubuntu-24.04, 3.8) (push) Has been cancelled
ci / tests (3.10, ubuntu-24.04, 3.9) (push) Has been cancelled
ci / tests (3.10, windows-2022, 3.10) (push) Has been cancelled
ci / tests (3.10, windows-2022, 3.11) (push) Has been cancelled
ci / tests (3.10, windows-2022, 3.12) (push) Has been cancelled
ci / tests (3.10, windows-2022, 3.13) (push) Has been cancelled
ci / tests (3.10, windows-2022, 3.8) (push) Has been cancelled
ci / tests (3.10, windows-2022, 3.9) (push) Has been cancelled
ci / tests (3.11, ubuntu-24.04, 3.10) (push) Has been cancelled
ci / tests (3.11, ubuntu-24.04, 3.11) (push) Has been cancelled
ci / tests (3.11, ubuntu-24.04, 3.12) (push) Has been cancelled
ci / tests (3.11, ubuntu-24.04, 3.13) (push) Has been cancelled
ci / tests (3.11, ubuntu-24.04, 3.8) (push) Has been cancelled
ci / tests (3.11, ubuntu-24.04, 3.9) (push) Has been cancelled
ci / tests (3.11, windows-2022, 3.10) (push) Has been cancelled
ci / tests (3.11, windows-2022, 3.11) (push) Has been cancelled
ci / tests (3.11, windows-2022, 3.12) (push) Has been cancelled
ci / tests (3.11, windows-2022, 3.13) (push) Has been cancelled
ci / tests (3.11, windows-2022, 3.8) (push) Has been cancelled
ci / tests (3.11, windows-2022, 3.9) (push) Has been cancelled
ci / tests (3.12, ubuntu-24.04, 3.10) (push) Has been cancelled
ci / tests (3.12, ubuntu-24.04, 3.11) (push) Has been cancelled
ci / tests (3.12, ubuntu-24.04, 3.12) (push) Has been cancelled
ci / tests (3.12, ubuntu-24.04, 3.13) (push) Has been cancelled
ci / tests (3.12, ubuntu-24.04, 3.8) (push) Has been cancelled
ci / tests (3.12, ubuntu-24.04, 3.9) (push) Has been cancelled
ci / tests (3.12, windows-2022, 3.10) (push) Has been cancelled
ci / tests (3.12, windows-2022, 3.11) (push) Has been cancelled
ci / tests (3.12, windows-2022, 3.12) (push) Has been cancelled
ci / tests (3.12, windows-2022, 3.13) (push) Has been cancelled
ci / tests (3.12, windows-2022, 3.8) (push) Has been cancelled
ci / tests (3.12, windows-2022, 3.9) (push) Has been cancelled
ci / tests (3.13, ubuntu-24.04, 3.10) (push) Has been cancelled
ci / tests (3.13, ubuntu-24.04, 3.11) (push) Has been cancelled
ci / tests (3.13, ubuntu-24.04, 3.12) (push) Has been cancelled
ci / tests (3.13, ubuntu-24.04, 3.13) (push) Has been cancelled
ci / tests (3.13, ubuntu-24.04, 3.8) (push) Has been cancelled
ci / tests (3.13, ubuntu-24.04, 3.9) (push) Has been cancelled
ci / tests (3.13, windows-2022, 3.10) (push) Has been cancelled
ci / tests (3.13, windows-2022, 3.11) (push) Has been cancelled
ci / tests (3.13, windows-2022, 3.12) (push) Has been cancelled
ci / tests (3.13, windows-2022, 3.13) (push) Has been cancelled
ci / tests (3.13, windows-2022, 3.8) (push) Has been cancelled
ci / tests (3.13, windows-2022, 3.9) (push) Has been cancelled
ci / tests (3.8, ubuntu-24.04, 3.10) (push) Has been cancelled
ci / tests (3.8, ubuntu-24.04, 3.11) (push) Has been cancelled
ci / tests (3.8, ubuntu-24.04, 3.12) (push) Has been cancelled
ci / tests (3.8, ubuntu-24.04, 3.13) (push) Has been cancelled
ci / tests (3.8, ubuntu-24.04, 3.8) (push) Has been cancelled
ci / tests (3.8, ubuntu-24.04, 3.9) (push) Has been cancelled
ci / tests (3.8, windows-2022, 3.10) (push) Has been cancelled
ci / tests (3.8, windows-2022, 3.11) (push) Has been cancelled
ci / tests (3.8, windows-2022, 3.12) (push) Has been cancelled
ci / tests (3.8, windows-2022, 3.13) (push) Has been cancelled
ci / tests (3.8, windows-2022, 3.8) (push) Has been cancelled
ci / tests (3.8, windows-2022, 3.9) (push) Has been cancelled
ci / tests (3.9, ubuntu-24.04, 3.10) (push) Has been cancelled
ci / tests (3.9, ubuntu-24.04, 3.11) (push) Has been cancelled
ci / tests (3.9, ubuntu-24.04, 3.12) (push) Has been cancelled
ci / tests (3.9, ubuntu-24.04, 3.13) (push) Has been cancelled
ci / tests (3.9, ubuntu-24.04, 3.8) (push) Has been cancelled
ci / tests (3.9, ubuntu-24.04, 3.9) (push) Has been cancelled
ci / tests (3.9, windows-2022, 3.10) (push) Has been cancelled
ci / tests (3.9, windows-2022, 3.11) (push) Has been cancelled
ci / tests (3.9, windows-2022, 3.12) (push) Has been cancelled
ci / tests (3.9, windows-2022, 3.13) (push) Has been cancelled
ci / tests (3.9, windows-2022, 3.8) (push) Has been cancelled
ci / tests (3.9, windows-2022, 3.9) (push) Has been cancelled
ci / tests (interpreter, ubuntu-24.04, 3.10) (push) Has been cancelled
ci / tests (interpreter, ubuntu-24.04, 3.11) (push) Has been cancelled
ci / tests (interpreter, ubuntu-24.04, 3.12) (push) Has been cancelled
ci / tests (interpreter, ubuntu-24.04, 3.13) (push) Has been cancelled
ci / tests (interpreter, ubuntu-24.04, 3.8) (push) Has been cancelled
ci / tests (interpreter, ubuntu-24.04, 3.9) (push) Has been cancelled
ci / tests (interpreter, windows-2022, 3.10) (push) Has been cancelled
ci / tests (interpreter, windows-2022, 3.11) (push) Has been cancelled
ci / tests (interpreter, windows-2022, 3.12) (push) Has been cancelled
ci / tests (interpreter, windows-2022, 3.13) (push) Has been cancelled
ci / tests (interpreter, windows-2022, 3.8) (push) Has been cancelled
ci / tests (interpreter, windows-2022, 3.9) (push) Has been cancelled
ci / code-quality (push) Has been cancelled
ci / coverage (push) Has been cancelled
2026-01-20 02:05:51 +01:00
Dave Halter 3ac1632a5c Avoid the need to import search_ancestor 2026-01-19 20:30:03 +01:00
Dave Halter 4a7b5f4879 Increase the required vesion of parso 2026-01-19 17:08:11 +01:00
Dave Halter d4fb9c4531 Move Mypy config to pyproject.toml
ci / tests (3.10, ubuntu-24.04, 3.10) (push) Has been cancelled
ci / tests (3.10, ubuntu-24.04, 3.11) (push) Has been cancelled
ci / tests (3.10, ubuntu-24.04, 3.12) (push) Has been cancelled
ci / tests (3.10, ubuntu-24.04, 3.13) (push) Has been cancelled
ci / tests (3.10, ubuntu-24.04, 3.8) (push) Has been cancelled
ci / tests (3.10, ubuntu-24.04, 3.9) (push) Has been cancelled
ci / tests (3.10, windows-2022, 3.10) (push) Has been cancelled
ci / tests (3.10, windows-2022, 3.11) (push) Has been cancelled
ci / tests (3.10, windows-2022, 3.12) (push) Has been cancelled
ci / tests (3.10, windows-2022, 3.13) (push) Has been cancelled
ci / tests (3.10, windows-2022, 3.8) (push) Has been cancelled
ci / tests (3.10, windows-2022, 3.9) (push) Has been cancelled
ci / tests (3.11, ubuntu-24.04, 3.10) (push) Has been cancelled
ci / tests (3.11, ubuntu-24.04, 3.11) (push) Has been cancelled
ci / tests (3.11, ubuntu-24.04, 3.12) (push) Has been cancelled
ci / tests (3.11, ubuntu-24.04, 3.13) (push) Has been cancelled
ci / tests (3.11, ubuntu-24.04, 3.8) (push) Has been cancelled
ci / tests (3.11, ubuntu-24.04, 3.9) (push) Has been cancelled
ci / tests (3.11, windows-2022, 3.10) (push) Has been cancelled
ci / tests (3.11, windows-2022, 3.11) (push) Has been cancelled
ci / tests (3.11, windows-2022, 3.12) (push) Has been cancelled
ci / tests (3.11, windows-2022, 3.13) (push) Has been cancelled
ci / tests (3.11, windows-2022, 3.8) (push) Has been cancelled
ci / tests (3.11, windows-2022, 3.9) (push) Has been cancelled
ci / tests (3.12, ubuntu-24.04, 3.10) (push) Has been cancelled
ci / tests (3.12, ubuntu-24.04, 3.11) (push) Has been cancelled
ci / tests (3.12, ubuntu-24.04, 3.12) (push) Has been cancelled
ci / tests (3.12, ubuntu-24.04, 3.13) (push) Has been cancelled
ci / tests (3.12, ubuntu-24.04, 3.8) (push) Has been cancelled
ci / tests (3.12, ubuntu-24.04, 3.9) (push) Has been cancelled
ci / tests (3.12, windows-2022, 3.10) (push) Has been cancelled
ci / tests (3.12, windows-2022, 3.11) (push) Has been cancelled
ci / tests (3.12, windows-2022, 3.12) (push) Has been cancelled
ci / tests (3.12, windows-2022, 3.13) (push) Has been cancelled
ci / tests (3.12, windows-2022, 3.8) (push) Has been cancelled
ci / tests (3.12, windows-2022, 3.9) (push) Has been cancelled
ci / tests (3.13, ubuntu-24.04, 3.10) (push) Has been cancelled
ci / tests (3.13, ubuntu-24.04, 3.11) (push) Has been cancelled
ci / tests (3.13, ubuntu-24.04, 3.12) (push) Has been cancelled
ci / tests (3.13, ubuntu-24.04, 3.13) (push) Has been cancelled
ci / tests (3.13, ubuntu-24.04, 3.8) (push) Has been cancelled
ci / tests (3.13, ubuntu-24.04, 3.9) (push) Has been cancelled
ci / tests (3.13, windows-2022, 3.10) (push) Has been cancelled
ci / tests (3.13, windows-2022, 3.11) (push) Has been cancelled
ci / tests (3.13, windows-2022, 3.12) (push) Has been cancelled
ci / tests (3.13, windows-2022, 3.13) (push) Has been cancelled
ci / tests (3.13, windows-2022, 3.8) (push) Has been cancelled
ci / tests (3.13, windows-2022, 3.9) (push) Has been cancelled
ci / tests (3.8, ubuntu-24.04, 3.10) (push) Has been cancelled
ci / tests (3.8, ubuntu-24.04, 3.11) (push) Has been cancelled
ci / tests (3.8, ubuntu-24.04, 3.12) (push) Has been cancelled
ci / tests (3.8, ubuntu-24.04, 3.13) (push) Has been cancelled
ci / tests (3.8, ubuntu-24.04, 3.8) (push) Has been cancelled
ci / tests (3.8, ubuntu-24.04, 3.9) (push) Has been cancelled
ci / tests (3.8, windows-2022, 3.10) (push) Has been cancelled
ci / tests (3.8, windows-2022, 3.11) (push) Has been cancelled
ci / tests (3.8, windows-2022, 3.12) (push) Has been cancelled
ci / tests (3.8, windows-2022, 3.13) (push) Has been cancelled
ci / tests (3.8, windows-2022, 3.8) (push) Has been cancelled
ci / tests (3.8, windows-2022, 3.9) (push) Has been cancelled
ci / tests (3.9, ubuntu-24.04, 3.10) (push) Has been cancelled
ci / tests (3.9, ubuntu-24.04, 3.11) (push) Has been cancelled
ci / tests (3.9, ubuntu-24.04, 3.12) (push) Has been cancelled
ci / tests (3.9, ubuntu-24.04, 3.13) (push) Has been cancelled
ci / tests (3.9, ubuntu-24.04, 3.8) (push) Has been cancelled
ci / tests (3.9, ubuntu-24.04, 3.9) (push) Has been cancelled
ci / tests (3.9, windows-2022, 3.10) (push) Has been cancelled
ci / tests (3.9, windows-2022, 3.11) (push) Has been cancelled
ci / tests (3.9, windows-2022, 3.12) (push) Has been cancelled
ci / tests (3.9, windows-2022, 3.13) (push) Has been cancelled
ci / tests (3.9, windows-2022, 3.8) (push) Has been cancelled
ci / tests (3.9, windows-2022, 3.9) (push) Has been cancelled
ci / tests (interpreter, ubuntu-24.04, 3.10) (push) Has been cancelled
ci / tests (interpreter, ubuntu-24.04, 3.11) (push) Has been cancelled
ci / tests (interpreter, ubuntu-24.04, 3.12) (push) Has been cancelled
ci / tests (interpreter, ubuntu-24.04, 3.13) (push) Has been cancelled
ci / tests (interpreter, ubuntu-24.04, 3.8) (push) Has been cancelled
ci / tests (interpreter, ubuntu-24.04, 3.9) (push) Has been cancelled
ci / tests (interpreter, windows-2022, 3.10) (push) Has been cancelled
ci / tests (interpreter, windows-2022, 3.11) (push) Has been cancelled
ci / tests (interpreter, windows-2022, 3.12) (push) Has been cancelled
ci / tests (interpreter, windows-2022, 3.13) (push) Has been cancelled
ci / tests (interpreter, windows-2022, 3.8) (push) Has been cancelled
ci / tests (interpreter, windows-2022, 3.9) (push) Has been cancelled
ci / code-quality (push) Has been cancelled
ci / coverage (push) Has been cancelled
2026-01-19 14:47:06 +01:00
Dave Halter 2b37bc3518 Change the Zuban link to GitHub 2026-01-19 13:26:43 +01:00
Dave HalterandGitHub ade9131d04 Merge pull request #2083 from diekhans/issue-2082-None-file-attr
ci / tests (3.10, ubuntu-24.04, 3.10) (push) Has been cancelled
ci / tests (3.10, ubuntu-24.04, 3.11) (push) Has been cancelled
ci / tests (3.10, ubuntu-24.04, 3.12) (push) Has been cancelled
ci / tests (3.10, ubuntu-24.04, 3.13) (push) Has been cancelled
ci / tests (3.10, ubuntu-24.04, 3.8) (push) Has been cancelled
ci / tests (3.10, ubuntu-24.04, 3.9) (push) Has been cancelled
ci / tests (3.10, windows-2022, 3.10) (push) Has been cancelled
ci / tests (3.10, windows-2022, 3.11) (push) Has been cancelled
ci / tests (3.10, windows-2022, 3.12) (push) Has been cancelled
ci / tests (3.10, windows-2022, 3.13) (push) Has been cancelled
ci / tests (3.10, windows-2022, 3.8) (push) Has been cancelled
ci / tests (3.10, windows-2022, 3.9) (push) Has been cancelled
ci / tests (3.11, ubuntu-24.04, 3.10) (push) Has been cancelled
ci / tests (3.11, ubuntu-24.04, 3.11) (push) Has been cancelled
ci / tests (3.11, ubuntu-24.04, 3.12) (push) Has been cancelled
ci / tests (3.11, ubuntu-24.04, 3.13) (push) Has been cancelled
ci / tests (3.11, ubuntu-24.04, 3.8) (push) Has been cancelled
ci / tests (3.11, ubuntu-24.04, 3.9) (push) Has been cancelled
ci / tests (3.11, windows-2022, 3.10) (push) Has been cancelled
ci / tests (3.11, windows-2022, 3.11) (push) Has been cancelled
ci / tests (3.11, windows-2022, 3.12) (push) Has been cancelled
ci / tests (3.11, windows-2022, 3.13) (push) Has been cancelled
ci / tests (3.11, windows-2022, 3.8) (push) Has been cancelled
ci / tests (3.11, windows-2022, 3.9) (push) Has been cancelled
ci / tests (3.12, ubuntu-24.04, 3.10) (push) Has been cancelled
ci / tests (3.12, ubuntu-24.04, 3.11) (push) Has been cancelled
ci / tests (3.12, ubuntu-24.04, 3.12) (push) Has been cancelled
ci / tests (3.12, ubuntu-24.04, 3.13) (push) Has been cancelled
ci / tests (3.12, ubuntu-24.04, 3.8) (push) Has been cancelled
ci / tests (3.12, ubuntu-24.04, 3.9) (push) Has been cancelled
ci / tests (3.12, windows-2022, 3.10) (push) Has been cancelled
ci / tests (3.12, windows-2022, 3.11) (push) Has been cancelled
ci / tests (3.12, windows-2022, 3.12) (push) Has been cancelled
ci / tests (3.12, windows-2022, 3.13) (push) Has been cancelled
ci / tests (3.12, windows-2022, 3.8) (push) Has been cancelled
ci / tests (3.12, windows-2022, 3.9) (push) Has been cancelled
ci / tests (3.13, ubuntu-24.04, 3.10) (push) Has been cancelled
ci / tests (3.13, ubuntu-24.04, 3.11) (push) Has been cancelled
ci / tests (3.13, ubuntu-24.04, 3.12) (push) Has been cancelled
ci / tests (3.13, ubuntu-24.04, 3.13) (push) Has been cancelled
ci / tests (3.13, ubuntu-24.04, 3.8) (push) Has been cancelled
ci / tests (3.13, ubuntu-24.04, 3.9) (push) Has been cancelled
ci / tests (3.13, windows-2022, 3.10) (push) Has been cancelled
ci / tests (3.13, windows-2022, 3.11) (push) Has been cancelled
ci / tests (3.13, windows-2022, 3.12) (push) Has been cancelled
ci / tests (3.13, windows-2022, 3.13) (push) Has been cancelled
ci / tests (3.13, windows-2022, 3.8) (push) Has been cancelled
ci / tests (3.13, windows-2022, 3.9) (push) Has been cancelled
ci / tests (3.8, ubuntu-24.04, 3.10) (push) Has been cancelled
ci / tests (3.8, ubuntu-24.04, 3.11) (push) Has been cancelled
ci / tests (3.8, ubuntu-24.04, 3.12) (push) Has been cancelled
ci / tests (3.8, ubuntu-24.04, 3.13) (push) Has been cancelled
ci / tests (3.8, ubuntu-24.04, 3.8) (push) Has been cancelled
ci / tests (3.8, ubuntu-24.04, 3.9) (push) Has been cancelled
ci / tests (3.8, windows-2022, 3.10) (push) Has been cancelled
ci / tests (3.8, windows-2022, 3.11) (push) Has been cancelled
ci / tests (3.8, windows-2022, 3.12) (push) Has been cancelled
ci / tests (3.8, windows-2022, 3.13) (push) Has been cancelled
ci / tests (3.8, windows-2022, 3.8) (push) Has been cancelled
ci / tests (3.8, windows-2022, 3.9) (push) Has been cancelled
ci / tests (3.9, ubuntu-24.04, 3.10) (push) Has been cancelled
ci / tests (3.9, ubuntu-24.04, 3.11) (push) Has been cancelled
ci / tests (3.9, ubuntu-24.04, 3.12) (push) Has been cancelled
ci / tests (3.9, ubuntu-24.04, 3.13) (push) Has been cancelled
ci / tests (3.9, ubuntu-24.04, 3.8) (push) Has been cancelled
ci / tests (3.9, ubuntu-24.04, 3.9) (push) Has been cancelled
ci / tests (3.9, windows-2022, 3.10) (push) Has been cancelled
ci / tests (3.9, windows-2022, 3.11) (push) Has been cancelled
ci / tests (3.9, windows-2022, 3.12) (push) Has been cancelled
ci / tests (3.9, windows-2022, 3.13) (push) Has been cancelled
ci / tests (3.9, windows-2022, 3.8) (push) Has been cancelled
ci / tests (3.9, windows-2022, 3.9) (push) Has been cancelled
ci / tests (interpreter, ubuntu-24.04, 3.10) (push) Has been cancelled
ci / tests (interpreter, ubuntu-24.04, 3.11) (push) Has been cancelled
ci / tests (interpreter, ubuntu-24.04, 3.12) (push) Has been cancelled
ci / tests (interpreter, ubuntu-24.04, 3.13) (push) Has been cancelled
ci / tests (interpreter, ubuntu-24.04, 3.8) (push) Has been cancelled
ci / tests (interpreter, ubuntu-24.04, 3.9) (push) Has been cancelled
ci / tests (interpreter, windows-2022, 3.10) (push) Has been cancelled
ci / tests (interpreter, windows-2022, 3.11) (push) Has been cancelled
ci / tests (interpreter, windows-2022, 3.12) (push) Has been cancelled
ci / tests (interpreter, windows-2022, 3.13) (push) Has been cancelled
ci / tests (interpreter, windows-2022, 3.8) (push) Has been cancelled
ci / tests (interpreter, windows-2022, 3.9) (push) Has been cancelled
ci / code-quality (push) Has been cancelled
ci / coverage (push) Has been cancelled
Handle object with __file__ attribute having a None value (issue #2082)
2025-12-21 01:47:23 +00:00
Mark Diekhans a89757a966 Handle object with __file__ attribute having a None value (issue #2082) 2025-12-20 17:24:25 -08:00
Dave HalterandGitHub b80c0b8992 Merge pull request #2079 from Hoblovski/fix/star-unpack
ci / tests (3.10, ubuntu-24.04, 3.10) (push) Has been cancelled
ci / tests (3.10, ubuntu-24.04, 3.11) (push) Has been cancelled
ci / tests (3.10, ubuntu-24.04, 3.12) (push) Has been cancelled
ci / tests (3.10, ubuntu-24.04, 3.13) (push) Has been cancelled
ci / tests (3.10, ubuntu-24.04, 3.8) (push) Has been cancelled
ci / tests (3.10, ubuntu-24.04, 3.9) (push) Has been cancelled
ci / tests (3.10, windows-2022, 3.10) (push) Has been cancelled
ci / tests (3.10, windows-2022, 3.11) (push) Has been cancelled
ci / tests (3.10, windows-2022, 3.12) (push) Has been cancelled
ci / tests (3.10, windows-2022, 3.13) (push) Has been cancelled
ci / tests (3.10, windows-2022, 3.8) (push) Has been cancelled
ci / tests (3.10, windows-2022, 3.9) (push) Has been cancelled
ci / tests (3.11, ubuntu-24.04, 3.10) (push) Has been cancelled
ci / tests (3.11, ubuntu-24.04, 3.11) (push) Has been cancelled
ci / tests (3.11, ubuntu-24.04, 3.12) (push) Has been cancelled
ci / tests (3.11, ubuntu-24.04, 3.13) (push) Has been cancelled
ci / tests (3.11, ubuntu-24.04, 3.8) (push) Has been cancelled
ci / tests (3.11, ubuntu-24.04, 3.9) (push) Has been cancelled
ci / tests (3.11, windows-2022, 3.10) (push) Has been cancelled
ci / tests (3.11, windows-2022, 3.11) (push) Has been cancelled
ci / tests (3.11, windows-2022, 3.12) (push) Has been cancelled
ci / tests (3.11, windows-2022, 3.13) (push) Has been cancelled
ci / tests (3.11, windows-2022, 3.8) (push) Has been cancelled
ci / tests (3.11, windows-2022, 3.9) (push) Has been cancelled
ci / tests (3.12, ubuntu-24.04, 3.10) (push) Has been cancelled
ci / tests (3.12, ubuntu-24.04, 3.11) (push) Has been cancelled
ci / tests (3.12, ubuntu-24.04, 3.12) (push) Has been cancelled
ci / tests (3.12, ubuntu-24.04, 3.13) (push) Has been cancelled
ci / tests (3.12, ubuntu-24.04, 3.8) (push) Has been cancelled
ci / tests (3.12, ubuntu-24.04, 3.9) (push) Has been cancelled
ci / tests (3.12, windows-2022, 3.10) (push) Has been cancelled
ci / tests (3.12, windows-2022, 3.11) (push) Has been cancelled
ci / tests (3.12, windows-2022, 3.12) (push) Has been cancelled
ci / tests (3.12, windows-2022, 3.13) (push) Has been cancelled
ci / tests (3.12, windows-2022, 3.8) (push) Has been cancelled
ci / tests (3.12, windows-2022, 3.9) (push) Has been cancelled
ci / tests (3.13, ubuntu-24.04, 3.10) (push) Has been cancelled
ci / tests (3.13, ubuntu-24.04, 3.11) (push) Has been cancelled
ci / tests (3.13, ubuntu-24.04, 3.12) (push) Has been cancelled
ci / tests (3.13, ubuntu-24.04, 3.13) (push) Has been cancelled
ci / tests (3.13, ubuntu-24.04, 3.8) (push) Has been cancelled
ci / tests (3.13, ubuntu-24.04, 3.9) (push) Has been cancelled
ci / tests (3.13, windows-2022, 3.10) (push) Has been cancelled
ci / tests (3.13, windows-2022, 3.11) (push) Has been cancelled
ci / tests (3.13, windows-2022, 3.12) (push) Has been cancelled
ci / tests (3.13, windows-2022, 3.13) (push) Has been cancelled
ci / tests (3.13, windows-2022, 3.8) (push) Has been cancelled
ci / tests (3.13, windows-2022, 3.9) (push) Has been cancelled
ci / tests (3.8, ubuntu-24.04, 3.10) (push) Has been cancelled
ci / tests (3.8, ubuntu-24.04, 3.11) (push) Has been cancelled
ci / tests (3.8, ubuntu-24.04, 3.12) (push) Has been cancelled
ci / tests (3.8, ubuntu-24.04, 3.13) (push) Has been cancelled
ci / tests (3.8, ubuntu-24.04, 3.8) (push) Has been cancelled
ci / tests (3.8, ubuntu-24.04, 3.9) (push) Has been cancelled
ci / tests (3.8, windows-2022, 3.10) (push) Has been cancelled
ci / tests (3.8, windows-2022, 3.11) (push) Has been cancelled
ci / tests (3.8, windows-2022, 3.12) (push) Has been cancelled
ci / tests (3.8, windows-2022, 3.13) (push) Has been cancelled
ci / tests (3.8, windows-2022, 3.8) (push) Has been cancelled
ci / tests (3.8, windows-2022, 3.9) (push) Has been cancelled
ci / tests (3.9, ubuntu-24.04, 3.10) (push) Has been cancelled
ci / tests (3.9, ubuntu-24.04, 3.11) (push) Has been cancelled
ci / tests (3.9, ubuntu-24.04, 3.12) (push) Has been cancelled
ci / tests (3.9, ubuntu-24.04, 3.13) (push) Has been cancelled
ci / tests (3.9, ubuntu-24.04, 3.8) (push) Has been cancelled
ci / tests (3.9, ubuntu-24.04, 3.9) (push) Has been cancelled
ci / tests (3.9, windows-2022, 3.10) (push) Has been cancelled
ci / tests (3.9, windows-2022, 3.11) (push) Has been cancelled
ci / tests (3.9, windows-2022, 3.12) (push) Has been cancelled
ci / tests (3.9, windows-2022, 3.13) (push) Has been cancelled
ci / tests (3.9, windows-2022, 3.8) (push) Has been cancelled
ci / tests (3.9, windows-2022, 3.9) (push) Has been cancelled
ci / tests (interpreter, ubuntu-24.04, 3.10) (push) Has been cancelled
ci / tests (interpreter, ubuntu-24.04, 3.11) (push) Has been cancelled
ci / tests (interpreter, ubuntu-24.04, 3.12) (push) Has been cancelled
ci / tests (interpreter, ubuntu-24.04, 3.13) (push) Has been cancelled
ci / tests (interpreter, ubuntu-24.04, 3.8) (push) Has been cancelled
ci / tests (interpreter, ubuntu-24.04, 3.9) (push) Has been cancelled
ci / tests (interpreter, windows-2022, 3.10) (push) Has been cancelled
ci / tests (interpreter, windows-2022, 3.11) (push) Has been cancelled
ci / tests (interpreter, windows-2022, 3.12) (push) Has been cancelled
ci / tests (interpreter, windows-2022, 3.13) (push) Has been cancelled
ci / tests (interpreter, windows-2022, 3.8) (push) Has been cancelled
ci / tests (interpreter, windows-2022, 3.9) (push) Has been cancelled
ci / code-quality (push) Has been cancelled
ci / coverage (push) Has been cancelled
Fix unhandled '*' operator in infer_node
2025-11-13 15:53:08 +00:00
Hoblovski 1b33f0d77c fix: move test to arrays.py 2025-11-13 21:12:15 +08:00
Hoblovski 3454ebb1de fix: let star_expr infer to NO_VALUES instead of crashing 2025-11-13 20:41:58 +08:00
Hoblovski 3d2ce2e01f tests: add bad case 2025-11-13 20:33:00 +08:00
112 changed files with 954 additions and 640 deletions
+6 -6
View File
@@ -7,8 +7,8 @@ jobs:
strategy:
matrix:
os: [ubuntu-24.04, windows-2022]
python-version: ["3.13", "3.12", "3.11", "3.10", "3.9", "3.8"]
environment: ['3.8', '3.13', '3.12', '3.11', '3.10', '3.9', 'interpreter']
python-version: ["3.14", "3.13", "3.12", "3.11", "3.10"]
environment: ['3.14', '3.13', '3.12', '3.11', '3.10', 'interpreter']
steps:
- name: Checkout code
uses: actions/checkout@v4
@@ -27,7 +27,7 @@ jobs:
allow-prereleases: true
- name: Install dependencies
run: 'pip install .[testing]'
run: 'pip install .[dev]'
- name: Run tests
run: python -m pytest
@@ -43,12 +43,12 @@ jobs:
submodules: recursive
- name: Install dependencies
run: 'pip install .[qa]'
run: 'pip install .[dev]'
- name: Run tests
run: |
python -m flake8 jedi test setup.py
python -m mypy jedi sith.py setup.py
zuban check
coverage:
runs-on: ubuntu-24.04
@@ -60,7 +60,7 @@ jobs:
submodules: recursive
- name: Install dependencies
run: 'pip install .[testing] coverage'
run: 'pip install .[dev] coverage'
- name: Run tests
run: |
+2 -2
View File
@@ -14,8 +14,8 @@ sphinx:
configuration: docs/conf.py
build:
os: ubuntu-22.04
os: ubuntu-24.04
tools:
python: "3.11"
python: "3.14"
apt_packages:
- graphviz
+11
View File
@@ -6,6 +6,17 @@ Changelog
Unreleased
++++++++++
0.20.0 (2026-05-02)
+++++++++++++++++++
- Python 3.14 support
- Removed support for Python 3.8 and 3.9
- Upgraded Typeshed
- Better support for Final/ClassVar
- ``__new__`` is now also recognized as a signature and TypeVar inference
- Support for ``Self``
- Support for ``TypeAlias``, generics for ``type[...]`` and ``tuple[...]``
0.19.2 (2024-11-10)
+++++++++++++++++++
+4 -4
View File
@@ -3,7 +3,7 @@ Jedi - an awesome autocompletion, static analysis and refactoring library for Py
####################################################################################
**I released the successor to Jedi: A
Mypy-Compatible Python Language Server Built in Rust** - `ZubanLS <https://zubanls.com>`_
Mypy-Compatible Python Language Server Built in Rust** - `Zuban <https://github.com/zubanls/zuban>`_
.. image:: http://isitmaintained.com/badge/open/davidhalter/jedi.svg
:target: https://github.com/davidhalter/jedi/issues
@@ -102,7 +102,7 @@ Features and Limitations
Jedi's features are listed here:
`Features <https://jedi.readthedocs.org/en/latest/docs/features.html>`_.
You can run Jedi on Python 3.8+ but it should also
You can run Jedi on Python 3.10+ but it should also
understand code that is older than those versions. Additionally you should be
able to use `Virtualenvs <https://jedi.readthedocs.org/en/latest/docs/api.html#environments>`_
very well.
@@ -183,10 +183,10 @@ The test suite uses ``pytest``::
pip install pytest
If you want to test only a specific Python version (e.g. Python 3.8), it is as
If you want to test only a specific Python version (e.g. Python 3.14), it is as
easy as::
python3.8 -m pytest
python3.14 -m pytest
For more detailed information visit the `testing documentation
<https://jedi.readthedocs.org/en/latest/docs/testing.html>`_.
+7 -21
View File
@@ -42,7 +42,7 @@ def pytest_addoption(parser):
help="Warnings are treated as errors.")
parser.addoption("--env", action='store',
help="Execute the tests in that environment (e.g. 39 for python3.9).")
help="Execute the tests in that environment (e.g. 314 for python3.14).")
parser.addoption("--interpreter-env", "-I", action='store_true',
help="Don't use subprocesses to guarantee having safe "
"code execution. Useful for debugging.")
@@ -133,11 +133,13 @@ def goto_or_help(request, Script):
@pytest.fixture(scope='session', params=['goto', 'help', 'infer'])
def goto_or_help_or_infer(request, Script):
def do(code, *args, **kwargs):
return getattr(Script(code), request.param)(*args, **kwargs)
class GotoOrHelpOrInfer:
def __call__(self, code, *args, **kwargs):
return getattr(Script(code), request.param)(*args, **kwargs)
do.type = request.param
return do
type = request.param
return GotoOrHelpOrInfer()
@pytest.fixture(scope='session', params=['goto', 'complete', 'help'])
@@ -162,19 +164,3 @@ def skip_pre_python311(environment):
# This if is just needed to avoid that tests ever skip way more than
# they should for all Python versions.
pytest.skip()
@pytest.fixture()
def skip_pre_python38(environment):
if environment.version_info < (3, 8):
# This if is just needed to avoid that tests ever skip way more than
# they should for all Python versions.
pytest.skip()
@pytest.fixture()
def skip_pre_python37(environment):
if environment.version_info < (3, 7):
# This if is just needed to avoid that tests ever skip way more than
# they should for all Python versions.
pytest.skip()
+1 -1
View File
@@ -107,7 +107,7 @@ Completions
>>> code = '''import json; json.l'''
>>> script = jedi.Script(code, path='example.py')
>>> script
<Script: 'example.py' <SameEnvironment: 3.9.0 in /usr>>
<Script: 'example.py' <SameEnvironment: 3.14.0 in /usr>>
>>> completions = script.complete(1, 19)
>>> completions
[<Completion: load>, <Completion: loads>]
+1 -1
View File
@@ -16,7 +16,7 @@ Jedi's main API calls and features are:
Basic Features
--------------
- Python 3.8+ support
- Python 3.10+ support
- Ignores syntax errors and wrong indentation
- Can deal with complex module / function / class structures
- Great ``virtualenv``/``venv`` support
+2 -2
View File
@@ -7,10 +7,10 @@ The test suite depends on ``pytest``::
pip install pytest
If you want to test only a specific Python version (e.g. Python 3.8), it is as
If you want to test only a specific Python version (e.g. Python 3.14), it is as
easy as::
python3.8 -m pytest
python3.14 -m pytest
Tests are also run automatically on `GitHub Actions
<https://github.com/davidhalter/jedi/actions>`_.
+3 -3
View File
@@ -3,7 +3,7 @@
Using Jedi
==========
|jedi| is can be used with a variety of :ref:`plugins <editor-plugins>`,
|jedi| can be used with a variety of :ref:`plugins <editor-plugins>`,
:ref:`language servers <language-servers>` and other software.
It is also possible to use |jedi| in the :ref:`Python shell or with IPython
<repl-completion>`.
@@ -13,7 +13,7 @@ Below you can also find a list of :ref:`recipes for type hinting <recipes>`.
.. _language-servers:
Language Servers
--------------
----------------
- `jedi-language-server <https://github.com/pappasam/jedi-language-server>`_
- `python-language-server <https://github.com/palantir/python-language-server>`_ (currently unmaintained)
@@ -97,7 +97,7 @@ Web Debugger
xonsh shell
~~~~~~~~~~~
Jedi is a preinstalled extension in `xonsh shell <https://xon.sh/contents.html>`_.
Jedi is a preinstalled extension in `xonsh shell <https://xon.sh/contents.html>`_.
Run the following command to enable:
::
+1 -1
View File
@@ -27,7 +27,7 @@ ad
load
"""
__version__ = '0.19.2'
__version__ = '0.20.0'
from jedi.api import Script, Interpreter, set_debug_function, preload_module
from jedi import settings
+2 -3
View File
@@ -483,7 +483,7 @@ class Script:
module_context = self._get_module_context()
n = tree.search_ancestor(leaf, 'funcdef', 'classdef')
n = leaf.search_ancestor('funcdef', 'classdef')
if n is not None and n.start_pos < pos <= n.children[-1].start_pos:
# This is a bit of a special case. The context of a function/class
# name/param/keyword is always it's parent context, not the
@@ -779,8 +779,7 @@ def preload_module(*modules):
:param modules: different module names, list of string.
"""
for m in modules:
s = "import %s as x; x." % m
Script(s).complete(1, len(s))
Script(f"import {m}").infer()
def set_debug_function(func_cb=debug.print_to_stdout, warnings=True,
+2 -4
View File
@@ -17,8 +17,6 @@ import re
from pathlib import Path
from typing import Optional
from parso.tree import search_ancestor
from jedi import settings
from jedi import debug
from jedi.inference.utils import unite
@@ -98,7 +96,7 @@ class BaseName:
@property
def module_path(self) -> Optional[Path]:
"""
Shows the file path of a module. e.g. ``/usr/lib/python3.9/os.py``
Shows the file path of a module. e.g. ``/usr/lib/python3.14/os.py``
"""
module = self._get_module_context()
if module.is_stub() or not module.is_compiled():
@@ -509,7 +507,7 @@ class BaseName:
# - param: The parent_context of a param is not its function but
# e.g. the outer class or module.
cls_or_func_node = self._name.tree_name.get_definition()
parent = search_ancestor(cls_or_func_node, 'funcdef', 'classdef', 'file_input')
parent = cls_or_func_node.search_ancestor('funcdef', 'classdef', 'file_input')
context = self._get_module_context().create_value(parent).as_context()
else:
context = self._name.parent_context
+9 -6
View File
@@ -1,10 +1,11 @@
import re
from textwrap import dedent
from typing import Any
from inspect import Parameter
from parso.python.token import PythonTokenTypes
from parso.python import tree
from parso.tree import search_ancestor, Leaf
from parso.tree import Leaf
from parso import split_lines
from jedi import debug
@@ -244,8 +245,8 @@ class Completion:
if previous_leaf is not None:
stmt = previous_leaf
while True:
stmt = search_ancestor(
stmt, 'if_stmt', 'for_stmt', 'while_stmt', 'try_stmt',
stmt = stmt.search_ancestor(
'if_stmt', 'for_stmt', 'while_stmt', 'try_stmt',
'error_node',
)
if stmt is None:
@@ -265,7 +266,7 @@ class Completion:
elif type_ == 'for_stmt':
allowed_transitions.append('else')
completion_names = []
completion_names: list[Any] = []
kwargs_only = False
if any(t in allowed_transitions for t in (PythonTokenTypes.NAME,
@@ -290,6 +291,8 @@ class Completion:
)
elif nonterminals[-1] in ('trailer', 'dotted_name') and nodes[-1] == '.':
dot = self._module_node.get_leaf_for_position(self._position)
if dot.type == "newline":
dot = dot.get_previous_leaf()
if dot.type == "endmarker":
# This is a bit of a weird edge case, maybe we can somehow
# generalize this.
@@ -356,7 +359,7 @@ class Completion:
stack_node = self.stack[-3]
if stack_node.nonterminal == 'funcdef':
context = get_user_context(self._module_context, self._position)
node = search_ancestor(leaf, 'error_node', 'funcdef')
node = leaf.search_ancestor('error_node', 'funcdef')
if node is not None:
if node.type == 'error_node':
n = node.children[0]
@@ -426,7 +429,7 @@ class Completion:
Autocomplete inherited methods when overriding in child class.
"""
leaf = self._module_node.get_leaf_for_position(self._position, include_prefixes=True)
cls = tree.search_ancestor(leaf, 'classdef')
cls = leaf.search_ancestor('classdef')
if cls is None:
return
+29 -25
View File
@@ -8,7 +8,7 @@ import hashlib
import filecmp
from collections import namedtuple
from shutil import which
from typing import TYPE_CHECKING
from typing import TYPE_CHECKING, Any
from jedi.cache import memoize_method, time_cache
from jedi.inference.compiled.subprocess import CompiledSubprocess, \
@@ -22,7 +22,7 @@ if TYPE_CHECKING:
_VersionInfo = namedtuple('VersionInfo', 'major minor micro') # type: ignore[name-match]
_SUPPORTED_PYTHONS = ['3.13', '3.12', '3.11', '3.10', '3.9', '3.8']
_SUPPORTED_PYTHONS = ['3.14', '3.13', '3.12', '3.11', '3.10']
_SAFE_PATHS = ['/usr/bin', '/usr/local/bin']
_CONDA_VAR = 'CONDA_PREFIX'
_CURRENT_VERSION = '%s.%s' % (sys.version_info.major, sys.version_info.minor)
@@ -36,6 +36,9 @@ class InvalidPythonEnvironment(Exception):
class _BaseEnvironment:
version_info: Any
executable: Any
@memoize_method
def get_grammar(self):
version_string = '%s.%s' % (self.version_info.major, self.version_info.minor)
@@ -251,7 +254,7 @@ def get_cached_default_environment():
# /path/to/env so we need to fully resolve the paths in order to
# compare them.
if var and os.path.realpath(var) != os.path.realpath(environment.path):
_get_cached_default_environment.clear_cache()
_get_cached_default_environment.clear_cache() # type: ignore[attr-defined]
return _get_cached_default_environment()
return environment
@@ -355,7 +358,7 @@ def get_system_environment(version, *, env_vars=None):
return SameEnvironment()
return Environment(exe)
if os.name == 'nt':
if sys.platform == "win32":
for exe in _get_executables_from_windows_registry(version):
try:
return Environment(exe, env_vars=env_vars)
@@ -383,7 +386,7 @@ def _get_executable_path(path, safe=True):
Returns None if it's not actually a virtual env.
"""
if os.name == 'nt':
if sys.platform == "win32":
pythons = [os.path.join(path, 'Scripts', 'python.exe'), os.path.join(path, 'python.exe')]
else:
pythons = [os.path.join(path, 'bin', 'python')]
@@ -397,27 +400,28 @@ def _get_executable_path(path, safe=True):
return python
def _get_executables_from_windows_registry(version):
import winreg
if sys.platform == "win32":
def _get_executables_from_windows_registry(version):
import winreg
# TODO: support Python Anaconda.
sub_keys = [
r'SOFTWARE\Python\PythonCore\{version}\InstallPath',
r'SOFTWARE\Wow6432Node\Python\PythonCore\{version}\InstallPath',
r'SOFTWARE\Python\PythonCore\{version}-32\InstallPath',
r'SOFTWARE\Wow6432Node\Python\PythonCore\{version}-32\InstallPath'
]
for root_key in [winreg.HKEY_CURRENT_USER, winreg.HKEY_LOCAL_MACHINE]:
for sub_key in sub_keys:
sub_key = sub_key.format(version=version)
try:
with winreg.OpenKey(root_key, sub_key) as key:
prefix = winreg.QueryValueEx(key, '')[0]
exe = os.path.join(prefix, 'python.exe')
if os.path.isfile(exe):
yield exe
except WindowsError:
pass
# TODO: support Python Anaconda.
sub_keys = [
r'SOFTWARE\Python\PythonCore\{version}\InstallPath',
r'SOFTWARE\Wow6432Node\Python\PythonCore\{version}\InstallPath',
r'SOFTWARE\Python\PythonCore\{version}-32\InstallPath',
r'SOFTWARE\Wow6432Node\Python\PythonCore\{version}-32\InstallPath'
]
for root_key in [winreg.HKEY_CURRENT_USER, winreg.HKEY_LOCAL_MACHINE]:
for sub_key in sub_keys:
sub_key = sub_key.format(version=version)
try:
with winreg.OpenKey(root_key, sub_key) as key:
prefix = winreg.QueryValueEx(key, '')[0]
exe = os.path.join(prefix, 'python.exe')
if os.path.isfile(exe):
yield exe
except WindowsError:
pass
def _assert_safe(executable_path, safe):
+8
View File
@@ -61,6 +61,7 @@ class MixedModuleContext(ModuleContext):
)
def get_filters(self, until_position=None, origin_scope=None):
yield MergedFilter(
MixedParserTreeFilter(
parent_context=self,
@@ -72,3 +73,10 @@ class MixedModuleContext(ModuleContext):
for mixed_object in self.mixed_values:
yield from mixed_object.get_filters(until_position, origin_scope)
# Now that we have merged the filter for this mixed context we have to
# remove the first entry (which is the module itself), but we want to
# add the other filters like the star imports.
filters = self._value.get_filters(origin_scope)
next(filters, None)
yield from filters
+1 -1
View File
@@ -41,7 +41,7 @@ def imitate_pydoc(string):
try:
# is a tuple now
label, related = string
label, related = string # type: ignore[misc]
except TypeError:
return ''
+1 -1
View File
@@ -9,7 +9,7 @@ just use IPython instead::
Then you will be able to use Jedi completer in your Python interpreter::
$ python
Python 3.9.2+ (default, Jul 20 2020, 22:15:08)
Python 3.14.0+ (default, Jul 20 2020, 22:15:08)
[GCC 4.6.1] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
+1 -1
View File
@@ -93,7 +93,7 @@ def time_cache(seconds):
cache[key] = time.time(), result
return result
wrapper.clear_cache = lambda: cache.clear()
wrapper.clear_cache = lambda: cache.clear() # type: ignore[attr-defined]
return wrapper
return decorator
+1 -1
View File
@@ -36,7 +36,7 @@ try:
# pytest resets the stream at the end - causes troubles. Since
# after every output the stream is reset automatically we don't
# need this.
initialise.atexit_done = True
initialise.atexit_done = True # type: ignore[attr-defined]
try:
init(strip=False)
except Exception:
+3
View File
@@ -1,4 +1,5 @@
import os
from typing import Any
from parso import file_io
@@ -58,6 +59,8 @@ class FolderIO(AbstractFolderIO):
class FileIOFolderMixin:
path: Any
def get_parent_folder(self):
return FolderIO(os.path.dirname(self.path))
+18
View File
@@ -62,6 +62,8 @@ I need to mention now that lazy type inference is really good because it
only *inferes* what needs to be *inferred*. All the statements and modules
that are not used are just being ignored.
"""
from typing import Any
import parso
from jedi.file_io import FileIO
@@ -82,6 +84,8 @@ from jedi.plugins import plugin_manager
class InferenceState:
analysis_modules: "list[Any]"
def __init__(self, project, environment=None, script_path=None):
if environment is None:
environment = project.get_environment()
@@ -135,6 +139,20 @@ class InferenceState:
typing_module, = self.import_module(('typing',))
return typing_module
@property
@inference_state_function_cache()
def types_module(self):
typing_module, = self.import_module(('types',))
return typing_module
@inference_state_function_cache()
def typing_tuple(self):
return self.typing_module.py__getattribute__("Tuple")
@inference_state_function_cache()
def typing_type(self):
return self.typing_module.py__getattribute__("Type")
def reset_recursion_limitations(self):
self.recursion_detector = recursion.RecursionDetector()
self.execution_recursion_detector = recursion.ExecutionRecursionDetector(self)
+4 -1
View File
@@ -1,5 +1,6 @@
import re
from itertools import zip_longest
from typing import Any
from parso.python import tree
@@ -134,7 +135,7 @@ class _AbstractArgumentsMixin:
class AbstractArguments(_AbstractArgumentsMixin):
context = None
argument_node = None
argument_node: Any = None
trailer = None
@@ -164,6 +165,8 @@ def unpack_arglist(arglist):
class TreeArguments(AbstractArguments):
context: Any
def __init__(self, inference_state, context, argument_node, trailer=None):
"""
:param argument_node: May be an argument_node or a list of nodes.
+26 -7
View File
@@ -9,6 +9,7 @@ just one.
from functools import reduce
from operator import add
from itertools import zip_longest
from typing import TYPE_CHECKING, Any
from parso.python.tree import Name
@@ -21,12 +22,25 @@ from jedi.cache import memoize_method
sentinel = object()
if TYPE_CHECKING:
from jedi.inference import InferenceState
class HasNoContext(Exception):
pass
class HelperValueMixin:
parent_context: Any
inference_state: "InferenceState"
name: Any
get_filters: Any
is_stub: Any
py__getattribute__alternatives: Any
py__iter__: Any
py__mro__: Any
_as_context: Any
def get_root_context(self):
value = self
if value.parent_context is None:
@@ -45,7 +59,7 @@ class HelperValueMixin:
arguments = ValuesArguments([ValueSet([value]) for value in value_list])
return self.inference_state.execute(self, arguments)
def execute_annotation(self):
def execute_annotation(self, context):
return self.execute_with_values()
def gather_annotation_classes(self):
@@ -337,11 +351,16 @@ class _ValueWrapperBase(HelperValueMixin):
class LazyValueWrapper(_ValueWrapperBase):
@safe_property
@memoize_method
def _wrapped_value(self):
with debug.increase_indent_cm('Resolve lazy value wrapper'):
return self._get_wrapped_value()
if TYPE_CHECKING:
@property
def _wrapped_value(self) -> Any:
return
else:
@safe_property
@memoize_method
def _wrapped_value(self):
with debug.increase_indent_cm('Resolve lazy value wrapper'):
return self._get_wrapped_value()
def __repr__(self):
return '<%s>' % (self.__class__.__name__)
@@ -499,7 +518,7 @@ class ValueSet:
return ValueSet.from_sets(_getitem(c, *args, **kwargs) for c in self._set)
def try_merge(self, function_name):
value_set = self.__class__([])
value_set = ValueSet([])
for c in self._set:
try:
method = getattr(c, function_name)
+3 -2
View File
@@ -14,8 +14,9 @@ def builtin_from_name(inference_state, string):
else:
filter_ = next(typing_builtins_module.get_filters())
name, = filter_.get(string)
value, = name.infer()
return value
# Most of the time there is only symbol, but sometimes there are different
# sys.version_infos, where there are multiple ones, just use the first one.
return next(iter(name.infer()))
class ExactValue(LazyValueWrapper):
+21 -4
View File
@@ -184,7 +184,7 @@ class DirectObjectAccess:
def py__file__(self) -> Optional[Path]:
try:
return Path(self._obj.__file__)
except AttributeError:
except (AttributeError, TypeError):
return None
def py__doc__(self):
@@ -471,18 +471,23 @@ class DirectObjectAccess:
op = _OPERATORS[operator]
return self._create_access_path(op(self._obj, other_access._obj))
def get_annotation_name_and_args(self):
def get_annotation_name_and_args(self) -> tuple[str | None, tuple[AccessPath, ...]]:
"""
Returns Tuple[Optional[str], Tuple[AccessPath, ...]]
"""
name = None
args = ()
if safe_getattr(self._obj, '__module__', default='') == 'typing':
if type(self._obj) is typing.Union: # zuban: ignore[comparison-overlap] # TODO zuban
# This is mostly formatted like `int | str` and we therefor need to
# check the type.
args = typing.get_args(self._obj)
name = "Union"
elif safe_getattr(self._obj, '__module__', default='') == 'typing':
# Try regex first (works for most types)
m = re.match(r'typing.(\w+)\[', repr(self._obj))
if m is not None:
name = m.group(1)
import typing
if sys.version_info >= (3, 8):
args = typing.get_args(self._obj)
else:
@@ -493,6 +498,18 @@ class DirectObjectAccess:
return inspect.isclass(self._obj) and self._obj != type
def _annotation_to_str(self, annotation):
# In Python 3.14+, Union types are displayed as X | Y instead of Union[X, Y]
# We normalize to that for consistency
import typing
origin = typing.get_origin(annotation)
if origin is typing.Union:
# Get the args and format them as Union[...]
args = typing.get_args(annotation)
return ' | '.join(
self._annotation_to_str(arg) if hasattr(arg, '__origin__')
else getattr(arg, '__name__', str(arg))
for arg in args
)
return inspect.formatannotation(annotation)
def get_signature_params(self):
+6 -3
View File
@@ -39,7 +39,7 @@ def _is_type(obj):
def _shadowed_dict(klass):
dict_attr = type.__dict__["__dict__"]
dict_attr = type.__dict__["__dict__"] # type: ignore[index]
for entry in _static_getmro(klass):
try:
class_dict = dict_attr.__get__(entry)["__dict__"]
@@ -54,7 +54,7 @@ def _shadowed_dict(klass):
def _static_getmro(klass):
mro = type.__dict__['__mro__'].__get__(klass)
mro = type.__dict__['__mro__'].__get__(klass) # type: ignore[index]
if not isinstance(mro, (tuple, list)):
# There are unfortunately no tests for this, I was not able to
# reproduce this in pure Python. However should still solve the issue
@@ -90,7 +90,10 @@ def getattr_static(obj, attr, default=_sentinel):
if not _is_type(obj):
klass = type(obj)
dict_attr = _shadowed_dict(klass)
if (dict_attr is _sentinel or type(dict_attr) is types.MemberDescriptorType):
# In Python 3.15+, __dict__ is a GetSetDescriptorType instead of being _sentinel
if (dict_attr is _sentinel
or type(dict_attr) is types.MemberDescriptorType
or type(dict_attr) is types.GetSetDescriptorType):
instance_result = _check_instance(obj, attr)
else:
klass = obj
@@ -33,7 +33,7 @@ import traceback
import weakref
from functools import partial
from threading import Thread
from typing import Dict, TYPE_CHECKING
from typing import Dict, TYPE_CHECKING, Any
from jedi._compatibility import pickle_dump, pickle_load
from jedi import debug
@@ -52,7 +52,7 @@ PICKLE_PROTOCOL = 4
def _GeneralizedPopen(*args, **kwargs):
if os.name == 'nt':
if sys.platform == "win32":
try:
# Was introduced in Python 3.7.
CREATE_NO_WINDOW = subprocess.CREATE_NO_WINDOW
@@ -104,6 +104,8 @@ def _cleanup_process(process, thread):
class _InferenceStateProcess:
get_compiled_method_return: Any
def __init__(self, inference_state: 'InferenceState') -> None:
self._inference_state_weakref = weakref.ref(inference_state)
self._handles: Dict[int, AccessHandle] = {}
@@ -158,7 +158,10 @@ def _find_module(string, path=None, full_name=None, is_global_search=True):
if loader is None and not spec.has_location:
# This is a namespace package.
full_name = string if not path else full_name
implicit_ns_info = ImplicitNSInfo(full_name, spec.submodule_search_locations._path)
implicit_ns_info = ImplicitNSInfo(
full_name,
spec.submodule_search_locations._path, # type: ignore[union-attr]
)
return implicit_ns_info, True
break
+10 -8
View File
@@ -54,7 +54,7 @@ class CompiledValue(Value):
return create_from_access_path(
self.inference_state,
return_annotation
).execute_annotation()
).execute_annotation(arguments.context)
try:
self.access_handle.getattr_paths('__call__')
@@ -241,7 +241,7 @@ class CompiledValue(Value):
except TypeError:
return NO_VALUES
def execute_annotation(self):
def execute_annotation(self, context):
if self.access_handle.get_repr() == 'None':
# None as an annotation doesn't need to be executed.
return ValueSet([self])
@@ -252,7 +252,9 @@ class CompiledValue(Value):
for path in args
]
if name == 'Union':
return ValueSet.from_sets(arg.execute_annotation() for arg in arguments)
return ValueSet.from_sets(
arg.execute_annotation(context)
for arg in arguments)
elif name:
# While with_generics only exists on very specific objects, we
# should probably be fine, because we control all the typing
@@ -260,8 +262,8 @@ class CompiledValue(Value):
return ValueSet([
v.with_generics(arguments)
for v in self.inference_state.typing_module.py__getattribute__(name)
]).execute_annotation()
return super().execute_annotation()
]).execute_annotation(context)
return super().execute_annotation(context)
def negate(self):
return create_from_access_path(self.inference_state, self.access_handle.negate())
@@ -459,7 +461,7 @@ class CompiledValueFilter(AbstractFilter):
values = create_from_access_path(
self._inference_state,
property_return_annotation
).execute_annotation()
).execute_annotation(None)
if values:
return [CompiledValueName(v, name) for v in values]
@@ -592,7 +594,7 @@ def create_from_name(inference_state, compiled_value, name):
value = create_cached_compiled_value(
inference_state,
access_path,
parent_context=None if value is None else value.as_context(),
parent_context=None if value is None else value.as_context(), # type: ignore # TODO
)
return value
@@ -610,7 +612,7 @@ def create_from_access_path(inference_state, access_path):
value = create_cached_compiled_value(
inference_state,
access,
parent_context=None if value is None else value.as_context()
parent_context=None if value is None else value.as_context() # type: ignore # TODO
)
return value
+13 -6
View File
@@ -1,9 +1,8 @@
from abc import abstractmethod
from contextlib import contextmanager
from pathlib import Path
from typing import Optional
from typing import Optional, Any
from parso.tree import search_ancestor
from parso.python.tree import Name
from jedi.inference.filters import ParserTreeFilter, MergedFilter, \
@@ -17,6 +16,8 @@ from jedi import parser_utils
class AbstractContext:
# Must be defined: inference_state and tree_node and parent_context as an attribute/property
tree_node: Any
parent_context: Any
def __init__(self, inference_state):
self.inference_state = inference_state
@@ -219,6 +220,13 @@ class ValueContext(AbstractContext):
class TreeContextMixin:
tree_node: Any
is_module: Any
get_value: Any
inference_state: Any
is_class: Any
parent_context: Any
def infer_node(self, node):
from jedi.inference.syntax_tree import infer_node
return infer_node(self, node)
@@ -290,7 +298,7 @@ class TreeContextMixin:
def create_name(self, tree_name):
definition = tree_name.get_definition()
if definition and definition.type == 'param' and definition.name == tree_name:
funcdef = search_ancestor(definition, 'funcdef', 'lambdef')
funcdef = definition.search_ancestor('funcdef', 'lambdef')
func = self.create_value(funcdef)
return AnonymousParamName(func, tree_name)
else:
@@ -301,7 +309,6 @@ class TreeContextMixin:
class FunctionContext(TreeContextMixin, ValueContext):
def get_filters(self, until_position=None, origin_scope=None):
yield ParserTreeFilter(
self.inference_state,
parent_context=self,
until_position=until_position,
origin_scope=origin_scope
@@ -416,13 +423,13 @@ def _get_global_filters_for_name(context, name_or_none, position):
# function and get inferred in the value before the function. So
# make sure to exclude the function/class name.
if name_or_none is not None:
ancestor = search_ancestor(name_or_none, 'funcdef', 'classdef', 'lambdef')
ancestor = name_or_none.search_ancestor('funcdef', 'classdef', 'lambdef')
lambdef = None
if ancestor == 'lambdef':
# For lambdas it's even more complicated since parts will
# be inferred later.
lambdef = ancestor
ancestor = search_ancestor(name_or_none, 'funcdef', 'classdef')
ancestor = name_or_none.search_ancestor('funcdef', 'classdef')
if ancestor is not None:
colon = ancestor.children[-2]
if position is not None and position < colon.start_pos:
+1 -1
View File
@@ -16,6 +16,6 @@ class DocstringModuleContext(ModuleContext):
super().__init__(module_value)
self._in_module_context = in_module_context
def get_filters(self, origin_scope=None, until_position=None):
def get_filters(self, until_position=None, origin_scope=None):
yield from super().get_filters(until_position=until_position)
yield from self._in_module_context.get_filters()
+1 -1
View File
@@ -246,7 +246,7 @@ def _execute_array_values(inference_state, array):
cls = FakeTuple if array.array_type == 'tuple' else FakeList
return {cls(inference_state, values)}
else:
return array.execute_annotation()
return array.execute_annotation(None)
@inference_state_method_cache()
+2 -2
View File
@@ -109,7 +109,7 @@ def _search_function_arguments(module_context, funcdef, string_name):
if string_name == '__init__':
cls = get_parent_scope(funcdef)
if cls.type == 'classdef':
string_name = cls.name.value
string_name = cls.name.value # type: ignore[union-attr]
compare_node = cls
found_arguments = False
@@ -203,7 +203,7 @@ def _check_name_for_execution(inference_state, context, compare_node, name, trai
# Here we're trying to find decorators by checking the first
# parameter. It's not very generic though. Should find a better
# solution that also applies to nested decorators.
param_names = value.parent_context.get_param_names()
param_names = value.parent_context.get_param_names() # type: ignore[attr-defined]
if len(param_names) != 1:
continue
values = param_names[0].infer()
+7 -5
View File
@@ -3,10 +3,9 @@ Filters are objects that you can use to filter names in different scopes. They
are needed for name resolution.
"""
from abc import abstractmethod
from typing import List, MutableMapping, Type
from typing import MutableMapping, Type, Any
import weakref
from parso.tree import search_ancestor
from parso.python.tree import Name, UsedNamesMapping
from jedi.inference import flow_analysis
@@ -17,8 +16,8 @@ from jedi.inference.utils import to_list
from jedi.inference.names import TreeNameDefinition, ParamName, \
AnonymousParamName, AbstractNameDefinition, NameWrapper
_definition_name_cache: MutableMapping[UsedNamesMapping, List[Name]]
_definition_name_cache = weakref.WeakKeyDictionary()
_definition_name_cache: 'MutableMapping[UsedNamesMapping, dict[str, tuple[Name, ...]]]' \
= weakref.WeakKeyDictionary()
class AbstractFilter:
@@ -181,7 +180,7 @@ class _FunctionExecutionFilter(ParserTreeFilter):
@to_list
def _convert_names(self, names):
for name in names:
param = search_ancestor(name, 'param')
param = name.search_ancestor('param')
# Here we don't need to check if the param is a default/annotation,
# because those are not definitions and never make it to this
# point.
@@ -347,6 +346,9 @@ class _OverwriteMeta(type):
class _AttributeOverwriteMixin:
overwritten_methods: Any
_wrapped_value: Any
def get_filters(self, *args, **kwargs):
yield SpecialMethodFilter(self, self.overwritten_methods, self._wrapped_value)
yield from self._wrapped_value.get_filters(*args, **kwargs)
+1 -2
View File
@@ -15,7 +15,6 @@ Unfortunately every other thing is being ignored (e.g. a == '' would be easy to
check for -> a is a string). There's big potential in these checks.
"""
from parso.tree import search_ancestor
from parso.python.tree import Name
from jedi import settings
@@ -76,7 +75,7 @@ def check_flow_information(value, flow, search_name, pos):
])
for name in names:
ass = search_ancestor(name, 'assert_stmt')
ass = name.search_ancestor('assert_stmt')
if ass is not None:
result = _check_isinstance_type(value, ass.assertion, search_name)
if result is not None:
+18 -15
View File
@@ -32,17 +32,20 @@ def infer_annotation(context, annotation):
Also checks for forward references (strings)
"""
value_set = context.infer_node(annotation)
if len(value_set) != 1:
debug.warning("Inferred typing index %s should lead to 1 object, "
" not %s" % (annotation, value_set))
if len(value_set) == 0:
debug.warning(
"Inferred typing index %s should lead to 1 object, not %s" % (annotation, value_set))
return value_set
inferred_value = list(value_set)[0]
if is_string(inferred_value):
result = _get_forward_reference_node(context, inferred_value.get_safe_value())
if result is not None:
return context.infer_node(result)
return value_set
strings_removed = NO_VALUES
for part in value_set:
if is_string(part):
result = _get_forward_reference_node(context, part.get_safe_value())
if result is not None:
strings_removed |= context.infer_node(result)
continue
strings_removed |= ValueSet([part])
return strings_removed
def _infer_annotation_string(context, string, index=None):
@@ -249,12 +252,12 @@ def infer_return_types(function, arguments):
return _infer_annotation_string(
context,
match.group(1).strip()
).execute_annotation()
).execute_annotation(context)
unknown_type_vars = find_unknown_type_vars(context, annotation)
annotation_values = infer_annotation(context, annotation)
if not unknown_type_vars:
return annotation_values.execute_annotation()
return annotation_values.execute_annotation(context)
type_var_dict = infer_type_vars_for_execution(function, arguments, all_annotations)
@@ -262,7 +265,7 @@ def infer_return_types(function, arguments):
ann.define_generics(type_var_dict)
if isinstance(ann, (DefineGenericBaseClass, TypeVar)) else ValueSet({ann})
for ann in annotation_values
).execute_annotation()
).execute_annotation(context)
def infer_type_vars_for_execution(function, arguments, annotation_dict):
@@ -315,7 +318,7 @@ def infer_return_for_callable(arguments, param_values, result_values):
if isinstance(v, (DefineGenericBaseClass, TypeVar))
else ValueSet({v})
for v in result_values
).execute_annotation()
).execute_annotation(arguments.context)
def _infer_type_vars_for_callable(arguments, lazy_params):
@@ -391,7 +394,7 @@ def merge_pairwise_generics(annotation_value, annotated_argument_class):
for annotation_generics_set, actual_generic_set in zip(annotation_generics, actual_generics):
merge_type_var_dicts(
type_var_dict,
annotation_generics_set.infer_type_vars(actual_generic_set.execute_annotation()),
annotation_generics_set.infer_type_vars(actual_generic_set.execute_annotation(None)),
)
return type_var_dict
@@ -438,7 +441,7 @@ def _find_type_from_comment_hint(context, node, varlist, name):
return []
return _infer_annotation_string(
context, match.group(1).strip(), index
).execute_annotation()
).execute_annotation(context)
def find_unknown_type_vars(context, node):
+4 -4
View File
@@ -195,7 +195,7 @@ class GenericClass(DefineGenericBaseClass, ClassMixin):
@to_list
def py__bases__(self):
for base in self._wrapped_value.py__bases__():
for base in self._wrapped_value.py__bases__(): # type: ignore[attr-defined]
yield _LazyGenericBaseClass(self, base, self._generics_manager)
def _create_instance_with_generics(self, generics_manager):
@@ -306,7 +306,7 @@ class _GenericInstanceWrapper(ValueWrapper):
if cls.py__name__() == 'Generator':
generics = cls.get_generics()
try:
return generics[2].execute_annotation()
return generics[2].execute_annotation(None)
except IndexError:
pass
elif cls.py__name__() == 'Iterator':
@@ -384,7 +384,7 @@ class BaseTypingValue(LazyValueWrapper):
return _PseudoTreeNameClass(self.parent_context, self._tree_name)
def get_signatures(self):
return self._wrapped_value.get_signatures()
return self._wrapped_value.get_signatures() # type: ignore[attr-defined]
def __repr__(self):
return '%s(%s)' % (self.__class__.__name__, self._tree_name.value)
@@ -427,7 +427,7 @@ class BaseTypingInstance(LazyValueWrapper):
return ValueName(self, self._tree_name)
def _get_wrapped_value(self):
object_, = builtin_from_name(self.inference_state, 'object').execute_annotation()
object_, = builtin_from_name(self.inference_state, 'object').execute_annotation(None)
return object_
def __repr__(self):
+10 -1
View File
@@ -2,6 +2,7 @@
This module is about generics, like the `int` in `List[int]`. It's not about
the Generic class.
"""
from abc import abstractmethod
from jedi import debug
from jedi.cache import memoize_method
@@ -24,9 +25,17 @@ def _resolve_forward_references(context, value_set):
class _AbstractGenericManager:
@abstractmethod
def __getitem__(self, index):
raise NotImplementedError
@abstractmethod
def to_tuple(self):
raise NotImplementedError
def get_index_and_execute(self, index):
try:
return self[index].execute_annotation()
return self[index].execute_annotation(None)
except IndexError:
debug.warning('No param #%s found for annotation %s', index, self)
return NO_VALUES
+3 -3
View File
@@ -100,8 +100,8 @@ class TypeVar(BaseTypingValue):
return found
return ValueSet({self})
def execute_annotation(self):
return self._get_classes().execute_annotation()
def execute_annotation(self, context):
return self._get_classes().execute_annotation(context)
def infer_type_vars(self, value_set):
def iterate():
@@ -123,5 +123,5 @@ class TypeWrapper(ValueWrapper):
super().__init__(wrapped_value)
self._original_value = original_value
def execute_annotation(self):
def execute_annotation(self, context):
return ValueSet({self._original_value})
+3 -15
View File
@@ -1,5 +1,4 @@
import os
import re
from functools import wraps
from collections import namedtuple
from typing import Dict, Mapping, Tuple
@@ -58,19 +57,8 @@ def _create_stub_map(directory_path_info):
def _get_typeshed_directories(version_info):
check_version_list = ['2and3', '3']
for base in ['stdlib', 'third_party']:
base_path = TYPESHED_PATH.joinpath(base)
base_list = os.listdir(base_path)
for base_list_entry in base_list:
match = re.match(r'(\d+)\.(\d+)$', base_list_entry)
if match is not None:
if match.group(1) == '3' and int(match.group(2)) <= version_info.minor:
check_version_list.append(base_list_entry)
for check_version in check_version_list:
is_third_party = base != 'stdlib'
yield PathInfo(str(base_path.joinpath(check_version)), is_third_party)
yield PathInfo(str(TYPESHED_PATH.joinpath("stdlib")), False)
yield PathInfo(str(TYPESHED_PATH.joinpath("stubs")), True)
_version_cache: Dict[Tuple[int, int], Mapping[str, PathInfo]] = {}
@@ -293,7 +281,7 @@ def parse_stub_module(inference_state, file_io):
def create_stub_module(inference_state, grammar, python_value_set,
stub_module_node, file_io, import_names):
if import_names == ('typing',):
if import_names in [('typing',), ('typing_extensions',)]:
module_cls = TypingModuleWrapper
else:
module_cls = StubModuleValue
+31 -15
View File
@@ -6,6 +6,7 @@ values.
This file deals with all the typing.py cases.
"""
import itertools
from typing import Any
from jedi import debug
from jedi.inference.compiled import builtin_from_name, create_simple_object
@@ -32,7 +33,8 @@ _TYPE_ALIAS_TYPES = {
'DefaultDict': 'collections.defaultdict',
'Deque': 'collections.deque',
}
_PROXY_TYPES = 'Optional Union ClassVar Annotated'.split()
_PROXY_TYPES = ['Optional', 'Union', 'ClassVar', 'Annotated', 'Final']
IGNORE_ANNOTATION_PARTS = ['ClassVar', 'Annotated', 'Final']
class TypingModuleName(NameWrapper):
@@ -81,6 +83,9 @@ class TypingModuleName(NameWrapper):
elif name == 'cast':
cast_fn, = self._wrapped_name.infer()
yield CastFunction.create_cached(inference_state, cast_fn)
elif name == 'Self':
yield SelfClass.create_cached(
inference_state, self.parent_context, self.tree_name)
elif name == 'TypedDict':
# TODO doesn't even exist in typeshed/typing.py, yet. But will be
# added soon.
@@ -98,24 +103,24 @@ class TypingModuleFilterWrapper(FilterWrapper):
class ProxyWithGenerics(BaseTypingClassWithGenerics):
def execute_annotation(self):
def execute_annotation(self, context):
string_name = self._tree_name.value
if string_name == 'Union':
# This is kind of a special case, because we have Unions (in Jedi
# ValueSets).
return self.gather_annotation_classes().execute_annotation()
return self.gather_annotation_classes().execute_annotation(context)
elif string_name == 'Optional':
# Optional is basically just saying it's either None or the actual
# type.
return self.gather_annotation_classes().execute_annotation() \
return self.gather_annotation_classes().execute_annotation(context) \
| ValueSet([builtin_from_name(self.inference_state, 'None')])
elif string_name == 'Type':
# The type is actually already given in the index_value
return self._generics_manager[0]
elif string_name in ['ClassVar', 'Annotated']:
elif string_name in IGNORE_ANNOTATION_PARTS:
# For now don't do anything here, ClassVars are always used.
return self._generics_manager[0].execute_annotation()
return self._generics_manager[0].execute_annotation(context)
mapped = {
'Tuple': Tuple,
@@ -186,6 +191,8 @@ class ProxyTypingValue(BaseTypingValue):
class _TypingClassMixin(ClassMixin):
_tree_name: Any
def py__bases__(self):
return [LazyKnownValues(
self.inference_state.builtins_module.py__getattribute__('object')
@@ -213,17 +220,17 @@ class TypingClassWithGenerics(ProxyWithGenerics, _TypingClassMixin):
# This is basically a trick to avoid extra code: We execute the
# incoming classes to be able to use the normal code for type
# var inference.
value_set.execute_annotation(),
value_set.execute_annotation(None),
)
elif annotation_name == 'Callable':
if len(annotation_generics) == 2:
return annotation_generics[1].infer_type_vars(
value_set.execute_annotation(),
value_set.execute_annotation(None),
)
elif annotation_name == 'Tuple':
tuple_annotation, = self.execute_annotation()
tuple_annotation, = self.execute_annotation(None)
return tuple_annotation.infer_type_vars(value_set)
return type_var_dict
@@ -319,7 +326,7 @@ class Tuple(BaseTypingInstance):
yield LazyKnownValues(self._generics_manager.get_index_and_execute(0))
else:
for v in self._generics_manager.to_tuple():
yield LazyKnownValues(v.execute_annotation())
yield LazyKnownValues(v.execute_annotation(None))
def py__getitem__(self, index_value_set, contextualized_node):
if self._is_homogenous():
@@ -327,11 +334,11 @@ class Tuple(BaseTypingInstance):
return ValueSet.from_sets(
self._generics_manager.to_tuple()
).execute_annotation()
).execute_annotation(None)
def _get_wrapped_value(self):
tuple_, = self.inference_state.builtins_module \
.py__getattribute__('tuple').execute_annotation()
.py__getattribute__('tuple').execute_annotation(None)
return tuple_
@property
@@ -388,11 +395,20 @@ class Protocol(BaseTypingInstance):
class AnyClass(BaseTypingValue):
def execute_annotation(self):
def execute_annotation(self, context):
debug.warning('Used Any - returned no results')
return NO_VALUES
class SelfClass(BaseTypingValue):
def execute_annotation(self, context):
debug.warning('Used Self')
if context is not None:
# Execute the class of Self
return context.get_value().execute_annotation(None)
return NO_VALUES
class OverloadFunction(BaseTypingValue):
@repack_with_argument_clinic('func, /')
def py__call__(self, func_value_set):
@@ -427,7 +443,7 @@ class NewType(Value):
return c
def py__call__(self, arguments):
return self._type_value_set.execute_annotation()
return self._type_value_set.execute_annotation(arguments.context)
@property
def name(self):
@@ -441,7 +457,7 @@ class NewType(Value):
class CastFunction(ValueWrapper):
@repack_with_argument_clinic('type, object, /')
def py__call__(self, type_value_set, object_value_set):
return type_value_set.execute_annotation()
return type_value_set.execute_annotation(None)
class TypedDictClass(BaseTypingValue):
+1 -1
View File
@@ -19,7 +19,7 @@ def load_proper_stub_module(inference_state, grammar, file_io, import_names, mod
# /[...]/stdlib/3/os/__init__.pyi -> stdlib/3/os/__init__
rest = relative_path.with_suffix('')
# Remove the stdlib/3 or third_party/3.6 part
import_names = rest.parts[2:]
import_names = rest.parts[1:]
if rest.name == '__init__':
import_names = import_names[:-1]
+2 -2
View File
@@ -5,12 +5,12 @@ import os
from itertools import chain
from contextlib import contextmanager
from parso.python import tree
from parso import tree
def is_stdlib_path(path):
# Python standard library paths look like this:
# /usr/lib/python3.9/...
# /usr/lib/python3.14/...
# TODO The implementation below is probably incorrect and not complete.
parts = path.parts
if 'dist-packages' in parts or 'site-packages' in parts:
+7 -8
View File
@@ -12,7 +12,6 @@ import os
from pathlib import Path
from parso.python import tree
from parso.tree import search_ancestor
from jedi import debug
from jedi import settings
@@ -95,7 +94,7 @@ def goto_import(context, tree_name):
def _prepare_infer_import(module_context, tree_name):
import_node = search_ancestor(tree_name, 'import_name', 'import_from')
import_node = tree_name.search_ancestor('import_name', 'import_from')
import_path = import_node.get_path_for_name(tree_name)
from_import_name = None
try:
@@ -371,16 +370,16 @@ def import_module_by_names(inference_state, import_names, sys_path=None,
i.value if isinstance(i, tree.Name) else i
for i in import_names
)
value_set = [None]
base = [None]
for i, name in enumerate(import_names):
value_set = ValueSet.from_sets([
base = value_set = ValueSet.from_sets([
import_module(
inference_state,
str_import_names[:i+1],
parent_module_value,
sys_path,
prefer_stubs=prefer_stubs,
) for parent_module_value in value_set
prefer_stubs=prefer_stubs, # type: ignore[call-arg]
) for parent_module_value in base
])
if not value_set:
message = 'No module named ' + '.'.join(str_import_names)
@@ -475,7 +474,7 @@ def _load_python_module(inference_state, file_io,
)
def _load_builtin_module(inference_state, import_names=None, sys_path=None):
def _load_builtin_module(inference_state, import_names, sys_path):
project = inference_state.project
if sys_path is None:
sys_path = inference_state.get_sys_path()
@@ -549,7 +548,7 @@ def load_namespace_from_path(inference_state, folder_io):
def follow_error_node_imports_if_possible(context, name):
error_node = tree.search_ancestor(name, 'error_node')
error_node = name.search_ancestor('error_node')
if error_node is not None:
# Get the first command start of a started simple_stmt. The error
# node is sometimes a small_stmt and sometimes a simple_stmt. Check
+26 -19
View File
@@ -1,11 +1,8 @@
from abc import abstractmethod
from inspect import Parameter
from typing import Optional, Tuple
from parso.tree import search_ancestor
from typing import Optional, Tuple, Any
from jedi.parser_utils import find_statement_documentation, clean_scope_docstring
from jedi.inference.utils import unite
from jedi.inference.base_value import ValueSet, NO_VALUES
from jedi.inference.cache import inference_state_method_cache
from jedi.inference import docstrings
@@ -39,7 +36,6 @@ class AbstractNameDefinition:
def infer(self):
raise NotImplementedError
@abstractmethod
def goto(self):
# Typically names are already definitions and therefore a goto on that
# name will always result on itself.
@@ -107,12 +103,15 @@ class AbstractArbitraryName(AbstractNameDefinition):
class AbstractTreeName(AbstractNameDefinition):
tree_name: Any
parent_context: Any
def __init__(self, parent_context, tree_name):
self.parent_context = parent_context
self.tree_name = tree_name
def get_qualified_names(self, include_module_names=False):
import_node = search_ancestor(self.tree_name, 'import_name', 'import_from')
import_node = self.tree_name.search_ancestor('import_name', 'import_from')
# For import nodes we cannot just have names, because it's very unclear
# how they would look like. For now we just ignore them in most cases.
# In case of level == 1, it works always, because it's like a submodule
@@ -196,24 +195,23 @@ class AbstractTreeName(AbstractNameDefinition):
new_dotted = deep_ast_copy(par)
new_dotted.children[index - 1:] = []
values = context.infer_node(new_dotted)
return unite(
value.goto(name, name_context=context)
return [
n
for value in values
)
for n in value.goto(name, name_context=context)
]
if node_type == 'trailer' and par.children[0] == '.':
values = infer_call_of_leaf(context, name, cut_own_trailer=True)
return values.goto(name, name_context=context)
else:
stmt = search_ancestor(
name, 'expr_stmt', 'lambdef'
) or name
stmt = name.search_ancestor('expr_stmt', 'lambdef') or name
if stmt.type == 'lambdef':
stmt = name
return context.goto(name, position=stmt.start_pos)
def is_import(self):
imp = search_ancestor(self.tree_name, 'import_from', 'import_name')
imp = self.tree_name.search_ancestor('import_from', 'import_name')
return imp is not None
@property
@@ -226,6 +224,9 @@ class AbstractTreeName(AbstractNameDefinition):
class ValueNameMixin:
_value: Any
parent_context: Any
def infer(self):
return ValueSet([self._value])
@@ -244,7 +245,7 @@ class ValueNameMixin:
def get_root_context(self):
if self.parent_context is None: # A module
return self._value.as_context()
return super().get_root_context()
return super().get_root_context() # type: ignore
def get_defining_qualified_value(self):
context = self.parent_context
@@ -361,14 +362,16 @@ class TreeNameDefinition(AbstractTreeName):
class _ParamMixin:
get_kind: Any
def maybe_positional_argument(self, include_star=True):
options = [Parameter.POSITIONAL_ONLY, Parameter.POSITIONAL_OR_KEYWORD]
options: list[int] = [Parameter.POSITIONAL_ONLY, Parameter.POSITIONAL_OR_KEYWORD]
if include_star:
options.append(Parameter.VAR_POSITIONAL)
return self.get_kind() in options
def maybe_keyword_argument(self, include_stars=True):
options = [Parameter.KEYWORD_ONLY, Parameter.POSITIONAL_OR_KEYWORD]
options: list[int] = [Parameter.KEYWORD_ONLY, Parameter.POSITIONAL_OR_KEYWORD]
if include_stars:
options.append(Parameter.VAR_KEYWORD)
return self.get_kind() in options
@@ -451,7 +454,7 @@ class _ActualTreeParamName(BaseTreeParamName):
self.function_value = function_value
def _get_param_node(self):
return search_ancestor(self.tree_name, 'param')
return self.tree_name.search_ancestor('param')
@property
def annotation_node(self):
@@ -463,7 +466,7 @@ class _ActualTreeParamName(BaseTreeParamName):
self.function_value, self._get_param_node(),
ignore_stars=ignore_stars)
if execute_annotation:
values = values.execute_annotation()
values = values.execute_annotation(self.function_value.get_default_param_context())
return values
def infer_default(self):
@@ -633,6 +636,10 @@ class NameWrapper:
class StubNameMixin:
api_type: str
tree_name: Any
infer: Any
def py__doc__(self):
from jedi.inference.gradual.conversion import convert_names
# Stubs are not complicated and we can just follow simple statements
@@ -644,7 +651,7 @@ class StubNameMixin:
names = convert_names(names, prefer_stub_to_compiled=False)
if self in names:
return super().py__doc__()
return super().py__doc__() # type: ignore
else:
# We have signatures ourselves in stubs, so don't use signatures
# from the implementation.
+7
View File
@@ -1,4 +1,5 @@
from inspect import Parameter
from typing import Any
from jedi.cache import memoize_method
from jedi import debug
@@ -6,6 +7,10 @@ from jedi import parser_utils
class _SignatureMixin:
get_param_names: Any
name: Any
annotation_string: Any
def to_string(self):
def param_strings():
is_positional = False
@@ -36,6 +41,8 @@ class _SignatureMixin:
class AbstractSignature(_SignatureMixin):
_function_value: Any
def __init__(self, value, is_bound=False):
self.value = value
self.is_bound = is_bound
+2 -5
View File
@@ -12,15 +12,12 @@ The signature here for bar should be `bar(b, c)` instead of bar(*args).
"""
from inspect import Parameter
from parso import tree
from jedi.inference.utils import to_list
from jedi.inference.names import ParamNameWrapper
from jedi.inference.helpers import is_big_annoying_library
def _iter_nodes_for_param(param_name):
from parso.python.tree import search_ancestor
from jedi.inference.arguments import TreeArguments
execution_context = param_name.parent_context
@@ -28,7 +25,7 @@ def _iter_nodes_for_param(param_name):
# tree rather than going via the execution context so that we're agnostic of
# the specific scope we're evaluating within (i.e: module or function,
# etc.).
function_node = tree.search_ancestor(param_name.tree_name, 'funcdef', 'lambdef')
function_node = param_name.tree_name.search_ancestor('funcdef', 'lambdef')
module_node = function_node.get_root_node()
start = function_node.children[-1].start_pos
end = function_node.children[-1].end_pos
@@ -38,7 +35,7 @@ def _iter_nodes_for_param(param_name):
argument = name.parent
if argument.type == 'argument' \
and argument.children[0] == '*' * param_name.star_count:
trailer = search_ancestor(argument, 'trailer')
trailer = argument.search_ancestor('trailer')
if trailer is not None: # Make sure we're in a function
context = execution_context.create_context(trailer)
if _goes_to_param_name(param_name, context, name):
+37 -14
View File
@@ -30,6 +30,8 @@ from jedi.inference.names import TreeNameDefinition
from jedi.inference.context import CompForContext
from jedi.inference.value.decorator import Decoratee
from jedi.plugins import plugin_manager
from jedi.inference.gradual.typing import ProxyTypingValue, IGNORE_ANNOTATION_PARTS
from jedi.inference.gradual.type_var import TypeVar
operator_to_magic_method = {
'+': '__add__',
@@ -89,6 +91,7 @@ def infer_node(context, element):
if isinstance(context, CompForContext):
return _infer_node(context, element)
name_dicts = [{}]
if_stmt = element
while if_stmt is not None:
if_stmt = if_stmt.parent
@@ -104,7 +107,6 @@ def infer_node(context, element):
if predefined_if_name_dict is None and if_stmt \
and if_stmt.type == 'if_stmt' and context.inference_state.is_analysis:
if_stmt_test = if_stmt.children[1]
name_dicts = [{}]
# If we already did a check, we don't want to do it again -> If
# value.predefined_names is filled, we stop.
# We don't want to check the if stmt itself, it's just about
@@ -238,7 +240,7 @@ def _infer_node(context, element):
return context.infer_node(element.children[0])
elif typ == 'annassign':
return annotation.infer_annotation(context, element.children[1]) \
.execute_annotation()
.execute_annotation(context)
elif typ == 'yield_expr':
if len(element.children) and element.children[1].type == 'yield_arg':
# Implies that it's a yield from.
@@ -251,6 +253,8 @@ def _infer_node(context, element):
return NO_VALUES
elif typ == 'namedexpr_test':
return context.infer_node(element.children[2])
elif typ == 'star_expr':
return NO_VALUES
else:
return infer_or_test(context, element)
@@ -288,7 +292,7 @@ def infer_atom(context, atom):
state = context.inference_state
if atom.type == 'name':
# This is the first global lookup.
stmt = tree.search_ancestor(atom, 'expr_stmt', 'lambdef', 'if_stmt') or atom
stmt = atom.search_ancestor('expr_stmt', 'lambdef', 'if_stmt') or atom
if stmt.type == 'if_stmt':
if not any(n.start_pos <= atom.start_pos < n.end_pos for n in stmt.get_test_nodes()):
stmt = atom
@@ -434,7 +438,7 @@ def _infer_expr_stmt(context, stmt, seek_name=None):
else:
operator = copy.copy(first_operator)
operator.value = operator.value[:-1]
for_stmt = tree.search_ancestor(stmt, 'for_stmt')
for_stmt = stmt.search_ancestor('for_stmt')
if for_stmt is not None and for_stmt.type == 'for_stmt' and value_set \
and parser_utils.for_stmt_defines_one_name(for_stmt):
# Iterate through result and add the values, that's possible
@@ -494,7 +498,7 @@ def infer_factor(value_set, operator):
b = value.py__bool__()
if b is None: # Uncertainty.
yield list(value.inference_state.builtins_module.py__getattribute__('bool')
.execute_annotation()).pop()
.execute_annotation(None)).pop()
else:
yield compiled.create_simple_object(value.inference_state, not b)
else:
@@ -527,7 +531,7 @@ def _infer_comparison(context, left_values, operator, right_values):
result = (left_values or NO_VALUES) | (right_values or NO_VALUES)
return _literals_to_types(state, result)
elif operator_str == "|" and all(
value.is_class() or value.is_compiled()
value.is_class() or value.is_compiled() or isinstance(value, TypeVar)
for value in itertools.chain(left_values, right_values)
):
# ^^^ A naive hack for PEP 604
@@ -547,7 +551,7 @@ def _infer_comparison(context, left_values, operator, right_values):
def _is_annotation_name(name):
ancestor = tree.search_ancestor(name, 'param', 'funcdef', 'expr_stmt')
ancestor = name.search_ancestor('param', 'funcdef', 'expr_stmt')
if ancestor is None:
return False
@@ -647,7 +651,9 @@ def _infer_comparison_part(inference_state, context, left, operator, right):
_bool_to_value(inference_state, False)
])
elif str_operator in ('in', 'not in'):
return inference_state.builtins_module.py__getattribute__('bool').execute_annotation()
return inference_state.builtins_module.py__getattribute__('bool').execute_annotation(
context
)
def check(obj):
"""Checks if a Jedi object is either a float or an int."""
@@ -698,17 +704,28 @@ def tree_name_to_values(inference_state, context, tree_name):
if expr_stmt.type == "expr_stmt" and expr_stmt.children[1].type == "annassign":
correct_scope = parser_utils.get_parent_scope(name) == context.tree_node
ann_assign = expr_stmt.children[1]
if correct_scope:
found_annotation = True
first = ann_assign.children[1]
code = first.get_code()
if correct_scope and not (code.endswith(".TypeAlias")
or code.strip() == "TypeAlias"):
if (
(ann_assign.children[1].type == 'name')
(first.type == 'name')
and (ann_assign.children[1].value == tree_name.value)
and context.parent_context
):
context = context.parent_context
value_set |= annotation.infer_annotation(
found = annotation.infer_annotation(
context, expr_stmt.children[1].children[1]
).execute_annotation()
)
set_found_annotation = True
if len(found) == 1:
first = next(iter(found))
set_found_annotation = not (
isinstance(first, ProxyTypingValue)
and first.name.string_name in IGNORE_ANNOTATION_PARTS
)
found_annotation = set_found_annotation
value_set |= found.execute_annotation(context)
if found_annotation:
return value_set
@@ -766,7 +783,7 @@ def tree_name_to_values(inference_state, context, tree_name):
coro = enter_methods.execute_with_values()
return coro.py__await__().py__stop_iteration_returns()
enter_methods = value_managers.py__getattribute__('__enter__')
return enter_methods.execute_with_values()
return enter_methods.execute_annotation(context)
elif typ in ('import_from', 'import_name'):
types = imports.infer_import(context, tree_name)
elif typ in ('funcdef', 'classdef'):
@@ -852,10 +869,16 @@ def check_tuple_assignments(name, value_set):
# For no star unpacking is not possible.
return NO_VALUES
i = 0
lazy_value = None
while i <= index:
try:
lazy_value = next(iterated)
except StopIteration:
# A desperate attempt to fix inference for tuples from an
# iterator.
if lazy_value is not None:
return lazy_value.infer()
# We could do this with the default param in next. But this
# would allow this loop to run for a very long time if the
# index number is high. Therefore break if the loop is
-1
View File
@@ -74,7 +74,6 @@ class PushBackIterator:
def __init__(self, iterator):
self.pushes = []
self.iterator = iterator
self.current = None
def push_back(self, value):
self.pushes.append(value)
+11 -7
View File
@@ -1,4 +1,4 @@
from parso.python import tree
from typing import Any
from jedi import debug
from jedi.inference.cache import inference_state_method_cache, CachedMetaClass
@@ -55,6 +55,10 @@ class FunctionAndClassBase(TreeValue):
class FunctionMixin:
api_type = 'function'
tree_node: Any
py__class__: Any
as_context: Any
get_signature_functions: Any
def get_filters(self, origin_scope=None):
cls = self.py__class__()
@@ -262,8 +266,8 @@ class BaseFunctionExecutionContext(ValueContext, TreeContextMixin):
@recursion.execution_recursion_decorator(default=iter([]))
def get_yield_lazy_values(self, is_async=False):
# TODO: if is_async, wrap yield statements in Awaitable/async_generator_asend
for_parents = [(y, tree.search_ancestor(y, 'for_stmt', 'funcdef',
'while_stmt', 'if_stmt'))
for_parents = [(y, y.search_ancestor('for_stmt', 'funcdef',
'while_stmt', 'if_stmt'))
for y in get_yield_exprs(self.inference_state, self.tree_node)]
# Calculate if the yields are placed within the same for loop.
@@ -334,15 +338,15 @@ class BaseFunctionExecutionContext(ValueContext, TreeContextMixin):
return ValueSet(
GenericClass(c, TupleGenericManager(generics))
for c in async_generator_classes
).execute_annotation()
).execute_annotation(None)
else:
async_classes = inference_state.typing_module.py__getattribute__('Coroutine')
async_classes = inference_state.types_module.py__getattribute__('CoroutineType')
return_values = self.get_return_values()
# Only the first generic is relevant.
generics = (return_values.py__class__(), NO_VALUES, NO_VALUES)
generics = (NO_VALUES, NO_VALUES, return_values.py__class__())
return ValueSet(
GenericClass(c, TupleGenericManager(generics)) for c in async_classes
).execute_annotation()
).execute_annotation(None)
else:
# If there are annotations, prefer them over anything else.
if self.is_generator() and not self.infer_annotations():
+12 -9
View File
@@ -1,6 +1,5 @@
from abc import abstractproperty
from parso.tree import search_ancestor
from typing import Any
from jedi import debug
from jedi import settings
@@ -18,7 +17,7 @@ from jedi.inference.arguments import ValuesArguments, TreeArgumentsWrapper
from jedi.inference.value.function import \
FunctionValue, FunctionMixin, OverloadedFunctionValue, \
BaseFunctionExecutionContext, FunctionExecutionContext, FunctionNameInClass
from jedi.inference.value.klass import ClassFilter
from jedi.inference.value.klass import ClassFilter, init_or_new_func
from jedi.inference.value.dynamic_arrays import get_dynamic_array_instance
from jedi.parser_utils import function_is_staticmethod, function_is_classmethod
@@ -156,8 +155,9 @@ class AbstractInstanceValue(Value):
return super().py__iter__(contextualized_node)
def iterate():
for generator in self.execute_function_slots(iter_slot_names):
yield from generator.py__next__(contextualized_node)
yield LazyKnownValues(
self.execute_function_slots(iter_slot_names).py__next__(contextualized_node).infer()
)
return iterate()
def __repr__(self):
@@ -189,6 +189,9 @@ class CompiledInstance(AbstractInstanceValue):
class _BaseTreeInstance(AbstractInstanceValue):
get_defined_names: Any
_arguments: Any
@property
def array_type(self):
name = self.class_value.py__name__()
@@ -229,7 +232,7 @@ class _BaseTreeInstance(AbstractInstanceValue):
new = node
while True:
func_node = new
new = search_ancestor(new, 'funcdef', 'classdef')
new = new.search_ancestor('funcdef', 'classdef')
if class_context.tree_node is new:
func = FunctionValue.from_context(class_context, func_node)
bound_method = BoundMethod(self, class_context, func)
@@ -324,7 +327,7 @@ class TreeInstance(_BaseTreeInstance):
infer_type_vars_for_execution
args = InstanceArguments(self, self._arguments)
for signature in self.class_value.py__getattribute__('__init__').get_signatures():
for signature in init_or_new_func(self.class_value).get_signatures():
# Just take the first result, it should always be one, because we
# control the typeshed code.
funcdef = signature.value.tree_node
@@ -498,13 +501,13 @@ class SelfName(TreeNameDefinition):
return self._instance
def infer(self):
stmt = search_ancestor(self.tree_name, 'expr_stmt')
stmt = self.tree_name.search_ancestor('expr_stmt')
if stmt is not None:
if stmt.children[1].type == "annassign":
from jedi.inference.gradual.annotation import infer_annotation
values = infer_annotation(
self.parent_context, stmt.children[1].children[1]
).execute_annotation()
).execute_annotation(None)
if values:
return values
return super().infer()
+20 -4
View File
@@ -2,6 +2,8 @@
Contains all classes and functions to deal with lists, dicts, generators and
iterators in general.
"""
from typing import Any
from jedi.inference import compiled
from jedi.inference import analysis
from jedi.inference.lazy_value import LazyKnownValue, LazyKnownValues, \
@@ -20,6 +22,9 @@ from jedi.inference.value.dynamic_arrays import check_array_additions
class IterableMixin:
py__iter__: Any
inference_state: Any
def py__next__(self, contextualized_node=None):
return self.py__iter__(contextualized_node)
@@ -39,11 +44,11 @@ class GeneratorBase(LazyAttributeOverwrite, IterableMixin):
array_type = None
def _get_wrapped_value(self):
instance, = self._get_cls().execute_annotation()
instance, = self._get_cls().execute_annotation(None)
return instance
def _get_cls(self):
generator, = self.inference_state.typing_module.py__getattribute__('Generator')
generator, = self.inference_state.types_module.py__getattribute__('GeneratorType')
return generator
def py__bool__(self):
@@ -128,6 +133,12 @@ def comprehension_from_atom(inference_state, value, atom):
class ComprehensionMixin:
_defining_context: Any
_entry_node: Any
array_type: Any
_value_node: Any
_sync_comp_for_node: Any
@inference_state_method_cache()
def _get_comp_for_context(self, parent_context, comp_for):
return CompForContext(parent_context, comp_for)
@@ -176,6 +187,8 @@ class ComprehensionMixin:
class _DictMixin:
get_mapping_item_values: Any
def _get_generics(self):
return tuple(c_set.py__class__() for c_set in self.get_mapping_item_values())
@@ -201,7 +214,7 @@ class Sequence(LazyAttributeOverwrite, IterableMixin):
c, = GenericClass(
klass,
TupleGenericManager(self._cached_generics())
).execute_annotation()
).execute_annotation(None)
return c
def py__bool__(self):
@@ -220,7 +233,7 @@ class Sequence(LazyAttributeOverwrite, IterableMixin):
class _BaseComprehension(ComprehensionMixin):
def __init__(self, inference_state, defining_context, sync_comp_for_node, entry_node):
assert sync_comp_for_node.type == 'sync_comp_for'
super().__init__(inference_state)
super().__init__(inference_state) # type: ignore[call-arg]
self._defining_context = defining_context
self._sync_comp_for_node = sync_comp_for_node
self._entry_node = entry_node
@@ -248,6 +261,9 @@ class GeneratorComprehension(_BaseComprehension, GeneratorBase):
class _DictKeyMixin:
_dict_keys: Any
_dict_values: Any
# TODO merge with _DictMixin?
def get_mapping_item_values(self):
return self._dict_keys(), self._dict_values()
+35 -3
View File
@@ -38,7 +38,7 @@ py__doc__() Returns the docstring for a value.
"""
from __future__ import annotations
from typing import List, Optional, Tuple
from typing import List, Optional, Tuple, TYPE_CHECKING, Any
from jedi import debug
from jedi.parser_utils import get_cached_parent_scope, expr_is_dotted, \
@@ -61,6 +61,9 @@ from inspect import Parameter
from jedi.inference.names import BaseTreeParamName
from jedi.inference.signature import AbstractSignature
if TYPE_CHECKING:
from jedi.inference import InferenceState
class ClassName(TreeNameDefinition):
def __init__(self, class_value, tree_name, name_context, apply_decorators):
@@ -197,6 +200,15 @@ def get_dataclass_param_names(cls) -> List[DataclassParamName]:
class ClassMixin:
tree_node: Any
parent_context: Any
inference_state: InferenceState
py__bases__: Any
get_metaclasses: Any
get_metaclass_filters: Any
get_metaclass_signatures: Any
list_type_vars: Any
def is_class(self):
return True
@@ -273,7 +285,6 @@ class ClassMixin:
if not is_instance and include_type_when_class:
from jedi.inference.compiled import builtin_from_name
type_ = builtin_from_name(self.inference_state, 'type')
assert isinstance(type_, ClassValue)
if type_ != self:
# We are not using execute_with_values here, because the
# plugin function for type would get executed instead of an
@@ -365,7 +376,8 @@ class ClassMixin:
if sigs:
return sigs
args = ValuesArguments([])
init_funcs = self.py__call__(args).py__getattribute__('__init__')
instance = self.py__call__(args)
init_funcs = init_or_new_func(instance)
dataclass_sigs = self._get_dataclass_transform_signatures()
if dataclass_sigs:
@@ -458,6 +470,23 @@ class ClassMixin:
return ValueSet({self})
def init_or_new_func(value):
init_funcs = value.py__getattribute__('__init__')
if len(init_funcs) == 1:
init = next(iter(init_funcs))
try:
class_context = init.class_context
except AttributeError:
pass
else:
# In the case where we are on object.__init__, we try to use
# __new__.
if class_context.get_root_context().is_builtins_module() \
and init.class_context.name.string_name == "object":
return value.py__getattribute__('__new__')
return init_funcs
class DataclassParamName(BaseTreeParamName):
"""
Represent a field declaration on a class with dataclass semantics.
@@ -682,6 +711,9 @@ class ClassValue(ClassMixin, FunctionAndClassBase, metaclass=CachedMetaClass):
"""
bases_arguments = self._get_bases_arguments()
if bases_arguments is None:
return None
if bases_arguments.argument_node.type != "arglist":
# If it is not inheriting from the base model and having
# extra parameters, then init behavior is not changed.
+13 -1
View File
@@ -1,6 +1,6 @@
import os
from pathlib import Path
from typing import Optional
from typing import Optional, TYPE_CHECKING, Any
from jedi.inference.cache import inference_state_method_cache
from jedi.inference.names import AbstractNameDefinition, ModuleName
@@ -13,6 +13,9 @@ from jedi.inference.compiled import create_simple_object
from jedi.inference.base_value import ValueSet
from jedi.inference.context import ModuleContext
if TYPE_CHECKING:
from jedi.inference import InferenceState
class _ModuleAttributeName(AbstractNameDefinition):
"""
@@ -35,6 +38,11 @@ class _ModuleAttributeName(AbstractNameDefinition):
class SubModuleDictMixin:
inference_state: "InferenceState"
is_package: Any
py__path__: Any
as_context: Any
@inference_state_method_cache()
def sub_modules_dict(self):
"""
@@ -57,6 +65,10 @@ class SubModuleDictMixin:
class ModuleMixin(SubModuleDictMixin):
_module_name_class = ModuleName
tree_node: Any
string_names: Any
sub_modules_dict: Any
py__file__: Any
def get_filters(self, origin_scope=None):
yield MergedFilter(
+1 -1
View File
@@ -259,7 +259,7 @@ def get_parent_scope(node, include_flows=False):
# the if, but the parent of the if.
if not (scope.type == 'if_stmt'
and any(n.start_pos <= node.start_pos < n.end_pos
for n in scope.get_test_nodes())):
for n in scope.get_test_nodes())): # type: ignore[attr-defined]
return scope
scope = scope.parent
+4 -3
View File
@@ -2,6 +2,7 @@
Module is used to infer Django model fields.
"""
from inspect import Parameter
from typing import Any
from jedi import debug
from jedi.inference.cache import inference_state_function_cache
@@ -45,7 +46,7 @@ _FILTER_LIKE_METHODS = ('create', 'filter', 'exclude', 'update', 'get',
def _get_deferred_attributes(inference_state):
return inference_state.import_module(
('django', 'db', 'models', 'query_utils')
).py__getattribute__('DeferredAttribute').execute_annotation()
).py__getattribute__('DeferredAttribute').execute_annotation(None)
def _infer_scalar_field(inference_state, field_name, field_tree_instance, is_instance):
@@ -129,7 +130,7 @@ def _create_manager_for(cls, manager_cls='BaseManager'):
for m in managers:
if m.is_class_mixin():
generics_manager = TupleGenericManager((ValueSet([cls]),))
for c in GenericClass(m, generics_manager).execute_annotation():
for c in GenericClass(m, generics_manager).execute_annotation(None):
return c
return None
@@ -140,7 +141,7 @@ def _new_dict_filter(cls, is_instance):
include_metaclasses=False,
include_type_when_class=False)
)
dct = {
dct: dict[str, Any] = {
name.string_name: DjangoModelName(cls, name, is_instance)
for filter_ in reversed(filters)
for name in filter_.values()
+9 -24
View File
@@ -2,7 +2,6 @@ import sys
from typing import List
from pathlib import Path
from parso.tree import search_ancestor
from jedi.inference.cache import inference_state_method_cache
from jedi.inference.imports import goto_import, load_module_from_path
from jedi.inference.filters import ParserTreeFilter
@@ -38,7 +37,7 @@ def infer_anonymous_param(func):
== ('typing', 'Generator')
for v in result):
return ValueSet.from_sets(
v.py__getattribute__('__next__').execute_annotation()
v.py__getattribute__('__next__').execute_annotation(None)
for v in result
)
return result
@@ -120,7 +119,7 @@ def _is_a_pytest_param_and_inherited(param_name):
This is a heuristic and will work in most cases.
"""
funcdef = search_ancestor(param_name.tree_name, 'funcdef')
funcdef = param_name.tree_name.search_ancestor('funcdef')
if funcdef is None: # A lambda
return False, False
decorators = funcdef.get_decorators()
@@ -139,28 +138,14 @@ def _find_pytest_plugin_modules() -> List[List[str]]:
See https://docs.pytest.org/en/stable/how-to/writing_plugins.html#setuptools-entry-points
"""
if sys.version_info >= (3, 8):
from importlib.metadata import entry_points
if sys.version_info >= (3, 10):
pytest_entry_points = entry_points(group="pytest11")
else:
pytest_entry_points = entry_points().get("pytest11", ())
if sys.version_info >= (3, 9):
return [ep.module.split(".") for ep in pytest_entry_points]
else:
# Python 3.8 doesn't have `EntryPoint.module`. Implement equivalent
# to what Python 3.9 does (with additional None check to placate `mypy`)
matches = [
ep.pattern.match(ep.value)
for ep in pytest_entry_points
]
return [x.group('module').split(".") for x in matches if x]
from importlib.metadata import entry_points
if sys.version_info >= (3, 10):
pytest_entry_points = entry_points(group="pytest11")
else:
from pkg_resources import iter_entry_points
return [ep.module_name.split(".") for ep in iter_entry_points(group="pytest11")]
pytest_entry_points = entry_points().get("pytest11", ())
return [ep.module.split(".") for ep in pytest_entry_points]
@inference_state_method_cache()
@@ -193,7 +178,7 @@ def _iter_pytest_modules(module_context, skip_own_module=False):
folder = folder.get_parent_folder()
# prevent an infinite for loop if the same parent folder is return twice
if last_folder is not None and folder.path == last_folder.path:
if last_folder is not None and folder.path == last_folder.path: # type: ignore # TODO
break
last_folder = folder # keep track of the last found parent name
+38 -8
View File
@@ -134,7 +134,7 @@ def execute(callback):
except KeyError:
pass
else:
return func(value, arguments=arguments, callback=call)
return func(value, arguments=arguments, callback=call) # type: ignore
return call()
return wrapper
@@ -789,6 +789,13 @@ def _os_path_join(args_set, callback):
return callback()
_path_overrides = {
'dirname': _create_string_input_function(os.path.dirname),
'abspath': _create_string_input_function(os.path.abspath),
'relpath': _create_string_input_function(os.path.relpath),
'join': _os_path_join,
}
_implemented = {
'builtins': {
'getattr': builtins_getattr,
@@ -851,12 +858,8 @@ _implemented = {
# For now this works at least better than Jedi trying to understand it.
'dataclass': _dataclass
},
'os.path': {
'dirname': _create_string_input_function(os.path.dirname),
'abspath': _create_string_input_function(os.path.abspath),
'relpath': _create_string_input_function(os.path.relpath),
'join': _os_path_join,
}
'posixpath': _path_overrides,
'ntpath': _path_overrides,
}
@@ -906,11 +909,38 @@ class EnumInstance(LazyValueWrapper):
yield f
# Make sure tuple[...] behaves like Tuple[...]
class TupleClassWrapper(ValueWrapper):
def py__getitem__(self, index_value_set, contextualized_node):
return self.inference_state.typing_tuple().py__getitem__(
index_value_set,
contextualized_node,
)
# Make sure type[...] behaves like Type[...]
class TypeClassWrapper(ValueWrapper):
def py__getitem__(self, index_value_set, contextualized_node):
return self.inference_state.typing_type().py__getitem__(
index_value_set,
contextualized_node,
)
def tree_name_to_values(func):
def wrapper(inference_state, context, tree_name):
if tree_name.value == 'sep' and context.is_module() and context.py__name__() == 'os.path':
if tree_name.value == 'sep' \
and context.is_module() and context.py__name__() in ('posixpath', 'ntpath'):
return ValueSet({
compiled.create_simple_object(inference_state, os.path.sep),
})
if tree_name.value == 'tuple' \
and context.is_module() and context.py__name__() == 'builtins':
tup, = func(inference_state, context, tree_name)
return ValueSet([TupleClassWrapper(tup)])
if tree_name.value == 'type' \
and context.is_module() and context.py__name__() == 'builtins':
tup, = func(inference_state, context, tree_name)
return ValueSet([TypeClassWrapper(tup)])
return func(inference_state, context, tree_name)
return wrapper
+14
View File
@@ -0,0 +1,14 @@
[tool.zuban]
strict = true
enable_error_code = ["ignore-without-code"]
# Revert some --strict specific flags:
allow_untyped_calls = true
allow_untyped_defs = true
allow_incomplete_defs = true
allow_untyped_globals = true
untyped_strict_optional = false
implicit_reexport = true
# Exclude our copies of external stubs
exclude = "^jedi/third_party|^test/(completion|refactor|static_analysis|examples)/"
-50
View File
@@ -1,50 +0,0 @@
#!/usr/bin/env python
"""
Profile a piece of Python code with ``cProfile`` that uses the diff parser.
Usage:
profile.py <file> [-d] [-s <sort>]
profile.py -h | --help
Options:
-h --help Show this screen.
-d --debug Enable Jedi internal debugging.
-s <sort> Sort the profile results, e.g. cumtime, name [default: time].
"""
import cProfile
from docopt import docopt
from jedi.parser.python import load_grammar
from jedi.parser.diff import DiffParser
from jedi.parser.python import ParserWithRecovery
from jedi.common import splitlines
import jedi
def run(parser, lines):
diff_parser = DiffParser(parser)
diff_parser.update(lines)
# Make sure used_names is loaded
parser.module.used_names
def main(args):
if args['--debug']:
jedi.set_debug_function(notices=True)
with open(args['<file>']) as f:
code = f.read()
grammar = load_grammar()
parser = ParserWithRecovery(grammar, code)
# Make sure used_names is loaded
parser.module.used_names
code = code + '\na\n' # Add something so the diff parser needs to run.
lines = splitlines(code, keepends=True)
cProfile.runctx('run(parser, lines)', globals(), locals(), sort=args['-s'])
if __name__ == '__main__':
args = docopt(__doc__)
main(args)
+1 -1
View File
@@ -13,7 +13,7 @@ Note: This requires the psutil library, available on PyPI.
import time
import sys
import os
import psutil
import psutil # type: ignore[import-untyped]
sys.path.insert(0, os.path.abspath(os.path.dirname(__file__) + '/..'))
import jedi
+1 -1
View File
@@ -56,7 +56,7 @@ def main(args):
run(code, i, infer=infer)
if args['--precision']:
pstats.f8 = f8
pstats.f8 = f8 # type: ignore[attr-defined] # TODO this does not seem to exist?!
jedi.set_debug_function(notices=args['--debug'])
if args['--omit']:
+2 -2
View File
@@ -17,11 +17,11 @@ import sys
try:
import urllib.request as urllib2
except ImportError:
import urllib2
import urllib2 # type: ignore[import-not-found, no-redef]
import gc
from os.path import abspath, dirname
import objgraph
import objgraph # type: ignore[import-untyped]
sys.path.insert(0, dirname(dirname(abspath(__file__))))
import jedi
-33
View File
@@ -31,36 +31,3 @@ exclude =
[pycodestyle]
max-line-length = 100
[mypy]
# Exclude our copies of external stubs
exclude = ^jedi/third_party
show_error_codes = true
enable_error_code = ignore-without-code
# Ensure generics are explicit about what they are (e.g: `List[str]` rather than
# just `List`)
disallow_any_generics = True
disallow_subclassing_any = True
# Avoid creating future gotchas emerging from bad typing
warn_redundant_casts = True
warn_unused_ignores = True
warn_return_any = True
warn_unused_configs = True
warn_unreachable = True
# Require values to be explicitly re-exported; this makes things easier for
# Flake8 too and avoids accidentally importing thing from the "wrong" place
# (which helps avoid circular imports)
implicit_reexport = False
strict_equality = True
[mypy-jedi,jedi.inference.compiled,jedi.inference.value,parso]
# Various __init__.py files which contain re-exports we want to implicitly make.
implicit_reexport = True
+33 -35
View File
@@ -35,11 +35,11 @@ setup(name='jedi',
keywords='python completion refactoring vim',
long_description=readme,
packages=find_packages(exclude=['test', 'test.*']),
python_requires='>=3.8',
python_requires='>=3.10',
# Python 3.13 grammars are added to parso in 0.8.4
install_requires=['parso>=0.8.4,<0.9.0'],
install_requires=['parso>=0.8.6,<0.9.0'],
extras_require={
'testing': [
'dev': [
'pytest<9.0.0',
# docopt for sith doctests
'docopt',
@@ -48,42 +48,41 @@ setup(name='jedi',
'Django',
'attrs',
'typing_extensions',
],
'qa': [
# latest version on 2025-06-16
'flake8==7.2.0',
# latest version supporting Python 3.6
'mypy==1.16',
'flake8==7.1.2',
'zuban==0.7.0',
# Arbitrary pins, latest at the time of pinning
'types-setuptools==80.9.0.20250529',
],
'docs': [
# Just pin all of these.
'Jinja2==2.11.3',
'MarkupSafe==1.1.1',
'Pygments==2.8.1',
'alabaster==0.7.12',
'babel==2.9.1',
'chardet==4.0.0',
'commonmark==0.8.1',
'docutils==0.17.1',
'future==0.18.2',
'idna==2.10',
'imagesize==1.2.0',
'mock==1.0.1',
'packaging==20.9',
'pyparsing==2.4.7',
'pytz==2021.1',
'readthedocs-sphinx-ext==2.1.4',
'recommonmark==0.5.0',
'requests==2.25.1',
'six==1.15.0',
'snowballstemmer==2.1.0',
'sphinx==1.8.5',
'sphinx-rtd-theme==0.4.3',
'sphinxcontrib-serializinghtml==1.1.4',
'sphinxcontrib-websupport==1.2.4',
'urllib3==1.26.4',
'alabaster==1.0.0',
'babel==2.18.0',
'certifi==2026.4.22',
'charset-normalizer==3.4.7',
'docutils==0.22.4',
'idna==3.13',
'imagesize==2.0.0',
'iniconfig==2.3.0',
'Jinja2==3.1.6',
'MarkupSafe==3.0.3',
'packaging==26.2',
'pluggy==1.6.0',
'Pygments==2.20.0',
'pytest==9.0.3',
'requests==2.33.1',
'roman-numerals==4.1.0',
'snowballstemmer==3.0.1',
'Sphinx==9.1.0',
'sphinx_rtd_theme==3.1.0',
'sphinxcontrib-applehelp==2.0.0',
'sphinxcontrib-devhelp==2.0.0',
'sphinxcontrib-htmlhelp==2.1.0',
'sphinxcontrib-jquery==4.1',
'sphinxcontrib-jsmath==1.0.1',
'sphinxcontrib-qthelp==2.0.0',
'sphinxcontrib-serializinghtml==2.0.0',
'urllib3==2.6.3',
],
},
package_data={'jedi': ['*.pyi', 'third_party/typeshed/LICENSE',
@@ -96,12 +95,11 @@ setup(name='jedi',
'License :: OSI Approved :: MIT License',
'Operating System :: OS Independent',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3.11',
'Programming Language :: Python :: 3.12',
'Programming Language :: Python :: 3.13',
'Programming Language :: Python :: 3.14',
'Topic :: Software Development :: Libraries :: Python Modules',
'Topic :: Text Editors :: Integrated Development Environments (IDE)',
'Topic :: Utilities',
-2
View File
@@ -35,7 +35,6 @@ Usage:
Options:
-h --help Show this screen.
--record=<file> Exceptions are recorded in here [default: record.json].
-f, --fs-cache By default, file system cache is off for reproducibility.
-n, --maxtries=<nr> Maximum of random tries [default: 100]
-d, --debug Jedi print debugging when an error is raised.
-s Shows the path/line numbers of every completion before it starts.
@@ -187,7 +186,6 @@ def main(arguments):
'pudb' if arguments['--pudb'] else None
record = arguments['--record']
jedi.settings.use_filesystem_cache = arguments['--fs-cache']
if arguments['--debug']:
jedi.set_debug_function()
+17 -5
View File
@@ -207,16 +207,16 @@ C().a
(f, g) = (1,)
#? int()
f
#? []
g.
#? int()
g
(f, g, h) = (1,'')
#? int()
f
#? str()
g
#? []
h.
#? str()
h
(f1, g1) = 1
#? []
@@ -311,9 +311,13 @@ for x in {1: 3.0, '': 1j}:
dict().values().__iter__
d = dict(a=3, b='')
x, = d.values()
x, y, z = d.values()
#? int() str()
x
#? int() str()
y
#? int() str()
z
#? int()
d['a']
#? int() str() None
@@ -527,3 +531,11 @@ lc = [x for a, *x in [(1, '', 1.0)]]
lc[0][0]
#?
lc[0][1]
xy = (1,)
x, y = *xy, None
# whatever it is should not crash
#?
x
+5 -3
View File
@@ -232,13 +232,14 @@ def a():
#?
# str literals in comment """ upper
# python >= 3.11
def completion_in_comment():
#? ['Exception']
#? ['Exception', 'ExceptionGroup']
# might fail because the comment is not a leaf: Exception
pass
some_word
#? ['Exception']
#? ['Exception', 'ExceptionGroup']
# Very simple comment completion: Exception
# Commment after it
@@ -388,7 +389,8 @@ with open('') as f:
#? ['closed']
f.closed
for line in f:
#? str() bytes()
# TODO this is wrong
#? bytes()
line
with open('') as f1, open('') as f2:
+3 -2
View File
@@ -31,14 +31,15 @@ if x:
#? ['else']
else
# python >= 3.11
try:
pass
#? ['except', 'Exception']
#? ['except', 'Exception', 'ExceptionGroup']
except
try:
pass
#? 6 ['except', 'Exception']
#? 6 ['except', 'Exception', 'ExceptionGroup']
except AttributeError:
pass
#? ['finally']
+2 -1
View File
@@ -1,3 +1,4 @@
# python >= 3.11
class Foo:
bar = 1
@@ -13,7 +14,7 @@ Fr'{Foo.bar'
Fr'{Foo.bar
#? ['bar']
Fr'{Foo.bar
#? ['Exception']
#? ['Exception', 'ExceptionGroup']
F"{Excepti
#? 8 Foo
+2 -1
View File
@@ -2,7 +2,8 @@
#? ['raise']
raise
#? ['Exception']
# python >= 3.11
#? ['Exception', 'ExceptionGroup']
except
#? []
-1
View File
@@ -1,7 +1,6 @@
# For assignment expressions / named expressions / walrus operators / whatever
# they are called.
# python >= 3.8
b = (a:=1, a)
#? int()
+8 -6
View File
@@ -108,33 +108,35 @@ def z(bam, bar=2, *, bas=1):
#? 7 ['bar=', 'baz=']
x(1, ba)
# python >= 3.11
#? 14 ['baz=']
x(1, bar=2, ba)
#? 7 ['bar=', 'baz=']
x(1, ba, baz=3)
#? 14 ['baz=']
x(1, bar=2, baz=3)
#? 7 ['BaseException']
#? 7 ['BaseException', 'BaseExceptionGroup']
x(basee)
#? 22 ['bar=', 'baz=']
x(1, 2, 3, 4, 5, 6, bar=2)
#? 14 ['baz=']
y(1, bar=2, ba)
#? 7 ['bar=', 'BaseException', 'baz=']
#? 7 ['bar=', 'BaseException', 'BaseExceptionGroup', 'baz=']
y(1, ba, baz=3)
#? 14 ['baz=']
y(1, bar=2, baz=3)
#? 7 ['BaseException']
#? 7 ['BaseException', 'BaseExceptionGroup']
y(basee)
#? 22 ['bar=', 'BaseException', 'baz=']
#? 22 ['bar=', 'BaseException', 'BaseExceptionGroup', 'baz=']
y(1, 2, 3, 4, 5, 6, bar=2)
#? 11 ['bar=', 'bas=']
z(bam=1, bar=2, bas=3)
#? 8 ['BaseException', 'bas=']
#? 8 ['BaseException', 'BaseExceptionGroup', 'bas=']
z(1, bas=2)
#? 12 ['BaseException']
#? 12 ['BaseException', 'BaseExceptionGroup']
z(1, bas=bas)
#? 19 ['dict']
+35
View File
@@ -203,3 +203,38 @@ class NotCalledClass:
self.w: float
#? float()
self.w
def tuple_func() -> tuple[int, str]:
return 1, ""
x = tuple_func()
a, b = x
#? int()
a
#? str()
b
#? int()
x[0]
#? str()
x[1]
def check_newstyle_unions(u1: int | str, u2: list[int] | list[str]):
#? int() str()
u1
#? list()
u2
#? int() str()
u2[1]
def use_type_with_annotation() -> type[int]: ...
#? int
use_type_with_annotation()
def union_with_forward_references(x: int | "str", y: "int" | str, z: "int | str"):
#? int() str()
x
#? int() str()
y
#? int() str()
z
@@ -11,6 +11,7 @@ from typing import (
TypeVar,
Union,
Sequence,
Self,
)
K = TypeVar('K')
@@ -387,3 +388,19 @@ first(custom_partial2_unbound_instance)
#? str()
values(custom_partial2_unbound_instance)[0]
def generic_func1(arg: T) -> int | str | T: pass
def generic_func2(arg: T) -> Union[int, str, T]: pass
#? int() str() bytes()
generic_func1(b"hello")
#? int() str() bytes()
generic_func2(b"hello")
class CustomGeneric2(Generic[T_co]):
val: T_co
def __init__(cls, val: T_co) -> Self:
raise NotImplementedError
#? int()
CustomGeneric2(1).val
+57 -9
View File
@@ -3,7 +3,7 @@ Test the typing library, with docstrings and annotations
"""
import typing
from typing import Sequence, MutableSequence, List, Iterable, Iterator, \
AbstractSet, Tuple, Mapping, Dict, Union, Optional
AbstractSet, Tuple, Mapping, Dict, Union, Optional, Final, Self
class B:
pass
@@ -49,11 +49,7 @@ def iterators(ps: Iterable[int], qs: Iterator[str], rs:
a, b = ps
#? int()
a
##? int() --- TODO fix support for tuple assignment
# https://github.com/davidhalter/jedi/pull/663#issuecomment-172317854
# test below is just to make sure that in case it gets fixed by accident
# these tests will be fixed as well the way they should be
#?
#? int()
b
for q in qs:
@@ -76,7 +72,7 @@ def sets(p: AbstractSet[int], q: typing.MutableSet[float]):
#? ["add"]
q.a
def tuple(p: Tuple[int], q: Tuple[int, str, float], r: Tuple[B, ...]):
def tupletest(p: Tuple[int], q: Tuple[int, str, float], r: Tuple[B, ...]):
#? int()
p[0]
#? ['index']
@@ -476,8 +472,6 @@ dynamic_annotation('')
# TypeDict
# -------------------------
# python >= 3.8
class Foo(typing.TypedDict):
foo: str
bar: typing.List[float]
@@ -557,3 +551,57 @@ def typed_dict_test_foo(arg: Bar):
arg['an_int']
#? int()
arg['another_variable']
# -----------------
# Self
# -----------------
import typing_extensions
# From #2023, #2068
class Builder:
def __init__(self):
self.x = 0
self.y = 0
def add_x(self: Self, x: int) -> Self:
self.x = x
return self
def add_y(self: Self, y: int) -> Self:
self.y = y
return self
def add_not_implemented(self: Self, y: int) -> Self:
raise NotImplementedError
def add_not_implemented_typing_extensions(self: Self, y: int) -> typing_extensions.Self:
raise NotImplementedError
b = Builder()
#? Builder()
b.add_x(2)
#? Builder()
b.add_x(2).add_y(5)
# python >= 3.11
#? Builder()
b.add_x(2).add_not_implemented(5)
#? Builder()
b.add_x(2).add_not_implemented_typing_extensions(5)
# -----------------
# TypeAlias (see also #1969)
# -----------------
from typing import TypeAlias
IntX: typing.TypeAlias = int
IntY: TypeAlias = int
#? int
IntX
def f(x: IntX, y: IntY):
#? int()
x
#? int()
y
+44 -3
View File
@@ -59,6 +59,7 @@ class VarClass:
var_class1: typing.ClassVar[str] = 1
var_class2: typing.ClassVar[bytes]
var_class3 = None
var_class4: typing.ClassVar = ""
def __init__(self):
#? int()
@@ -71,7 +72,7 @@ class VarClass:
d.var_class2
#? []
d.int
#? ['var_class1', 'var_class2', 'var_instance1', 'var_instance2', 'var_class3']
#? ['var_class1', 'var_class2', 'var_instance1', 'var_instance2', 'var_class3', 'var_class4']
self.var_
class VarClass2(VarClass):
@@ -81,7 +82,7 @@ class VarClass2(VarClass):
#? int()
self.var_class3
#? ['var_class1', 'var_class2', 'var_instance1', 'var_class3', 'var_instance2']
#? ['var_class1', 'var_class2', 'var_class4', 'var_instance1', 'var_class3', 'var_instance2']
VarClass.var_
#? int()
VarClass.var_instance1
@@ -91,11 +92,13 @@ VarClass.var_instance2
VarClass.var_class1
#? bytes()
VarClass.var_class2
#? str()
VarClass.var_class4
#? []
VarClass.int
d = VarClass()
#? ['var_class1', 'var_class2', 'var_class3', 'var_instance1', 'var_instance2']
#? ['var_class1', 'var_class2', 'var_class3', 'var_class4', 'var_instance1', 'var_instance2']
d.var_
#? int()
d.var_instance1
@@ -105,6 +108,8 @@ d.var_instance2
d.var_class1
#? bytes()
d.var_class2
#? str()
d.var_class4
#? []
d.int
@@ -117,3 +122,39 @@ class DC:
#? int()
DC().name
# -------------------------
# Final
# -------------------------
# TODO this is wrong, but shouldn't matter that much
#? 0 int()
x: typing.Final[str] = 1
#? 0 int()
y: typing.Final = 1
#? str()
x
#? int()
y
def f(x: typing.Final[str]):
#? str()
x
class C:
x: typing.Final[bytes] = 1
#? 4 str()
y: typing.Final = ""
#? bytes()
x
#? str()
y
#? bytes()
C.x
#? str()
C.y
#? bytes()
C().x
#? str()
C().y
-2
View File
@@ -1,5 +1,3 @@
# python >= 3.9
from typing import Annotated
# This is just a dummy and very meaningless thing to use with to the Annotated
@@ -0,0 +1,14 @@
# python >= 3.12
# -----------------
# new generic syntax should not fail
# -----------------
class C[T]:
def c(self) -> str: ...
def f[T](x: T, y: T) -> int: ...
#? int()
f()
#? str()
C().c()
@@ -1,5 +1,3 @@
# python >= 3.8
def positional_only_call(a, /, b):
#? str()
a
+2 -2
View File
@@ -54,7 +54,7 @@ a
#? int()
(3 ** 3)
#? int()
#? int() float()
(3 ** 'a')
#? int()
(3 + 'a')
@@ -167,7 +167,7 @@ from datetime import datetime, timedelta
(datetime - timedelta)
#? datetime()
(datetime() - timedelta())
#? timedelta()
#? timedelta() datetime()
(datetime() - datetime())
#? timedelta()
(timedelta() - datetime())
+7 -6
View File
@@ -25,7 +25,7 @@ next(reversed(yielder()))
#?
next(reversed())
#? str() bytes()
#? str()
next(open(''))
#? int()
@@ -91,7 +91,7 @@ os._T
with open('foo') as f:
for line in f.readlines():
#? str() bytes()
#? bytes()
line
# -----------------
# enumerate
@@ -196,7 +196,10 @@ class A(object):
class B(object):
def shout(self): pass
cls = random.choice([A, B])
#? ['say', 'shout']
# TODO why is this not inferred? This used to work...
#?
cls
#? []
cls().s
# -----------------
@@ -360,7 +363,7 @@ X.attr_x.value
X.attr_y.name
#? float()
X.attr_y.value
#? str()
#?
X().name
#? float()
X().attr_x.attr_y.value
@@ -459,8 +462,6 @@ X().just_partial('')[0]
#? str()
X().just_partial('')[1]
# python >= 3.8
@functools.lru_cache
def x() -> int: ...
@functools.lru_cache()
+2 -1
View File
@@ -2,10 +2,11 @@
# non array
# -----------------
# python >= 3.12
#? ['imag']
int.imag
#? []
#? ['is_integer']
int.is_integer
#? ['is_integer']
+1 -1
View File
@@ -389,6 +389,6 @@ if False:
# -----------------
import socket
#< (1, 21), (0, 7), ('socket', ..., 6), ('stub:socket', ..., 4), ('imports', ..., 7)
#< (1, 21), (0, 7), ('socket', ..., 6), ('stub:socket', ..., 6), ('imports', ..., 7)
socket.SocketIO
some_socket = socket.SocketIO()
+1 -1
View File
@@ -14,7 +14,7 @@ from jedi.api.interpreter import MixedModuleContext
# For interpreter tests sometimes the path of this directory is in the sys
# path, which we definitely don't want. So just remove it globally.
try:
sys.path.remove(helpers.test_dir)
sys.path.remove(str(helpers.test_dir))
except ValueError:
pass
+1 -1
View File
@@ -2,7 +2,7 @@
import sys
sys.path[0:0] = [
'/usr/lib/python3.8/site-packages',
'/usr/lib/python3.14/site-packages',
'/tmp/.buildout/eggs/important_package.egg'
]
+4 -5
View File
@@ -104,10 +104,7 @@ import os
import re
import sys
import operator
if sys.version_info < (3, 8):
literal_eval = eval
else:
from ast import literal_eval
from ast import literal_eval
from io import StringIO
from functools import reduce
from unittest.mock import ANY
@@ -168,6 +165,8 @@ class BaseTestCase(object):
class IntegrationTestCase(BaseTestCase):
source: str # Defined as a side effect
def __init__(self, test_type, correct, line_nr, column, start, line,
path=None, skip_version_info=None):
super().__init__(skip_version_info)
@@ -446,7 +445,7 @@ Options:
--pdb Enable pdb debugging on fail.
-d, --debug Enable text output debugging (please install ``colorama``).
--thirdparty Also run thirdparty tests (in ``completion/thirdparty``).
--env <dotted> A Python version, like 3.9, 3.8, etc.
--env <dotted> A Python version, like 3.14, 3.13, etc.
"""
if __name__ == '__main__':
import docopt
+2 -2
View File
@@ -134,7 +134,7 @@ def test_infer_on_non_name(Script):
def test_infer_on_generator(Script, environment):
script = Script('def x(): yield 1\ny=x()\ny')
def_, = script.infer()
assert def_.name == 'Generator'
assert def_.name == 'GeneratorType'
def_, = script.infer(only_stubs=True)
assert def_.name == 'Generator'
@@ -173,7 +173,7 @@ def test_get_line_code(Script):
return Script(source).complete(line=line)[0].get_line_code(**kwargs).replace('\r', '')
# On builtin
assert get_line_code('abs') == 'def abs(__x: SupportsAbs[_T]) -> _T: ...\n'
assert get_line_code('abs') == 'def abs(x: SupportsAbs[_T], /) -> _T: ...\n'
# On custom code
first_line = 'def foo():\n'
+22 -15
View File
@@ -27,6 +27,17 @@ def test_valid_call(Script):
assert_signature(Script, 'bool()', 'bool', column=5)
def test_dunder_new(Script):
# From #2073
s = dedent("""\
from typing import Self
class C:
def __new__(cls, b) -> Self:
pass
C( )""")
assert_signature(Script, s, 'C', 0, line=5, column=2)
class TestSignatures(TestCase):
@pytest.fixture(autouse=True)
def init(self, Script):
@@ -72,9 +83,9 @@ class TestSignatures(TestCase):
run(s6, '__eq__', 0)
run(s6, 'bool', 0, 5)
s7 = "str().upper().center("
# s7 = "str().upper().center("
s8 = "bool(int[abs("
run(s7, 'center', 0)
# run(s7, 'center', 0)
run(s8, 'abs', 0)
run(s8, 'bool', 0, 10)
@@ -199,9 +210,10 @@ def test_chained_calls(Script):
def test_return(Script):
source = dedent('''
def foo():
return '.'.join()''')
return (1).conjugate()''')
assert_signature(Script, source, 'join', 0, column=len(" return '.'.join("))
assert_signature(
Script, source, 'conjugate', expected_index=None, column=len(" return (1).conjugate("))
def test_find_signature_on_module(Script):
@@ -238,9 +250,9 @@ def test_complex(Script, environment):
# Do these checks just for Python 3, I'm too lazy to deal with this
# legacy stuff. ~ dave.
assert get_signature(func1.tree_node) \
== 'compile(pattern: AnyStr, flags: _FlagsType = ...) -> Pattern[AnyStr]'
== 'compile(pattern: AnyStr, flags: _FlagsType = 0) -> Pattern[AnyStr]'
assert get_signature(func2.tree_node) \
== 'compile(pattern: Pattern[AnyStr], flags: _FlagsType = ...) ->\nPattern[AnyStr]'
== 'compile(pattern: Pattern[AnyStr], flags: _FlagsType = 0) ->\nPattern[AnyStr]'
# jedi-vim #70
s = """def foo("""
@@ -420,7 +432,7 @@ _calls = [
(code1, 'f(a,b,xy', 4),
(code1, 'f(a,b,xyz=', 4),
(code1, 'f(a,b,xy=', None),
(code1, 'f(u=', (0, None)),
(code1, 'f(u=', None),
(code1, 'f(v=', 1),
# **kwargs
@@ -438,7 +450,7 @@ _calls = [
(code2, 'g(a,b,abc=1,abd=4,abd=', 5),
(code2, 'g(a,b,kw', 5),
(code2, 'g(a,b,kwargs=', 5),
(code2, 'g(u=', (0, 5)),
(code2, 'g(u=', 5),
(code2, 'g(v=', 1),
# *args
@@ -450,7 +462,7 @@ _calls = [
(code3, 'h(a,b,c,(3,)', 2),
(code3, 'h(a,b,args=', None),
(code3, 'h(u,v=', 1),
(code3, 'h(u=', (0, None)),
(code3, 'h(u=', None),
(code3, 'h(u,*xxx', 1),
(code3, 'h(u,*xxx,*yyy', 1),
(code3, 'h(u,*[]', 1),
@@ -483,7 +495,7 @@ _calls = [
(code4, 'i(1, [a?b,*', 2),
(code4, 'i(?b,*r,c', 1),
(code4, 'i(?*', 0),
(code4, 'i(?**', (0, 1)),
(code4, 'i(?**', 1),
# Random
(code4, 'i(()', 0),
@@ -497,11 +509,6 @@ _calls = [
@pytest.mark.parametrize('ending', ['', ')'])
@pytest.mark.parametrize('code, call, expected_index', _calls)
def test_signature_index(Script, environment, code, call, expected_index, ending):
if isinstance(expected_index, tuple):
expected_index = expected_index[environment.version_info > (3, 8)]
if environment.version_info < (3, 8):
code = code.replace('/,', '')
sig, = Script(code + '\n' + call + ending).get_signatures(column=len(call))
index = sig.index
assert expected_index == index
+11 -7
View File
@@ -188,11 +188,15 @@ def test_functions_should_have_params(Script):
assert c.get_signatures()
def test_hashlib_params(Script):
def test_hashlib_params(Script, environment):
script = Script('from hashlib import sha256')
c, = script.complete()
sig, = c.get_signatures()
assert [p.name for p in sig.params] == ['string']
if environment.version_info >= (3, 13):
wanted = ['data', 'usedforsecurity', 'string']
else:
wanted = ['string', 'usedforsecurity']
assert [p.name for p in sig.params] == wanted
def test_signature_params(Script):
@@ -465,7 +469,7 @@ def test_import(get_names):
nms = nms[2].goto()
assert nms
assert all(n.type == 'module' for n in nms)
assert 'posixpath' in {n.name for n in nms}
assert 'path' in {n.name for n in nms}
nms = get_names('import os.path', references=True)
n = nms[0].goto()[0]
@@ -523,7 +527,7 @@ def test_added_equals_to_params(Script):
def test_builtin_module_with_path(Script):
"""
This test simply tests if a module from /usr/lib/python3.8/lib-dynload/ has
This test simply tests if a module from /usr/lib/python3.14/lib-dynload/ has
a path or not. It shouldn't have a module_path, because that is just
confusing.
"""
@@ -614,9 +618,9 @@ def test_definition_goto_follow_imports(Script):
('n = {1: ""}; n', 'Dict[int, str]'),
('n = {1: "", 1.0: b""}; n', 'Dict[Union[float, int], Union[bytes, str]]'),
('n = next; n', 'Union[next(__i: Iterator[_T]) -> _T, '
'next(__i: Iterator[_T], default: _VT) -> Union[_T, _VT]]'),
('abs', 'abs(__x: SupportsAbs[_T]) -> _T'),
('n = next; n', 'Union[next(i: SupportsNext[_T], /) -> _T, '
'next(i: SupportsNext[_T], default: _VT, /) -> _T | _VT]'),
('abs', 'abs(x: SupportsAbs[_T], /) -> _T'),
('def foo(x, y): return x if xxxx else y\nfoo(str(), 1)\nfoo',
'foo(x: str, y: int) -> Union[int, str]'),
('def foo(x, y = None): return x if xxxx else y\nfoo(str(), 1)\nfoo',
+2 -1
View File
@@ -3,6 +3,7 @@ import os
from textwrap import dedent
from itertools import count
from pathlib import Path
from typing import Any
import pytest
@@ -301,7 +302,7 @@ def test_file_path_should_have_completions(Script):
assert Script('r"').complete() # See GH #1503
_dict_keys_completion_tests = [
_dict_keys_completion_tests: "list[tuple[str, int | None, list[str | Any]]]" = [
('ints[', 5, ['1', '50', Ellipsis]),
('ints[]', 5, ['1', '50', Ellipsis]),
('ints[1]', 5, ['1', '50', Ellipsis]),
+2 -2
View File
@@ -26,13 +26,13 @@ def test_find_system_environments():
@pytest.mark.parametrize(
'version',
['3.8', '3.9', '3.10', '3.11', '3.12', '3.13']
jedi.api.environment._SUPPORTED_PYTHONS,
)
def test_versions(version):
try:
env = get_system_environment(version)
except InvalidPythonEnvironment:
if int(version.replace('.', '')) == str(sys.version_info[0]) + str(sys.version_info[1]):
if version.replace('.', '') == str(sys.version_info[0]) + str(sys.version_info[1]):
# At least the current version has to work
raise
pytest.skip()
+4 -1
View File
@@ -15,6 +15,7 @@ There are three kinds of test:
import textwrap
from unittest import TestCase
from typing import Any
import pytest
@@ -22,6 +23,8 @@ import jedi
class MixinTestFullName(object):
assertEqual: Any
operation = None
@pytest.fixture(autouse=True)
@@ -49,7 +52,7 @@ class TestFullNameWithGotoDefinitions(MixinTestFullName, TestCase):
self.check("""
import re
any_re = re.compile('.*')
any_re""", 'typing.Pattern')
any_re""", 're.Pattern')
def test_from_import(self):
self.check('from os import path', 'os.path')
+33 -19
View File
@@ -78,7 +78,7 @@ def test_numpy_like_non_zero():
def test_nested_resolve():
class XX:
def x():
def x(): # type: ignore[misc]
pass
cls = get_completion('XX', locals())
@@ -92,7 +92,7 @@ def test_side_effect_completion():
Python code, however we want references to Python code as well. Therefore
we need some mixed kind of magic for tests.
"""
_GlobalNameSpace.SideEffectContainer.foo = 1
_GlobalNameSpace.SideEffectContainer.foo = 1 # type: ignore[attr-defined]
side_effect = get_completion('SideEffectContainer', _GlobalNameSpace.__dict__)
# It's a class that contains MixedObject.
@@ -166,7 +166,7 @@ def test_getitem_side_effects():
# Possible side effects here, should therefore not call this.
if True:
raise NotImplementedError()
return index
return index # type: ignore[unreachable]
foo = Foo2()
_assert_interpreter_complete('foo["asdf"].upper', locals(), ['upper'])
@@ -198,7 +198,7 @@ def test__getattr__completions(allow_unsafe_getattr, class_is_findable):
raise AttributeError(name)
def __dir__(self):
return ['foo', 'fbar'] + object.__dir__(self)
return ['foo', 'fbar'] + object.__dir__(self) # type: ignore[operator]
if not class_is_findable:
CompleteGetattr.__name__ = "something_somewhere"
@@ -388,7 +388,7 @@ def test_dir_magic_method(allow_unsafe_getattr):
raise AttributeError(name)
def __dir__(self):
return ['foo', 'bar'] + object.__dir__(self)
return ['foo', 'bar'] + object.__dir__(self) # type: ignore[operator]
itp = jedi.Interpreter("ca.", [{'ca': CompleteAttrs()}])
completions = itp.complete()
@@ -410,7 +410,7 @@ def test_dir_magic_method(allow_unsafe_getattr):
def test_name_not_findable():
class X():
if 0:
NOT_FINDABLE # noqa: F821
NOT_FINDABLE # type: ignore[unreachable] # noqa: F821
def hidden(self):
return
@@ -493,7 +493,7 @@ def test__wrapped__():
def test_illegal_class_instance():
class X:
__class__ = 1
__class__ = 1 # type: ignore[assignment]
X.__name__ = 'asdf'
d, = jedi.Interpreter('foo', [{'foo': X()}]).infer()
v, = d._name.infer()
@@ -537,7 +537,7 @@ def test_partial_signatures(code, expected, index):
def test_type_var():
"""This was an issue before, see Github #1369"""
x = typing.TypeVar('myvar')
x = typing.TypeVar('myvar') # type: ignore[misc]
def_, = jedi.Interpreter('x', [locals()]).infer()
assert def_.name == 'TypeVar'
@@ -576,7 +576,7 @@ def test_dict_completion(code, column, expected):
strs = {'asdf': 1, """foo""": 2, r'fbar': 3}
mixed = {1: 2, 1.10: 4, None: 6, r'a\sdf': 8, b'foo': 9}
class Inherited(dict):
class Inherited(dict): # type: ignore[type-arg]
pass
inherited = Inherited(blablu=3)
@@ -624,10 +624,10 @@ def test_dunders(class_is_findable, code, expected, allow_unsafe_getattr):
def __getitem__(self, key) -> int:
return 1
def __iter__(self, key) -> Iterator[str]:
def __iter__(self, key) -> Iterator[str]: # type: ignore[empty-body]
pass
def __next__(self, key) -> float:
def __next__(self, key) -> float: # type: ignore[empty-body]
pass
if not class_is_findable:
@@ -661,17 +661,15 @@ def bar():
# typing is available via globals.
({'return': 'typing.Union[str, int]'}, ['int', 'str'], ''),
({'return': 'typing.Union["str", int]'},
['int', 'str'] if sys.version_info >= (3, 9) else ['int'], ''),
({'return': 'typing.Union["str", int]'}, ['int', 'str'], ''),
({'return': 'typing.Union["str", 1]'},
['str'] if sys.version_info >= (3, 11) else [], ''),
(['str'] if (3, 14) > sys.version_info >= (3, 11) else []), ''),
({'return': 'typing.Optional[str]'}, ['NoneType', 'str'], ''),
({'return': 'typing.Optional[str, int]'}, [], ''), # Takes only one arg
({'return': 'typing.Any'},
['_AnyMeta'] if sys.version_info >= (3, 11) else [], ''),
({'return': 'typing.Tuple[int, str]'},
['Tuple' if sys.version_info[:2] == (3, 6) else 'tuple'], ''),
({'return': 'typing.Tuple[int, str]'}, ['tuple'], ''),
({'return': 'typing.Tuple[int, str]'}, ['int'], 'x()[0]'),
({'return': 'typing.Tuple[int, str]'}, ['str'], 'x()[1]'),
({'return': 'typing.Tuple[int, str]'}, [], 'x()[2]'),
@@ -746,7 +744,8 @@ def test_complete_not_findable_class_source():
def test_param_infer_default():
abs_sig, = jedi.Interpreter('abs(', [{'abs': abs}]).get_signatures()
param, = abs_sig.params
assert param.name == 'x'
# Parameter name changed from 'x' to 'number' in Python 3.15
assert param.name in ('x', 'number')
assert param.infer_default() == []
@@ -810,11 +809,11 @@ def test_try_to_use_return_annotation_for_property(class_is_findable):
raise BaseException
@property
def with_annotation_garbage1(self) -> 'asldjflksjdfljdslkjfsl': # noqa
def with_annotation_garbage1(self) -> 'asldjflksjdfljdslkjfsl': # type: ignore[name-defined] # noqa
return Hello()
@property
def with_annotation_garbage2(self) -> 'sdf$@@$5*+8': # noqa
def with_annotation_garbage2(self) -> 'sdf & 8': # type: ignore[valid-type] # noqa
return Hello()
@property
@@ -859,3 +858,18 @@ def test_custom__getitem__(class_is_findable, allow_unsafe_getattr):
else:
expected = ['upper']
_assert_interpreter_complete('c["a"].up', namespace, expected)
def test_star_import_completions():
# From #2087
completions = jedi.Interpreter("from json import *\ndum", []).complete(2, 3)
names = [c.name for c in completions]
assert 'dump' in names
assert 'dumps' in names
def test_whitespace_after_dot_completion(Script):
# From #1954
completions = jedi.Interpreter("object. \n", []).complete(1, 8)
assert "mro" in [c.name for c in completions]
-1
View File
@@ -54,7 +54,6 @@ def test_rename_mod(Script, dir_with_content):
''').format(dir=dir_with_content)
@pytest.mark.skipif('sys.version_info[:2] < (3, 8)', message="Python 3.8 introduces dirs_exist_ok")
def test_namespace_package(Script, tmpdir):
origin = get_example_dir('implicit_namespace_package')
shutil.copytree(origin, tmpdir.strpath, dirs_exist_ok=True)
+1 -1
View File
@@ -13,7 +13,7 @@ class SomeClass:
def twice(self, b):
pass
def some_function():
def some_function(self):
pass
+1 -1
View File
@@ -68,4 +68,4 @@ def test_param_kind_and_name(code, index, param_code, kind, Script):
def test_staticmethod(Script):
s, = Script('staticmethod(').get_signatures()
assert s.to_string() == 'staticmethod(f: Callable[..., Any])'
assert s.to_string() == 'staticmethod(f: Callable[_P, _R_co], /)'
@@ -67,7 +67,7 @@ def test_path_from_sys_path_assignment(Script):
import sys
sys.path[0:0] = [
{os.path.abspath('/usr/lib/python3.8/site-packages')!r},
{os.path.abspath('/usr/lib/python3.14/site-packages')!r},
{os.path.abspath('/home/test/.buildout/eggs/important_package.egg')!r},
]
+1 -1
View File
@@ -86,7 +86,7 @@ def test_time_docstring():
import time
comp, = jedi.Script('import time\ntime.sleep').complete()
assert comp.docstring(raw=True) == time.sleep.__doc__
expected = 'sleep(secs: float) -> None\n\n' + time.sleep.__doc__
expected = 'sleep(seconds: _SupportsFloatOrIndex, /) -> None\n\n' + time.sleep.__doc__
assert comp.docstring() == expected

Some files were not shown because too many files have changed in this diff Show More