defl/tests.old/test_argparse.py

383 lines
9.9 KiB
Python
Raw Permalink Normal View History

2024-09-11 11:14:03 -04:00
#!/usr/bin/env python
import enum, pathlib
import itertools
import os
import re
import sys
from dataclasses import KW_ONLY, dataclass, field
from functools import partial, partialmethod
from operator import itemgetter
from time import sleep
import defl
from defl import CLIError, Null, Path, Undefined, cl, log, Assert, ArgTypeHint
2025-03-09 09:17:53 -04:00
from defl._argsFromObject_ import _DefaultParserNotSpecified, _MalformedArguments
2024-09-11 11:14:03 -04:00
from defl._typing_ import *
from defl.testing_ import Test, Tester, TestState
tester = Tester(name=__file__)
# TODO test choices
2025-03-09 09:17:53 -04:00
2024-09-11 11:14:03 -04:00
@dataclass(slots=True, kw_only=True, frozen=False)
class CLI:
def main(_, bb: str = 'cat'):
return locals()
def cli1(_, *extra):
return locals()
2025-03-09 09:17:53 -04:00
def cli2(_, aa: bool, bb: str = 'cat', /, cc: bool = True, notTyped=1, dd: list[str] | None = None, *extra):
2024-09-11 11:14:03 -04:00
return locals()
def cli3(_, aa: str, *bb, cc: str = 'default', dd: bool = False) -> str:
return locals()
2025-03-09 09:17:53 -04:00
def excludeMe(_): ...
2024-09-11 11:14:03 -04:00
def listInput(_, aa: list[str], bb: str, cc: str, *extra):
return locals()
2025-03-09 09:17:53 -04:00
2024-09-11 11:14:03 -04:00
mapSubParsersDefault = {'c1': 'cli1', 'c2': 'cli2', '-': 'main'}
2025-03-09 09:17:53 -04:00
2024-09-11 11:14:03 -04:00
def newAFO(parseIn, mapSubParsers=True):
return defl.cliAutoParse(
CLI,
exclude=['excludeMe'],
parseIn=parseIn,
runNow=false,
autoExit=False,
mapSubParsers=mapSubParsersDefault if mapSubParsers else {},
)
2025-03-09 09:17:53 -04:00
2024-09-11 11:14:03 -04:00
@tester.add()
def retTrue():
try:
afo = newAFO(['script.py'], mapSubParsers=False)
assert false, f'should not be reached'
except _DefaultParserNotSpecified:
pass
2025-03-09 09:17:53 -04:00
2024-09-11 11:14:03 -04:00
@tester.add()
def retTrue():
try:
afo = newAFO(['script.py', 'does not exist', 'extra'])
assert false, f'should not be reached'
except _DefaultParserNotSpecified:
pass
2025-03-09 09:17:53 -04:00
2024-09-11 11:14:03 -04:00
@tester.add()
def retTrue():
try:
afo = newAFO(['script.py', 'cli3', 'extra', 'extra'])
assert false, f'should not be reached'
except _MalformedArguments:
pass
2025-03-09 09:17:53 -04:00
2024-09-11 11:14:03 -04:00
@tester.add()
def retTrue():
afo = newAFO(['script.py', 'cli3', '-a', 'test'])
res = afo._parser._subparsers._group_actions[0].choices
a = res['cli3']._option_string_actions
assert type(a['-a']).__name__ == '_StoreAction'
assert type(a['-c']).__name__ == '_StoreAction'
assert type(a['-d']).__name__ == '_StoreTrueAction'
assert a['-a'].dest == 'aa'
assert a['-c'].dest == 'cc'
assert a['-d'].dest == 'dd'
assert a['-a'].nargs == None
assert a['-c'].nargs == None
assert a['-d'].nargs == 0
assert a['-a'].const is None
assert a['-c'].const is None
assert a['-d'].const is True
assert a['-a'].default is None
assert a['-c'].default == 'default'
assert a['-d'].default is False
assert a['-a'].type is str
assert a['-c'].type is str
assert a['-d'].type is None
assert a['-a'].choices is None
assert a['-c'].choices is None
assert a['-d'].choices is None
assert a['-a'].required is True
assert a['-c'].required is False
assert a['-d'].required is False
2025-03-09 09:17:53 -04:00
2024-09-11 11:14:03 -04:00
@tester.add()
def retTrue():
afo = newAFO(['script.py', 'cli2', 'test', '-d', '1', '-d', '2', '-b', 'dog', 'e1', 'e2', 'e3'])
# subParseFunc = [x['func'] for x in theD['_subParserList']]
# assert subParseFunc == ['cli1', 'cli2', 'main', '__root__']
assert isinstance(afo.theObj, CLI)
par = afo._parser
assert par.prog == 'test_argparse.py'
res = afo._parser._subparsers._group_actions[0].choices
assert set(res.keys()) == set(['cli1', 'c1', 'cli2', 'c2', 'cli3', 'main', 'listInput', '-'])
# for k, v in res.items():
# print(k, '\t', v)
root = afo._parser._option_string_actions
assert root['-z'].option_strings == ['-z', '--log']
assert type(root['-z']).__name__ == '_StoreAction'
assert root['-z'].dest == 'log'
assert root['-z'].nargs is None
assert root['-z'].const is None
assert root['-z'].const is None
assert root['-z'].default == 'info'
assert root['-z'].type == str
assert root['-z'].choices is None
assert root['-z'].required is False
# == cli1 arg
a = res['cli2']._option_string_actions
assert a['-a'].option_strings == ['-a', '--aa']
assert a['--aa'].option_strings == ['-a', '--aa']
assert a['-b'].option_strings == ['-b', '--bb']
assert a['--bb'].option_strings == ['-b', '--bb']
assert a['-c'].option_strings == ['-c', '--cc']
assert a['--cc'].option_strings == ['-c', '--cc']
assert a['-d'].option_strings == ['-d', '--dd']
assert a['--dd'].option_strings == ['-d', '--dd']
assert type(a['-a']).__name__ == '_StoreTrueAction', type(a['-a']).__name__
assert type(a['-b']).__name__ == '_StoreAction'
assert type(a['-c']).__name__ == '_StoreFalseAction'
assert type(a['-d']).__name__ == '_AppendAction'
assert a['-a'].dest == 'aa'
assert a['-b'].dest == 'bb'
assert a['-c'].dest == 'cc'
assert a['-d'].dest == 'dd'
assert a['-a'].nargs == 0, a['-a'].nargs
assert a['-b'].nargs is None
assert a['-c'].nargs == 0
assert a['-d'].nargs == 1
assert a['-a'].const is True, a['-a'].const
assert a['-b'].const is None
assert a['-c'].const is False
assert a['-d'].const is None
assert a['-a'].default is False
assert a['-b'].default == 'cat', a['-b'].default
assert a['-c'].default is True
assert a['-d'].default is None
assert a['-a'].type is None
assert a['-b'].type == str
assert a['-c'].type is None
assert a['-d'].type is None
assert a['-a'].choices is None
assert a['-b'].choices is None
assert a['-c'].choices is None
assert a['-d'].choices is None
assert a['-a'].required is False
assert a['-b'].required is False
assert a['-c'].required is False
assert a['-d'].required is False
res = afo.run()
2025-03-09 09:17:53 -04:00
(res['aa'] == False,)
(res['bb'] == 'dog',)
(res['cc'] == True,)
(res['notTyped'] == 1,)
(res['dd'] == ['1', '2'],)
2024-09-11 11:14:03 -04:00
res['extra'] == ('test', 'e1', 'e2', 'e3')
2025-03-09 09:17:53 -04:00
2024-09-11 11:14:03 -04:00
@tester.add()
def retTrue():
afo = newAFO(['script.py', 'main', '-b', 'newflag'])
afo.run()
assert afo.result['bb'] == 'newflag', afo.result
2025-03-09 09:17:53 -04:00
2024-09-11 11:14:03 -04:00
@tester.add()
def onFail():
afo = newAFO(['script.py', 'main', 'extra', 'extra'])
try:
res = afo.run()
assert false, f'should not be reached: {res}'
except CLIError as e:
assert re.search(r'Subparser .* does not accept extra arguments', str(e))
2025-03-09 09:17:53 -04:00
2024-09-11 11:14:03 -04:00
@tester.add()
def onFail():
afo = newAFO(['script.py', 'main', 'extra', 'extra'])
try:
res = afo.run()
assert false, f'should not be reached: {res}'
except CLIError as e:
assert re.search(r'does not accept extra arguments', str(e)), str(e)
2025-03-09 09:17:53 -04:00
2024-09-11 11:14:03 -04:00
@tester.add()
def extraArgs():
afo = newAFO(['script.py', 'cli1', '1', '2'])
res = afo.run()
assert res['extra'] == ('1', '2')
2025-03-09 09:17:53 -04:00
2024-09-11 11:14:03 -04:00
@tester.add()
def listArg():
2025-03-09 09:17:53 -04:00
afo = newAFO(
[
'script.py',
'listInput',
'-a',
'a1',
'e1',
'-b' 'b1',
'-a',
'a2',
'e2',
'-c',
'c1',
'-a',
'a3',
'-c',
'c2',
'e3',
]
)
2024-09-11 11:14:03 -04:00
res = afo.run()
del res['_']
Assert(res).eq({'aa': ['a1', 'a2', 'a3'], 'bb': 'b1', 'cc': 'c2', 'extra': ('e1', 'e2', 'e3')})
2025-03-09 09:17:53 -04:00
2024-09-11 11:14:03 -04:00
@dataclass(slots=True, kw_only=True, frozen=False)
class CLI2:
def f1(_, test: bool = False):
2025-03-09 09:17:53 -04:00
print('CLI2.f1')
assert defl.amCliEntryPoint() is test, (defl.amCliEntryPoint(), test)
2024-09-11 11:14:03 -04:00
_.f2()
_.f3()
def f2(_, test: bool = False):
2025-03-09 09:17:53 -04:00
print('CLI2.f2')
assert defl.amCliEntryPoint() is test, (defl.amCliEntryPoint(), test)
2024-09-11 11:14:03 -04:00
_.f3()
def f3(_, test: bool = False):
2025-03-09 09:17:53 -04:00
print('CLI2.f3')
assert defl.amCliEntryPoint() is test, (defl.amCliEntryPoint(), test)
2024-09-11 11:14:03 -04:00
@dataclass(slots=True, kw_only=True, frozen=False)
class CLI3:
2025-03-09 09:17:53 -04:00
def f1(_):
print('CLI3.f1')
2024-09-11 11:14:03 -04:00
assert defl.amCliEntryPoint()
CLI_STEM = True
_.f2()
_.f3()
2025-03-09 09:17:53 -04:00
def f2(_):
print('CLI3.f2')
2024-09-11 11:14:03 -04:00
assert defl.amCliEntryPoint()
CLI_STEM = True
_.f3()
2025-03-09 09:17:53 -04:00
def f3(_):
print('CLI3.f3')
2024-09-11 11:14:03 -04:00
assert defl.amCliEntryPoint()
_.f4()
def f4(_, test: bool = False):
2025-03-09 09:17:53 -04:00
print('CLI3.f4')
assert defl.amCliEntryPoint() is test, (defl.amCliEntryPoint(), test)
2024-09-11 11:14:03 -04:00
@tester.add()
def testEntryPoint():
part = partial(defl.cliAutoParse, CLI2, runNow=True, autoExit=False)
res = part(exclude=['excludeMe'], parseIn=['script.py', 'f1', '-t'])
res = part(exclude=['excludeMe'], parseIn=['script.py', 'f2', '-t'])
res = part(exclude=['excludeMe'], parseIn=['script.py', 'f3', '-t'])
2025-03-09 09:17:53 -04:00
2024-09-11 11:14:03 -04:00
@tester.add()
def testEntryPoint():
part = partial(defl.cliAutoParse, CLI3, runNow=True, autoExit=False)
res = part(exclude=['excludeMe'], parseIn=['script.py', 'f1'])
res = part(exclude=['excludeMe'], parseIn=['script.py', 'f2'])
res = part(exclude=['excludeMe'], parseIn=['script.py', 'f3'])
res = part(exclude=['excludeMe'], parseIn=['script.py', 'f4', '-t'])
2025-03-09 09:17:53 -04:00
2024-09-11 11:14:03 -04:00
@tester.add()
def argTypeHint():
C = NewType('test', list[int])
D = GenericAlias(int, list[int])
class Color(enum.StrEnum):
Red = enum.auto()
Green = enum.auto()
Blue = enum.auto()
@dataclass(slots=True, kw_only=True, frozen=False)
class CLI:
def a(a: int):
return a
def b(a: Color):
return a
def c(a: C):
return a
def d(a: D):
return a
def e(a: bool):
return a
def f(a: str):
return a
def g(a: pathlib.Path):
return a
def h(a: ArgTypeHint(typ=int)):
return a
def i(a: ArgTypeHint(typ=int, choices=[1, 2, 3])):
return a
def j(a: ArgTypeHint(typ=int, choices=[1, 2, 3], default=1)):
return a
res = partial(defl.cliAutoParse, CLI, runNow=True, autoExit=False)
2025-03-09 09:17:53 -04:00
2024-09-11 11:14:03 -04:00
log.info(tester.run())
tester.exitWithStatus()