assertpy
Advanced tools
+27
| Copyright (c) 2015-2018, Activision Publishing, Inc. | ||
| All rights reserved. | ||
| Redistribution and use in source and binary forms, with or without modification, | ||
| are permitted provided that the following conditions are met: | ||
| 1. Redistributions of source code must retain the above copyright notice, this | ||
| list of conditions and the following disclaimer. | ||
| 2. Redistributions in binary form must reproduce the above copyright notice, | ||
| this list of conditions and the following disclaimer in the documentation | ||
| and/or other materials provided with the distribution. | ||
| 3. Neither the name of the copyright holder nor the names of its contributors | ||
| may be used to endorse or promote products derived from this software without | ||
| specific prior written permission. | ||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | ||
| ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
| DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR | ||
| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | ||
| ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
+156
-6
@@ -1,2 +0,2 @@ | ||
| # Copyright (c) 2015-2017, Activision Publishing, Inc. | ||
| # Copyright (c) 2015-2018, Activision Publishing, Inc. | ||
| # All rights reserved. | ||
@@ -41,7 +41,8 @@ # | ||
| import contextlib | ||
| import json | ||
| __version__ = '0.12' | ||
| __version__ = '0.13' | ||
| __tracebackhide__ = True # clean tracebacks via py.test integration | ||
| contextlib.__tracebackhide__ = True # monkey patch contextlib with clean py.teest tracebacks | ||
| contextlib.__tracebackhide__ = True # monkey patch contextlib with clean py.test tracebacks | ||
@@ -161,6 +162,10 @@ if sys.version_info[0] == 3: | ||
| def is_equal_to(self, other): | ||
| def is_equal_to(self, other, **kwargs): | ||
| """Asserts that val is equal to other.""" | ||
| if self.val != other: | ||
| self._err('Expected <%s> to be equal to <%s>, but was not.' % (self.val, other)) | ||
| if self._check_dict_like(self.val, check_values=False, return_as_bool=True) and self._check_dict_like(other, check_values=False, return_as_bool=True): | ||
| if self._dict_not_equal(self.val, other, ignore=kwargs.get('ignore')): | ||
| self._dict_err(self.val, other, ignore=kwargs.get('ignore')) | ||
| else: | ||
| if self.val != other: | ||
| self._err('Expected <%s> to be equal to <%s>, but was not.' % (self.val, other)) | ||
| return self | ||
@@ -299,2 +304,9 @@ | ||
| self._err('Expected <%s> to contain only %s, but did contain %s.' % (self.val, self._fmt_items(items), self._fmt_items(extra))) | ||
| missing = [] | ||
| for i in items: | ||
| if i not in self.val: | ||
| missing.append(i) | ||
| if missing: | ||
| self._err('Expected <%s> to contain only %s, but did not contain %s.' % (self.val, self._fmt_items(items), self._fmt_items(missing))) | ||
| return self | ||
@@ -1145,1 +1157,139 @@ | ||
| return True | ||
| def _dict_not_equal(self, val, other, ignore=None): | ||
| if ignore: | ||
| ignores = self._dict_ignore(ignore) | ||
| k1 = set([k for k in val if k not in ignores]) | ||
| k2 = set([k for k in other if k not in ignores]) | ||
| if k1 != k2: | ||
| return True | ||
| else: | ||
| for k in k1: | ||
| if self._check_dict_like(val[k], check_values=False, return_as_bool=True) and self._check_dict_like(other[k], check_values=False, return_as_bool=True): | ||
| return self._dict_not_equal(val[k], other[k], ignore=[i[1:] for i in ignores if type(i) is tuple and i[0] == k]) | ||
| elif val[k] != other[k]: | ||
| return True | ||
| return False | ||
| #return k1 != k2 or any(val[k] != other[k] for k in k1) | ||
| else: | ||
| return val != other | ||
| def _dict_ignore(self, ignore): | ||
| return [i[0] if type(i) is tuple and len(i) == 1 else i \ | ||
| for i in (ignore if type(ignore) is list else [ignore])] | ||
| def _dict_err(self, val, other, ignore=None): | ||
| def _dict_repr(d, other): | ||
| out = '' | ||
| ellip = False | ||
| for k,v in d.items(): | ||
| if k not in other: | ||
| out += '%s%s: %s' % (', ' if len(out) > 0 else '', repr(k), repr(v)) | ||
| elif v != other[k]: | ||
| out += '%s%s: %s' % (', ' if len(out) > 0 else '', repr(k), | ||
| _dict_repr(v, other[k]) if self._check_dict_like(v, check_values=False, return_as_bool=True) and self._check_dict_like(other[k], check_values=False, return_as_bool=True) else repr(v) | ||
| ) | ||
| else: | ||
| ellip = True | ||
| return '{%s%s}' % ('..' if ellip and len(out) == 0 else '.., ' if ellip else '', out) | ||
| if ignore: | ||
| ignores = self._dict_ignore(ignore) | ||
| ignore_err = ' ignoring keys %s' % self._fmt_items(['.'.join([str(s) for s in i]) if type(i) is tuple else i for i in ignores]) | ||
| self._err('Expected <%s> to be equal to <%s>%s, but was not.' % ( | ||
| _dict_repr(val, other), | ||
| _dict_repr(other, val), | ||
| ignore_err if ignore else '' | ||
| )) | ||
| ### snapshot testing ### | ||
| def snapshot(self, id=None, path='__snapshots'): | ||
| if sys.version_info[0] < 3: | ||
| raise NotImplementedError('snapshot testing requires Python 3') | ||
| class _Encoder(json.JSONEncoder): | ||
| def default(self, o): | ||
| if isinstance(o, set): | ||
| return {'__type__': 'set', '__data__': list(o)} | ||
| elif isinstance(o, complex): | ||
| return {'__type__': 'complex', '__data__': [o.real, o.imag]} | ||
| elif isinstance(o, datetime.datetime): | ||
| return {'__type__': 'datetime', '__data__': o.strftime('%Y-%m-%d %H:%M:%S')} | ||
| elif '__dict__' in dir(o) and type(o) is not type: | ||
| return { | ||
| '__type__': 'instance', | ||
| '__class__': o.__class__.__name__, | ||
| '__module__': o.__class__.__module__, | ||
| '__data__': o.__dict__ | ||
| } | ||
| return json.JSONEncoder.default(self, o) | ||
| class _Decoder(json.JSONDecoder): | ||
| def __init__(self): | ||
| json.JSONDecoder.__init__(self, object_hook=self.object_hook) | ||
| def object_hook(self, d): | ||
| if '__type__' in d and '__data__' in d: | ||
| if d['__type__'] == 'set': | ||
| return set(d['__data__']) | ||
| elif d['__type__'] == 'complex': | ||
| return complex(d['__data__'][0], d['__data__'][1]) | ||
| elif d['__type__'] == 'datetime': | ||
| return datetime.datetime.strptime(d['__data__'], '%Y-%m-%d %H:%M:%S') | ||
| elif d['__type__'] == 'instance': | ||
| mod = __import__(d['__module__'], fromlist=[d['__class__']]) | ||
| klass = getattr(mod, d['__class__']) | ||
| inst = klass.__new__(klass) | ||
| inst.__dict__ = d['__data__'] | ||
| return inst | ||
| return d | ||
| def _save(name, val): | ||
| with open(name, 'w') as fp: | ||
| json.dump(val, fp, indent=2, separators=(',', ': '), sort_keys=True, cls=_Encoder) | ||
| def _load(name): | ||
| with open(name, 'r') as fp: | ||
| return json.load(fp, cls=_Decoder) | ||
| def _name(path, name): | ||
| try: | ||
| return os.path.join(path, 'snap-%s.json' % name.replace(' ','_').lower()) | ||
| except Exception: | ||
| raise ValueError('failed to create snapshot filename, either bad path or bad name') | ||
| if id: | ||
| # custom id | ||
| snapname = _name(path, id) | ||
| else: | ||
| # make id from filename and line number | ||
| f = inspect.currentframe() | ||
| fpath = os.path.basename(f.f_back.f_code.co_filename) | ||
| fname = os.path.splitext(fpath)[0] | ||
| lineno = str(f.f_back.f_lineno) | ||
| snapname = _name(path, fname) | ||
| if not os.path.exists(path): | ||
| os.makedirs(path) | ||
| if os.path.isfile(snapname): | ||
| # snap exists, so load | ||
| snap = _load(snapname) | ||
| if id: | ||
| # custom id, so test | ||
| return self.is_equal_to(snap) | ||
| else: | ||
| if lineno in snap: | ||
| # found sub-snap, so test | ||
| return self.is_equal_to(snap[lineno]) | ||
| else: | ||
| # lineno not in snap, so create sub-snap and pass | ||
| snap[lineno] = self.val | ||
| _save(snapname, snap) | ||
| else: | ||
| # no snap, so create and pass | ||
| _save(snapname, self.val if id else {lineno: self.val}) | ||
| return self |
+2
-3
| Metadata-Version: 1.1 | ||
| Name: assertpy | ||
| Version: 0.12 | ||
| Version: 0.13 | ||
| Summary: Assertion library for python unit testing with a fluent API | ||
@@ -9,3 +9,3 @@ Home-page: https://github.com/ActivisionGameScience/assertpy | ||
| License: BSD | ||
| Download-URL: https://codeload.github.com/ActivisionGameScience/assertpy/tar.gz/0.12 | ||
| Download-URL: https://codeload.github.com/ActivisionGameScience/assertpy/tar.gz/0.13 | ||
| Description: assertpy | ||
@@ -41,3 +41,2 @@ ======== | ||
| Classifier: Programming Language :: Python :: 2 | ||
| Classifier: Programming Language :: Python :: 2.6 | ||
| Classifier: Programming Language :: Python :: 2.7 | ||
@@ -44,0 +43,0 @@ Classifier: Programming Language :: Python :: 3 |
+0
-1
@@ -46,3 +46,2 @@ from distutils.core import setup | ||
| 'Programming Language :: Python :: 2', | ||
| 'Programming Language :: Python :: 2.6', | ||
| 'Programming Language :: Python :: 2.7', | ||
@@ -49,0 +48,0 @@ 'Programming Language :: Python :: 3', |
Alert delta unavailable
Currently unable to show alert delta for PyPI packages.
63112
14.63%6
20%1198
12.28%