"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "poetry/utils/setup_reader.py" between
poetry-1.1.15.tar.gz and poetry-1.2.0.tar.gz

About: Poetry is a tool for dependency management and packaging in Python.

setup_reader.py  (poetry-1.1.15):setup_reader.py  (poetry-1.2.0)
from __future__ import annotations
import ast import ast
from configparser import ConfigParser
from pathlib import Path
from typing import Any from typing import Any
from typing import Dict
from typing import Iterable
from typing import List
from typing import Optional
from typing import Tuple
from typing import Union
from poetry.core.semver import Version
from ._compat import PY35
from ._compat import Path
from ._compat import basestring
try:
from configparser import ConfigParser
except ImportError:
from ConfigParser import ConfigParser
class SetupReader(object): from poetry.core.semver.version import Version
class SetupReader:
""" """
Class that reads a setup.py file without executing it. Class that reads a setup.py file without executing it.
""" """
DEFAULT = { DEFAULT: dict[str, Any] = {
"name": None, "name": None,
"version": None, "version": None,
"install_requires": [], "install_requires": [],
"extras_require": {}, "extras_require": {},
"python_requires": None, "python_requires": None,
} }
FILES = ["setup.py", "setup.cfg"] FILES = ["setup.py", "setup.cfg"]
@classmethod @classmethod
def read_from_directory( def read_from_directory(cls, directory: str | Path) -> dict[str, Any]:
cls, directory if isinstance(directory, str):
): # type: (Union[basestring, Path]) -> Dict[str, Union[List, Dict]]
if isinstance(directory, basestring):
directory = Path(directory) directory = Path(directory)
result = cls.DEFAULT.copy() result = cls.DEFAULT.copy()
for filename in cls.FILES: for filename in cls.FILES:
filepath = directory / filename filepath = directory / filename
if not filepath.exists(): if not filepath.exists():
continue continue
new_result = getattr(cls(), "read_{}".format(filename.replace(".", " read_file_func = getattr(cls(), "read_" + filename.replace(".", "_")
_")))( )
filepath new_result = read_file_func(filepath)
)
for key in result.keys(): for key in result.keys():
if new_result[key]: if new_result[key]:
result[key] = new_result[key] result[key] = new_result[key]
return result return result
@classmethod def read_setup_py(self, filepath: str | Path) -> dict[str, Any]:
def _is_empty_result(cls, result): # type: (Dict[str, Any]) -> bool if isinstance(filepath, str):
return (
not result["install_requires"]
and not result["extras_require"]
and not result["python_requires"]
)
def read_setup_py(
self, filepath
): # type: (Union[basestring, Path]) -> Dict[str, Union[List, Dict]]
if not PY35:
return self.DEFAULT
if isinstance(filepath, basestring):
filepath = Path(filepath) filepath = Path(filepath)
with filepath.open(encoding="utf-8") as f: with filepath.open(encoding="utf-8") as f:
content = f.read() content = f.read()
result = {} result: dict[str, Any] = {}
body = ast.parse(content).body body = ast.parse(content).body
setup_call, body = self._find_setup_call(body) setup_call = self._find_setup_call(body)
if not setup_call: if setup_call is None:
return self.DEFAULT return self.DEFAULT
# Inspecting keyword arguments # Inspecting keyword arguments
result["name"] = self._find_single_string(setup_call, body, "name") call, body = setup_call
result["version"] = self._find_single_string(setup_call, body, "version" result["name"] = self._find_single_string(call, body, "name")
) result["version"] = self._find_single_string(call, body, "version")
result["install_requires"] = self._find_install_requires(setup_call, bod result["install_requires"] = self._find_install_requires(call, body)
y) result["extras_require"] = self._find_extras_require(call, body)
result["extras_require"] = self._find_extras_require(setup_call, body)
result["python_requires"] = self._find_single_string( result["python_requires"] = self._find_single_string(
setup_call, body, "python_requires" call, body, "python_requires"
) )
return result return result
def read_setup_cfg( def read_setup_cfg(self, filepath: str | Path) -> dict[str, Any]:
self, filepath
): # type: (Union[basestring, Path]) -> Dict[str, Union[List, Dict]]
parser = ConfigParser() parser = ConfigParser()
parser.read(str(filepath)) parser.read(str(filepath))
name = None name = None
version = None version = None
if parser.has_option("metadata", "name"): if parser.has_option("metadata", "name"):
name = parser.get("metadata", "name") name = parser.get("metadata", "name")
if parser.has_option("metadata", "version"): if parser.has_option("metadata", "version"):
version = Version.parse(parser.get("metadata", "version")).text version = Version.parse(parser.get("metadata", "version")).text
install_requires = [] install_requires = []
extras_require = {} extras_require: dict[str, list[str]] = {}
python_requires = None python_requires = None
if parser.has_section("options"): if parser.has_section("options"):
if parser.has_option("options", "install_requires"): if parser.has_option("options", "install_requires"):
for dep in parser.get("options", "install_requires").split("\n") : for dep in parser.get("options", "install_requires").split("\n") :
dep = dep.strip() dep = dep.strip()
if not dep: if not dep:
continue continue
install_requires.append(dep) install_requires.append(dep)
skipping to change at line 149 skipping to change at line 121
return { return {
"name": name, "name": name,
"version": version, "version": version,
"install_requires": install_requires, "install_requires": install_requires,
"extras_require": extras_require, "extras_require": extras_require,
"python_requires": python_requires, "python_requires": python_requires,
} }
def _find_setup_call( def _find_setup_call(
self, elements self, elements: list[ast.stmt]
): # type: (List[Any]) -> Tuple[Optional[ast.Call], Optional[List[Any]]] ) -> tuple[ast.Call, list[ast.stmt]] | None:
funcdefs = [] funcdefs: list[ast.stmt] = []
for i, element in enumerate(elements): for i, element in enumerate(elements):
if isinstance(element, ast.If) and i == len(elements) - 1: if isinstance(element, ast.If) and i == len(elements) - 1:
# Checking if the last element is an if statement # Checking if the last element is an if statement
# and if it is 'if __name__ == "__main__"' which # and if it is 'if __name__ == "__main__"' which
# could contain the call to setup() # could contain the call to setup()
test = element.test test = element.test
if not isinstance(test, ast.Compare): if not isinstance(test, ast.Compare):
continue continue
left = test.left left = test.left
if not isinstance(left, ast.Name): if not isinstance(left, ast.Name):
continue continue
if left.id != "__name__": if left.id != "__name__":
continue continue
setup_call, body = self._find_sub_setup_call([element]) setup_call = self._find_sub_setup_call([element])
if not setup_call: if setup_call is None:
continue continue
return setup_call, body + elements call, body = setup_call
return call, body + elements
if not isinstance(element, ast.Expr): if not isinstance(element, ast.Expr):
if isinstance(element, ast.FunctionDef): if isinstance(element, ast.FunctionDef):
funcdefs.append(element) funcdefs.append(element)
continue continue
value = element.value value = element.value
if not isinstance(value, ast.Call): if not isinstance(value, ast.Call):
continue continue
func = value.func func = value.func
if not (isinstance(func, ast.Name) and func.id == "setup") and not ( if not (isinstance(func, ast.Name) and func.id == "setup") and not (
isinstance(func, ast.Attribute) isinstance(func, ast.Attribute)
and hasattr(func.value, "id") and getattr(func.value, "id", None) == "setuptools"
and func.value.id == "setuptools"
and func.attr == "setup" and func.attr == "setup"
): ):
continue continue
return value, elements return value, elements
# Nothing, we inspect the function definitions # Nothing, we inspect the function definitions
return self._find_sub_setup_call(funcdefs) return self._find_sub_setup_call(funcdefs)
def _find_sub_setup_call( def _find_sub_setup_call(
self, elements self, elements: list[ast.stmt]
): # type: (List[Any]) -> Tuple[Optional[ast.Call], Optional[List[Any]]] ) -> tuple[ast.Call, list[ast.stmt]] | None:
for element in elements: for element in elements:
if not isinstance(element, (ast.FunctionDef, ast.If)): if not isinstance(element, (ast.FunctionDef, ast.If)):
continue continue
setup_call = self._find_setup_call(element.body) setup_call = self._find_setup_call(element.body)
if setup_call != (None, None): if setup_call is not None:
setup_call, body = setup_call sub_call, body = setup_call
body = elements + body body = elements + body
return setup_call, body return sub_call, body
return None, None return None
def _find_install_requires( def _find_install_requires(self, call: ast.Call, body: list[ast.stmt]) -> li
self, call, body st[str]:
): # type: (ast.Call, Iterable[Any]) -> List[str] install_requires: list[str] = []
install_requires = []
value = self._find_in_call(call, "install_requires") value = self._find_in_call(call, "install_requires")
if value is None: if value is None:
# Trying to find in kwargs # Trying to find in kwargs
kwargs = self._find_call_kwargs(call) kwargs = self._find_call_kwargs(call)
if kwargs is None or not isinstance(kwargs, ast.Name): if kwargs is None or not isinstance(kwargs, ast.Name):
return install_requires return install_requires
variable = self._find_variable_in_body(body, kwargs.id) variable = self._find_variable_in_body(body, kwargs.id)
if not isinstance(variable, (ast.Dict, ast.Call)): if not isinstance(variable, (ast.Dict, ast.Call)):
skipping to change at line 246 skipping to change at line 217
value = self._find_in_call(variable, "install_requires") value = self._find_in_call(variable, "install_requires")
else: else:
value = self._find_in_dict(variable, "install_requires") value = self._find_in_dict(variable, "install_requires")
if value is None: if value is None:
return install_requires return install_requires
if isinstance(value, ast.List): if isinstance(value, ast.List):
for el in value.elts: for el in value.elts:
install_requires.append(el.s) if isinstance(el, ast.Str):
install_requires.append(el.s)
elif isinstance(value, ast.Name): elif isinstance(value, ast.Name):
variable = self._find_variable_in_body(body, value.id) variable = self._find_variable_in_body(body, value.id)
if variable is not None and isinstance(variable, ast.List): if variable is not None and isinstance(variable, ast.List):
for el in variable.elts: for el in variable.elts:
install_requires.append(el.s) if isinstance(el, ast.Str):
install_requires.append(el.s)
return install_requires return install_requires
def _find_extras_require( def _find_extras_require(
self, call, body self, call: ast.Call, body: list[ast.stmt]
): # type: (ast.Call, Iterable[Any]) -> Dict[str, List] ) -> dict[str, list[str]]:
extras_require = {} extras_require: dict[str, list[str]] = {}
value = self._find_in_call(call, "extras_require") value = self._find_in_call(call, "extras_require")
if value is None: if value is None:
# Trying to find in kwargs # Trying to find in kwargs
kwargs = self._find_call_kwargs(call) kwargs = self._find_call_kwargs(call)
if kwargs is None or not isinstance(kwargs, ast.Name): if kwargs is None or not isinstance(kwargs, ast.Name):
return extras_require return extras_require
variable = self._find_variable_in_body(body, kwargs.id) variable = self._find_variable_in_body(body, kwargs.id)
if not isinstance(variable, (ast.Dict, ast.Call)): if not isinstance(variable, (ast.Dict, ast.Call)):
skipping to change at line 287 skipping to change at line 260
return extras_require return extras_require
value = self._find_in_call(variable, "extras_require") value = self._find_in_call(variable, "extras_require")
else: else:
value = self._find_in_dict(variable, "extras_require") value = self._find_in_dict(variable, "extras_require")
if value is None: if value is None:
return extras_require return extras_require
if isinstance(value, ast.Dict): if isinstance(value, ast.Dict):
val: ast.expr | None
for key, val in zip(value.keys, value.values): for key, val in zip(value.keys, value.values):
if not isinstance(key, ast.Str):
continue
if isinstance(val, ast.Name): if isinstance(val, ast.Name):
val = self._find_variable_in_body(body, val.id) val = self._find_variable_in_body(body, val.id)
if isinstance(val, ast.List): if isinstance(val, ast.List):
extras_require[key.s] = [e.s for e in val.elts] extras_require[key.s] = [
e.s for e in val.elts if isinstance(e, ast.Str)
]
elif isinstance(value, ast.Name): elif isinstance(value, ast.Name):
variable = self._find_variable_in_body(body, value.id) variable = self._find_variable_in_body(body, value.id)
if variable is None or not isinstance(variable, ast.Dict): if variable is None or not isinstance(variable, ast.Dict):
return extras_require return extras_require
for key, val in zip(variable.keys, variable.values): for key, val in zip(variable.keys, variable.values):
if not isinstance(key, ast.Str):
continue
if isinstance(val, ast.Name): if isinstance(val, ast.Name):
val = self._find_variable_in_body(body, val.id) val = self._find_variable_in_body(body, val.id)
if isinstance(val, ast.List): if isinstance(val, ast.List):
extras_require[key.s] = [e.s for e in val.elts] extras_require[key.s] = [
e.s for e in val.elts if isinstance(e, ast.Str)
]
return extras_require return extras_require
def _find_single_string( def _find_single_string(
self, call, body, name self, call: ast.Call, body: list[ast.stmt], name: str
): # type: (ast.Call, List[Any], str) -> Optional[str] ) -> str | None:
value = self._find_in_call(call, name) value = self._find_in_call(call, name)
if value is None: if value is None:
# Trying to find in kwargs # Trying to find in kwargs
kwargs = self._find_call_kwargs(call) kwargs = self._find_call_kwargs(call)
if kwargs is None or not isinstance(kwargs, ast.Name): if kwargs is None or not isinstance(kwargs, ast.Name):
return return None
variable = self._find_variable_in_body(body, kwargs.id) variable = self._find_variable_in_body(body, kwargs.id)
if not isinstance(variable, (ast.Dict, ast.Call)): if not isinstance(variable, (ast.Dict, ast.Call)):
return return None
if isinstance(variable, ast.Call): if isinstance(variable, ast.Call):
if not isinstance(variable.func, ast.Name): if not isinstance(variable.func, ast.Name):
return return None
if variable.func.id != "dict": if variable.func.id != "dict":
return return None
value = self._find_in_call(variable, name) value = self._find_in_call(variable, name)
else: else:
value = self._find_in_dict(variable, name) value = self._find_in_dict(variable, name)
if value is None: if value is None:
return return None
if isinstance(value, ast.Str): if isinstance(value, ast.Str):
return value.s return value.s
elif isinstance(value, ast.Name): elif isinstance(value, ast.Name):
variable = self._find_variable_in_body(body, value.id) variable = self._find_variable_in_body(body, value.id)
if variable is not None and isinstance(variable, ast.Str): if variable is not None and isinstance(variable, ast.Str):
return variable.s return variable.s
def _find_in_call(self, call, name): # type: (ast.Call, str) -> Optional[An return None
y]
def _find_in_call(self, call: ast.Call, name: str) -> Any | None:
for keyword in call.keywords: for keyword in call.keywords:
if keyword.arg == name: if keyword.arg == name:
return keyword.value return keyword.value
return None
def _find_call_kwargs(self, call): # type: (ast.Call) -> Optional[Any] def _find_call_kwargs(self, call: ast.Call) -> Any | None:
kwargs = None kwargs = None
for keyword in call.keywords: for keyword in call.keywords:
if keyword.arg is None: if keyword.arg is None:
kwargs = keyword.value kwargs = keyword.value
return kwargs return kwargs
def _find_variable_in_body( def _find_variable_in_body(
self, body, name self, body: list[ast.stmt], name: str
): # type: (Iterable[Any], str) -> Optional[Any] ) -> ast.expr | None:
found = None
for elem in body: for elem in body:
if found:
break
if not isinstance(elem, ast.Assign): if not isinstance(elem, ast.Assign):
continue continue
for target in elem.targets: for target in elem.targets:
if not isinstance(target, ast.Name): if not isinstance(target, ast.Name):
continue continue
if target.id == name: if target.id == name:
return elem.value return elem.value
def _find_in_dict(self, dict_, name): # type: (ast.Call, str) -> Optional[A return None
ny]
def _find_in_dict(self, dict_: ast.Dict, name: str) -> ast.expr | None:
for key, val in zip(dict_.keys, dict_.values): for key, val in zip(dict_.keys, dict_.values):
if isinstance(key, ast.Str) and key.s == name: if isinstance(key, ast.Str) and key.s == name:
return val return val
return None
 End of changes. 44 change blocks. 
99 lines changed or deleted 81 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)