From 2a01f314e1f4e0091e4bab2ddb498b4e7c789045 Mon Sep 17 00:00:00 2001 From: Avasam Date: Mon, 25 Nov 2024 17:29:14 -0500 Subject: [PATCH] Coerce Distribution.script_args to list --- distutils/core.py | 5 ++++- distutils/dist.py | 4 +++- distutils/fancy_getopt.py | 6 ++++-- distutils/tests/test_dist.py | 6 ++++++ 4 files changed, 17 insertions(+), 4 deletions(-) diff --git a/distutils/core.py b/distutils/core.py index bc06091a..bd62546b 100644 --- a/distutils/core.py +++ b/distutils/core.py @@ -6,9 +6,12 @@ really defined in distutils.dist and distutils.cmd. """ +from __future__ import annotations + import os import sys import tokenize +from collections.abc import Iterable from .cmd import Command from .debug import DEBUG @@ -215,7 +218,7 @@ def run_commands(dist): return dist -def run_setup(script_name, script_args=None, stop_after="run"): +def run_setup(script_name, script_args: Iterable[str] | None = None, stop_after="run"): """Run a setup script in a somewhat controlled environment, and return the Distribution instance that drives things. This is useful if you need to find out the distribution meta-data (passed as diff --git a/distutils/dist.py b/distutils/dist.py index 8e1e6d0b..b633a622 100644 --- a/distutils/dist.py +++ b/distutils/dist.py @@ -169,7 +169,7 @@ def __init__(self, attrs=None): # noqa: C901 # and sys.argv[1:], but they can be overridden when the caller is # not necessarily a setup script run from the command-line. self.script_name = None - self.script_args = None + self.script_args: list[str] | None = None # 'command_options' is where we store command options between # parsing them (from config files, the command-line, etc.) and when @@ -269,6 +269,8 @@ def __init__(self, attrs=None): # noqa: C901 self.want_user_cfg = True if self.script_args is not None: + # Coerce any possible iterable from attrs into a list + self.script_args = list(self.script_args) for arg in self.script_args: if not arg.startswith('-'): break diff --git a/distutils/fancy_getopt.py b/distutils/fancy_getopt.py index 4ea89603..c4aeaf23 100644 --- a/distutils/fancy_getopt.py +++ b/distutils/fancy_getopt.py @@ -8,6 +8,8 @@ * options set attributes of a passed-in object """ +from __future__ import annotations + import getopt import re import string @@ -219,7 +221,7 @@ def _grok_option_table(self): # noqa: C901 self.short_opts.append(short) self.short2long[short[0]] = long - def getopt(self, args=None, object=None): # noqa: C901 + def getopt(self, args: Sequence[str] | None = None, object=None): # noqa: C901 """Parse command-line options in args. Store as attributes on object. If 'args' is None or not supplied, uses 'sys.argv[1:]'. If @@ -375,7 +377,7 @@ def print_help(self, header=None, file=None): file.write(line + "\n") -def fancy_getopt(options, negative_opt, object, args): +def fancy_getopt(options, negative_opt, object, args: Sequence[str] | None): parser = FancyGetopt(options) parser.set_negative_aliases(negative_opt) return parser.getopt(args, object) diff --git a/distutils/tests/test_dist.py b/distutils/tests/test_dist.py index 4d78a198..7f44777e 100644 --- a/distutils/tests/test_dist.py +++ b/distutils/tests/test_dist.py @@ -246,6 +246,12 @@ def test_find_config_files_disable(self, temp_home): # make sure --no-user-cfg disables the user cfg file assert len(all_files) - 1 == len(files) + def test_script_args_list_coercion(self): + d = Distribution(attrs={'script_args': ('build', '--no-user-cfg')}) + + # make sure script_args is a list even if it started as a different iterable + assert d.script_args == ['build', '--no-user-cfg'] + @pytest.mark.skipif( 'platform.system() == "Windows"', reason='Windows does not honor chmod 000',