Skip to content

Commit

Permalink
Drop Python 3.7
Browse files Browse the repository at this point in the history
  • Loading branch information
AA-Turner committed Sep 27, 2022
1 parent b65f0e4 commit fa9ba26
Show file tree
Hide file tree
Showing 24 changed files with 108 additions and 250 deletions.
16 changes: 0 additions & 16 deletions .circleci/config.yml

This file was deleted.

2 changes: 0 additions & 2 deletions .github/workflows/main.yml
Expand Up @@ -13,8 +13,6 @@ jobs:
fail-fast: false
matrix:
include:
- python: "3.7"
docutils: du15
- python: "3.8"
docutils: du16
- python: "3.9"
Expand Down
2 changes: 1 addition & 1 deletion doc/usage/installation.rst
Expand Up @@ -12,7 +12,7 @@ Installing Sphinx
Overview
--------

Sphinx is written in `Python`__ and supports Python 3.7+. It builds upon the
Sphinx is written in `Python`__ and supports Python 3.8+. It builds upon the
shoulders of many third-party libraries such as `Docutils`__ and `Jinja`__,
which are installed when Sphinx is installed.

Expand Down
6 changes: 2 additions & 4 deletions pyproject.toml
Expand Up @@ -13,7 +13,7 @@ urls.Download = "https://pypi.org/project/Sphinx/"
urls.Homepage = "https://www.sphinx-doc.org/"
urls."Issue tracker" = "https://github.com/sphinx-doc/sphinx/issues"
license.text = "BSD"
requires-python = ">=3.7"
requires-python = ">=3.8"

# Classifiers list: https://pypi.org/classifiers/
classifiers = [
Expand All @@ -30,7 +30,6 @@ classifiers = [
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
Expand Down Expand Up @@ -94,7 +93,6 @@ lint = [
test = [
"pytest>=4.6",
"html5lib",
"typed_ast; python_version < '3.8'",
"cython",
]

Expand Down Expand Up @@ -143,7 +141,7 @@ disallow_incomplete_defs = true
follow_imports = "skip"
ignore_missing_imports = true
no_implicit_optional = true
python_version = "3.7"
python_version = "3.8"
show_column_numbers = true
show_error_codes = true
show_error_context = true
Expand Down
17 changes: 2 additions & 15 deletions sphinx/domains/python.py
@@ -1,9 +1,9 @@
"""The Python domain."""

import ast
import builtins
import inspect
import re
import sys
import typing
from inspect import Parameter
from typing import Any, Dict, Iterable, Iterator, List, NamedTuple, Optional, Tuple, Type, cast
Expand All @@ -21,7 +21,6 @@
from sphinx.domains import Domain, Index, IndexEntry, ObjType
from sphinx.environment import BuildEnvironment
from sphinx.locale import _, __
from sphinx.pycode.ast import ast
from sphinx.pycode.ast import parse as ast_parse
from sphinx.roles import XRefRole
from sphinx.util import logging
Expand Down Expand Up @@ -138,7 +137,7 @@ def unparse(node: ast.AST) -> List[Node]:
return [addnodes.desc_sig_space(),
addnodes.desc_sig_punctuation('', '|'),
addnodes.desc_sig_space()]
elif isinstance(node, ast.Constant): # type: ignore
elif isinstance(node, ast.Constant):
if node.value is Ellipsis:
return [addnodes.desc_sig_punctuation('', "...")]
elif isinstance(node.value, bool):
Expand Down Expand Up @@ -204,18 +203,6 @@ def unparse(node: ast.AST) -> List[Node]:

return result
else:
if sys.version_info[:2] <= (3, 7):
if isinstance(node, ast.Bytes):
return [addnodes.desc_sig_literal_string('', repr(node.s))]
elif isinstance(node, ast.Ellipsis):
return [addnodes.desc_sig_punctuation('', "...")]
elif isinstance(node, ast.NameConstant):
return [nodes.Text(node.value)]
elif isinstance(node, ast.Num):
return [addnodes.desc_sig_literal_string('', repr(node.n))]
elif isinstance(node, ast.Str):
return [addnodes.desc_sig_literal_string('', repr(node.s))]

raise SyntaxError # unsupported syntax

try:
Expand Down
10 changes: 2 additions & 8 deletions sphinx/domains/std.py
@@ -1,10 +1,9 @@
"""The standard domain."""

import re
import sys
from copy import copy
from typing import (TYPE_CHECKING, Any, Callable, Dict, Iterable, Iterator, List, Optional,
Tuple, Type, Union, cast)
from typing import (TYPE_CHECKING, Any, Callable, Dict, Final, Iterable, Iterator, List,
Optional, Tuple, Type, Union, cast)

from docutils import nodes
from docutils.nodes import Element, Node, system_message
Expand All @@ -29,11 +28,6 @@

logger = logging.getLogger(__name__)

if sys.version_info[:2] >= (3, 8):
from typing import Final
else:
Final = Any

# RE for option descriptions
option_desc_re = re.compile(r'((?:/|--|-|\+)?[^\s=]+)(=?\s*.*)')
# RE for grammar tokens
Expand Down
10 changes: 3 additions & 7 deletions sphinx/ext/autodoc/preserve_defaults.py
Expand Up @@ -6,8 +6,6 @@

import ast
import inspect
import sys
from inspect import Parameter
from typing import Any, Dict, List, Optional

from sphinx.application import Sphinx
Expand Down Expand Up @@ -48,8 +46,6 @@ def get_function_def(obj: Any) -> Optional[ast.FunctionDef]:

def get_default_value(lines: List[str], position: ast.AST) -> Optional[str]:
try:
if sys.version_info[:2] <= (3, 7): # only for py38+
return None
if position.lineno == position.end_lineno:
line = lines[position.lineno - 1]
return line[position.col_offset:position.end_col_offset]
Expand Down Expand Up @@ -89,18 +85,18 @@ def update_defvalue(app: Sphinx, obj: Any, bound_method: bool) -> None:
default = defaults.pop(0)
value = get_default_value(lines, default)
if value is None:
value = ast_unparse(default) # type: ignore
value = ast_unparse(default)
parameters[i] = param.replace(default=DefaultValue(value))
else:
default = kw_defaults.pop(0)
value = get_default_value(lines, default)
if value is None:
value = ast_unparse(default) # type: ignore
value = ast_unparse(default)
parameters[i] = param.replace(default=DefaultValue(value))

if bound_method and inspect.ismethod(obj):
# classmethods
cls = inspect.Parameter('cls', Parameter.POSITIONAL_OR_KEYWORD)
cls = inspect.Parameter('cls', inspect.Parameter.POSITIONAL_OR_KEYWORD)
parameters.insert(0, cls)

sig = sig.replace(parameters=parameters)
Expand Down
11 changes: 5 additions & 6 deletions sphinx/ext/autodoc/type_comment.py
@@ -1,12 +1,12 @@
"""Update annotations info of living objects using type_comments."""

import ast
from inspect import Parameter, Signature, getsource
from typing import Any, Dict, List, cast

import sphinx
from sphinx.application import Sphinx
from sphinx.locale import __
from sphinx.pycode.ast import ast
from sphinx.pycode.ast import parse as ast_parse
from sphinx.pycode.ast import unparse as ast_unparse
from sphinx.util import inspect, logging
Expand Down Expand Up @@ -34,10 +34,9 @@ def signature_from_ast(node: ast.FunctionDef, bound_method: bool,
:param bound_method: Specify *node* is a bound method or not
"""
params = []
if hasattr(node.args, "posonlyargs"): # for py38+
for arg in node.args.posonlyargs: # type: ignore
param = Parameter(arg.arg, Parameter.POSITIONAL_ONLY, annotation=arg.type_comment)
params.append(param)
for arg in node.args.posonlyargs:
param = Parameter(arg.arg, Parameter.POSITIONAL_ONLY, annotation=arg.type_comment)
params.append(param)

for arg in node.args.args:
param = Parameter(arg.arg, Parameter.POSITIONAL_OR_KEYWORD,
Expand Down Expand Up @@ -80,7 +79,7 @@ def get_type_comment(obj: Any, bound_method: bool = False) -> Signature:
"""Get type_comment'ed FunctionDef object from living object.
This tries to parse original code for living object and returns
Signature for given *obj*. It requires py38+ or typed_ast module.
Signature for given *obj*.
"""
try:
source = getsource(obj)
Expand Down
2 changes: 1 addition & 1 deletion sphinx/locale/__init__.py
Expand Up @@ -41,7 +41,7 @@ def data(self) -> str: # type: ignore
# replace function from UserString; it instantiates a self.__class__
# for the encoding result

def encode(self, encoding: str = None, errors: str = None) -> bytes: # type: ignore
def encode(self, encoding: str = None, errors: str = None) -> bytes:
if encoding:
if errors:
return self.data.encode(encoding, errors)
Expand Down
62 changes: 12 additions & 50 deletions sphinx/pycode/ast.py
@@ -1,18 +1,8 @@
"""Helpers for AST (Abstract Syntax Tree)."""

import sys
import ast
from typing import Dict, List, Optional, Type, overload

if sys.version_info[:2] >= (3, 8):
import ast
else:
try:
# use typed_ast module if installed
from typed_ast import ast3 as ast
except ImportError:
import ast # type: ignore


OPERATORS: Dict[Type[ast.AST], str] = {
ast.Add: "+",
ast.And: "and",
Expand All @@ -37,21 +27,13 @@


def parse(code: str, mode: str = 'exec') -> "ast.AST":
"""Parse the *code* using the built-in ast or typed_ast libraries.
This enables "type_comments" feature if possible.
"""
"""Parse the *code* using the built-in ast module."""
try:
# type_comments parameter is available on py38+
return ast.parse(code, mode=mode, type_comments=True) # type: ignore
return ast.parse(code, mode=mode, type_comments=True)
except SyntaxError:
# Some syntax error found. To ignore invalid type comments, retry parsing without
# type_comments parameter (refs: https://github.com/sphinx-doc/sphinx/issues/8652).
return ast.parse(code, mode=mode)
except TypeError:
# fallback to ast module.
# typed_ast is used to parse type_comments if installed.
return ast.parse(code, mode=mode)


@overload
Expand Down Expand Up @@ -102,10 +84,8 @@ def _visit_arg_with_default(self, arg: ast.arg, default: Optional[ast.AST]) -> s
def visit_arguments(self, node: ast.arguments) -> str:
defaults: List[Optional[ast.expr]] = list(node.defaults)
positionals = len(node.args)
posonlyargs = 0
if hasattr(node, "posonlyargs"): # for py38+
posonlyargs += len(node.posonlyargs) # type:ignore
positionals += posonlyargs
posonlyargs = len(node.posonlyargs)
positionals += posonlyargs
for _ in range(len(defaults), positionals):
defaults.insert(0, None)

Expand All @@ -114,12 +94,11 @@ def visit_arguments(self, node: ast.arguments) -> str:
kw_defaults.insert(0, None)

args: List[str] = []
if hasattr(node, "posonlyargs"): # for py38+
for i, arg in enumerate(node.posonlyargs): # type: ignore
args.append(self._visit_arg_with_default(arg, defaults[i]))
for i, arg in enumerate(node.posonlyargs):
args.append(self._visit_arg_with_default(arg, defaults[i]))

if node.posonlyargs: # type: ignore
args.append('/')
if node.posonlyargs:
args.append('/')

for i, arg in enumerate(node.args):
args.append(self._visit_arg_with_default(arg, defaults[i + posonlyargs]))
Expand Down Expand Up @@ -155,12 +134,12 @@ def visit_Call(self, node: ast.Call) -> str:
["%s=%s" % (k.arg, self.visit(k.value)) for k in node.keywords])
return "%s(%s)" % (self.visit(node.func), ", ".join(args))

def visit_Constant(self, node: ast.Constant) -> str: # type: ignore
def visit_Constant(self, node: ast.Constant) -> str:
if node.value is Ellipsis:
return "..."
elif isinstance(node.value, (int, float, complex)):
if self.code and sys.version_info[:2] >= (3, 8):
return ast.get_source_segment(self.code, node) # type: ignore
if self.code:
return ast.get_source_segment(self.code, node)
else:
return repr(node.value)
else:
Expand Down Expand Up @@ -219,22 +198,5 @@ def visit_Tuple(self, node: ast.Tuple) -> str:
else:
return "(" + ", ".join(self.visit(e) for e in node.elts) + ")"

if sys.version_info[:2] <= (3, 7):
# these ast nodes were deprecated in python 3.8
def visit_Bytes(self, node: ast.Bytes) -> str:
return repr(node.s)

def visit_Ellipsis(self, node: ast.Ellipsis) -> str:
return "..."

def visit_NameConstant(self, node: ast.NameConstant) -> str:
return repr(node.value)

def visit_Num(self, node: ast.Num) -> str:
return repr(node.n)

def visit_Str(self, node: ast.Str) -> str:
return repr(node.s)

def generic_visit(self, node):
raise NotImplementedError('Unable to parse %s object' % type(node).__name__)

0 comments on commit fa9ba26

Please sign in to comment.