Skip to content

Commit

Permalink
release 3.140.20326
Browse files Browse the repository at this point in the history
  • Loading branch information
klahnakoski committed Nov 21, 2020
2 parents b5593de + 90b0f09 commit 1f7ec88
Show file tree
Hide file tree
Showing 18 changed files with 944 additions and 167 deletions.
9 changes: 6 additions & 3 deletions mo_dots/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@
is_many,
LIST,
list_types,
container_types, finite_types,
container_types,
finite_types,
)
from mo_dots.nones import Null, NullType
from mo_dots.objects import DataObject
Expand Down Expand Up @@ -166,7 +167,9 @@ def join_field(path):
for i, step in enumerate(path):
if step != -1:
parents = "." + ("." * i)
return parents + ".".join([f.replace(".", "\\.") for f in path[i:] if f != None])
return parents + ".".join([
f.replace(".", "\\.") for f in path[i:] if f != None
])
return "." + ("." * len(path))
output = ".".join([f.replace(".", "\\.") for f in path if f != None])
return output if output else "."
Expand Down Expand Up @@ -543,7 +546,7 @@ def list_to_data(v):
return output


def to_data(v):
def to_data(v=None):
"""
WRAP AS Data OBJECT FOR DATA PROCESSING: https://github.com/klahnakoski/mo-dots/tree/dev/docs
:param v: THE VALUE TO WRAP
Expand Down
9 changes: 4 additions & 5 deletions mo_dots/datas.py
Original file line number Diff line number Diff line change
Expand Up @@ -293,9 +293,10 @@ def __eq__(self, other):
def __ne__(self, other):
return not self.__eq__(other)

def get(self, key, default=None):
d = self._internal_dict
return d.get(key, default)
get = __getitem__
# def get(self, key, default=None):
# d = self._internal_dict
# return d.get(key, default)

def items(self):
d = self._internal_dict
Expand Down Expand Up @@ -510,5 +511,3 @@ def is_data(d):
:return: True IF d IS A TYPE THAT HOLDS DATA
"""
return d.__class__ in data_types


18 changes: 11 additions & 7 deletions mo_dots/lists.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@
from mo_dots.utils import CLASS

Log = delay_import("mo_logs.Log")
datawrap, coalesce, list_to_data, to_data, from_data, Null, EMPTY = expect("datawrap", "coalesce", "list_to_data", "to_data", "from_data", "Null", "EMPTY")
datawrap, coalesce, list_to_data, to_data, from_data, Null, EMPTY = expect(
"datawrap", "coalesce", "list_to_data", "to_data", "from_data", "Null", "EMPTY"
)


LIST = str("list")
Expand Down Expand Up @@ -99,7 +101,7 @@ def get(self, key):
"""
output = []
for v in _get(self, LIST):
element = coalesce(datawrap(v), Null).get(key)
element = datawrap(v).get(key)
if element.__class__ == FlatList:
output.extend(from_data(element))
else:
Expand All @@ -110,13 +112,14 @@ def select(self, key):
Log.error("Not supported. Use `get()`")

def filter(self, _filter):
return FlatList(
vals=[from_data(u) for u in (to_data(v) for v in _get(self, LIST)) if _filter(u)]
)
return FlatList(vals=[
from_data(u) for u in (to_data(v) for v in _get(self, LIST)) if _filter(u)
])

def __delslice__(self, i, j):
Log.error(
"Can not perform del on slice: modulo arithmetic was performed on the parameters. You can try using clear()"
"Can not perform del on slice: modulo arithmetic was performed on the"
" parameters. You can try using clear()"
)

def __clear__(self):
Expand Down Expand Up @@ -145,7 +148,8 @@ def __getslice__(self, i, j):
if _emit_slice_warning:
_emit_slice_warning = False
Log.warning(
"slicing is broken in Python 2.7: a[i:j] == a[i+len(a), j] sometimes. Use [start:stop:step] (see "
"slicing is broken in Python 2.7: a[i:j] == a[i+len(a), j] sometimes."
" Use [start:stop:step] (see "
"https://github.com/klahnakoski/mo-dots/tree/dev/docs#the-slice-operator-in-python27-is-inconsistent"
")"
)
Expand Down
9 changes: 6 additions & 3 deletions mo_dots/nones.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,9 @@ def __eq__(self, other):
return other == None

def __ne__(self, other):
return other is not None and _get(other, CLASS) is not NullType and other != None
return (
other is not None and _get(other, CLASS) is not NullType and other != None
)

def __or__(self, other):
if other is True:
Expand Down Expand Up @@ -190,6 +192,7 @@ def __getattr__(self, key):
return to_data(v.get(key))
except Exception as e:
from mo_logs import Log

Log.error("not expected", cause=e)

def __setattr__(self, key, value):
Expand Down Expand Up @@ -237,7 +240,7 @@ def __hash__(self):
return _null_hash


Null = NullType() # INSTEAD OF None!!!
Null = NullType() # INSTEAD OF None!!!


def _assign_to_null(obj, path, value, force=True):
Expand All @@ -253,7 +256,7 @@ def _assign_to_null(obj, path, value, force=True):
d = _get(obj, "__dict__")
o = d[OBJ]
p = d["__key__"]
s = [p]+path
s = [p] + path
return _assign_to_null(o, s, value)

path0 = path[0]
Expand Down
32 changes: 22 additions & 10 deletions mo_dots/objects.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,22 @@

from mo_dots.datas import register_data, Data, SLOT
from mo_dots.lists import FlatList
from mo_dots.nones import NullType
from mo_dots.nones import NullType, Null
from mo_dots.utils import CLASS, OBJ
from mo_future import binary_type, generator_types, get_function_arguments, get_function_defaults, none_type, text, Mapping
from mo_future import (
binary_type,
generator_types,
get_function_arguments,
get_function_defaults,
none_type,
text,
Mapping,
)
from mo_imports import export, expect

get_attr, set_attr, list_to_data, to_data, from_data = expect("get_attr", "set_attr", "list_to_data", "to_data", "from_data")
get_attr, set_attr, list_to_data, to_data, from_data = expect(
"get_attr", "set_attr", "list_to_data", "to_data", "from_data"
)

_new = object.__new__
_get = object.__getattribute__
Expand Down Expand Up @@ -62,21 +72,21 @@ def items(self):
return obj.__dict__.items()
except Exception as e:
return [
(k, getattr(obj, k, None))
for k in dir(obj)
if not k.startswith("__")
(k, getattr(obj, k, None)) for k in dir(obj) if not k.startswith("__")
]

def iteritems(self):
obj = _get(self, OBJ)
try:
return obj.__dict__.iteritems()
except Exception as e:

def output():
for k in dir(obj):
if k.startswith("__"):
continue
yield k, getattr(obj, k, None)

return output()

def __data__(self):
Expand Down Expand Up @@ -118,12 +128,12 @@ def datawrap(v):
return list_to_data(v)
elif type_ in (Data, DataObject, FlatList, NullType):
return v
elif type_ in (none_type, text, binary_type, int, float, Decimal, datetime, date):
elif type_ in (text, binary_type, int, float, Decimal, datetime, date):
return v
elif type_ in generator_types:
return (to_data(vv) for vv in v)
elif isinstance(v, (text, binary_type, int, float, Decimal, datetime, date, FlatList, NullType, Mapping, none_type)):
return v
elif v == None:
return Null
elif hasattr(v, "__data__"):
return v.__data__()
else:
Expand Down Expand Up @@ -153,7 +163,9 @@ def __call__(self, *args, **kwargs):

ordered_params = dict(zip(params, args))

output = self.class_(**params_pack(params, ordered_params, kwargs, settings, defaults))
output = self.class_(
**params_pack(params, ordered_params, kwargs, settings, defaults)
)
return DataObject(output)


Expand Down
15 changes: 10 additions & 5 deletions mo_dots/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ def get_logger():
return _Log
try:
from mo_logs import Log as _Log

return _Log
except Exception as e:
_Log = PoorLogger()
Expand All @@ -36,23 +37,27 @@ def get_module(name):
try:
return importlib.import_module(name)
except Exception as e:
get_logger().error("`pip install " + name.split(".")[0].replace("_", "-") + "` to enable this feature", cause=e)
get_logger().error(
"`pip install "
+ name.split(".")[0].replace("_", "-")
+ "` to enable this feature",
cause=e,
)


class PoorLogger(object):
@classmethod
def note(cls, note, **kwargs):
STDOUT.write(note.encode('utf8')+b"\n")
STDOUT.write(note.encode("utf8") + b"\n")

@classmethod
def warning(cls, note, **kwargs):
STDOUT.write(b"WARNING: " + note.encode('utf8') + b"\n")
STDOUT.write(b"WARNING: " + note.encode("utf8") + b"\n")

@classmethod
def error(cls, note, **kwargs):
STDERR.write(note.encode('utf8'))
STDERR.write(note.encode("utf8"))
if str("cause") in kwargs:
raise kwargs[str("cause")]
else:
raise Exception(note)

4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@
classifiers=["Development Status :: 4 - Beta","Topic :: Software Development :: Libraries","Topic :: Software Development :: Libraries :: Python Modules","License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)","Programming Language :: Python :: 2.7","Programming Language :: Python :: 3.6","Programming Language :: Python :: 3.7"],
description='More Dots! Dot-access to Python dicts like Javascript',
include_package_data=True,
install_requires=["mo-future==3.130.20302","mo-imports==3.135.20303"],
install_requires=["mo-future==3.136.20306","mo-imports==3.135.20303"],
license='MPL 2.0',
long_description='\n# More Dots!\n\n\n|Branch |Status |\n|------------|---------|\n|master | [![Build Status](https://travis-ci.org/klahnakoski/mo-dots.svg?branch=master)](https://travis-ci.org/klahnakoski/mo-dots) |\n|dev | [![Build Status](https://travis-ci.org/klahnakoski/mo-dots.svg?branch=dev)](https://travis-ci.org/klahnakoski/mo-dots) [![Coverage Status](https://coveralls.io/repos/github/klahnakoski/mo-dots/badge.svg?branch=dev)](https://coveralls.io/github/klahnakoski/mo-dots?branch=dev) |\n\n\n\n## Overview\n\nThis library defines a `Data` class that can serve as a replacement for `dict`, with additional features. \n\n >>> from mo_dots import to_data, Data\n\n*See the [full documentation](https://github.com/klahnakoski/mo-dots/tree/dev/docs) for all the features of `mo-dots`*\n\n### Easy Definition\n\nDefine `Data` using named parameters, just like you would a `dict`\n\n >>> Data(b=42, c="hello world")\n Data({\'b\': 42, \'c\': \'hello world\'})\n\nYou can also wrap existing `dict`s so they can be used like `Data`\n\n >>> to_data({\'b\': 42, \'c\': \'hello world\'})\n Data({\'b\': 42, \'c\': \'hello world\'})\n\n### Dot Access\n\nAccess properties with attribute dots: `a.b == a["b"]`. You have probably seen this before.\n\n### Path Access\n\nAccess properties by dot-delimited path.\n\n\t>>> a = to_data({"b": {"c": 42}})\n\t>>> a["b.c"] == 42\n\tTrue\n\n### Safe Access\n\nIf a property does not exist then return `Null` rather than raising an error.\n\n\t>>> a = Data()\n\ta == {}\n\t>>> a.b == None\n\tTrue\n\t>>> a.b.c == None\n\tTrue\n\t>>> a[None] == None\n\tTrue\n\n### Path assignment\n\nNo need to make intermediate `dicts`\n\n >>> a = Data()\n a == {}\n >>> a["b.c"] = 42 # same as a.b.c = 42\n a == {"b": {"c": 42}}\n\n### Path accumulation\n\nUse `+=` to add to a property; default zero (`0`)\n\n >>> a = Data()\n a == {}\n >>> a.b.c += 1\n a == {"b": {"c": 1}}\n >>> a.b.c += 42\n a == {"b": {"c": 43}}\n\nUse `+=` with a list ([]) to append to a list; default empty list (`[]`)\n\n >>> a = Data()\n a == {}\n >>> a.b.c += [1]\n a == {"b": {"c": [1]}}\n >>> a.b.c += [42]\n a == {"b": {"c": [1, 42]}}\n\n## Serializing to JSON\n\nThe standard Python JSON library does not recognize `Data` as serializable. You may overcome this by providing `default=from_data`; which converts the data structures in this module into Python primitives of the same. \n\n from mo_dots import from_data, to_data\n \n s = to_data({"a": ["b", 1]})\n result = json.dumps(s, default=from_data) \n\nAlternatively, you may consider [mo-json](https://pypi.org/project/mo-json/) which has a function `value2json` that converts a larger number of data structures into JSON.\n\n\n## Summary\n\nThis library is the basis for a data transformation algebra: We want a succinct way of transforming data in Python. We want operations on data to result in yet more data. We do not want data operations to raise exceptions. This library is solves Python\'s lack of consistency (lack of closure) under the dot (`.`) and slice `[::]` operators when operating on data objects. \n\n[Full documentation](https://github.com/klahnakoski/mo-dots/tree/dev/docs)\n',
long_description_content_type='text/markdown',
name='mo-dots',
packages=["mo_dots"],
url='https://github.com/klahnakoski/mo-dots',
version='3.135.20303',
version='3.140.20326',
zip_safe=False
)
4 changes: 2 additions & 2 deletions setuptools.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
],
"description": "More Dots! Dot-access to Python dicts like Javascript",
"include_package_data": true,
"install_requires": ["mo-future==3.130.20302", "mo-imports==3.135.20303"],
"install_requires": ["mo-future==3.136.20306", "mo-imports==3.135.20303"],
"license": "MPL 2.0",
"long_description": {
"$concat": [
Expand Down Expand Up @@ -126,6 +126,6 @@
"name": "mo-dots",
"packages": ["mo_dots"],
"url": "https://github.com/klahnakoski/mo-dots",
"version": "3.135.20303",
"version": "3.140.20326",
"zip_safe": false
}
16 changes: 11 additions & 5 deletions tests/speedtest_wrap.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

from __future__ import absolute_import, division, unicode_literals

import gc
Expand Down Expand Up @@ -26,10 +25,13 @@ def test_wrap_1():
lambda: Data(i=Random.int(2000)),
lambda: {"i": Random.int(2000)},
lambda: FlatList([{"i": Random.int(2000)}]),
lambda: [{"i": Random.int(2000)}]
lambda: [{"i": Random.int(2000)}],
]

inputs = [switch[min(len(switch) - 1, int(floor(-log(Random.float(), 2))))]() for i in range(NUM_INPUT)]
inputs = [
switch[min(len(switch) - 1, int(floor(-log(Random.float(), 2))))]()
for i in range(NUM_INPUT)
]

for i in range(NUM_REPEAT):
results = []
Expand All @@ -55,10 +57,13 @@ def test_wrap_2():
lambda: {"i": Random.int(2000)},
lambda: Data(i=Random.int(2000)),
lambda: FlatList([{"i": Random.int(2000)}]),
lambda: [{"i": Random.int(2000)}]
lambda: [{"i": Random.int(2000)}],
]

inputs = [switch[min(len(switch) - 1, int(floor(-log(Random.float(), 2))))]() for i in range(NUM_INPUT)]
inputs = [
switch[min(len(switch) - 1, int(floor(-log(Random.float(), 2))))]()
for i in range(NUM_INPUT)
]

for i in range(NUM_REPEAT):
results = []
Expand All @@ -75,5 +80,6 @@ def test_wrap_2():

Log.note("Done {{i}} of {{num}}", i=i, num=NUM_REPEAT)


test_wrap_1()
test_wrap_2()

0 comments on commit 1f7ec88

Please sign in to comment.