11from __future__ import annotations
22
33import json
4- from calendar import Calendar , TextCalendar
54from dataclasses import dataclass
6- from importlib .util import find_spec
75from typing import Any , Callable , List , Mapping , Optional , Union
86
97import 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+
9299def 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
122125class 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
320323def 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
357360class 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
394397def 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
638641class 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
643646def 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
658661class 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
663666def 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
680683class 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
685688class 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
690693def 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
703706def 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
10931096def test_on_instantiate_link_failure_cycle_self ():
0 commit comments