Skip to content

Remove Python 3.6 branches from typeshed - #8269

Merged
srittau merged 6 commits into
python:masterfrom
AlexWaygood:36
Jul 11, 2022
Merged

Remove Python 3.6 branches from typeshed#8269
srittau merged 6 commits into
python:masterfrom
AlexWaygood:36

Conversation

@AlexWaygood

@AlexWaygoodAlexWaygood commented Jul 10, 2022

Copy link
Copy Markdown
Member

The first commit here was done using the following script:

Details
#!/usr/bin/env python3importastimportsubprocessimportsysfromcollectionsimportCounterfromcollections.abcimportIteratorfromcontextlibimportcontextmanagerfromdataclassesimportdataclassfromitertoolsimportchainfrompathlibimportPath@dataclassclassNestingCounter:
nesting: int=0@contextmanagerdefenabled(self) ->Iterator[None]:
self.nesting+=1try:
yieldfinally:
self.nesting-=1@propertydefactive(self) ->bool:
"""Determine whether the level of nesting is currently non-zero"""returnbool(self.nesting)
deffix_bad_syntax(path: Path) ->None:
withopen(path) asf:
stub=f.read()
lines=dict(enumerate(stub.splitlines()))
tree=ast.parse(stub)
lines_to_delete: list[int] = []
classOldSyntaxReplacer(ast.NodeVisitor):
def__init__(self) ->None:
self.visiting_orelse=NestingCounter()
self.visiting_class=NestingCounter()
self.single_statement_class=Falseself.class_stmt_has_orelse=False@staticmethoddefget_linenos(node: ast.AST) ->tuple[int, int]:
lineno, end_lineno=node.lineno, node.end_linenoassertisinstance(lineno, int)
assertisinstance(end_lineno, int)
returnlineno, end_linenodefdelete_node(self, node: ast.AST, *, first_line_only: bool=False) ->None:
lineno, end_lineno=self.get_linenos(node)
ifisinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)):
lineno-=len(node.decorator_list)
ifself.visiting_class.activeandself.single_statement_classandnotself.class_stmt_has_orelse:
lines[lineno-2] +=' ...'iffirst_line_only:
lines_to_delete.append(lineno-1)
else:
lines_to_delete.extend(range(lineno-1, end_lineno))
defvisit_ClassDef(self, node: ast.ClassDef) ->None:
old_val=self.single_statement_classiflen(node.body) ==1:
self.single_statement_class=Trueclass_stmt_node=node.body[0]
ifisinstance(class_stmt_node, ast.If):
self.class_stmt_has_orelse=bool(class_stmt_node.orelse)
withself.visiting_class.enabled():
self.generic_visit(node)
self.single_statement_class=old_valdefvisit_If(self, node: ast.If) ->None:
test, body, orelse=node.test, node.body, node.orelseifisinstance(test, ast.Compare):
ifnotast.unparse(test).startswith("sys.version_info "):
self.generic_visit(node)
elifast.unparse(test) =="sys.version_info < (3, 7)":
returnself.delete_node(node)
elifast.unparse(test) =="sys.version_info >= (3, 7)":
ifself.visiting_orelse.active:
lines[node.lineno] =lines[node.lineno].replace("elif sys.version_info >= (3, 7):", "else:")
else:
self.delete_node(node, first_line_only=True)
ifbody:
start, _=self.get_linenos(test)
_, end=self.get_linenos(body[-1])
forlinenoinrange(start, end):
lines[lineno] =lines[lineno][4:]
iforelse:
_, lineno_to_delete=self.get_linenos(body[-1])
line=lines[lineno_to_delete]
whileline.strip() !="else:":
lineno_to_delete+=1line=lines[lineno_to_delete]
lines_to_delete.append(lineno_to_delete)
forchildinorelse:
self.delete_node(child)
forchildinbody:
self.generic_visit(child)
else:
forchildinbody:
self.generic_visit(child)
withself.visiting_orelse.enabled():
forchildinorelse:
self.generic_visit(child)
else:
self.generic_visit(node)
OldSyntaxReplacer().visit(tree)
ifnotlines_to_delete:
returnforlinenoinlines_to_delete:
try:
dellines[lineno]
exceptKeyError:
continuenew_stub='\n'.join(lines.values())
try:
new_tree=ast.parse(new_stub)
except:
print('OLD\n\n')
print('\n'.join(stub.splitlines()[140:150]))
print('\n\nNEW\n\n')
print('\n'.join(new_stub.splitlines()[140:150]))
raisenames_count: Counter[str] =Counter()
classNameFinder(ast.NodeVisitor):
defvisit_Name(self, node: ast.Name) ->None:
names_count[node.id] +=1NameFinder().visit(new_tree)
ifnames_count["sys"] ==1:
fornodeinnew_tree.body:
ifisinstance(node, ast.Import) andnode.names[0].name=="sys":
dellines[node.lineno-1]
new_stub='\n'.join(lines.values())
breakwithopen(path, "w") asf:
f.write(new_stub+"\n")
defmain() ->None:
print("STARTING RUN: Will attempt to fix new syntax in the stubs directory...\n\n")
forpathinchain(Path("stubs").rglob("*.pyi"), Path("stdlib").rglob("*.pyi")):
if"@python2"notinpath.partsand ("protobuf"notinpath.partsor"_pb2"notinstr(path)):
print(f"Attempting to convert {path} to new syntax.")
fix_bad_syntax(path)
print("\n\nSTARTING ISORT...\n\n")
subprocess.run([sys.executable, "-m", "isort", "."])
print("\n\nSTARTING BLACK...\n\n")
subprocess.run([sys.executable, "-m", "black", "."])
print('\n\nRunning "check_new_syntax.py"...\n\n')
subprocess.run([sys.executable, "tests/check_new_syntax.py"])
print("\n\nRunning flake8...\n\n")
subprocess.run([sys.executable, "-m", "flake8", "stdlib stubs"])
if__name__=="__main__":
main()

The second and third commit were done manually.

Closes#6189

@github-actions

This comment has been minimized.

@srittausrittau left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks, one thing I noticed below.

Comment threadstdlib/contextlib.pyi Outdated
IO,
Any,
AsyncContextManager as AbstractAsyncContextManager,
ContextManager as AbstractContextManager,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This does not re-export, according to PEP 484. (Existing type checkers might still re-export due to __all__, but that is undefined behavior.)

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Interesting, I think we're a little inconsistent about that at the moment, e.g. in our stubs for _collections_abc. Anyhow, I've made the change!

@github-actions

Copy link
Copy Markdown
Contributor

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

sphinx (https://github.com/sphinx-doc/sphinx)
+ sphinx/util/typing.py: note: In function "_restify_py36":+ sphinx/util/typing.py:267:26: error: Module has no attribute "GenericMeta"; maybe "Generic"? [attr-defined]+ sphinx/util/typing.py: note: In function "_stringify_py36":+ sphinx/util/typing.py:505:33: error: Module has no attribute "GenericMeta"; maybe "Generic"? [attr-defined]+ sphinx/util/typing.py: note: At top level:+ sphinx/util/typing.py:507: error: Unused "type: ignore" comment+ sphinx/util/typing.py:508: error: Unused "type: ignore" comment+ sphinx/util/typing.py:509: error: Unused "type: ignore" comment+ sphinx/util/typing.py:510: error: Unused "type: ignore" comment+ sphinx/util/typing.py:513: error: Unused "type: ignore" comment+ sphinx/util/typing.py:514: error: Unused "type: ignore" comment

@AlexWaygood
AlexWaygood requested a review from srittauJuly 11, 2022 08:40
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Python 3.6 EOL (not before July 2022)

2 participants

@AlexWaygood@srittau