Skip to content

Commit

Permalink
Merge pull request #3 from pkyosx/feature/new-tools
Browse files Browse the repository at this point in the history
New tool for code formatting and package publishing
  • Loading branch information
pkyosx authored Apr 22, 2022
2 parents e4e3d28 + 8673b13 commit 8a92aa4
Show file tree
Hide file tree
Showing 15 changed files with 216 additions and 126 deletions.
3 changes: 1 addition & 2 deletions .github/workflows/python-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,7 @@ jobs:
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install pytest pytest-cov coverage-lcov
pip install -e .
pip install -e ".[test]"
- name: Test with pytest
run: |
pytest --junitxml=junit_report.xml --cov=believe tests
Expand Down
9 changes: 4 additions & 5 deletions .github/workflows/python-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,10 @@ jobs:
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install setuptools wheel twine
pip install -e ".[publish]"
- name: Build and publish
env:
TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }}
TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
FLIT_USERNAME: ${{ secrets.PYPI_USERNAME }}
FLIT_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
run: |
python setup.py sdist bdist_wheel
twine upload dist/*
flit publish
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -127,3 +127,9 @@ dmypy.json

# Pyre type checker
.pyre/

# customized
.direnv
.envrc
junit_report.xml
lcov.info
7 changes: 5 additions & 2 deletions believe/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,15 @@
from .str_matcher import AnySHA1

# Put all Matcher into BelieveMixin
class BelieveMixin(object): pass
class BelieveMixin(object):
pass


for c, cls in dict(locals()).items():
try:
if issubclass(cls, BelieveBase) and cls != BelieveBase:
setattr(BelieveMixin, c, cls)
except TypeError:
pass

__version__ = "1.0.11"
__version__ = "1.0.12"
55 changes: 42 additions & 13 deletions believe/dict_matcher.py
Original file line number Diff line number Diff line change
@@ -1,67 +1,96 @@
import json
import typing
from .internal import BelieveBase
from .internal import validate
from .internal import NO_CHECK


class Dict(BelieveBase):
def __init__(self, dict_obj: typing.Dict):
def __init__(self, dict_obj: typing.Dict) -> None:
assert isinstance(dict_obj, dict)

super().__init__(dict_obj)
self.__dict_obj = dict_obj

def validate(self, rhs, e_path=""):
def validate(self, rhs: typing.Dict, e_path: str = "") -> None:
if not isinstance(rhs, dict):
self.raise_validate_error(rhs, e_path=e_path, e_msg="not_dict")

# validate required field
for k, v in self.__dict_obj.items():
if not isinstance(v, Optional):
if k not in rhs:
self.raise_validate_error(rhs, e_path=e_path, e_msg=f'missing_required_field: {k}')
self.raise_validate_error(
rhs, e_path=e_path, e_msg=f"missing_required_field: {k}"
)

# validate field value
for k, v in rhs.items():
if k in self.__dict_obj:
validate(self.__dict_obj[k], v, "%s.%s" % (e_path, k))
else:
self.raise_validate_error(rhs, e_path=e_path, e_msg="unknown_field", e_unsafe_msg=f'unknown_field: {k}')
self.raise_validate_error(
rhs,
e_path=e_path,
e_msg="unknown_field",
e_unsafe_msg=f"unknown_field: {k}",
)


class DictOf(BelieveBase):
def __init__(self, key: typing.Any, value: typing.Any, n_item: int = NO_CHECK, min_item: int = NO_CHECK, max_item: int = NO_CHECK):
def __init__(
self,
key: typing.Any,
value: typing.Any,
n_item: int = NO_CHECK,
min_item: int = NO_CHECK,
max_item: int = NO_CHECK,
) -> None:
assert n_item == NO_CHECK or isinstance(n_item, int)
assert min_item == NO_CHECK or isinstance(min_item, int)
assert max_item == NO_CHECK or isinstance(max_item, int)

super().__init__(key, value, n_item=n_item, min_item=min_item, max_item=max_item)
super().__init__(
key, value, n_item=n_item, min_item=min_item, max_item=max_item
)
self.__key = key
self.__value = value
self.__n_item = n_item
self.__min_item = min_item
self.__max_item = max_item

def validate(self, rhs, e_path=""):
def validate(self, rhs: Dict, e_path: str = "") -> None:
if not isinstance(rhs, dict):
self.raise_validate_error(rhs, e_path=e_path, e_msg="not_dict")
if self.__n_item != NO_CHECK:
if not len(rhs) == self.__n_item:
self.raise_validate_error(rhs, e_path=e_path, e_msg=f'mismatch_item_count: {len(rhs)} != {self.__n_item}')
self.raise_validate_error(
rhs,
e_path=e_path,
e_msg=f"mismatch_item_count: {len(rhs)} != {self.__n_item}",
)
if self.__min_item != NO_CHECK:
if len(rhs) < self.__min_item:
self.raise_validate_error(rhs, e_path=e_path, e_msg=f'too_few_items: {len(rhs)} < {self.__min_item}')
self.raise_validate_error(
rhs,
e_path=e_path,
e_msg=f"too_few_items: {len(rhs)} < {self.__min_item}",
)
if self.__max_item != NO_CHECK:
if len(rhs) > self.__max_item:
self.raise_validate_error(rhs, e_path=e_path, e_msg=f'too_many_items: {len(rhs)} > {self.__max_item}')
self.raise_validate_error(
rhs,
e_path=e_path,
e_msg=f"too_many_items: {len(rhs)} > {self.__max_item}",
)
for k, v in rhs.items():
validate(self.__key, k, "%s.%s" % (e_path, k))
validate(self.__value, v, "%s.%s" % (e_path, k))


class Optional(BelieveBase):
def __init__(self, value: typing.Any):
def __init__(self, value: typing.Any) -> None:
super().__init__(value)
self.__value = value

def validate(self, rhs: typing.Any, e_path: str = ""):
def validate(self, rhs: typing.Any, e_path: str = "") -> None:
validate(rhs, self.__value, e_path=e_path)
24 changes: 11 additions & 13 deletions believe/error.py
Original file line number Diff line number Diff line change
@@ -1,31 +1,29 @@

from typing import Any, List


class ValidateError(Exception):
def __init__(self, v1: Any, v2: Any, **kwargs: Any):
def __init__(self, v1: Any, v2: Any, **kwargs: Any) -> None:
self.v1 = repr(v1)
self.v2 = repr(v2)
self.kwargs = kwargs

def kwargs_to_string(self, fields: List[str], with_v2: bool):
def kwargs_to_string(self, fields: List[str], with_v2: bool) -> str:
result = []
for k in fields:
if self.kwargs.get(k):
if k == 'e_path':
result.append(f'[{k}=${self.kwargs[k]}]')
if k == "e_path":
result.append(f"[{k}=${self.kwargs[k]}]")
else:
result.append(f'[{k}={self.kwargs[k]}]')
result.append(f"[{k}={self.kwargs[k]}]")
if with_v2:
result.append(f'{self.v2} != {self.v1}')
result.append(f"{self.v2} != {self.v1}")
return " ".join(result)

def xss_unsafe_message(self):
return self.kwargs_to_string(['e_path', 'e_msg', 'e_unsafe_msg'], True)
def xss_unsafe_message(self) -> str:
return self.kwargs_to_string(["e_path", "e_msg", "e_unsafe_msg"], True)

def xss_safe_message(self):
return self.kwargs_to_string(['e_path', 'e_msg'], False)
def xss_safe_message(self) -> str:
return self.kwargs_to_string(["e_path", "e_msg"], False)

def __str__(self):
def __str__(self) -> str:
return self.xss_unsafe_message()

27 changes: 14 additions & 13 deletions believe/internal.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,48 +7,49 @@
# We use Ellipsis to differentiate if caller assign non-default value for kwargs
NO_CHECK = USE_DEFAULT = Ellipsis


class BelieveBase(abc.ABC):
def __init__(self, *args: Any, **kwargs: Any):
self.__arg_str = self.init_arg_str(*args, **kwargs)
def __init__(self, *args: Any, **kwargs: Any) -> None:
self.__arg_str = self.__init_arg_str(*args, **kwargs)

def __ne__(self, rhs: Any):
def __ne__(self, rhs: Any) -> bool:
return not self.__eq__(rhs)

def __eq__(self, rhs: Any):
def __eq__(self, rhs: Any) -> bool:
try:
self.validate(rhs)
return True
except ValidateError:
return False

def __str__(self):
def __str__(self) -> str:
return "%s(%s)" % (self.__class__.__name__, self.__arg_str)

def __repr__(self):
def __repr__(self) -> str:
return self.__str__()

def to_str(self, val: Any) -> str:
def __to_str(self, val: Any) -> str:
if inspect.isclass(val) and hasattr(val, "__name__"):
return val.__name__
else:
return str(val)

def init_arg_str(self, *args: Any, **kwargs: Any):
def __init_arg_str(self, *args: Any, **kwargs: Any) -> str:
list_of_arg = list(args)
for k, v in kwargs.items():
if v != Ellipsis: # only show overwritten kwargs
if v != Ellipsis: # only show overwritten kwargs
list_of_arg.append("%s=%s" % (k, v))
return ", ".join([self.to_str(i) for i in list_of_arg])
return ", ".join([self.__to_str(i) for i in list_of_arg])

def raise_validate_error(self, rhs: Any, **kwargs: Any):
def raise_validate_error(self, rhs: Any, **kwargs: Any) -> None:
raise ValidateError(self, rhs, **kwargs)

@abc.abstractmethod
def validate(self, rhs: Any, e_path: str = ""):
def validate(self, rhs: Any, e_path: str = "") -> None:
raise NotImplemented()


def validate(v1: Any, v2: Any, e_path: str = ""):
def validate(v1: Any, v2: Any, e_path: str = "") -> None:
if isinstance(v1, BelieveBase):
v1.validate(v2, e_path=e_path)
elif isinstance(v2, BelieveBase):
Expand Down
40 changes: 30 additions & 10 deletions believe/list_matcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,38 +6,46 @@


class OneOf(BelieveBase):
def __init__(self, *candidates: Any):
def __init__(self, *candidates: Any) -> None:
super().__init__(*candidates)
self.__candidates = candidates

def validate(self, rhs: Any, e_path: str = ""):
def validate(self, rhs: Any, e_path: str = "") -> None:
for i in self.__candidates:
if i == rhs:
return
self.raise_validate_error(rhs, e_path=e_path, e_msg="invalid_argument")


class AnyOrder(BelieveBase):
def __init__(self, list_obj: List):
def __init__(self, list_obj: List) -> None:
assert isinstance(list_obj, list)

super().__init__(list_obj)
self.__list_obj = list_obj

def validate(self, rhs: List[Any], e_path: str = ""):
def validate(self, rhs: List[Any], e_path: str = "") -> None:
if not isinstance(rhs, list):
self.raise_validate_error(rhs, e_path=e_path)
if len(rhs) != len(self.__list_obj):
self.raise_validate_error(rhs, e_path=e_path, e_msg="different_length")
list_obj = self.__list_obj[:]
for idx, i in enumerate(rhs):
if not i in list_obj:
self.raise_validate_error(rhs, e_path=e_path, e_msg=f'item_not_found_at_index: {idx}')
self.raise_validate_error(
rhs, e_path=e_path, e_msg=f"item_not_found_at_index: {idx}"
)
list_obj.remove(i)


class ListOf(BelieveBase):
def __init__(self, one_item: Any, n_item: int = NO_CHECK, min_item: int = NO_CHECK, max_item: int = NO_CHECK):
def __init__(
self,
one_item: Any,
n_item: int = NO_CHECK,
min_item: int = NO_CHECK,
max_item: int = NO_CHECK,
) -> None:
assert n_item == NO_CHECK or isinstance(n_item, int)
assert min_item == NO_CHECK or isinstance(min_item, int)
assert max_item == NO_CHECK or isinstance(max_item, int)
Expand All @@ -49,17 +57,29 @@ def __init__(self, one_item: Any, n_item: int = NO_CHECK, min_item: int = NO_CHE
self.__min_item = min_item
self.__max_item = max_item

def validate(self, rhs: List, e_path: str = ""):
def validate(self, rhs: List, e_path: str = "") -> None:
if not isinstance(rhs, list):
self.raise_validate_error(rhs, e_path=e_path, e_msg="not_list")
if self.__n_item != NO_CHECK:
if not len(rhs) == self.__n_item:
self.raise_validate_error(rhs, e_path=e_path, e_msg=f'mismatch_item_count: {len(rhs)} != {self.__n_item}')
self.raise_validate_error(
rhs,
e_path=e_path,
e_msg=f"mismatch_item_count: {len(rhs)} != {self.__n_item}",
)
if self.__min_item != NO_CHECK:
if len(rhs) < self.__min_item:
self.raise_validate_error(rhs, e_path=e_path, e_msg=f'too_few_items: {len(rhs)} < {self.__min_item}')
self.raise_validate_error(
rhs,
e_path=e_path,
e_msg=f"too_few_items: {len(rhs)} < {self.__min_item}",
)
if self.__max_item != NO_CHECK:
if len(rhs) > self.__max_item:
self.raise_validate_error(rhs, e_path=e_path, e_msg=f'too_many_items: {len(rhs)} > {self.__max_item}')
self.raise_validate_error(
rhs,
e_path=e_path,
e_msg=f"too_many_items: {len(rhs)} > {self.__max_item}",
)
for idx, val in enumerate(rhs):
validate(self.__one_item, val, "%s.%s" % (e_path, str(idx)))
Loading

1 comment on commit 8a92aa4

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Coverage for this commit

98.67%

Coverage Report
FileBranchesFuncsLinesUncovered Lines
believe
   __init__.py100%100%100%
   dict_matcher.py100%100%100%
   error.py100%100%100%
   internal.py100%100%97.62%49
   list_matcher.py100%100%96.15%29, 35
   number_matcher.py100%100%100%
   other_matcher.py100%100%100%
   str_matcher.py100%100%98.06%52–53

Please sign in to comment.