From e09780624fbbaf1ad5839dd3d88bb3609d983b41 Mon Sep 17 00:00:00 2001 From: Dani Pinyol Date: Wed, 29 Dec 2021 18:21:30 +0100 Subject: [PATCH 01/11] Fix failure setting optimize option (#480) --- src/julia/options.py | 2 +- src/julia/tests/test_juliaoptions.py | 2 +- src/julia/tests/test_options.py | 8 +++++++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/julia/options.py b/src/julia/options.py index 5b2728b4..52d93647 100644 --- a/src/julia/options.py +++ b/src/julia/options.py @@ -134,7 +134,7 @@ class JuliaOptions(object): compile = Choices("compile", yes_no_etc("all", "min")) depwarn = Choices("depwarn", yes_no_etc("error")) warn_overwrite = Choices("warn_overwrite", yes_no_etc()) - optimize = Choices("optimize", dict(zip(range(4), range(4)))) + optimize = Choices("optimize", dict(zip(range(4), map(str, range(4))))) inline = Choices("inline", yes_no_etc()) check_bounds = Choices("check_bounds", yes_no_etc()) diff --git a/src/julia/tests/test_juliaoptions.py b/src/julia/tests/test_juliaoptions.py index 9e18ddf2..bb46523d 100644 --- a/src/julia/tests/test_juliaoptions.py +++ b/src/julia/tests/test_juliaoptions.py @@ -11,7 +11,7 @@ (dict(compiled_modules="no"), ["--compiled-modules", "no"]), (dict(depwarn="error"), ["--depwarn", "error"]), (dict(sysimage="PATH"), ["--sysimage", "PATH"]), - (dict(bindir="PATH"), ["--home", "PATH"]), + (dict(optimize=3), ["--optimize", "3"]), ]) # fmt: on def test_as_args(kwargs, args): diff --git a/src/julia/tests/test_options.py b/src/julia/tests/test_options.py index c11e4bd3..09e8c95b 100644 --- a/src/julia/tests/test_options.py +++ b/src/julia/tests/test_options.py @@ -1,4 +1,4 @@ -from julia.options import JuliaOptions, options_docs +from julia.options import JuliaOptions, options_docs, parse_jl_options def parse_options_docs(docs): @@ -23,3 +23,9 @@ def test_options_docs(): odef = optdefs.pop(desc.name) assert odef["domain"] == desc._domain() assert not optdefs + + +def test_parse_jl_options(): + opts = parse_jl_options(["--home", "/home", "--sysimage", "/sys/image", "--optimize", "3"]) + assert opts.home == "/home" + assert opts.sysimage == "/sys/image" From aa8063ee3daf9a199d81f258dfa9a002d16d5bf7 Mon Sep 17 00:00:00 2001 From: Dani Pinyol Date: Wed, 6 Apr 2022 16:30:44 +0200 Subject: [PATCH 02/11] Add threads & min_optlevel julia args now all long opts are generated with "--arg=val" instead of "--arg val" since julia required arguments support both syntaxes, but optional arguments require the first one --- src/julia/options.py | 8 ++++++-- src/julia/tests/test_juliaoptions.py | 2 ++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/julia/options.py b/src/julia/options.py index 52d93647..7faea587 100644 --- a/src/julia/options.py +++ b/src/julia/options.py @@ -134,9 +134,11 @@ class JuliaOptions(object): compile = Choices("compile", yes_no_etc("all", "min")) depwarn = Choices("depwarn", yes_no_etc("error")) warn_overwrite = Choices("warn_overwrite", yes_no_etc()) + min_optlevel = Choices("min_optlevel", dict(zip(range(4), map(str, range(4))))) optimize = Choices("optimize", dict(zip(range(4), map(str, range(4))))) inline = Choices("inline", yes_no_etc()) check_bounds = Choices("check_bounds", yes_no_etc()) + threads = Choices("threads", dict(zip(range(12), map(str, range(12))))) def __init__(self, **kwargs): unsupported = [] @@ -168,8 +170,10 @@ def specified(self): def as_args(self): args = [] for (desc, value) in self.specified(): - args.append(desc.cli_argument_name()) - args.append(value) + if len(desc.cli_argument_name()) == 1: + args.append(desc.cli_argument_name() + str(value)) + else: + args.append(desc.cli_argument_name()+"="+str(value)) return args @classmethod diff --git a/src/julia/tests/test_juliaoptions.py b/src/julia/tests/test_juliaoptions.py index bb46523d..bd2e3c42 100644 --- a/src/julia/tests/test_juliaoptions.py +++ b/src/julia/tests/test_juliaoptions.py @@ -12,6 +12,8 @@ (dict(depwarn="error"), ["--depwarn", "error"]), (dict(sysimage="PATH"), ["--sysimage", "PATH"]), (dict(optimize=3), ["--optimize", "3"]), + (dict(threads=4), ["--threads", "4"]), + (dict(min_optlevel=2), ["--min-optlevel", "2"]), ]) # fmt: on def test_as_args(kwargs, args): From 939d2149c468269b836486a4b59ad006641fa8d2 Mon Sep 17 00:00:00 2001 From: MilesCranmer Date: Wed, 9 Nov 2022 13:59:09 -0500 Subject: [PATCH 03/11] Fix options test --- src/julia/tests/test_juliaoptions.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/julia/tests/test_juliaoptions.py b/src/julia/tests/test_juliaoptions.py index 906bd3b8..f0804dc2 100644 --- a/src/julia/tests/test_juliaoptions.py +++ b/src/julia/tests/test_juliaoptions.py @@ -7,13 +7,13 @@ @pytest.mark.parametrize("kwargs, args", [ ({}, []), (dict(compiled_modules=None), []), - (dict(compiled_modules=False), ["--compiled-modules", "no"]), - (dict(compiled_modules="no"), ["--compiled-modules", "no"]), - (dict(depwarn="error"), ["--depwarn", "error"]), - (dict(sysimage="PATH"), ["--sysimage", "PATH"]), - (dict(optimize=3), ["--optimize", "3"]), - (dict(threads=4), ["--threads", "4"]), - (dict(min_optlevel=2), ["--min-optlevel", "2"]), + (dict(compiled_modules=False), ["--compiled-modules=no"]), + (dict(compiled_modules="no"), ["--compiled-modules=no"]), + (dict(depwarn="error"), ["--depwarn=error"]), + (dict(sysimage="PATH"), ["--sysimage=PATH"]), + (dict(optimize=3), ["--optimize=3"]), + (dict(threads=4), ["--threads=4"]), + (dict(min_optlevel=2), ["--min-optlevel=2"]), ]) # fmt: on def test_as_args(kwargs, args): From f27efd137e758b1b4076f976a98ce719b7989be3 Mon Sep 17 00:00:00 2001 From: MilesCranmer Date: Wed, 9 Nov 2022 14:02:09 -0500 Subject: [PATCH 04/11] Add missing option to docstring --- src/julia/options.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/julia/options.py b/src/julia/options.py index 7faea587..fdc39b9d 100644 --- a/src/julia/options.py +++ b/src/julia/options.py @@ -110,6 +110,9 @@ def yes_no_etc(*etc): warn_overwrite: {True, False, 'yes', 'no'} Enable or disable method overwrite warnings. + +min_optlevel: {0, 1, 2, 3} + Lower bound on the optimization level. """ From 5dd3dcbbf75c51fe20fe6aab1393e5714efac002 Mon Sep 17 00:00:00 2001 From: MilesCranmer Date: Wed, 9 Nov 2022 14:03:39 -0500 Subject: [PATCH 05/11] Add docstring for threads --- src/julia/options.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/julia/options.py b/src/julia/options.py index fdc39b9d..855213c0 100644 --- a/src/julia/options.py +++ b/src/julia/options.py @@ -113,6 +113,9 @@ def yes_no_etc(*etc): min_optlevel: {0, 1, 2, 3} Lower bound on the optimization level. + +threads: int or "auto" + How many threads to use. """ From 3fb8cf5f743e3400a864f275f7abc5295cac0a25 Mon Sep 17 00:00:00 2001 From: MilesCranmer Date: Fri, 11 Nov 2022 14:53:42 -0500 Subject: [PATCH 06/11] Allow arbitrary int for threads --- src/julia/options.py | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/src/julia/options.py b/src/julia/options.py index 855213c0..b1041d5a 100644 --- a/src/julia/options.py +++ b/src/julia/options.py @@ -41,6 +41,26 @@ def _domain(self): # used in test return str +class IntEtc(OptionDescriptor): + def __init__(self, name, *, etc={}): + self.name = name + self.default = etc + + def __set__(self, instance, value): + if instance is None: + raise AttributeError(self.name) + elif value in {None, *self.default} or isinstance(value, int): + setattr(instance, self.dataname, value) + else: + part = f" or {self.default}" if self.default else "" + raise ValueError( + f"Option {self.name} only accepts integers{part}. Got: {value}" + ) + + def _domain(self): + return {int, *self.default} + + class Choices(OptionDescriptor): def __init__(self, name, choicemap, default=None): self.name = name @@ -114,7 +134,7 @@ def yes_no_etc(*etc): min_optlevel: {0, 1, 2, 3} Lower bound on the optimization level. -threads: int or "auto" +threads: {int, 'auto'} How many threads to use. """ @@ -144,7 +164,7 @@ class JuliaOptions(object): optimize = Choices("optimize", dict(zip(range(4), map(str, range(4))))) inline = Choices("inline", yes_no_etc()) check_bounds = Choices("check_bounds", yes_no_etc()) - threads = Choices("threads", dict(zip(range(12), map(str, range(12))))) + threads = IntEtc("threads", etc={"auto"}) def __init__(self, **kwargs): unsupported = [] @@ -179,7 +199,7 @@ def as_args(self): if len(desc.cli_argument_name()) == 1: args.append(desc.cli_argument_name() + str(value)) else: - args.append(desc.cli_argument_name()+"="+str(value)) + args.append(desc.cli_argument_name() + "=" + str(value)) return args @classmethod From 624dc96d778fd1df669a87cfb99a780578d0807c Mon Sep 17 00:00:00 2001 From: MilesCranmer Date: Fri, 11 Nov 2022 15:04:32 -0500 Subject: [PATCH 07/11] Add CLI spec for IntEtc --- src/julia/options.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/julia/options.py b/src/julia/options.py index b1041d5a..21363f65 100644 --- a/src/julia/options.py +++ b/src/julia/options.py @@ -49,10 +49,13 @@ def __init__(self, name, *, etc={}): def __set__(self, instance, value): if instance is None: raise AttributeError(self.name) - elif value in {None, *self.default} or isinstance(value, int): + elif value in self.default or isinstance(value, int): setattr(instance, self.dataname, value) else: - part = f" or {self.default}" if self.default else "" + if self.default: + part = " or " + " ".join(map(str, self.default)) + else: + part = "" raise ValueError( f"Option {self.name} only accepts integers{part}. Got: {value}" ) @@ -60,6 +63,12 @@ def __set__(self, instance, value): def _domain(self): return {int, *self.default} + def cli_argument_spec(self): + return dict( + super(IntEtc, self).cli_argument_spec(), + choices=list(self.default) + ["1", "2", "3", "..."], + ) + class Choices(OptionDescriptor): def __init__(self, name, choicemap, default=None): From daaff7cb20ff9011f229decb60c2790da4ea57e3 Mon Sep 17 00:00:00 2001 From: MilesCranmer Date: Fri, 11 Nov 2022 15:28:42 -0500 Subject: [PATCH 08/11] Get `value=None` working for options --- src/julia/options.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/julia/options.py b/src/julia/options.py index 21363f65..00ba9801 100644 --- a/src/julia/options.py +++ b/src/julia/options.py @@ -49,7 +49,7 @@ def __init__(self, name, *, etc={}): def __set__(self, instance, value): if instance is None: raise AttributeError(self.name) - elif value in self.default or isinstance(value, int): + elif value in {None, *self.default} or isinstance(value, int): setattr(instance, self.dataname, value) else: if self.default: @@ -205,7 +205,9 @@ def specified(self): def as_args(self): args = [] for (desc, value) in self.specified(): - if len(desc.cli_argument_name()) == 1: + if value is None: + ... + elif len(desc.cli_argument_name()) == 1: args.append(desc.cli_argument_name() + str(value)) else: args.append(desc.cli_argument_name() + "=" + str(value)) From b9985eaf848ac7c6da4f32eee0a70d39401a429e Mon Sep 17 00:00:00 2001 From: MilesCranmer Date: Fri, 11 Nov 2022 15:36:00 -0500 Subject: [PATCH 09/11] Ensure Python2.7 is not tested --- src/julia/tests/test_compatible_exe.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/julia/tests/test_compatible_exe.py b/src/julia/tests/test_compatible_exe.py index afa78cf9..13a61c1f 100644 --- a/src/julia/tests/test_compatible_exe.py +++ b/src/julia/tests/test_compatible_exe.py @@ -23,7 +23,7 @@ def discover_other_pythons(): [sys.executable, "--version"], universal_newlines=True, stderr=subprocess.STDOUT ) - candidate_names = ["python", "python2", "python2.7", "python3"] + [ + candidate_names = ["python", "python3"] + [ "python3.{}".format(i) for i in range(20) ] found = {} From e93569232b199c1f826c5d9cb2d2afcc29d4617d Mon Sep 17 00:00:00 2001 From: MilesCranmer Date: Fri, 11 Nov 2022 16:01:45 -0500 Subject: [PATCH 10/11] Apply formatting --- src/julia/tests/test_options.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/julia/tests/test_options.py b/src/julia/tests/test_options.py index 09e8c95b..1ab9cb8c 100644 --- a/src/julia/tests/test_options.py +++ b/src/julia/tests/test_options.py @@ -26,6 +26,8 @@ def test_options_docs(): def test_parse_jl_options(): - opts = parse_jl_options(["--home", "/home", "--sysimage", "/sys/image", "--optimize", "3"]) + opts = parse_jl_options( + ["--home", "/home", "--sysimage", "/sys/image", "--optimize", "3"] + ) assert opts.home == "/home" assert opts.sysimage == "/sys/image" From 2ce534baacd0070d59f251f919259de9cf8ef5a5 Mon Sep 17 00:00:00 2001 From: MilesCranmer Date: Fri, 11 Nov 2022 16:09:38 -0500 Subject: [PATCH 11/11] Test more combinations of options --- src/julia/tests/test_juliaoptions.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/julia/tests/test_juliaoptions.py b/src/julia/tests/test_juliaoptions.py index f0804dc2..34bd9a05 100644 --- a/src/julia/tests/test_juliaoptions.py +++ b/src/julia/tests/test_juliaoptions.py @@ -14,6 +14,9 @@ (dict(optimize=3), ["--optimize=3"]), (dict(threads=4), ["--threads=4"]), (dict(min_optlevel=2), ["--min-optlevel=2"]), + (dict(threads="auto", optimize=3), ["--optimize=3", '--threads=auto']), + (dict(optimize=3, threads="auto"), ["--optimize=3", '--threads=auto']), # passed order doesn't matter + (dict(compiled_modules=None, depwarn="yes"), ["--depwarn=yes"]), ]) # fmt: on def test_as_args(kwargs, args):