[lint] Add lint and tests.
This commit is contained in:
parent
e42e97064a
commit
800de70a43
1
.dir-locals.el
Normal file
1
.dir-locals.el
Normal file
@ -0,0 +1 @@
|
|||||||
|
((python-mode . ((flycheck-flake8rc . "setup.cfg"))))
|
14
.gitignore
vendored
14
.gitignore
vendored
@ -1,3 +1,13 @@
|
|||||||
|
# Editor files
|
||||||
*~
|
*~
|
||||||
*.pyc
|
|
||||||
**/__pycache__
|
# Documentation build
|
||||||
|
.tox
|
||||||
|
doc/_build
|
||||||
|
|
||||||
|
# Python files
|
||||||
|
__pycache__
|
||||||
|
.ipynb_checkpoints
|
||||||
|
.mypy_cache
|
||||||
|
**/*.egg-info
|
||||||
|
**/.eggs
|
||||||
|
42
setup.cfg
Normal file
42
setup.cfg
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
[flake8]
|
||||||
|
# Use black line length:
|
||||||
|
max-line-length = 88
|
||||||
|
extend-ignore =
|
||||||
|
# See https://github.com/PyCQA/pycodestyle/issues/373
|
||||||
|
E203,
|
||||||
|
|
||||||
|
[mypy]
|
||||||
|
warn_return_any = True
|
||||||
|
warn_unused_configs = True
|
||||||
|
|
||||||
|
[mypy-pytest.*]
|
||||||
|
ignore_missing_imports = True
|
||||||
|
|
||||||
|
[mypy-IPython.*]
|
||||||
|
ignore_missing_imports = True
|
||||||
|
|
||||||
|
[tox]
|
||||||
|
envlist = py35,py36,py37,py36-lint
|
||||||
|
|
||||||
|
[gh-actions]
|
||||||
|
python =
|
||||||
|
3.5: py35
|
||||||
|
3.6: py36, py36-lint
|
||||||
|
3.7: py37
|
||||||
|
|
||||||
|
[testenv]
|
||||||
|
deps =
|
||||||
|
pytest
|
||||||
|
commands =
|
||||||
|
pytest tests
|
||||||
|
|
||||||
|
[testenv:py36-lint]
|
||||||
|
deps =
|
||||||
|
black
|
||||||
|
flake8
|
||||||
|
flake8-black
|
||||||
|
mypy
|
||||||
|
commands =
|
||||||
|
black --check --diff setup.py simplex tests
|
||||||
|
flake8 simplex tests
|
||||||
|
mypy simplex tests
|
18
setup.py
18
setup.py
@ -2,23 +2,29 @@
|
|||||||
|
|
||||||
import setuptools
|
import setuptools
|
||||||
|
|
||||||
with open('README.md', 'r') as fh:
|
with open("README.md", "r") as fh:
|
||||||
long_description = fh.read()
|
long_description = fh.read()
|
||||||
|
|
||||||
|
install_requires = []
|
||||||
|
test_requires = ["pytest", "mypy", "black", "flake8", "flake8-black"]
|
||||||
|
|
||||||
setuptools.setup(
|
setuptools.setup(
|
||||||
name="simplex", # Replace with your own username
|
name="simplex", # Replace with your own username
|
||||||
version="0.0.1",
|
version="0.0.1",
|
||||||
author='Mikaël Capelle',
|
author="Mikaël Capelle",
|
||||||
author_email='capelle.mikael@gmail.com',
|
author_email="capelle.mikael@gmail.com",
|
||||||
description='Implementation of a simplex dictionary in python',
|
description="Implementation of a simplex dictionary in python",
|
||||||
long_description=long_description,
|
long_description=long_description,
|
||||||
long_description_content_type="text/markdown",
|
long_description_content_type="text/markdown",
|
||||||
url="https://github.com/mikael.capelle/simplex",
|
url="https://gitea.typename.fr/mikael.capelle/simplex",
|
||||||
packages=setuptools.find_packages(),
|
packages=setuptools.find_packages(),
|
||||||
|
install_requires=install_requires,
|
||||||
|
test_requires=test_requires,
|
||||||
|
extras_require={"test": test_requires},
|
||||||
classifiers=[
|
classifiers=[
|
||||||
"Programming Language :: Python :: 3",
|
"Programming Language :: Python :: 3",
|
||||||
"License :: OSI Approved :: MIT License",
|
"License :: OSI Approved :: MIT License",
|
||||||
"Operating System :: OS Independent",
|
"Operating System :: OS Independent",
|
||||||
],
|
],
|
||||||
python_requires='>=3.5',
|
python_requires=">=3.5",
|
||||||
)
|
)
|
||||||
|
@ -1,29 +1,48 @@
|
|||||||
# -*- encoding: utf-8 -*-
|
# -*- encoding: utf-8 -*-
|
||||||
|
|
||||||
|
import typing
|
||||||
|
|
||||||
|
V = typing.TypeVar("V")
|
||||||
|
T = typing.TypeVar("T")
|
||||||
|
|
||||||
|
|
||||||
|
class magic_dictionary(typing.Dict[V, T]):
|
||||||
|
|
||||||
class magic_dictionary(dict):
|
|
||||||
"""
|
"""
|
||||||
A magic dictionary is a dictionary that:
|
A magic dictionary is a dictionary that:
|
||||||
- May contain a default value, much like collections.defaultdict.
|
- May contain a default value, much like collections.defaultdict.
|
||||||
- Raise custom errors when the given key does not match a given
|
- Raise custom errors when the given key does not match a given
|
||||||
predicate.
|
predicate.
|
||||||
- Can convert values using a specific functor.
|
- Can convert values using a specific functor.
|
||||||
|
|
||||||
|
Magic dictionary can be constructed the same way standard python dictionary
|
||||||
|
are, except that the constructor takes three extra named parameters.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, *args, key_predicate=None, value_converter=None, default_factory=None, **kwargs):
|
key_predicate: typing.Optional[typing.Callable[[V], typing.Optional[str]]] = None
|
||||||
""" Create a new magic dictionary from the given arguments. Magic dictionary can be constructed
|
value_converter: typing.Optional[typing.Callable[[typing.Any], T]] = None
|
||||||
in the same way as standard python dictionary, except that the constructor takes three extra
|
default_factory: typing.Optional[typing.Callable[[], T]] = None
|
||||||
parameters.
|
|
||||||
|
|
||||||
Parameters:
|
def __init__(
|
||||||
- key_predicate Predicate to apply on new key, which should return None if the key is valid,
|
self,
|
||||||
or a message indicating why the key is invalid otherwize. The predicates is not applied on
|
*args,
|
||||||
the initial keys of the dictionary (from args or kwargs). Can be None.
|
key_predicate: typing.Callable[[V], typing.Optional[str]] = None,
|
||||||
- value_converter Functor to apply to values in this dictionary, when set by the index operator.
|
value_converter: typing.Callable[[typing.Any], T] = None,
|
||||||
This functor is also applied to all initial values of the dictionary. Can be None.
|
default_factory: typing.Callable[[], T] = None,
|
||||||
- default_facotry Default factory to use to create object when the key is not set. Can be None.
|
**kwargs
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Args:
|
||||||
|
key_predicate: Predicate to apply on new key, which should return None if
|
||||||
|
the key is valid, or a message indicating why the key is invalid
|
||||||
|
otherwize. The predicates is not applied on the initial keys of the
|
||||||
|
dictionary (from args or kwargs). Can be None.
|
||||||
|
value_converter: Functor to apply to values in this dictionary, when set
|
||||||
|
by the index operator. This functor is also applied to all initial
|
||||||
|
values of the dictionary. Can be None.
|
||||||
|
default_facotry: Default factory to use to create object when the key is
|
||||||
|
not set. Can be None.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
self.key_predicate = key_predicate
|
self.key_predicate = key_predicate
|
||||||
@ -51,7 +70,7 @@ class magic_dictionary(dict):
|
|||||||
for k in self:
|
for k in self:
|
||||||
super().__setitem__(k, self.value_converter(self[k]))
|
super().__setitem__(k, self.value_converter(self[k]))
|
||||||
|
|
||||||
def __getitem__(self, key):
|
def __getitem__(self, key: V) -> T:
|
||||||
|
|
||||||
# If the key does not exists:
|
# If the key does not exists:
|
||||||
if key not in self:
|
if key not in self:
|
||||||
@ -59,11 +78,10 @@ class magic_dictionary(dict):
|
|||||||
if self.default_factory is not None:
|
if self.default_factory is not None:
|
||||||
self.__setitem__(key, self.default_factory())
|
self.__setitem__(key, self.default_factory())
|
||||||
|
|
||||||
|
|
||||||
# Return the key:
|
# Return the key:
|
||||||
return super().__getitem__(key)
|
return super().__getitem__(key)
|
||||||
|
|
||||||
def __setitem__(self, key, value):
|
def __setitem__(self, key: V, value: typing.Any):
|
||||||
# If the key predicate is not empty, we check the key:
|
# If the key predicate is not empty, we check the key:
|
||||||
if self.key_predicate is not None:
|
if self.key_predicate is not None:
|
||||||
check = self.key_predicate(key)
|
check = self.key_predicate(key)
|
||||||
@ -77,8 +95,12 @@ class magic_dictionary(dict):
|
|||||||
super().__setitem__(key, value)
|
super().__setitem__(key, value)
|
||||||
|
|
||||||
def update(self, *args, **kargs):
|
def update(self, *args, **kargs):
|
||||||
super().update(magic_dictionary(
|
super().update(
|
||||||
*args, **kargs,
|
magic_dictionary(
|
||||||
|
*args,
|
||||||
|
**kargs,
|
||||||
value_converter=self.value_converter,
|
value_converter=self.value_converter,
|
||||||
key_predicate=self.key_predicate,
|
key_predicate=self.key_predicate,
|
||||||
default_factory=self.default_factory))
|
default_factory=self.default_factory
|
||||||
|
)
|
||||||
|
)
|
||||||
|
@ -1,17 +1,27 @@
|
|||||||
from IPython.display import display, Math
|
# -*- encoding: utf-8 -*-
|
||||||
|
|
||||||
|
import typing
|
||||||
|
|
||||||
from fractions import Fraction
|
from fractions import Fraction
|
||||||
|
|
||||||
from .magic_dictionary import magic_dictionary
|
from .magic_dictionary import magic_dictionary
|
||||||
|
|
||||||
|
# Type that can be converted by convert_value:
|
||||||
|
convertable_type = typing.Union[str, int, Fraction]
|
||||||
|
|
||||||
def convert_value(value):
|
|
||||||
|
def convert_value(value: convertable_type) -> Fraction:
|
||||||
if type(value) is float:
|
if type(value) is float:
|
||||||
# For float value, we don't handle float:
|
# For float value, we don't handle float:
|
||||||
raise TypeError('Cannot set value as float, use fractions.Fraction instead.')
|
raise TypeError("Cannot set value as float, use fractions.Fraction instead.")
|
||||||
return Fraction(value)
|
return Fraction(value)
|
||||||
|
|
||||||
|
|
||||||
class simplex_dictionary:
|
# Type of variables in a simplex_dictionary:
|
||||||
|
V = typing.TypeVar("V")
|
||||||
|
|
||||||
|
|
||||||
|
class simplex_dictionary(typing.Generic[V]):
|
||||||
|
|
||||||
""" Class representing a dictionary for the simplex algorithm. The class contains
|
""" Class representing a dictionary for the simplex algorithm. The class contains
|
||||||
multiple members representing the elements of a dictionary.
|
multiple members representing the elements of a dictionary.
|
||||||
@ -28,13 +38,14 @@ class simplex_dictionary:
|
|||||||
The magic member ".variables" can also be used to access the list of all
|
The magic member ".variables" can also be used to access the list of all
|
||||||
variables.
|
variables.
|
||||||
|
|
||||||
The various arrays of coefficients or values (b, a, c) are indexed by their respective
|
The various arrays of coefficients or values (b, a, c) are indexed by their
|
||||||
variables, which must be in B or N.
|
respective variables, which must be in B or N.
|
||||||
|
|
||||||
All values are converted to fractions.Fraction object in order to maintain consistency
|
All values are converted to fractions.Fraction object in order to maintain
|
||||||
in the dictionary.
|
consistency in the dictionary.
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
|
```
|
||||||
# Create a simplex dictionary with two basic and two non-basic variables:
|
# Create a simplex dictionary with two basic and two non-basic variables:
|
||||||
>>> sdict = simplex_dictionary(B=['x_1', 'x_2'], N=['x_3', 'x_4'])
|
>>> sdict = simplex_dictionary(B=['x_1', 'x_2'], N=['x_3', 'x_4'])
|
||||||
|
|
||||||
@ -43,114 +54,181 @@ class simplex_dictionary:
|
|||||||
|
|
||||||
# Set the coefficient of x_3 in x_1:
|
# Set the coefficient of x_3 in x_1:
|
||||||
>>> sdict.a['x_1']['x_3'] = 12
|
>>> sdict.a['x_1']['x_3'] = 12
|
||||||
|
```
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, B, N):
|
_a: magic_dictionary[V, magic_dictionary[V, Fraction]]
|
||||||
""" Create a new simplex dictionary with the given basic and non-basic variables.
|
_b: magic_dictionary[V, Fraction]
|
||||||
|
_c: magic_dictionary[V, Fraction]
|
||||||
|
_z: Fraction
|
||||||
|
|
||||||
Parameters:
|
def __init__(self, B: typing.Iterable[V], N: typing.Iterable[V]):
|
||||||
- B The list of basic variables.
|
|
||||||
- N The list of non-basic variables.
|
|
||||||
"""
|
"""
|
||||||
self.__B = tuple(B)
|
Args:
|
||||||
self.__N = tuple(N)
|
B The list of basic variables.
|
||||||
self.b = {}
|
N The list of non-basic variables.
|
||||||
self.a = {}
|
"""
|
||||||
self.c = {}
|
self.__B = list(B)
|
||||||
self.z = 0
|
self.__N = list(N)
|
||||||
|
self.b = {} # type: ignore
|
||||||
|
self.a = {} # type: ignore
|
||||||
|
self.c = {} # type: ignore
|
||||||
|
self.z = Fraction(0)
|
||||||
|
|
||||||
def _check_basic(self, key):
|
def _check_basic(self, key: V) -> typing.Optional[str]:
|
||||||
""" Check if the given key is a basic variable, returning None if it is,
|
""" Check if the given key is a basic variable, returning None if it is,
|
||||||
and a custom exception string if not. Suitable for magic_dictionary use. """
|
and a custom exception string if not. Suitable for magic_dictionary use. """
|
||||||
if key not in self.B:
|
if key not in self.B:
|
||||||
return '{} is not a basic variable.'.format(key)
|
return "{} is not a basic variable.".format(key)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def _check_non_basic(self, key):
|
def _check_non_basic(self, key: V) -> typing.Optional[str]:
|
||||||
""" Check if the given key is a non-basic variable, returning None if it is,
|
""" Check if the given key is a non-basic variable, returning None if it is,
|
||||||
and a custom exception string if not. Suitable for magic_dictionary use. """
|
and a custom exception string if not. Suitable for magic_dictionary use. """
|
||||||
if key not in self.N:
|
if key not in self.N:
|
||||||
return '{} is not a non-basic variable.'.format(key)
|
return "{} is not a non-basic variable.".format(key)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def variables(self): return sorted(self.B + self.N)
|
def variables(self) -> typing.List[V]:
|
||||||
|
return sorted(self.B + self.N)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def B(self): return self.__B
|
def B(self) -> typing.List[V]:
|
||||||
|
return self.__B
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def N(self): return self.__N
|
def N(self) -> typing.List[V]:
|
||||||
|
return self.__N
|
||||||
|
|
||||||
def __setattr__(self, key, value):
|
@property
|
||||||
|
def a(self) -> magic_dictionary[V, magic_dictionary[V, Fraction]]:
|
||||||
|
return self._a
|
||||||
|
|
||||||
# Base and non-basic:
|
@a.setter
|
||||||
if key == 'b':
|
def a(
|
||||||
value = magic_dictionary(
|
self,
|
||||||
value,
|
value: typing.Union[
|
||||||
key_predicate=self._check_basic,
|
typing.Mapping[V, typing.Mapping[V, convertable_type]],
|
||||||
value_converter=convert_value)
|
typing.Iterable[typing.Tuple[V, typing.Mapping[V, convertable_type]]],
|
||||||
elif key == 'c':
|
],
|
||||||
value = magic_dictionary(
|
):
|
||||||
value,
|
self._a = magic_dictionary(
|
||||||
key_predicate=self._check_non_basic,
|
|
||||||
value_converter=convert_value)
|
|
||||||
elif key == 'a':
|
|
||||||
value = magic_dictionary(
|
|
||||||
value,
|
value,
|
||||||
key_predicate=self._check_basic,
|
key_predicate=self._check_basic,
|
||||||
value_converter=lambda value: magic_dictionary(
|
value_converter=lambda value: magic_dictionary(
|
||||||
value, key_predicate=self._check_non_basic,
|
value,
|
||||||
value_converter=convert_value),
|
|
||||||
default_factory=lambda: magic_dictionary(
|
|
||||||
key_predicate=self._check_non_basic,
|
key_predicate=self._check_non_basic,
|
||||||
value_converter=convert_value))
|
value_converter=convert_value,
|
||||||
elif key == 'z':
|
),
|
||||||
value = convert_value(value)
|
default_factory=lambda: magic_dictionary(
|
||||||
|
key_predicate=self._check_non_basic, value_converter=convert_value
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
return super().__setattr__(key, value)
|
@property
|
||||||
|
def b(self) -> magic_dictionary[V, Fraction]:
|
||||||
|
return self._b
|
||||||
|
|
||||||
def name_latex(self, name):
|
@b.setter
|
||||||
""" Convert the given variable name. """
|
def b(
|
||||||
name = str(name)
|
self,
|
||||||
|
value: typing.Union[
|
||||||
|
typing.Mapping[V, convertable_type],
|
||||||
|
typing.Iterable[typing.Tuple[V, convertable_type]],
|
||||||
|
],
|
||||||
|
):
|
||||||
|
self._b = magic_dictionary(
|
||||||
|
value, key_predicate=self._check_basic, value_converter=convert_value
|
||||||
|
)
|
||||||
|
|
||||||
s = name.split('_')
|
@property
|
||||||
|
def c(self) -> magic_dictionary[V, Fraction]:
|
||||||
|
return self._c
|
||||||
|
|
||||||
|
@c.setter
|
||||||
|
def c(
|
||||||
|
self,
|
||||||
|
value: typing.Union[
|
||||||
|
typing.Mapping[V, convertable_type],
|
||||||
|
typing.Iterable[typing.Tuple[V, convertable_type]],
|
||||||
|
],
|
||||||
|
):
|
||||||
|
self._c = magic_dictionary(
|
||||||
|
value, key_predicate=self._check_non_basic, value_converter=convert_value
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def z(self) -> Fraction:
|
||||||
|
return self._z
|
||||||
|
|
||||||
|
@z.setter
|
||||||
|
def z(self, value: convertable_type):
|
||||||
|
self._z = convert_value(value)
|
||||||
|
|
||||||
|
def name_latex(self, name: typing.Any) -> str:
|
||||||
|
""" Convert the given variable name to a clean latex name.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
name: The name of the variable to convert.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A latex version of the given name.
|
||||||
|
"""
|
||||||
|
|
||||||
|
sname = str(name)
|
||||||
|
|
||||||
|
s = sname.split("_")
|
||||||
|
|
||||||
# We only handle special case:
|
# We only handle special case:
|
||||||
if len(s) == 1 or len(s) > 2:
|
if len(s) == 1 or len(s) > 2:
|
||||||
return name
|
return sname
|
||||||
|
|
||||||
return s[0] + '_{' + s[1] + '}'
|
return s[0] + "_{" + s[1] + "}"
|
||||||
|
|
||||||
def value_latex(self, value):
|
def value_latex(self, value: Fraction) -> str:
|
||||||
|
""" Convert the given fraction to a latex fraction.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
value: The fraction to convert.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A valid latex code that is either a number (if the fraction has a
|
||||||
|
denominator of 1), or a latex fraction.
|
||||||
|
"""
|
||||||
if value.denominator == 1:
|
if value.denominator == 1:
|
||||||
return str(value)
|
return str(value)
|
||||||
return r'{}\frac{{{}}}{{{}}}'.format(
|
return r"{}\frac{{{}}}{{{}}}".format(
|
||||||
'-' if value.numerator < 0 else '',
|
"-" if value.numerator < 0 else "", abs(value.numerator), value.denominator
|
||||||
abs(value.numerator), value.denominator)
|
)
|
||||||
|
|
||||||
def display(self, name=None):
|
def display(self, name: str = None):
|
||||||
""" Display this simplex dictionary on the standard Jupyter output.
|
""" Display this simplex dictionary on the standard Jupyter output.
|
||||||
|
|
||||||
Parameters:
|
Args:
|
||||||
- prefix Name of the dictionary.
|
name: Name of the dictionary.
|
||||||
"""
|
"""
|
||||||
d = (r'\begin{{array}}{{r||{}}}'.format(
|
from IPython.display import display, Math
|
||||||
'r|' * (1 + len(self.B)))
|
|
||||||
+ r' & b & ' + ' & '.join(self.name_latex(v) for v in self.N) + r'\\\hline '
|
d = (
|
||||||
+ r'\\'.join(
|
r"\begin{{array}}{{r||{}}}".format("r|" * (1 + len(self.B)))
|
||||||
'{} & {} &'.format(
|
+ r" & b & "
|
||||||
self.name_latex(b),
|
+ " & ".join(self.name_latex(v) for v in self.N)
|
||||||
self.value_latex(self.b[b])
|
+ r"\\\hline "
|
||||||
|
+ r"\\".join(
|
||||||
|
"{} & {} &".format(self.name_latex(b), self.value_latex(self.b[b]))
|
||||||
|
+ " & ".join(self.value_latex(-self.a[b][n]) for n in self.N)
|
||||||
|
for i, b in enumerate(self.B)
|
||||||
|
)
|
||||||
|
+ r"\\\hline\hline "
|
||||||
|
+ r"&".join(
|
||||||
|
["z", self.value_latex(self.z)]
|
||||||
|
+ [self.value_latex(self.c[n]) for n in self.N]
|
||||||
|
)
|
||||||
|
+ r"\\\hline\end{array}"
|
||||||
)
|
)
|
||||||
+ ' & '.join(self.value_latex(-self.a[b][n]) for n in self.N)
|
|
||||||
for i, b in enumerate(self.B))
|
|
||||||
+ r'\\\hline\hline '
|
|
||||||
+ r'&'.join(['z', self.value_latex(self.z)] + [self.value_latex(self.c[n])
|
|
||||||
for n in self.N])
|
|
||||||
+ r'\\\hline\end{array}')
|
|
||||||
|
|
||||||
if name is not None:
|
if name is not None:
|
||||||
d = r'{} = \left.{}\right.'.format(name, d)
|
d = r"{} = \left.{}\right.".format(name, d)
|
||||||
|
|
||||||
display(Math(d))
|
display(Math(d))
|
||||||
|
83
tests/test_magic_dictionary.py
Normal file
83
tests/test_magic_dictionary.py
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
# -*- encoding: utf-8 -*-
|
||||||
|
|
||||||
|
from simplex.magic_dictionary import magic_dictionary
|
||||||
|
|
||||||
|
|
||||||
|
def test_basic():
|
||||||
|
""" Tests that a non-customized magic_dictionary acts
|
||||||
|
as a standard python dictionary. """
|
||||||
|
|
||||||
|
d = magic_dictionary()
|
||||||
|
assert len(d) == 0
|
||||||
|
|
||||||
|
d["x"] = 1
|
||||||
|
d["y"] = "2"
|
||||||
|
|
||||||
|
assert len(d) == 2
|
||||||
|
assert d["x"] == 1
|
||||||
|
assert d["y"] == "2"
|
||||||
|
|
||||||
|
# Test copy:
|
||||||
|
d2 = magic_dictionary(d)
|
||||||
|
assert len(d2) == 2
|
||||||
|
assert d2["x"] == 1
|
||||||
|
assert d2["y"] == "2"
|
||||||
|
|
||||||
|
# Test construction:
|
||||||
|
d2 = magic_dictionary({"x": 1, "y": "2"})
|
||||||
|
assert len(d2) == 2
|
||||||
|
assert d2["x"] == 1
|
||||||
|
assert d2["y"] == "2"
|
||||||
|
|
||||||
|
# Test construction:
|
||||||
|
d2 = magic_dictionary(x=1, y="2")
|
||||||
|
assert len(d2) == 2
|
||||||
|
assert d2["x"] == 1
|
||||||
|
assert d2["y"] == "2"
|
||||||
|
|
||||||
|
# Test construction:
|
||||||
|
d2 = magic_dictionary((("x", 1), ("y", "2")))
|
||||||
|
assert len(d2) == 2
|
||||||
|
assert d2["x"] == 1
|
||||||
|
assert d2["y"] == "2"
|
||||||
|
|
||||||
|
|
||||||
|
def test_value_converter():
|
||||||
|
""" Tests that conversion is correctly done. """
|
||||||
|
|
||||||
|
# Convert a value to its string representation:
|
||||||
|
def converter(x):
|
||||||
|
return str(x)
|
||||||
|
|
||||||
|
d = magic_dictionary(value_converter=converter)
|
||||||
|
assert len(d) == 0
|
||||||
|
|
||||||
|
d["x"] = 2
|
||||||
|
d["y"] = 3
|
||||||
|
assert len(d) == 2
|
||||||
|
assert d["x"] == "2"
|
||||||
|
assert d["y"] == "3"
|
||||||
|
|
||||||
|
# Construction:
|
||||||
|
d = magic_dictionary(d, value_converter=converter)
|
||||||
|
assert len(d) == 2
|
||||||
|
assert d["x"] == "2"
|
||||||
|
assert d["y"] == "3"
|
||||||
|
|
||||||
|
# Construction:
|
||||||
|
d = magic_dictionary({"x": 2, "y": 3}, value_converter=converter)
|
||||||
|
assert len(d) == 2
|
||||||
|
assert d["x"] == "2"
|
||||||
|
assert d["y"] == "3"
|
||||||
|
|
||||||
|
# Construction:
|
||||||
|
d = magic_dictionary(x=2, y=3, value_converter=converter)
|
||||||
|
assert len(d) == 2
|
||||||
|
assert d["x"] == "2"
|
||||||
|
assert d["y"] == "3"
|
||||||
|
|
||||||
|
# Construction:
|
||||||
|
d = magic_dictionary([("x", 2), ("y", 3)], value_converter=converter)
|
||||||
|
assert len(d) == 2
|
||||||
|
assert d["x"] == "2"
|
||||||
|
assert d["y"] == "3"
|
Loading…
Reference in New Issue
Block a user