Skip to content

Commit

Permalink
release 1.24, fix Python 3.7 deprecation warnings about importing ABC…
Browse files Browse the repository at this point in the history
… types from collections vs collections.abc
  • Loading branch information
irmen committed Mar 1, 2018
1 parent e4d3d77 commit a0bb008
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 19 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ develop-eggs
.installed.cfg
lib
lib64
.idea/

# Build Folders (you can keep bin if you'd like, to store dlls and pdbs)
[Bb]in/
Expand Down
33 changes: 21 additions & 12 deletions serpent.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,16 +66,21 @@
import types
import os
import gc
import collections
import decimal
import datetime
import uuid
import array
import math
import numbers
import codecs
import collections
if sys.version_info >= (3, 4):
from collections.abc import KeysView, ValuesView, ItemsView
else:
from collections import KeysView, ValuesView, ItemsView

__version__ = "1.23"

__version__ = "1.24"
__all__ = ["dump", "dumps", "load", "loads", "register_class", "unregister_class", "tobytes"]

can_use_set_literals = sys.version_info >= (3, 2) # check if we can use set literals
Expand Down Expand Up @@ -151,17 +156,19 @@ def _ser_DictView(obj, serializer, outputstream, indentlevel):

def _reset_special_classes_registry():
_special_classes_registry.clear()
_special_classes_registry[collections.KeysView] = _ser_DictView
_special_classes_registry[collections.ValuesView] = _ser_DictView
_special_classes_registry[collections.ItemsView] = _ser_DictView
_special_classes_registry[KeysView] = _ser_DictView
_special_classes_registry[ValuesView] = _ser_DictView
_special_classes_registry[ItemsView] = _ser_DictView
if sys.version_info >= (2, 7):
_special_classes_registry[collections.OrderedDict] = _ser_OrderedDict
if sys.version_info >= (3, 4):
import enum

def _ser_Enum(obj, serializer, outputstream, indentlevel):
serializer._serialize(obj.value, outputstream, indentlevel)
_special_classes_registry[enum.Enum] = _ser_Enum


_reset_special_classes_registry()


Expand Down Expand Up @@ -284,7 +291,8 @@ def __init__(self, indent=False, set_literals=can_use_set_literals, module_in_cl
"""
Initialize the serializer.
indent=indent the output over multiple lines (default=false)
setLiterals=use set-literals or not (set to False if you need compatibility with Python < 3.2). Serpent chooses a sensible default for you.
setLiterals=use set-literals or not (set to False if you need compatibility with Python < 3.2).
Serpent chooses a sensible default for you.
module_in_classname = include module prefix for class names or only use the class name itself
"""
self.indent = indent
Expand All @@ -301,7 +309,7 @@ def serialize(self, obj):
if self.set_literals:
header += "python3.2\n" # set-literals require python 3.2+ to deserialize (ast.literal_eval limitation)
else:
header += "python2.6\n" # don't change this even though we don't support 2.6 any longer, otherwise we can't read older serpent strings
header += "python2.6\n" # don't change this, otherwise we can't read older serpent strings
out = [header]
if os.name == "java" and type(obj) is buffer:
obj = bytearray(obj)
Expand Down Expand Up @@ -455,8 +463,8 @@ def _check_hashable_type(self, t):
return
elif sys.version_info < (3, 0) and t is unicode:
return
raise TypeError("one of the keys in a dict or set is not of a primitive hashable type: "
+ str(t) + ". Use simple types as keys or use a list or tuple as container.")
raise TypeError("one of the keys in a dict or set is not of a primitive hashable type: " +
str(t) + ". Use simple types as keys or use a list or tuple as container.")

def ser_builtins_dict(self, dict_obj, out, level):
if id(dict_obj) in self.serialized_obj_ids:
Expand Down Expand Up @@ -544,11 +552,11 @@ def ser_decimal_Decimal(self, decimal_obj, out, level):
def ser_datetime_datetime(self, datetime_obj, out, level):
out.append(repr(datetime_obj.isoformat()))
dispatch[datetime.datetime] = ser_datetime_datetime

def ser_datetime_date(self, date_obj, out, level):
out.append(repr(date_obj.isoformat()))
dispatch[datetime.date] = ser_datetime_date

if os.name == "java" or sys.version_info < (2, 7): # jython bug http://bugs.jython.org/issue2010
def ser_datetime_timedelta(self, timedelta_obj, out, level):
secs = ((timedelta_obj.days * 86400 + timedelta_obj.seconds) * 10 ** 6 + timedelta_obj.microseconds) / 10 ** 6
Expand Down Expand Up @@ -614,7 +622,8 @@ def ser_default_class(self, obj, out, level):
value[slot] = getattr(obj, slot)
value["__class__"] = self.get_class_name(obj)
else:
raise TypeError("don't know how to serialize class " + str(obj.__class__) + ". Give it vars() or an appropriate __getstate__")
raise TypeError("don't know how to serialize class " +
str(obj.__class__) + ". Give it vars() or an appropriate __getstate__")
self._serialize(value, out, level)
finally:
self.serialized_obj_ids.discard(id(obj))
Expand Down
4 changes: 4 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
[wheel]
universal = 1

[pycodestyle]
max-line-length = 140
ignore = E402,E731
exclude = .git,__pycache__,.tox,docs,tests,build,dist,examples
10 changes: 7 additions & 3 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@
- ``ser_bytes = serpent.dumps(obj, indent=False, set_literals=True, module_in_classname=False):`` # serialize obj tree to bytes
- ``obj = serpent.loads(ser_bytes)`` # deserialize bytes back into object tree
- You can use ``ast.literal_eval`` yourself to deserialize, but ``serpent.deserialize`` works around a few corner cases. See source for details.
- You can use ``ast.literal_eval`` yourself to deserialize, but ``serpent.deserialize``
works around a few corner cases. See source for details.
Serpent is more sophisticated than a simple repr() + literal_eval():
Expand All @@ -61,11 +62,14 @@
- Why not use XML? Answer: because XML.
- Why not use JSON? Answer: because JSON is quite limited in the number of datatypes it supports, and you can't use comments in a JSON file.
- Why not use pickle? Answer: because pickle has security problems.
- Why not use ``repr()``/``ast.literal_eval()``? See above; serpent is a superset of this and provides more convenience. Serpent provides automatic serialization mappings for types other than the builtin primitive types. ``repr()`` can't serialize these to literals that ``ast.literal_eval()`` understands.
- Why not use ``repr()``/``ast.literal_eval()``? See above; serpent is a superset of this and provides more convenience.
Serpent provides automatic serialization mappings for types other than the builtin primitive types.
``repr()`` can't serialize these to literals that ``ast.literal_eval()`` understands.
- Why not a binary format? Answer: because binary isn't readable by humans.
- But I don't care about readability. Answer: doesn't matter, ``ast.literal_eval()`` wants a literal string, so that is what we produce.
- But I want better performance. Answer: ok, maybe you shouldn't use serpent in this case. Find an efficient binary protocol (protobuf?)
- Why only Python, Java and C#/.NET, but no bindings for insert-favorite-language-here? Answer: I don't speak that language. Maybe you could port serpent yourself?
- Why only Python, Java and C#/.NET, but no bindings for insert-favorite-language-here? Answer: I don't speak that language.
Maybe you could port serpent yourself?
- Where is the source? It's on Github: https://github.com/irmen/Serpent
- Can I use it everywhere? Sure, as long as you keep the copyright and disclaimer somewhere. See the LICENSE file.
Expand Down
15 changes: 11 additions & 4 deletions tests/test_serpent.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,12 @@
import traceback
import threading
import time
import collections
import types
import collections
if sys.version_info >= (3, 4):
from collections.abc import KeysView, ValuesView, ItemsView
else:
from collections import KeysView, ValuesView, ItemsView

if sys.version_info < (2, 7):
import unittest2 as unittest
Expand Down Expand Up @@ -918,8 +922,11 @@ def __init__(self, name, value):
def __getstate__(self):
return ("bogus", "state")


class BaseClass(object):
pass


class SubClass(BaseClass):
pass

Expand Down Expand Up @@ -978,9 +985,9 @@ def testRegisterOrderPreserving(self):
serpent.register_class(BaseClass, lambda: None)
serpent.register_class(SubClass, lambda: None)
classes = list(serpent._special_classes_registry)
self.assertEqual(collections.KeysView, classes.pop(0))
self.assertEqual(collections.ValuesView, classes.pop(0))
self.assertEqual(collections.ItemsView, classes.pop(0))
self.assertEqual(KeysView, classes.pop(0))
self.assertEqual(ValuesView, classes.pop(0))
self.assertEqual(ItemsView, classes.pop(0))
if sys.version_info >= (2, 7):
self.assertEqual(collections.OrderedDict, classes.pop(0))
if sys.version_info >= (3, 4):
Expand Down

0 comments on commit a0bb008

Please sign in to comment.