Skip to content

Commit

Permalink
fix: tighten AST to call only
Browse files Browse the repository at this point in the history
  • Loading branch information
henryiii committed Jan 23, 2021
1 parent be71178 commit 01d8901
Show file tree
Hide file tree
Showing 4 changed files with 24 additions and 27 deletions.
9 changes: 4 additions & 5 deletions cibuildwheel/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,12 +159,11 @@ def main() -> None:
test_extras = get_option_from_environment('CIBW_TEST_EXTRAS', platform=platform, default='')
build_verbosity_str = get_option_from_environment('CIBW_BUILD_VERBOSITY', platform=platform, default='')

setup_py = package_dir / 'setup.py'
setup_cfg = package_dir / 'setup.cfg'
pyproject_toml = package_dir / 'pyproject.toml'
package_files = {'setup.py', 'setup.cfg', 'pyproject.toml'}

if not pyproject_toml.exists() and not setup_cfg.exists() and not setup_py.exists():
print('cibuildwheel: Could not find setup.py, setup.cfg or pyproject.toml at root of package', file=sys.stderr)
if not any(package_dir.joinpath(name).exists() for name in package_files):
names = ', '.join(sorted(package_files, reverse=True))
print(f'cibuildwheel: Could not find any of {{{names}}} at root of package', file=sys.stderr)
sys.exit(2)

# Passing this in as an environment variable will override pyproject.toml, setup.cfg, or setup.py
Expand Down
37 changes: 17 additions & 20 deletions cibuildwheel/projectfiles.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import sys
from configparser import ConfigParser
from pathlib import Path
from typing import Any, Dict, Optional
from typing import Any, Optional

import toml

Expand All @@ -11,6 +11,8 @@

def get_constant(x: ast.Str) -> str:
return x.s


else:
Constant = ast.Constant

Expand All @@ -21,24 +23,23 @@ def get_constant(x: ast.Constant) -> Any:
class Analyzer(ast.NodeVisitor):
def __init__(self) -> None:
self.requires_python: Optional[str] = None
self.constants: Dict[str, str] = {}

def visit_Assign(self, node: ast.Assign) -> None:
for target in node.targets:
if (
isinstance(target, ast.Name)
and isinstance(node.value, Constant)
and isinstance(get_constant(node.value), str)
):
self.constants[target.id] = get_constant(node.value)
def visit(self, content: ast.AST) -> None:
for node in ast.walk(content):
for child in ast.iter_child_nodes(node):
child.parent = node # type: ignore
super().visit(content)

def visit_keyword(self, node: ast.keyword) -> None:
self.generic_visit(node)
if node.arg == "python_requires":
if isinstance(node.value, Constant):
# Must not be nested in an if or other structure
# This will be Module -> Expr -> Call -> keyword
if (
not hasattr(node.parent.parent.parent, "parent") # type: ignore
and isinstance(node.value, Constant)
):
self.requires_python = get_constant(node.value)
elif isinstance(node.value, ast.Name):
self.requires_python = self.constants.get(node.value.id)


def setup_py_python_requires(content: str) -> Optional[str]:
Expand All @@ -54,27 +55,23 @@ def setup_py_python_requires(content: str) -> Optional[str]:
def get_requires_python_str(package_dir: Path) -> Optional[str]:
"Return the python requires string from the most canonical source available, or None"

setup_py = package_dir / 'setup.py'
setup_cfg = package_dir / 'setup.cfg'
pyproject_toml = package_dir / 'pyproject.toml'

# Read in from pyproject.toml:project.requires-python
try:
info = toml.load(pyproject_toml)
info = toml.load(package_dir / 'pyproject.toml')
return str(info['project']['requires-python'])
except (FileNotFoundError, KeyError, IndexError, TypeError):
pass

# Read in from setup.cfg:options.python_requires
try:
config = ConfigParser()
config.read(setup_cfg)
config.read(package_dir / 'setup.cfg')
return str(config['options']['python_requires'])
except (FileNotFoundError, KeyError, IndexError, TypeError):
pass

try:
with open(setup_py) as f:
with open(package_dir / 'setup.py') as f:
return setup_py_python_requires(f.read())
except FileNotFoundError:
pass
Expand Down
1 change: 1 addition & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ dev =
requests
typing-extensions
rich>=9.6
mypy>=0.800

[options.packages.find]
include =
Expand Down
4 changes: 2 additions & 2 deletions unit_test/projectfiles_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ def test_read_setup_py_assign(tmp_path):
)
"""))

assert setup_py_python_requires(tmp_path.joinpath("setup.py").read_text()) == "3.21"
assert get_requires_python_str(tmp_path) == "3.21"
assert setup_py_python_requires(tmp_path.joinpath("setup.py").read_text()) is None
assert get_requires_python_str(tmp_path) is None


def test_read_setup_py_None(tmp_path):
Expand Down

0 comments on commit 01d8901

Please sign in to comment.