Skip to content

Commit

Permalink
Python 3.10 compat
Browse files Browse the repository at this point in the history
  • Loading branch information
dvershinin committed Feb 18, 2022
1 parent 8c70f50 commit 53a59e0
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 7 deletions.
2 changes: 1 addition & 1 deletion sde/__about__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '1.1.3'
__version__ = '1.1.4'
45 changes: 39 additions & 6 deletions sde/collection.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
# -*- coding: utf-8 -*-

import collections
import json
import re
import yaml

import sys
from abc import ABCMeta, abstractmethod

import yaml
from six import add_metaclass, string_types as basestring, iteritems

from six.moves import collections_abc

SPLIT_REGEX = r"(?<!\\)(\.)"

Expand Down Expand Up @@ -55,6 +54,7 @@ def split_key(key, max_keys=0):
class DottedCollection(object):
"""Abstract Base Class for DottedDict and DottedDict"""


@classmethod
def factory(cls, initial=None):
"""Returns a DottedDict or a DottedList based on the type of the
Expand All @@ -68,11 +68,13 @@ def factory(cls, initial=None):
else:
return initial


@classmethod
def load_json(cls, json_value):
"""Returns a DottedCollection from a JSON string"""
return cls.factory(json.loads(json_value))


@classmethod
def _factory_by_index(cls, dotted_key):
"""Returns the proper DottedCollection that best suits the next key in
Expand All @@ -89,6 +91,7 @@ def _factory_by_index(cls, dotted_key):

return DottedCollection.factory([] if next_key.isdigit() else {})


def __init__(self, initial):
"""Base constructor. If there are nested dicts or lists they are
transformed into DottedCollection instances.
Expand All @@ -111,6 +114,7 @@ def __init__(self, initial):
except ValueError:
pass


def _validate_initial(self, initial):
"""Validates data so no unescaped dotted key is present."""
if isinstance(initial, list):
Expand All @@ -123,47 +127,58 @@ def _validate_initial(self, initial):
"DottedCollection!".format(key))
self._validate_initial(item)


def __len__(self):
return len(self.store)


def __iter__(self):
return iter(self.store)


def __repr__(self):
return repr(self.store)


def to_json(self):
return json.dumps(self, cls=DottedJSONEncoder, indent=4)


def to_yaml(self):
return yaml.dump(self, Dumper=DottedYAMLDumper)


@abstractmethod
def __getitem__(self, name):
pass


@abstractmethod
def __setitem__(self, name, value):
pass


@abstractmethod
def __delitem__(self, name):
pass


@abstractmethod
def to_python(self):
pass


class DottedList(DottedCollection, collections.MutableSequence):
class DottedList(DottedCollection, collections_abc.MutableSequence):
"""A list with support for the dotted path syntax"""


def __init__(self, initial=None):
DottedCollection.__init__(
self,
[] if initial is None else list(initial)
)


def __getitem__(self, index):
if isinstance(index, slice):
return self.store[index]
Expand All @@ -189,6 +204,7 @@ def __getitem__(self, index):
else:
raise IndexError('cannot get %s in %s' % (index, repr(self.store)))


def __setitem__(self, index, value):
if isinstance(index, int) \
or (isinstance(index, basestring) and index.isdigit()):
Expand Down Expand Up @@ -219,6 +235,7 @@ def __setitem__(self, index, value):
raise IndexError('cannot use %s as index in %s' % (
index, repr(self.store)))


def __delitem__(self, index):
if isinstance(index, int) \
or (isinstance(index, basestring) and index.isdigit()):
Expand All @@ -239,6 +256,7 @@ def __delitem__(self, index):
raise IndexError('cannot delete %s in %s' % (
index, repr(self.store)))


def to_python(self):
"""Returns a plain python list and converts to plain python objects all
this object's descendants.
Expand All @@ -251,18 +269,22 @@ def to_python(self):

return result


def insert(self, index, value):
self.store.insert(index, value)


class DottedDict(DottedCollection, collections.MutableMapping):
class DottedDict(DottedCollection, collections_abc.MutableMapping):
"""A dict with support for the dotted path syntax"""


def __init__(self, initial=None):
DottedCollection.__init__(
self,
{} if initial is None else dict(initial)
)


def __getitem__(self, k):
key = self.__keytransform__(k)

Expand All @@ -282,6 +304,7 @@ def __getitem__(self, k):

return target[alt_key]


def __setitem__(self, k, value):
key = self.__keytransform__(k)

Expand All @@ -297,6 +320,7 @@ def __setitem__(self, k, value):

self.store[my_key][alt_key] = value


def __delitem__(self, k):
key = self.__keytransform__(k)

Expand All @@ -316,6 +340,7 @@ def __delitem__(self, k):

del target[alt_key]


def to_python(self):
"""Returns a plain python dict and converts to plain python objects all
this object's descendants.
Expand All @@ -328,8 +353,10 @@ def to_python(self):

return result


__getattr__ = __getitem__


# self.store does not exist before __init__() initializes it

def __setattr__(self, key, value):
Expand All @@ -338,12 +365,14 @@ def __setattr__(self, key, value):
else:
self.__setitem__(key, value)


def __delattr__(self, key):
if key in self.__dict__ or key == 'store':
object.__delattr__(self, key)
else:
self.__delitem__(key)


def __contains__(self, k):
key = self.__keytransform__(k)

Expand All @@ -358,6 +387,7 @@ def __contains__(self, k):

return alt_key in target


def __keytransform__(self, key):
return key

Expand All @@ -374,6 +404,7 @@ def default(self, obj):
else:
return json.JSONEncoder.default(obj)


#
# YAML stuff
#
Expand All @@ -390,6 +421,8 @@ class DottedYAMLDumper(yaml.Dumper):
This suggests making a custom dumper for a hiearchy of types:
https://github.com/yaml/pyyaml/issues/51
"""


def represent_data(self, data):
if isinstance(data, DottedCollection):
return self.represent_data(data.store)
Expand Down

0 comments on commit 53a59e0

Please sign in to comment.