Skip to content

Commit 467a359

Browse files
authored
Avoid using Python lib classes in tests when not necessary (#928)
1 parent 5559c81 commit 467a359

7 files changed

Lines changed: 407 additions & 368 deletions

File tree

jsonargparse_tests/test_core.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import os
55
import pickle
66
import sys
7-
from calendar import Calendar
87
from contextlib import redirect_stderr
98
from io import StringIO
109
from pathlib import Path
@@ -948,6 +947,10 @@ def test_print_config_reuse_name():
948947
assert json_or_yaml_load(out) == {"x": 1}
949948

950949

950+
class Subclass:
951+
pass
952+
953+
951954
def test_default_config_files(parser, subtests, tmp_cwd):
952955
default_config_file = tmp_cwd / "defaults.yaml"
953956
default_config_file.write_text(json_or_yaml_dump({"op1": "from default config file"}))
@@ -969,8 +972,8 @@ def test_default_config_files(parser, subtests, tmp_cwd):
969972

970973
with subtests.test("get_default"):
971974
assert parser.get_default("op1") == "from default config file"
972-
parser.add_subclass_arguments(Calendar, "cal")
973-
assert parser.get_default("cal") is None
975+
parser.add_subclass_arguments(Subclass, "cls")
976+
assert parser.get_default("cls") is None
974977

975978
with subtests.test("set invalid"):
976979
with pytest.raises(ValueError) as ctx:

jsonargparse_tests/test_link_arguments.py

Lines changed: 70 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
from __future__ import annotations
22

33
import json
4-
from calendar import Calendar, TextCalendar
54
from dataclasses import dataclass
6-
from importlib.util import find_spec
75
from typing import Any, Callable, List, Mapping, Optional, Union
86

97
import pytest
@@ -89,34 +87,39 @@ def a_prod(a):
8987
ctx.match('Parser key "b.v2"')
9088

9189

90+
class BaseC:
91+
def __init__(self, p: int = 0):
92+
self.p = p
93+
94+
95+
class SubC(BaseC):
96+
pass
97+
98+
9299
def test_on_parse_compute_fn_subclass_spec(parser, subtests):
93100
parser.add_argument("--cfg", action="config")
94-
parser.add_argument("--cal1", type=Calendar, default=lazy_instance(TextCalendar))
95-
parser.add_argument("--cal2", type=Calendar, default=lazy_instance(Calendar))
101+
parser.add_argument("--obj1", type=BaseC, default=lazy_instance(SubC))
102+
parser.add_argument("--obj2", type=BaseC, default=lazy_instance(BaseC))
96103
parser.link_arguments(
97-
"cal1",
98-
"cal2.init_args.firstweekday",
99-
compute_fn=lambda c: c.init_args.firstweekday + 1,
104+
"obj1",
105+
"obj2.init_args.p",
106+
compute_fn=lambda c: c.init_args.p + 1,
100107
)
101108

102109
with subtests.test("from config and default init_args"):
103-
cfg = parser.parse_args(['--cfg={"cal1": "Calendar"}'])
104-
assert cfg.cal1.init_args.firstweekday == 0
105-
assert cfg.cal2.init_args.firstweekday == 1
110+
cfg = parser.parse_args(['--cfg={"obj1": "BaseC"}'])
111+
assert cfg.obj1.init_args.p == 0
112+
assert cfg.obj2.init_args.p == 1
106113

107114
with subtests.test("from given init_args"):
108-
cfg = parser.parse_args(["--cal1.init_args.firstweekday=2"])
109-
assert cfg.cal1.init_args.firstweekday == 2
110-
assert cfg.cal2.init_args.firstweekday == 3
115+
cfg = parser.parse_args(["--obj1.init_args.p=2"])
116+
assert cfg.obj1.init_args.p == 2
117+
assert cfg.obj2.init_args.p == 3
111118

112119
with subtests.test("invalid init parameter"):
113-
parser.set_defaults(cal1=None)
114-
with pytest.raises(ArgumentError) as ctx:
115-
parser.parse_args(["--cal1.firstweekday=-"])
116-
if find_spec("typeshed_client"):
117-
ctx.match('Parser key "cal1"')
118-
else:
119-
ctx.match("Call to compute_fn of link")
120+
parser.set_defaults(obj1=None)
121+
with pytest.raises(ArgumentError, match='Parser key "obj1"'):
122+
parser.parse_args(["--obj1.p=-"])
120123

121124

122125
class ClassA:
@@ -312,46 +315,46 @@ class ClassF:
312315
def __init__(
313316
self,
314317
v: Union[int, str] = 1,
315-
c: Optional[Calendar] = None,
318+
c: Optional[BaseC] = None,
316319
):
317320
self.c = c
318321

319322

320323
def test_on_parse_add_subclass_arguments_with_instantiate_false(parser, subtests):
321324
parser.add_subclass_arguments(ClassF, "f")
322-
parser.add_subclass_arguments(Calendar, "c", instantiate=False)
325+
parser.add_subclass_arguments(BaseC, "c", instantiate=False)
323326
parser.link_arguments("c", "f.init_args.c")
324327

325328
f_value = {"class_path": f"{__name__}.ClassF"}
326329
c_value = {
327-
"class_path": "calendar.Calendar",
330+
"class_path": f"{__name__}.BaseC",
328331
"init_args": {
329-
"firstweekday": 3,
332+
"p": 3,
330333
},
331334
}
332335

333336
with subtests.test("parse_args"):
334337
cfg = parser.parse_args([f"--f={json.dumps(f_value)}", f"--c={json.dumps(c_value)}"])
335338
assert cfg.c.as_dict() == {
336-
"class_path": "calendar.Calendar",
337-
"init_args": {"firstweekday": 3},
339+
"class_path": f"{__name__}.BaseC",
340+
"init_args": {"p": 3},
338341
}
339342
assert cfg.c == cfg.f.init_args.c
340343

341344
with subtests.test("class instantiation"):
342345
init = parser.instantiate(cfg)
343346
assert isinstance(init.c, Namespace)
344347
assert isinstance(init.f, ClassF)
345-
assert isinstance(init.f.c, Calendar)
346-
assert init.f.c.firstweekday == 3
348+
assert isinstance(init.f.c, BaseC)
349+
assert init.f.c.p == 3
347350

348351
with subtests.test("dump removal of target"):
349352
dump = json_or_yaml_load(parser.dump(cfg))
350353
assert "c" not in dump["f"]["init_args"]
351354

352355
with subtests.test("dump keep target"):
353356
dump = json_or_yaml_load(parser.dump(cfg, skip_link_targets=False))
354-
assert dump["f"]["init_args"]["c"] == {"class_path": "calendar.Calendar", "init_args": {"firstweekday": 3}}
357+
assert dump["f"]["init_args"]["c"] == {"class_path": f"{__name__}.BaseC", "init_args": {"p": 3}}
355358

356359

357360
class ClassD:
@@ -369,16 +372,16 @@ def return_dict(value: dict):
369372
return value
370373

371374
parser.add_subclass_arguments(ClassD, "d")
372-
parser.add_subclass_arguments(Calendar, "c")
375+
parser.add_subclass_arguments(BaseC, "c")
373376
parser.link_arguments("c", "d.init_args.a1", compute_fn=return_dict)
374377
parser.link_arguments("c", "d.init_args.a2")
375378
parser.link_arguments("c", "d.init_args.a3")
376379

377380
d_value = {"class_path": f"{__name__}.ClassD"}
378381
c_value = {
379-
"class_path": "calendar.Calendar",
382+
"class_path": f"{__name__}.BaseC",
380383
"init_args": {
381-
"firstweekday": 3,
384+
"p": 3,
382385
},
383386
}
384387

@@ -388,7 +391,7 @@ def return_dict(value: dict):
388391

389392
init = parser.instantiate(cfg)
390393
assert isinstance(init.d, ClassD)
391-
assert isinstance(init.c, Calendar)
394+
assert isinstance(init.c, BaseC)
392395

393396

394397
def test_on_parse_add_subclass_help_group_title(parser):
@@ -636,78 +639,78 @@ def test_on_instantiate_link_from_subclass_with_compute_fn():
636639

637640

638641
class ClassN:
639-
def __init__(self, calendar: Calendar):
640-
self.calendar = calendar # pragma: no cover
642+
def __init__(self, obj: BaseC):
643+
self.obj = obj # pragma: no cover
641644

642645

643646
def test_on_parse_and_instantiate_link_entire_instance(parser):
644-
parser.add_argument("--firstweekday", type=int)
647+
parser.add_argument("--p", type=int)
645648
parser.add_class_arguments(ClassN, "n", instantiate=False)
646-
parser.add_class_arguments(Calendar, "c")
647-
parser.link_arguments("firstweekday", "c.firstweekday", apply_on="parse")
648-
parser.link_arguments("c", "n.calendar", apply_on="instantiate")
649+
parser.add_class_arguments(BaseC, "c")
650+
parser.link_arguments("p", "c.p", apply_on="parse")
651+
parser.link_arguments("c", "n.obj", apply_on="instantiate")
649652

650-
cfg = parser.parse_args(["--firstweekday=2"])
651-
assert cfg == Namespace(c=Namespace(firstweekday=2), firstweekday=2)
653+
cfg = parser.parse_args(["--p=2"])
654+
assert cfg == Namespace(c=Namespace(p=2), p=2)
652655
init = parser.instantiate(cfg)
653656
assert isinstance(init.n, Namespace)
654-
assert isinstance(init.c, Calendar)
655-
assert init.c is init.n.calendar
657+
assert isinstance(init.c, BaseC)
658+
assert init.c is init.n.obj
656659

657660

658661
class ClassM:
659-
def __init__(self, calendars: List[Calendar]):
660-
self.calendars = calendars
662+
def __init__(self, objs: List[BaseC]):
663+
self.objs = objs
661664

662665

663666
def test_on_instantiate_link_multi_source(parser):
664667
def as_list(*items):
665668
return [*items]
666669

667670
parser.add_class_arguments(ClassM, "m")
668-
parser.add_class_arguments(Calendar, "c.one")
669-
parser.add_class_arguments(TextCalendar, "c.two")
670-
parser.link_arguments(("c.one", "c.two"), "m.calendars", apply_on="instantiate", compute_fn=as_list)
671+
parser.add_class_arguments(BaseC, "c.one")
672+
parser.add_class_arguments(SubC, "c.two")
673+
parser.link_arguments(("c.one", "c.two"), "m.objs", apply_on="instantiate", compute_fn=as_list)
671674

672675
cfg = parser.parse_args([])
673-
assert cfg.as_dict() == {"c": {"one": {"firstweekday": 0}, "two": {"firstweekday": 0}}}
676+
assert cfg.as_dict() == {"c": {"one": {"p": 0}, "two": {"p": 0}}}
674677
init = parser.instantiate(cfg)
675-
assert isinstance(init.c.one, Calendar)
676-
assert isinstance(init.c.two, TextCalendar)
677-
assert init.m.calendars == [init.c.one, init.c.two]
678+
assert isinstance(init.c.one, BaseC)
679+
assert isinstance(init.c.two, SubC)
680+
assert init.m.objs == [init.c.one, init.c.two]
678681

679682

680683
class ClassP:
681-
def __init__(self, firstweekday: int = 1):
682-
self.calendar = Calendar(firstweekday=firstweekday)
684+
def __init__(self, p: int = 1):
685+
self.obj = BaseC(p=p)
683686

684687

685688
class ClassQ:
686-
def __init__(self, calendar: Calendar, q2: int = 2):
687-
self.calendar = calendar
689+
def __init__(self, obj: BaseC, q2: int = 2):
690+
self.obj = obj
688691

689692

690693
def test_on_instantiate_link_object_in_attribute(parser):
691694
parser.add_class_arguments(ClassP, "p")
692695
parser.add_class_arguments(ClassQ, "q")
693-
parser.link_arguments("p.calendar", "q.calendar", apply_on="instantiate")
696+
parser.link_arguments("p.obj", "q.obj", apply_on="instantiate")
694697

695-
cfg = parser.parse_args(["--p.firstweekday=2", "--q.q2=3"])
696-
assert cfg.p == Namespace(firstweekday=2)
698+
cfg = parser.parse_args(["--p.p=2", "--q.q2=3"])
699+
assert cfg.p == Namespace(p=2)
697700
assert cfg.q == Namespace(q2=3)
698701
init = parser.instantiate(cfg)
699-
assert init.p.calendar is init.q.calendar
700-
assert init.q.calendar.firstweekday == 2
702+
assert init.p.obj is init.q.obj
703+
assert init.q.obj.p == 2
701704

702705

703706
def test_on_parse_link_entire_subclass(parser):
704707
parser.add_class_arguments(ClassN, "n")
705708
parser.add_class_arguments(ClassQ, "q")
706-
parser.link_arguments("n.calendar", "q.calendar", apply_on="parse")
709+
parser.link_arguments("n.obj", "q.obj", apply_on="parse")
707710

708-
cal = {"class_path": "Calendar", "init_args": {"firstweekday": 4}}
709-
cfg = parser.parse_args([f"--n.calendar={json.dumps(cal)}", "--q.q2=7"])
710-
assert cfg.n.calendar == cfg.q.calendar
711+
obj = {"class_path": f"{__name__}.BaseC", "init_args": {"p": 4}}
712+
cfg = parser.parse_args([f"--n.obj={json.dumps(obj)}", "--q.q2=7"])
713+
assert cfg.n.obj == cfg.q.obj
711714
assert cfg.q.q2 == 7
712715

713716

@@ -1086,8 +1089,8 @@ def test_on_parse_link_failure_invalid_source_attribute(parser):
10861089
parser.add_class_arguments(ClassP, "p")
10871090
parser.add_class_arguments(ClassQ, "q")
10881091
with pytest.raises(ValueError) as ctx:
1089-
parser.link_arguments("p.calendar", "q.calendar", apply_on="parse")
1090-
ctx.match('key "p.calendar"')
1092+
parser.link_arguments("p.obj", "q.obj", apply_on="parse")
1093+
ctx.match('key "p.obj"')
10911094

10921095

10931096
def test_on_instantiate_link_failure_cycle_self():

jsonargparse_tests/test_parameter_resolvers.py

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import calendar
44
import inspect
55
import xml.dom
6-
from calendar import Calendar
76
from random import shuffle
87
from typing import Any, Callable, Dict, List, Optional, Union
98
from unittest.mock import patch
@@ -361,19 +360,28 @@ def __init__(self, params: List[int], lr: float, **kwargs): # pragma: no cover
361360
self.lr = lr
362361

363362

363+
class BaseC:
364+
def __init__(self, p: int = 0):
365+
self.p = p
366+
367+
368+
class SubC(BaseC):
369+
pass
370+
371+
364372
class ClassInstanceDefaults:
365373
def __init__(
366374
self,
367375
layers: int,
368376
number: float = 0.2,
369377
elements: Callable[..., List[int]] = lambda *a: list(a),
370378
node: Callable[[], xml.dom.Node] = lambda: xml.dom.Node(),
371-
cal1: Calendar = Calendar(firstweekday=1),
372-
cal2: Calendar = calendar.TextCalendar(2),
379+
inst1: BaseC = BaseC(p=1),
380+
inst2: BaseC = SubC(2),
373381
opt1: Callable[[List[int]], Optimizer] = lambda p: SGD(p, lr=0.01),
374382
opt2: Callable[[List[int]], Optimizer] = lambda p: SGD(p, 0.02),
375383
opt3: Callable[[List[int]], Optimizer] = lambda p, lr=0.1: SGD(p, lr=lr), # type: ignore[misc]
376-
opt4: Callable[[List[int]], Optimizer] = lambda p: Calendar(firstweekday=3), # type: ignore[assignment,return-value]
384+
opt4: Callable[[List[int]], Optimizer] = lambda p: BaseC(p=3), # type: ignore[assignment,return-value]
377385
**kwargs,
378386
):
379387
"""
@@ -382,8 +390,8 @@ def __init__(
382390
number: help for number
383391
elements: help for elements
384392
node: help for node
385-
cal1: help for cal1
386-
cal2: help for cal2
393+
inst1: help for inst1
394+
inst2: help for inst2
387395
opt1: help for opt1
388396
opt2: help for opt2
389397
opt3: help for opt3
@@ -708,8 +716,8 @@ def test_get_params_class_instance_defaults(subtests):
708716
"number",
709717
"elements",
710718
"node",
711-
"cal1",
712-
"cal2",
719+
"inst1",
720+
"inst2",
713721
"opt1",
714722
"opt2",
715723
"opt3",
@@ -722,10 +730,10 @@ def test_get_params_class_instance_defaults(subtests):
722730
assert is_lambda(params[2].default)
723731
with subtests.test("supported defaults"):
724732
assert params[3].default == dict(class_path="xml.dom.Node")
725-
assert params[4].default == dict(class_path="calendar.Calendar", init_args=dict(firstweekday=1))
733+
assert params[4].default == dict(class_path=f"{__name__}.BaseC", init_args=dict(p=1))
726734
assert params[6].default == dict(class_path=f"{__name__}.SGD", init_args=dict(lr=0.01))
727735
with subtests.test("unsupported defaults"):
728-
assert isinstance(params[5].default, calendar.TextCalendar)
736+
assert isinstance(params[5].default, SubC)
729737
assert is_lambda(params[7].default)
730738
assert is_lambda(params[9].default)
731739
with subtests.test("invalid defaults"):

0 commit comments

Comments
 (0)