Skip to content

Commit 0d11c8d

Browse files
committed
Merge branch 'py3.10' into dev
2 parents 613e727 + db98c5a commit 0d11c8d

File tree

13 files changed

+943
-27
lines changed

13 files changed

+943
-27
lines changed

.github/workflows/analyze.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ jobs:
1111
runs-on: ubuntu-latest
1212
strategy:
1313
matrix:
14-
python-version: [3.9]
14+
python-version: ['3.10']
1515

1616
steps:
1717
- uses: actions/checkout@v2

.github/workflows/test.yml

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ jobs:
1010
runs-on: ${{ matrix.os }}
1111
strategy:
1212
matrix:
13-
# Start Linux jobs last since they are fastest to start and complete, and start 3.9 first,
13+
# Start Linux jobs last since they are fastest to start and complete, and start 3.10 first,
1414
# since it pairs wiht macOS+Windows jobs, and 2.7+3.5 last since they only run tests and
1515
# don't use venv. (3.4 is not supported on GitHub anymore)
16-
python-version: [3.9, 3.6, 3.7, 3.8, 2.7, 3.5]
16+
python-version: ['3.10', 3.6, 3.7, 3.8, 3.9, 2.7, 3.5]
1717
os: [windows-latest, macos-latest, ubuntu-latest]
1818

1919
# Choose test script depending on OS.
@@ -25,7 +25,7 @@ jobs:
2525
- os: windows-latest
2626
test_script_name: ./misc/actions/test.ps1
2727

28-
# Only test on macOS and Windows with Python 3.9.
28+
# Only test on macOS and Windows with Python 3.10.
2929
exclude:
3030
- os: macos-latest
3131
python-version: 2.7
@@ -39,6 +39,8 @@ jobs:
3939
python-version: 3.7
4040
- os: macos-latest
4141
python-version: 3.8
42+
- os: macos-latest
43+
python-version: 3.9
4244
- os: windows-latest
4345
python-version: 2.7
4446
- os: windows-latest
@@ -51,6 +53,8 @@ jobs:
5153
python-version: 3.7
5254
- os: windows-latest
5355
python-version: 3.8
56+
- os: windows-latest
57+
python-version: 3.9
5458

5559
steps:
5660
- uses: actions/checkout@v2

README.rst

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ Concurrently detect the minimum Python versions needed to run code. Additionally
2424
vanilla Python, and it doesn't have any external dependencies, it works with v2.7+ and v3+.
2525

2626
It functions by parsing Python code into an abstract syntax tree (AST), which it traverses and
27-
matches against internal dictionaries with **3223** rules, covering v2.0-2.7 and v3.0-3.9, divided
27+
matches against internal dictionaries with **3223** rules, covering v2.0-2.7 and v3.0-3.10, divided
2828
into **139** modules, **2247** classes/functions/constants members of modules, **713** kwargs of
2929
functions, **4** strftime directives, **3** bytes format directives, **2** array typecodes, **3**
3030
codecs error handler names, **20** codecs encodings, **75** builtin generic annotation types, **8**
@@ -87,8 +87,9 @@ error handler names, encodings, ``%`` formatting and directives for bytes and by
8787
statement, multiple context expressions in a ``with`` statement, unpacking assignment, generalized
8888
unpacking, ellipsis literal (`...`) out of slices, dictionary union (``{..} | {..}``), dictionary
8989
union merge (``a = {..}; a |= {..}``), builtin generic type annotations (``list[str]``), function
90-
decorators, class decorators and relaxed decorators. It tries to detect and ignore user-defined
91-
functions, classes, arguments, and variables with names that clash with library-defined symbols.
90+
decorators, class decorators, relaxed decorators, pattern matching with ``match``, and union types
91+
written as ``X | Y``. It tries to detect and ignore user-defined functions, classes, arguments, and
92+
variables with names that clash with library-defined symbols.
9293

9394
Caveats
9495
=======
@@ -265,8 +266,8 @@ Will yield "f-strings require 3.6+" even though the branch will not be evaluated
265266

266267
The lax mode, via argument ``--lax``, was created to circumvent cases like this. *But it's not a
267268
perfect solution* since it will skip all ``if``, ternarys, ``for``, ``async for``, ``while``,
268-
``with``, ``try``, and boolean operations. Therefore it is recommended to run with and without lax
269-
mode to get a better understanding of individual cases.
269+
``with``, ``try``, boolean operations, and ``match``. Therefore it is recommended to run with and
270+
without lax mode to get a better understanding of individual cases.
270271

271272
Analysis Exclusions
272273
===================

tests/builtin_constants.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,41 @@ def test_c_contiguous_of_memoryview(self):
1515

1616
def test_f_contiguous_of_memoryview(self):
1717
self.assertOnlyIn((3, 3), self.detect("memoryview(b'1').f_contiguous"))
18+
19+
def test_mapping_of_dict_view(self):
20+
self.assertOnlyIn((3, 10), self.detect("{}.items().mapping"))
21+
self.assertOnlyIn((3, 10), self.detect("{}.keys().mapping"))
22+
self.assertOnlyIn((3, 10), self.detect("{}.values().mapping"))
23+
24+
self.assertOnlyIn((3, 10), self.detect("dict().items().mapping"))
25+
self.assertOnlyIn((3, 10), self.detect("dict().keys().mapping"))
26+
self.assertOnlyIn((3, 10), self.detect("dict().values().mapping"))
27+
28+
self.assertOnlyIn((3, 10), self.detect("""
29+
d = {}
30+
d.items().mapping
31+
"""))
32+
self.assertOnlyIn((3, 10), self.detect("""
33+
d = {}
34+
d.keys().mapping
35+
"""))
36+
self.assertOnlyIn((3, 10), self.detect("""
37+
d = {}
38+
d.values().mapping
39+
"""))
40+
41+
self.assertOnlyIn((3, 10), self.detect("""
42+
d = {}
43+
i = d.items()
44+
i.mapping
45+
"""))
46+
self.assertOnlyIn((3, 10), self.detect("""
47+
d = {}
48+
i = d.keys()
49+
i.mapping
50+
"""))
51+
self.assertOnlyIn((3, 10), self.detect("""
52+
d = {}
53+
i = d.values()
54+
i.mapping
55+
"""))

tests/builtin_functions.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,10 @@ def test_bit_length_of_int(self):
354354
self.assertOnlyIn(((2, 7), (3, 1)), self.detect("(42).bit_length()"))
355355
self.assertOnlyIn(((2, 7), (3, 1)), self.detect("n=42\nn.bit_length()"))
356356

357+
def test_bit_count_of_int(self):
358+
self.assertOnlyIn((3, 10), self.detect("(42).bit_count()"))
359+
self.assertOnlyIn((3, 10), self.detect("n=42\nn.bit_count()"))
360+
357361
def test_to_bytes_of_int(self):
358362
self.assertOnlyIn((3, 2), self.detect("(42).to_bytes()"))
359363
self.assertOnlyIn((3, 2), self.detect("n=42\nn.to_bytes()"))
@@ -447,3 +451,9 @@ def test_setter_of_property(self):
447451

448452
def test_indices_of_slice(self):
449453
self.assertOnlyIn(((2, 3), (3, 0)), self.detect("slice.indices()"))
454+
455+
def test_aiter(self):
456+
self.assertOnlyIn((3, 10), self.detect("aiter()"))
457+
458+
def test_anext(self):
459+
self.assertOnlyIn((3, 10), self.detect("anext()"))

tests/class.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,9 @@ def test_ExitStack_of_contextlib(self):
267267
def test_AsyncExitStack_of_contextlib(self):
268268
self.assertOnlyIn((3, 7), self.detect("from contextlib import AsyncExitStack"))
269269

270+
def test_AsyncContextDecorator_of_contextlib(self):
271+
self.assertOnlyIn((3, 10), self.detect("from contextlib import AsyncContextDecorator"))
272+
270273
def test_unix_dialect_of_csv(self):
271274
self.assertOnlyIn((3, 2), self.detect("from csv import unix_dialect"))
272275

@@ -543,6 +546,9 @@ def test_TypedDict_of_typing(self):
543546
self.assertTrue(self.config.add_backport("typing"))
544547
self.assertOnlyIn(((2, 7), (3, 8)), self.detect("from typing import TypedDict"))
545548

549+
def test_ParamSpec_of_typing(self):
550+
self.assertOnlyIn((3, 10), self.detect("from typing import ParamSpec"))
551+
546552
def test_SMTP_SSL_of_smtplib(self):
547553
self.assertOnlyIn(((2, 6), (3, 0)), self.detect("from smtplib import SMTP_SSL"))
548554

tests/constants.py

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,18 @@ def test_O_PATH_of_os(self):
7474
def test_O_TMPFILE_of_os(self):
7575
self.assertOnlyIn((3, 4), self.detect("from os import O_TMPFILE"))
7676

77+
def test_O_EVTONLY_of_os(self):
78+
self.assertOnlyIn((3, 10), self.detect("from os import O_EVTONLY"))
79+
80+
def test_O_FSYNC_of_os(self):
81+
self.assertOnlyIn((3, 10), self.detect("from os import O_FSYNC"))
82+
83+
def test_O_SYMLINK_of_os(self):
84+
self.assertOnlyIn((3, 10), self.detect("from os import O_SYMLINK"))
85+
86+
def test_O_NOFOLLOW_ANY_of_os(self):
87+
self.assertOnlyIn((3, 10), self.detect("from os import O_NOFOLLOW_ANY"))
88+
7789
def test_POSIX_FADV_NORMAL_of_os(self):
7890
self.assertOnlyIn((3, 3), self.detect("from os import POSIX_FADV_NORMAL"))
7991

@@ -276,6 +288,12 @@ def test_VERIFY_X509_STRICT_of_ssl(self):
276288
def test_VERIFY_X509_TRUSTED_FIRST_of_ssl(self):
277289
self.assertOnlyIn(((2, 7), (3, 4)), self.detect("from ssl import VERIFY_X509_TRUSTED_FIRST"))
278290

291+
def test_VERIFY_X509_PARTIAL_CHAIN_of_ssl(self):
292+
self.assertOnlyIn((3, 10), self.detect("from ssl import VERIFY_X509_PARTIAL_CHAIN"))
293+
294+
def test_VERIFY_ALLOW_PROXY_CERTS_of_ssl(self):
295+
self.assertOnlyIn((3, 10), self.detect("from ssl import VERIFY_ALLOW_PROXY_CERTS"))
296+
279297
def test_PROTOCOL_TLS_of_ssl(self):
280298
self.assertOnlyIn(((2, 7), (3, 6)), self.detect("from ssl import PROTOCOL_TLS"))
281299

@@ -321,6 +339,9 @@ def test_OP_NO_COMPRESSION_of_ssl(self):
321339
def test_OP_NO_TICKET_of_ssl(self):
322340
self.assertOnlyIn((3, 6), self.detect("from ssl import OP_NO_TICKET"))
323341

342+
def test_OP_IGNORE_UNEXPECTED_EOF_of_ssl(self):
343+
self.assertOnlyIn((3, 10), self.detect("from ssl import OP_IGNORE_UNEXPECTED_EOF"))
344+
324345
def test_HAS_ALPN_of_ssl(self):
325346
self.assertOnlyIn(((2, 7), (3, 5)), self.detect("from ssl import HAS_ALPN"))
326347

@@ -378,6 +399,9 @@ def test_session_reused_of_ssl_SSLSocket(self):
378399
def test_check_hostname_of_ssl_SSLContext(self):
379400
self.assertOnlyIn((3, 4), self.detect("from ssl import SSLContext\nSSLContext.check_hostname"))
380401

402+
def test_security_level_of_ssl_SSLContext(self):
403+
self.assertOnlyIn((3, 10), self.detect("from ssl import SSLContext\nSSLContext.security_level"))
404+
381405
def test_verify_flags_of_ssl_SSLContext(self):
382406
self.assertOnlyIn((3, 4), self.detect("from ssl import SSLContext\nSSLContext.verify_flags"))
383407

@@ -621,6 +645,9 @@ def test_MADV_CORE_of_mmap(self):
621645
def test_MADV_PROTECT_of_mmap(self):
622646
self.assertOnlyIn((3, 8), self.detect("import mmap\nmmap.MADV_PROTECT"))
623647

648+
def test_MAP_POPULATE_of_mmap(self):
649+
self.assertOnlyIn((3, 10), self.detect("import mmap\nmmap.MAP_POPULATE"))
650+
624651
def test_MFD_CLOEXEC_of_os(self):
625652
self.assertOnlyIn((3, 8), self.detect("from os import MFD_CLOEXEC"))
626653

@@ -1213,6 +1240,9 @@ def test_RWF_NOWAIT_of_os(self):
12131240
def test_RWF_SYNC_of_os(self):
12141241
self.assertOnlyIn((3, 7), self.detect("from os import RWF_SYNC"))
12151242

1243+
def test_RWF_APPEND_of_os(self):
1244+
self.assertOnlyIn((3, 10), self.detect("from os import RWF_APPEND"))
1245+
12161246
def test_SCHED_BATCH_of_os(self):
12171247
self.assertOnlyIn((3, 3), self.detect("from os import SCHED_BATCH"))
12181248

@@ -1312,6 +1342,24 @@ def test_killpg_of_os(self):
13121342
def test_P_PIDFD_of_os(self):
13131343
self.assertOnlyIn((3, 9), self.detect("from os import P_PIDFD"))
13141344

1345+
def test_SPLICE_F_MOVE_of_os(self):
1346+
self.assertOnlyIn((3, 10), self.detect("from os import SPLICE_F_MOVE"))
1347+
1348+
def test_SPLICE_F_NONBLOCK_of_os(self):
1349+
self.assertOnlyIn((3, 10), self.detect("from os import SPLICE_F_NONBLOCK"))
1350+
1351+
def test_SPLICE_F_MORE_of_os(self):
1352+
self.assertOnlyIn((3, 10), self.detect("from os import SPLICE_F_MORE"))
1353+
1354+
def test_EFD_CLOEXEC_of_os(self):
1355+
self.assertOnlyIn((3, 10), self.detect("from os import EFD_CLOEXEC"))
1356+
1357+
def test_EFD_NONBLOCK_of_os(self):
1358+
self.assertOnlyIn((3, 10), self.detect("from os import EFD_NONBLOCK"))
1359+
1360+
def test_EFD_SEMAPHORE_of_os(self):
1361+
self.assertOnlyIn((3, 10), self.detect("from os import EFD_SEMAPHORE"))
1362+
13151363
def test_st_atime_from_os_stat(self):
13161364
self.assertOnlyIn(((2, 2), (3, 0)),
13171365
self.detect("from os import stat\n"
@@ -1530,6 +1578,11 @@ def test_parent_from_pyclbr_Function(self):
15301578
self.detect("from pyclbr import Function\n"
15311579
"Function().parent"))
15321580

1581+
def test_is_async_from_pyclbr_Function(self):
1582+
self.assertOnlyIn((3, 10),
1583+
self.detect("from pyclbr import Function\n"
1584+
"Function().is_async"))
1585+
15331586
def test_colno_from_re_error(self):
15341587
self.assertOnlyIn((3, 5),
15351588
self.detect("from re import error\n"
@@ -1574,6 +1627,9 @@ def test_RLIMIT_NICE_of_resource(self):
15741627
def test_RLIMIT_NPTS_of_resource(self):
15751628
self.assertOnlyIn((3, 4), self.detect("from resource import RLIMIT_NPTS"))
15761629

1630+
def test_RLIMIT_KQUEUES_of_resource(self):
1631+
self.assertOnlyIn((3, 10), self.detect("from resource import RLIMIT_KQUEUES"))
1632+
15771633
def test_RLIMIT_RTPRIO_of_resource(self):
15781634
self.assertOnlyIn((3, 4), self.detect("from resource import RLIMIT_RTPRIO"))
15791635

@@ -2054,6 +2110,9 @@ def test_TCP_NOTSENT_LOWAT_of_socket(self):
20542110
def test_TCP_USER_TIMEOUT_of_socket(self):
20552111
self.assertOnlyIn((3, 6), self.detect("from socket import TCP_USER_TIMEOUT"))
20562112

2113+
def test_TCP_KEEPALIVE_of_socket(self):
2114+
self.assertOnlyIn((3, 10), self.detect("from socket import TCP_KEEPALIVE"))
2115+
20572116
def test_TIPC_ADDR_ID_of_socket(self):
20582117
self.assertOnlyIn(((2, 6), (3, 0)), self.detect("from socket import TIPC_ADDR_ID"))
20592118

@@ -2135,6 +2194,12 @@ def test_VMADDR_PORT_ANY_of_socket(self):
21352194
def test_IPPROTO_UDPLITE_of_socket(self):
21362195
self.assertOnlyIn((3, 9), self.detect("from socket import IPPROTO_UDPLITE"))
21372196

2197+
def test_IPPROTO_MPTCP_of_socket(self):
2198+
self.assertOnlyIn((3, 10), self.detect("from socket import IPPROTO_MPTCP"))
2199+
2200+
def test_IP_RECVTOS_of_socket(self):
2201+
self.assertOnlyIn((3, 10), self.detect("from socket import IP_RECVTOS"))
2202+
21382203
def test_has_ipv6_of_socket(self):
21392204
self.assertOnlyIn(((2, 3), (3, 0)), self.detect("from socket import has_ipv6"))
21402205

@@ -2483,6 +2548,12 @@ def test_int_info_of_sys(self):
24832548
def test_thread_info_of_sys(self):
24842549
self.assertOnlyIn((3, 3), self.detect("from sys import thread_info"))
24852550

2551+
def test_orig_argv_of_sys(self):
2552+
self.assertOnlyIn((3, 10), self.detect("from sys import orig_argv"))
2553+
2554+
def test_stdlib_module_names_of_sys(self):
2555+
self.assertOnlyIn((3, 10), self.detect("from sys import stdlib_module_names"))
2556+
24862557
def test_major_from_sys_version_info(self):
24872558
self.assertOnlyIn(((2, 7), (3, 0)),
24882559
self.detect("from sys import version_info\n"
@@ -2560,6 +2631,9 @@ def test_native_id_from_threading_Thread(self):
25602631
self.detect("from threading import Thread\n"
25612632
"Thread().native_id"))
25622633

2634+
def test___excepthook___from_threading(self):
2635+
self.assertOnlyIn((3, 10), self.detect("from threading import __excepthook__"))
2636+
25632637
def test_tm_gmtoff_from_time_struct_time(self):
25642638
self.assertOnlyIn((3, 3),
25652639
self.detect("from time import struct_time\n"
@@ -2618,6 +2692,18 @@ def test_ClassMethodDescriptorType_of_types(self):
26182692
def test_CoroutineType_of_types(self):
26192693
self.assertOnlyIn((3, 5), self.detect("from types import CoroutineType"))
26202694

2695+
def test_NoneType_of_types(self):
2696+
self.assertOnlyIn((3, 10), self.detect("from types import NoneType"))
2697+
2698+
def test_NotImplementedType_of_types(self):
2699+
self.assertOnlyIn((3, 10), self.detect("from types import NotImplementedType"))
2700+
2701+
def test_EllipsisType_of_types(self):
2702+
self.assertOnlyIn((3, 10), self.detect("from types import EllipsisType"))
2703+
2704+
def test_UnionType_of_types(self):
2705+
self.assertOnlyIn((3, 10), self.detect("from types import UnionType"))
2706+
26212707
def test_GeneratorType_of_types(self):
26222708
self.assertOnlyIn(((2, 2), (3, 0)), self.detect("from types import GeneratorType"))
26232709

@@ -2660,6 +2746,21 @@ def test_Literal_of_typing(self):
26602746
def test_Annotated_of_typing(self):
26612747
self.assertOnlyIn((3, 9), self.detect("from typing import Annotated"))
26622748

2749+
def test_Concatenate_of_typing(self):
2750+
self.assertOnlyIn((3, 10), self.detect("from typing import Concatenate"))
2751+
2752+
def test_ParamSpecArgs_of_typing(self):
2753+
self.assertOnlyIn((3, 10), self.detect("from typing import ParamSpecArgs"))
2754+
2755+
def test_ParamSpecKwargs_of_typing(self):
2756+
self.assertOnlyIn((3, 10), self.detect("from typing import ParamSpecKwargs"))
2757+
2758+
def test_TypeAlias_of_typing(self):
2759+
self.assertOnlyIn((3, 10), self.detect("from typing import TypeAlias"))
2760+
2761+
def test_TypeGuard_of_typing(self):
2762+
self.assertOnlyIn((3, 10), self.detect("from typing import TypeGuard"))
2763+
26632764
def test_ucd_3_2_0_of_unicodedata(self):
26642765
self.assertOnlyIn(((2, 3), (3, 0)), self.detect("from unicodedata import ucd_3_2_0"))
26652766

@@ -2981,3 +3082,18 @@ def test_kwargs_of_unittest_mock_Mock_call_args(self):
29813082

29823083
def test_status_of_urllib_response_addinfourl(self):
29833084
self.assertOnlyIn((3, 9), self.detect("from urllib.response.addinfourl import status"))
3085+
3086+
def test_COPY_DICT_WITHOUT_KEYS_of_dis(self):
3087+
self.assertOnlyIn((3, 10), self.detect("from dis import COPY_DICT_WITHOUT_KEYS"))
3088+
3089+
def test_GET_LEN_of_dis(self):
3090+
self.assertOnlyIn((3, 10), self.detect("from dis import GET_LEN"))
3091+
3092+
def test_MATCH_KEYS_of_dis(self):
3093+
self.assertOnlyIn((3, 10), self.detect("from dis import MATCH_KEYS"))
3094+
3095+
def test_MATCH_MAPPING_of_dis(self):
3096+
self.assertOnlyIn((3, 10), self.detect("from dis import MATCH_MAPPING"))
3097+
3098+
def test_MATCH_SEQUENCE_of_dis(self):
3099+
self.assertOnlyIn((3, 10), self.detect("from dis import MATCH_SEQUENCE"))

0 commit comments

Comments
 (0)