Add classes for Python function arguments

This commit is contained in:
2026-04-11 13:33:42 +02:00
parent d0e4ae54c3
commit 91cecae230
6 changed files with 508 additions and 2 deletions
+1
View File
@@ -16,3 +16,4 @@
- Add string representation for python namespace objects
- Add `PythonDocumentationGenerator` method to collect all namespaces
- Add class for existing files
- Add classes for Python function arguments
+152
View File
@@ -0,0 +1,152 @@
# Copyright 2026 jCloud Services GbR
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import annotations
from enum import Enum
from typing import Union
import ast
from ...utils import assert_that_is_instance
from ...exceptions import InvalidPythonIdentifierError, InvalidPythonAnnotationError
import keyword
import types
__all__ = [
'PythonArgumentKind',
'PythonFunctionArgumentDefault',
'PythonFunctionArgument',
'PythonASTArgumentsListParser'
]
class PythonArgumentKind(Enum):
NORMAL = 0
POSITIONAL_ONLY = 1
KEYWORD_ONLY = 2
VARARG = 3
KWARGS = 4
class PythonFunctionArgumentDefault:
'''
Represents the default value of a Python function argument.
:param value: The value
:type value: ast.expr
'''
def __init__(self, value: ast.expr) -> None:
assert_that_is_instance(value, ast.expr)
self.value = value
def __eq__(self, value: PythonFunctionArgumentDefault) -> bool:
if not isinstance(value, PythonFunctionArgumentDefault):
return False
return ast.dump(value.value, include_attributes = False) == ast.dump(self.value, include_attributes = False)
class PythonFunctionArgument:
'''
Represents an argument of a python function.
:param name: The name of the argument.
:type name: str
:param kind: The kind of the argument.
:type kind: ArgumentKind
:param default: The default value of the argument.
:type default: Union[PythonFunctionArgumentDefault, None]
:param annotation: The type annotation of the argument.
:type annotation: Union[str, None]
'''
def __init__(self, name: str, kind: PythonArgumentKind, default: Union[PythonFunctionArgumentDefault, None], annotation: Union[str, None]) -> None:
assert_that_is_instance(name, str)
assert_that_is_instance(kind, PythonArgumentKind)
assert_that_is_instance(default, (PythonFunctionArgumentDefault, types.NoneType))
assert_that_is_instance(annotation, (str, types.NoneType))
# check whether name is a valid identifier
if not name or not name.isidentifier() or keyword.iskeyword(name):
raise InvalidPythonIdentifierError('invalid identifier', identifier = name)
# check whether the annotation is a valid annotation
# Currently, it is only checked whether the parameter is not
# empty.
if annotation is not None and not annotation:
raise InvalidPythonAnnotationError('invalid annotation', annotation = annotation)
self.name = name
self.kind = kind
self.default = default
self.annotation = annotation
def __eq__(self, value: PythonFunctionArgument) -> bool:
if not isinstance(value, PythonFunctionArgument):
return False
return self.name == value.name and self.kind == value.kind and self.default == value.default and self.annotation == value.annotation
def __repr__(self) -> str:
return type(self).__name__ + repr((
self.name,
self.kind,
self.default,
self.annotation
))
class PythonASTArgumentsListParser:
'''
A parser for making ``PythonFunctionArgument`` objects from an
``ast.arguments`` arguments list.
:param ast_arguments_list: The ``ast.arguments`` arguments list.
:type ast_arguments_list: ast.arguments
'''
def __init__(self, ast_arguments_list: ast.arguments) -> None:
self.ast_arguments_list = ast_arguments_list
def to_argument_list(self) -> list[PythonFunctionArgument]:
'''
Converts the AST arguments list to a list of python function
argument objects.
:return: The list of python function argument objects.
:rtype: list[PythonFunctionArgument]
'''
arguments = []
for arg in self.ast_arguments_list.posonlyargs:
if arg.annotation is None:
arguments.append(PythonFunctionArgument(arg.arg, PythonArgumentKind.POSITIONAL_ONLY, None, None))
else:
arguments.append(PythonFunctionArgument(arg.arg, PythonArgumentKind.POSITIONAL_ONLY, None, arg.annotation.id))
for arg in self.ast_arguments_list.args:
if arg.annotation is None:
arguments.append(PythonFunctionArgument(arg.arg, PythonArgumentKind.NORMAL, None, None))
else:
arguments.append(PythonFunctionArgument(arg.arg, PythonArgumentKind.NORMAL, None, arg.annotation.id))
if self.ast_arguments_list.vararg is not None:
if self.ast_arguments_list.vararg.annotation is None:
arguments.append(PythonFunctionArgument(self.ast_arguments_list.vararg.arg, PythonArgumentKind.VARARG, None, None))
else:
arguments.append(PythonFunctionArgument(self.ast_arguments_list.vararg.arg, PythonArgumentKind.VARARG, None, self.ast_arguments_list.vararg.annotation.id))
for arg in self.ast_arguments_list.kwonlyargs:
if arg.annotation is None:
arguments.append(PythonFunctionArgument(arg.arg, PythonArgumentKind.KEYWORD_ONLY, None, None))
else:
arguments.append(PythonFunctionArgument(arg.arg, PythonArgumentKind.KEYWORD_ONLY, None, arg.annotation.id))
if self.ast_arguments_list.kwarg is not None:
if self.ast_arguments_list.kwarg.annotation is None:
arguments.append(PythonFunctionArgument(self.ast_arguments_list.kwarg.arg, PythonArgumentKind.KWARGS, None, None))
else:
arguments.append(PythonFunctionArgument(self.ast_arguments_list.kwarg.arg, PythonArgumentKind.KWARGS, None, self.ast_arguments_list.kwarg.annotation.id))
return arguments
+32
View File
@@ -29,3 +29,35 @@ class NamespaceError(ValueError):
class InvalidNamespaceError(NamespaceError): ...
class NamespaceNotFoundError(NamespaceError): ...
class NamespaceExistsError(NamespaceError): ...
class PythonIdentifierError(ValueError):
'''
Base class for Python identifier errors.
'''
def __init__(self, *args: object, identifier: str = '') -> None:
super().__init__(*args)
self.identifier = identifier
def __str__(self):
if not self.args:
return ''
else:
return f'{self.args[0]}{": " if self.identifier and self.args[0] else ""}{self.identifier if self.args[0] else ""}'
class InvalidPythonIdentifierError(PythonIdentifierError): ...
class PythonAnnotationError(ValueError):
'''
Base class for Python annotation errors.
'''
def __init__(self, *args: object, annotation: str = '') -> None:
super().__init__(*args)
self.annotation = annotation
def __str__(self):
if not self.args:
return ''
else:
return f'{self.args[0]}{": " if self.annotation and self.args[0] else ""}{self.annotation if self.args[0] else ""}'
class InvalidPythonAnnotationError(PythonAnnotationError): ...
@@ -0,0 +1,163 @@
# Copyright 2026 jCloud Services GbR
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from src.jcloud_docsgen.core.python.arguments import PythonASTArgumentsListParser, PythonFunctionArgument, PythonArgumentKind
import pytest
import ast
def argument_list(argument_list: str) -> ast.arguments:
'''
Returns an AST argument list from the argument list source code
:param argument_list: The argument list.
:type argument_list: str
:return: The AST argument list.
:rtype: ast.arguments
'''
return ast.parse('def func(' + argument_list + '): ...').body[0].args
@pytest.mark.parametrize('ast_arguments_list,expected', [
(argument_list('a'), [PythonFunctionArgument('a', PythonArgumentKind.NORMAL, None, None)]),
(argument_list('a: str'), [PythonFunctionArgument('a', PythonArgumentKind.NORMAL, None, 'str')]),
(argument_list('a: str, b'), [
PythonFunctionArgument('a', PythonArgumentKind.NORMAL, None, 'str'),
PythonFunctionArgument('b', PythonArgumentKind.NORMAL, None, None)
]),
(argument_list('a: str, b: int'), [
PythonFunctionArgument('a', PythonArgumentKind.NORMAL, None, 'str'),
PythonFunctionArgument('b', PythonArgumentKind.NORMAL, None, 'int')
]),
(argument_list('a, b: int'), [
PythonFunctionArgument('a', PythonArgumentKind.NORMAL, None, None),
PythonFunctionArgument('b', PythonArgumentKind.NORMAL, None, 'int')
]),
(argument_list('a, b, *args'), [
PythonFunctionArgument('a', PythonArgumentKind.NORMAL, None, None),
PythonFunctionArgument('b', PythonArgumentKind.NORMAL, None, None),
PythonFunctionArgument('args', PythonArgumentKind.VARARG, None, None)
]),
(argument_list('a: int, b, *args'), [
PythonFunctionArgument('a', PythonArgumentKind.NORMAL, None, 'int'),
PythonFunctionArgument('b', PythonArgumentKind.NORMAL, None, None),
PythonFunctionArgument('args', PythonArgumentKind.VARARG, None, None)
]),
(argument_list('a, b: str, *args'), [
PythonFunctionArgument('a', PythonArgumentKind.NORMAL, None, None),
PythonFunctionArgument('b', PythonArgumentKind.NORMAL, None, 'str'),
PythonFunctionArgument('args', PythonArgumentKind.VARARG, None, None)
]),
(argument_list('a: int, b: str, *args'), [
PythonFunctionArgument('a', PythonArgumentKind.NORMAL, None, 'int'),
PythonFunctionArgument('b', PythonArgumentKind.NORMAL, None, 'str'),
PythonFunctionArgument('args', PythonArgumentKind.VARARG, None, None)
]),
(argument_list('a: int, b: str, *args: float'), [
PythonFunctionArgument('a', PythonArgumentKind.NORMAL, None, 'int'),
PythonFunctionArgument('b', PythonArgumentKind.NORMAL, None, 'str'),
PythonFunctionArgument('args', PythonArgumentKind.VARARG, None, 'float')
]),
(argument_list('a: int, b, *args: float'), [
PythonFunctionArgument('a', PythonArgumentKind.NORMAL, None, 'int'),
PythonFunctionArgument('b', PythonArgumentKind.NORMAL, None, None),
PythonFunctionArgument('args', PythonArgumentKind.VARARG, None, 'float')
]),
(argument_list('a: int, *args: float'), [
PythonFunctionArgument('a', PythonArgumentKind.NORMAL, None, 'int'),
PythonFunctionArgument('args', PythonArgumentKind.VARARG, None, 'float')
]),
(argument_list('a: int, /, **kwargs'), [
PythonFunctionArgument('a', PythonArgumentKind.POSITIONAL_ONLY, None, 'int'),
PythonFunctionArgument('kwargs', PythonArgumentKind.KWARGS, None, None)
]),
(argument_list('a: int, **kwargs: str'), [
PythonFunctionArgument('a', PythonArgumentKind.NORMAL, None, 'int'),
PythonFunctionArgument('kwargs', PythonArgumentKind.KWARGS, None, 'str')
]),
(argument_list('a: int, /, b, **kwargs'), [
PythonFunctionArgument('a', PythonArgumentKind.POSITIONAL_ONLY, None, 'int'),
PythonFunctionArgument('b', PythonArgumentKind.NORMAL, None, None),
PythonFunctionArgument('kwargs', PythonArgumentKind.KWARGS, None, None)
]),
(argument_list('a: int, /, b'), [
PythonFunctionArgument('a', PythonArgumentKind.POSITIONAL_ONLY, None, 'int'),
PythonFunctionArgument('b', PythonArgumentKind.NORMAL, None, None),
]),
(argument_list('a: int, /, b, *, c'), [
PythonFunctionArgument('a', PythonArgumentKind.POSITIONAL_ONLY, None, 'int'),
PythonFunctionArgument('b', PythonArgumentKind.NORMAL, None, None),
PythonFunctionArgument('c', PythonArgumentKind.KEYWORD_ONLY, None, None),
]),
(argument_list('a, b, *, c'), [
PythonFunctionArgument('a', PythonArgumentKind.NORMAL, None, None),
PythonFunctionArgument('b', PythonArgumentKind.NORMAL, None, None),
PythonFunctionArgument('c', PythonArgumentKind.KEYWORD_ONLY, None, None),
]),
(argument_list('a, b, *args, c'), [
PythonFunctionArgument('a', PythonArgumentKind.NORMAL, None, None),
PythonFunctionArgument('b', PythonArgumentKind.NORMAL, None, None),
PythonFunctionArgument('args', PythonArgumentKind.VARARG, None, None),
PythonFunctionArgument('c', PythonArgumentKind.KEYWORD_ONLY, None, None),
]),
(argument_list('a, b, *args, c, **kwargs'), [
PythonFunctionArgument('a', PythonArgumentKind.NORMAL, None, None),
PythonFunctionArgument('b', PythonArgumentKind.NORMAL, None, None),
PythonFunctionArgument('args', PythonArgumentKind.VARARG, None, None),
PythonFunctionArgument('c', PythonArgumentKind.KEYWORD_ONLY, None, None),
PythonFunctionArgument('kwargs', PythonArgumentKind.KWARGS, None, None),
]),
(argument_list('a, b, /, *, c, **kwargs'), [
PythonFunctionArgument('a', PythonArgumentKind.POSITIONAL_ONLY, None, None),
PythonFunctionArgument('b', PythonArgumentKind.POSITIONAL_ONLY, None, None),
PythonFunctionArgument('c', PythonArgumentKind.KEYWORD_ONLY, None, None),
PythonFunctionArgument('kwargs', PythonArgumentKind.KWARGS, None, None),
]),
(argument_list('a, b, /, c, *, d, **kwargs'), [
PythonFunctionArgument('a', PythonArgumentKind.POSITIONAL_ONLY, None, None),
PythonFunctionArgument('b', PythonArgumentKind.POSITIONAL_ONLY, None, None),
PythonFunctionArgument('c', PythonArgumentKind.NORMAL, None, None),
PythonFunctionArgument('d', PythonArgumentKind.KEYWORD_ONLY, None, None),
PythonFunctionArgument('kwargs', PythonArgumentKind.KWARGS, None, None),
]),
(argument_list('a: str, b: int, /, c: float, d: list, *, e: tuple, f: dict, **kwargs: set'), [
PythonFunctionArgument('a', PythonArgumentKind.POSITIONAL_ONLY, None, 'str'),
PythonFunctionArgument('b', PythonArgumentKind.POSITIONAL_ONLY, None, 'int'),
PythonFunctionArgument('c', PythonArgumentKind.NORMAL, None, 'float'),
PythonFunctionArgument('d', PythonArgumentKind.NORMAL, None, 'list'),
PythonFunctionArgument('e', PythonArgumentKind.KEYWORD_ONLY, None, 'tuple'),
PythonFunctionArgument('f', PythonArgumentKind.KEYWORD_ONLY, None, 'dict'),
PythonFunctionArgument('kwargs', PythonArgumentKind.KWARGS, None, 'set'),
]),
(argument_list('a: str, b: int, /, c: float, d: list, *args: bytes, e: tuple, f: dict, **kwargs: set'), [
PythonFunctionArgument('a', PythonArgumentKind.POSITIONAL_ONLY, None, 'str'),
PythonFunctionArgument('b', PythonArgumentKind.POSITIONAL_ONLY, None, 'int'),
PythonFunctionArgument('c', PythonArgumentKind.NORMAL, None, 'float'),
PythonFunctionArgument('d', PythonArgumentKind.NORMAL, None, 'list'),
PythonFunctionArgument('args', PythonArgumentKind.VARARG, None, 'bytes'),
PythonFunctionArgument('e', PythonArgumentKind.KEYWORD_ONLY, None, 'tuple'),
PythonFunctionArgument('f', PythonArgumentKind.KEYWORD_ONLY, None, 'dict'),
PythonFunctionArgument('kwargs', PythonArgumentKind.KWARGS, None, 'set'),
]),
(argument_list('a: str, b: int, /, *args: bytes, c: tuple, d: dict, **kwargs: set'), [
PythonFunctionArgument('a', PythonArgumentKind.POSITIONAL_ONLY, None, 'str'),
PythonFunctionArgument('b', PythonArgumentKind.POSITIONAL_ONLY, None, 'int'),
PythonFunctionArgument('args', PythonArgumentKind.VARARG, None, 'bytes'),
PythonFunctionArgument('c', PythonArgumentKind.KEYWORD_ONLY, None, 'tuple'),
PythonFunctionArgument('d', PythonArgumentKind.KEYWORD_ONLY, None, 'dict'),
PythonFunctionArgument('kwargs', PythonArgumentKind.KWARGS, None, 'set'),
]),
])
def test_PythonASTArgumentsListParser_to_argument_list(ast_arguments_list, expected):
assert PythonASTArgumentsListParser(ast_arguments_list).to_argument_list() == expected
@@ -0,0 +1,103 @@
# Copyright 2026 jCloud Services GbR
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from src.jcloud_docsgen.core.python.arguments import PythonFunctionArgument, PythonArgumentKind, PythonFunctionArgumentDefault
from src.jcloud_docsgen.exceptions import InvalidPythonIdentifierError, InvalidPythonAnnotationError
import ast
import pytest
@pytest.mark.parametrize('name,kind,default,annotation,expected_exception,expected_exception_msg', [
(None, PythonArgumentKind.NORMAL, None, None, TypeError, 'expected \'str\', got \'NoneType\''),
(1, PythonArgumentKind.NORMAL, None, None, TypeError, 'expected \'str\', got \'int\''),
(42, PythonArgumentKind.NORMAL, None, None, TypeError, 'expected \'str\', got \'int\''),
(4.2, PythonArgumentKind.NORMAL, None, None, TypeError, 'expected \'str\', got \'float\''),
(4.2, PythonArgumentKind.NORMAL, None, None, TypeError, 'expected \'str\', got \'float\''),
('a', PythonArgumentKind.NORMAL, 1, None, TypeError, 'expected either \'PythonFunctionArgumentDefault\' or \'NoneType\', got \'int\''),
('a', PythonArgumentKind.NORMAL, None, 1, TypeError, 'expected either \'str\' or \'NoneType\', got \'int\''),
('a', 0, None, None, TypeError, 'expected \'PythonArgumentKind\', got \'int\''),
('a', PythonArgumentKind.NORMAL, None, '', InvalidPythonAnnotationError, 'invalid annotation'),
('', PythonArgumentKind.NORMAL, None, None, InvalidPythonIdentifierError, 'invalid identifier'),
('.', PythonArgumentKind.NORMAL, None, None, InvalidPythonIdentifierError, 'invalid identifier: .'),
('#', PythonArgumentKind.NORMAL, None, None, InvalidPythonIdentifierError, 'invalid identifier: #'),
('1a', PythonArgumentKind.NORMAL, None, None, InvalidPythonIdentifierError, 'invalid identifier: 1a'),
('1_', PythonArgumentKind.NORMAL, None, None, InvalidPythonIdentifierError, 'invalid identifier: 1_'),
('1,', PythonArgumentKind.NORMAL, None, None, InvalidPythonIdentifierError, 'invalid identifier: 1,'),
(',', PythonArgumentKind.NORMAL, None, None, InvalidPythonIdentifierError, 'invalid identifier: ,'),
(':', PythonArgumentKind.NORMAL, None, None, InvalidPythonIdentifierError, 'invalid identifier: :'),
('-', PythonArgumentKind.NORMAL, None, None, InvalidPythonIdentifierError, 'invalid identifier: -'),
(';', PythonArgumentKind.NORMAL, None, None, InvalidPythonIdentifierError, 'invalid identifier: ;'),
('|', PythonArgumentKind.NORMAL, None, None, InvalidPythonIdentifierError, 'invalid identifier: |'),
('<', PythonArgumentKind.NORMAL, None, None, InvalidPythonIdentifierError, 'invalid identifier: <'),
('>', PythonArgumentKind.NORMAL, None, None, InvalidPythonIdentifierError, 'invalid identifier: >'),
('a,', PythonArgumentKind.NORMAL, None, None, InvalidPythonIdentifierError, 'invalid identifier: a,'),
(',a', PythonArgumentKind.NORMAL, None, None, InvalidPythonIdentifierError, 'invalid identifier: ,a'),
('a:', PythonArgumentKind.NORMAL, None, None, InvalidPythonIdentifierError, 'invalid identifier: a:'),
(':a', PythonArgumentKind.NORMAL, None, None, InvalidPythonIdentifierError, 'invalid identifier: :a'),
('a-', PythonArgumentKind.NORMAL, None, None, InvalidPythonIdentifierError, 'invalid identifier: a-'),
('-a', PythonArgumentKind.NORMAL, None, None, InvalidPythonIdentifierError, 'invalid identifier: -a'),
('a;', PythonArgumentKind.NORMAL, None, None, InvalidPythonIdentifierError, 'invalid identifier: a;'),
(';a', PythonArgumentKind.NORMAL, None, None, InvalidPythonIdentifierError, 'invalid identifier: ;a'),
('a|', PythonArgumentKind.NORMAL, None, None, InvalidPythonIdentifierError, 'invalid identifier: a|'),
('|a', PythonArgumentKind.NORMAL, None, None, InvalidPythonIdentifierError, 'invalid identifier: |a'),
('a<', PythonArgumentKind.NORMAL, None, None, InvalidPythonIdentifierError, 'invalid identifier: a<'),
('<a', PythonArgumentKind.NORMAL, None, None, InvalidPythonIdentifierError, 'invalid identifier: <a'),
('a>', PythonArgumentKind.NORMAL, None, None, InvalidPythonIdentifierError, 'invalid identifier: a>'),
('>a', PythonArgumentKind.NORMAL, None, None, InvalidPythonIdentifierError, 'invalid identifier: >a'),
('class', PythonArgumentKind.NORMAL, None, None, InvalidPythonIdentifierError, 'invalid identifier: class'),
('def', PythonArgumentKind.NORMAL, None, None, InvalidPythonIdentifierError, 'invalid identifier: def'),
('lambda', PythonArgumentKind.NORMAL, None, None, InvalidPythonIdentifierError, 'invalid identifier: lambda'),
('None', PythonArgumentKind.NORMAL, None, None, InvalidPythonIdentifierError, 'invalid identifier: None'),
('True', PythonArgumentKind.NORMAL, None, None, InvalidPythonIdentifierError, 'invalid identifier: True'),
])
def test_PythonFunctionArgument_exceptions(name, kind, default, annotation, expected_exception, expected_exception_msg):
with pytest.raises(expected_exception) as exc_info:
PythonFunctionArgument(name, kind, default, annotation)
assert str(exc_info.value) == expected_exception_msg
@pytest.mark.parametrize('name', [
'a',
'_a',
'a1',
'a0',
'a_',
'_',
'_abc',
'abc',
'abc_',
'match',
'case',
'type',
'ä',
])
@pytest.mark.parametrize('kind', [
PythonArgumentKind.NORMAL,
PythonArgumentKind.POSITIONAL_ONLY,
PythonArgumentKind.KEYWORD_ONLY,
PythonArgumentKind.VARARG,
PythonArgumentKind.KWARGS,
])
@pytest.mark.parametrize('default', [
None,
PythonFunctionArgumentDefault(ast.Constant(value = 'x')),
PythonFunctionArgumentDefault(ast.Constant(value = 1)),
PythonFunctionArgumentDefault(ast.Constant(value = None)),
])
@pytest.mark.parametrize('annotation', [
None,
'a',
'list[int]',
'_',
])
def test_PythonFunctionArgument(name, kind, default, annotation):
PythonFunctionArgument(name, kind, default, annotation)
@@ -0,0 +1,55 @@
# Copyright 2026 jCloud Services GbR
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from src.jcloud_docsgen.core.python.arguments import PythonFunctionArgumentDefault
import pytest
import ast
@pytest.mark.parametrize('default,expected', [
(PythonFunctionArgumentDefault(ast.Constant(value = '')), ast.Constant),
(PythonFunctionArgumentDefault(ast.Constant(value = 'x')), ast.Constant),
(PythonFunctionArgumentDefault(ast.Constant(value = None)), ast.Constant),
(PythonFunctionArgumentDefault(ast.Constant(value = 1)), ast.Constant),
])
def test_PythonFunctionArgumentDefault_value_attribute_type(default, expected):
assert isinstance(default.value, expected)
@pytest.mark.parametrize('value,expected_exception_msg', [
(None, 'expected \'expr\', got \'NoneType\''),
(1, 'expected \'expr\', got \'int\''),
('x', 'expected \'expr\', got \'str\''),
(42, 'expected \'expr\', got \'int\''),
(4.2, 'expected \'expr\', got \'float\''),
])
def test_PythonFunctionArgumentDefault_raises_TypeError(value, expected_exception_msg):
with pytest.raises(TypeError) as exc_info:
PythonFunctionArgumentDefault(value)
assert str(exc_info.value) == expected_exception_msg
@pytest.mark.parametrize('default1,default2,expected', [
(PythonFunctionArgumentDefault(ast.Constant(value = 1)), PythonFunctionArgumentDefault(ast.Constant(value = 1)), True),
(PythonFunctionArgumentDefault(ast.Constant(value = 1)), PythonFunctionArgumentDefault(ast.Constant(value = 2)), False),
(PythonFunctionArgumentDefault(ast.Constant(value = 'a')), PythonFunctionArgumentDefault(ast.Constant(value = 2)), False),
(PythonFunctionArgumentDefault(ast.Constant(value = 'a')), PythonFunctionArgumentDefault(ast.Constant(value = 'a')), True),
(PythonFunctionArgumentDefault(ast.Constant(value = 'a')), PythonFunctionArgumentDefault(ast.Constant(value = 'b')), False),
(PythonFunctionArgumentDefault(ast.List(elts = [])), PythonFunctionArgumentDefault(ast.List(elts = [])), True),
(PythonFunctionArgumentDefault(ast.List(elts = [1])), PythonFunctionArgumentDefault(ast.List(elts = [])), False),
(PythonFunctionArgumentDefault(ast.List(elts = [1])), PythonFunctionArgumentDefault(ast.List(elts = [1])), True),
(PythonFunctionArgumentDefault(ast.List(elts = [1])), PythonFunctionArgumentDefault(ast.List(elts = [2])), False),
(PythonFunctionArgumentDefault(ast.List(elts = [1])), PythonFunctionArgumentDefault(ast.List(elts = [1, 2])), False),
(PythonFunctionArgumentDefault(ast.List(elts = [1, 2])), PythonFunctionArgumentDefault(ast.List(elts = [1, 2])), True),
(PythonFunctionArgumentDefault(ast.List(elts = [2, 1])), PythonFunctionArgumentDefault(ast.List(elts = [1, 2])), False),
])
def test_PythonFunctionArgumentDefault___eq__(default1, default2, expected):
assert (default1 == default2) == expected