Skip to content

Commit

Permalink
Merge pull request #46 from seperman/dev
Browse files Browse the repository at this point in the history
V3
  • Loading branch information
seperman committed Jan 27, 2017
2 parents ec30c3d + 85581fd commit a6d4ffb
Show file tree
Hide file tree
Showing 25 changed files with 2,919 additions and 597 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,5 @@ target/
# Editor / IDE files
*.swp
.idea/
.~lock*

3 changes: 2 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ python:
- "3.3"
- "3.4"
- "3.5"
- "pypy"
- "3.6"
- "pypy-5.4" # pypy on python 2.7
- "pypy3"

sudo: false
Expand Down
5 changes: 3 additions & 2 deletions AUTHORS
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
Primary Author:
Primary Authors:
* Seperman
* Victor Hahn Castell @ Flexoptix


Thanks to:
Expand All @@ -9,4 +10,4 @@ Thanks to:
* timoilya for comparing list of sets when ignoring order.
* Bernhard10 for significant digits comparison.
* b-jazz for PEP257 cleanup, Standardize on full names, fixing line endings.
* Victor Hahn Castell @ Flexoptix for deep set comparison and exclusion patterns
* finnhughes for fixing __slots__
15 changes: 9 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# deepdiff v 2.5.3
# deepdiff v 3.0.0

<!-- ![Downloads](https://img.shields.io/pypi/dm/deepdiff.svg?style=flat) -->
![Python Versions](https://img.shields.io/pypi/pyversions/deepdiff.svg?style=flat)
Expand All @@ -8,7 +8,7 @@
[![Coverage Status](https://coveralls.io/repos/github/seperman/deepdiff/badge.svg?branch=master)](https://coveralls.io/github/seperman/deepdiff?branch=master)

Deep Difference of dictionaries, iterables, strings and other objects. It will recursively look for all the changes.
Tested on Python 2.7, 3.3, 3.4, 3.5, Pypy, Pypy3
Tested on Python 2.7, 3.3, 3.4, 3.5, 3.6, Pypy, Pypy3

## Table of Contents

Expand Down Expand Up @@ -432,6 +432,7 @@ And here is more info: <http://zepworks.com/blog/diff-it-to-digg-it/>

##Changelog

- v3-0-0: Introducing Tree View
- v2-5-3: Bug fix on logging for content hash.
- v2-5-2: Bug fixes on content hash.
- v2-5-0: Adding ContentHash module to fix ignore_order once and for all.
Expand All @@ -453,22 +454,24 @@ And here is more info: <http://zepworks.com/blog/diff-it-to-digg-it/>
- v0-5-6: Adding slots support
- v0-5-5: Adding loop detection

## Primary Author
## Authors

Seperman (Sep Dehpour)

- [Github](https://github.com/seperman)
- [Linkedin](http://www.linkedin.com/in/sepehr)
- [ZepWorks](http://www.zepworks.com)

## Contributors
Victor Hahn Castell

Thanks to:
- [hahncastell.de](http://hahncastell.de)
- [flexoptix.net](http://www.flexoptix.net)

Also thanks to:

- nfvs for Travis-CI setup script.
- brbsix for initial Py3 porting.
- WangFenjin for unicode support.
- timoilya for comparing list of sets when ignoring order.
- Bernhard10 for significant digits comparison.
- b-jazz for PEP257 cleanup, Standardize on full names, fixing line endings.
- [Victor Hahn Castell](http://hahncastell.de) @ [Flexoptix](http://www.flexoptix.net) for deep set comparison and exclusion patterns
16 changes: 10 additions & 6 deletions README.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
**DeepDiff v 2.5.3**
**DeepDiff v 3.0.0**

Deep Difference of dictionaries, iterables, strings and other objects. It will recursively look for all the changes.

Tested on Python 2.7, 3.3, 3.4, 3.5, Pypy, Pypy3
Tested on Python 2.7, 3.3, 3.4, 3.5, 3.6, Pypy, Pypy3

Note: Checkout the github repo's readme for complete coverage of features:
https://github.com/seperman/deepdiff
Expand Down Expand Up @@ -226,6 +226,7 @@ http://zepworks.com/blog/diff-it-to-digg-it/

**Changelog**

- v3-0-0: Introducing Tree View
- v2-5-3: Bug fix on logging for content hash.
- v2-5-2: Bug fixes on content hash.
- v2-5-0: Adding ContentHash module to fix ignore_order once and for all.
Expand All @@ -247,22 +248,25 @@ http://zepworks.com/blog/diff-it-to-digg-it/
- v0-5-6: Adding slots support
- v0-5-5: Adding loop detection

**Primary Author**
**Authors**
Sep Dehpour

Github: https://github.com/seperman
Linkedin: http://www.linkedin.com/in/sepehr
ZepWorks: http://www.zepworks.com
Article about Deepdiff: http://zepworks.com/blog/diff-it-to-digg-it/

**Contributors**
Victor Hahn Castell

Thanks to:
- [hahncastell.de](http://hahncastell.de)
- [flexoptix.net](http://www.flexoptix.net)

Also thanks to:

- nfvs for Travis-CI setup script
- brbsix for initial Py3 porting
- WangFenjin for unicode support
- timoilya for comparing list of sets when ignoring order
- Bernhard10 for significant digits comparison
- b-jazz for PEP257 cleanup, Standardize on full names, fixing line endings.
- Victor Hahn Castell @ Flexoptix for deep set comparison and exclusion patterns
- finnhughes for fixing __slots__
2 changes: 0 additions & 2 deletions deepdiff/__init__.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import logging


if __name__ == '__main__':
logging.basicConfig(format='%(asctime)s %(levelname)8s %(message)s')


from .diff import DeepDiff
from .search import DeepSearch
from .contenthash import DeepHash
Expand Down
83 changes: 44 additions & 39 deletions deepdiff/contenthash.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,41 +3,19 @@
from __future__ import absolute_import
from __future__ import print_function
import sys
import datetime
from decimal import Decimal
from collections import Iterable
from collections import MutableMapping
from collections import defaultdict
from decimal import Decimal
from hashlib import sha1
import logging

from deepdiff.helper import py3

if py3: # pragma: no cover
from builtins import int
strings = (str, bytes) # which are both basestring
numbers = (int, float, complex, datetime.datetime, datetime.date, Decimal)
items = 'items'
else: # pragma: no cover
strings = (str, unicode)
numbers = (int, float, long, complex, datetime.datetime, datetime.date, Decimal)
items = 'iteritems'
from deepdiff.helper import py3, int, strings, numbers, items

logger = logging.getLogger(__name__)

WARNING_NUM = 0


def warn(*args, **kwargs): # pragma: no cover
global WARNING_NUM

if WARNING_NUM < 10:
WARNING_NUM += 1
logger.warning(*args, **kwargs)


class Skipped(object):

def __repr__(self):
return "Skipped" # pragma: no cover

Expand All @@ -46,7 +24,6 @@ def __str__(self):


class Unprocessed(object):

def __repr__(self):
return "Error: Unprocessed" # pragma: no cover

Expand All @@ -55,7 +32,6 @@ def __str__(self):


class NotHashed(object):

def __repr__(self):
return "Error: NotHashed" # pragma: no cover

Expand All @@ -64,22 +40,29 @@ def __str__(self):


class DeepHash(dict):

r"""
**DeepHash**
"""

show_warning = True

def __init__(self, obj, hashes=None, exclude_types=set(),
hasher=hash, ignore_repetition=True, **kwargs):
def __init__(self,
obj,
hashes=None,
exclude_types=set(),
hasher=hash,
ignore_repetition=True,
significant_digits=None,
**kwargs):
if kwargs:
raise ValueError(("The following parameter(s) are not valid: %s\n"
"The valid parameters are obj, hashes, exclude_types."
"hasher and ignore_repetition.") % ', '.join(kwargs.keys()))
raise ValueError(
("The following parameter(s) are not valid: %s\n"
"The valid parameters are obj, hashes, exclude_types."
"hasher and ignore_repetition.") % ', '.join(kwargs.keys()))
self.obj = obj
self.exclude_types = set(exclude_types)
self.exclude_types_tuple = tuple(exclude_types) # we need tuple for checking isinstance
self.exclude_types_tuple = tuple(
exclude_types) # we need tuple for checking isinstance
self.ignore_repetition = ignore_repetition

self.hasher = hasher
Expand All @@ -89,6 +72,7 @@ def __init__(self, obj, hashes=None, exclude_types=set(),
self.unprocessed = Unprocessed()
self.skipped = Skipped()
self.not_hashed = NotHashed()
self.significant_digits = significant_digits

self.__hash(obj, parents_ids=frozenset({id(obj)}))

Expand Down Expand Up @@ -118,7 +102,7 @@ def __add_to_frozen_set(parents_ids, item_id):
parents_ids.add(item_id)
return frozenset(parents_ids)

def __get_and_set_hash(self, obj):
def __get_and_set_str_hash(self, obj):
obj_id = id(obj)
result = self.hasher(obj)
result = "str:{}".format(result)
Expand All @@ -140,7 +124,8 @@ def __hash_obj(self, obj, parents_ids=frozenset({}), is_namedtuple=False):
return self.unprocessed

result = self.__hash_dict(obj, parents_ids)
result = "nt{}".format(result) if is_namedtuple else "obj{}".format(result)
result = "nt{}".format(result) if is_namedtuple else "obj{}".format(
result)
return result

def __skip_this(self, obj):
Expand Down Expand Up @@ -194,7 +179,9 @@ def __hash_iterable(self, obj, parents_ids=frozenset({})):
if self.ignore_repetition:
result = list(result.keys())
else:
result = ['{}|{}'.format(i[0], i[1]) for i in getattr(result, items)()]
result = [
'{}|{}'.format(i[0], i[1]) for i in getattr(result, items)()
]

result.sort()
result = ','.join(result)
Expand All @@ -203,7 +190,23 @@ def __hash_iterable(self, obj, parents_ids=frozenset({})):
return result

def __hash_str(self, obj):
return self.__get_and_set_hash(obj)
return self.__get_and_set_str_hash(obj)

def __hash_number(self, obj):
# Based on diff.DeepDiff.__diff_numbers
if self.significant_digits is not None and isinstance(obj, (
float, complex, Decimal)):
obj_s = ("{:.%sf}" % self.significant_digits).format(obj)

# Special case for 0: "-0.00" should compare equal to "0.00"
if set(obj_s) <= set("-0."):
obj_s = "0.00"
result = "number:{}".format(obj_s)
obj_id = id(obj)
self[obj_id] = result
else:
result = "{}:{}".format(type(obj).__name__, obj)
return result

def __hash_tuple(self, obj, parents_ids):
# Checking to see if it has _fields. Which probably means it is a named
Expand Down Expand Up @@ -234,7 +237,7 @@ def __hash(self, obj, parent="root", parents_ids=frozenset({})):
result = self.__hash_str(obj)

elif isinstance(obj, numbers):
result = "{}:{}".format(type(obj).__name__, obj)
result = self.__hash_number(obj)

elif isinstance(obj, MutableMapping):
result = self.__hash_dict(obj, parents_ids)
Expand All @@ -251,7 +254,8 @@ def __hash(self, obj, parent="root", parents_ids=frozenset({})):
else:
result = self.__hash_obj(obj, parents_ids)

if result != self.not_hashed and obj_id not in self and not isinstance(obj, numbers):
if result != self.not_hashed and obj_id not in self and not isinstance(
obj, numbers):
self[obj_id] = result

if result is self.not_hashed: # pragma: no cover
Expand All @@ -260,6 +264,7 @@ def __hash(self, obj, parent="root", parents_ids=frozenset({})):

return result


if __name__ == "__main__": # pragma: no cover
if not py3:
sys.exit("Please run with Python 3 to verify the doc strings.")
Expand Down
Loading

0 comments on commit a6d4ffb

Please sign in to comment.