Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2022 David Schenck
Copyright (c) 2024 David Schenck

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
3 changes: 1 addition & 2 deletions docs/contents/API.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,4 @@ API
API/easytree.unfreeze
API/easytree.seal
API/easytree.sealed
API/easytree.unseal
API/deprecated
API/easytree.unseal
12 changes: 0 additions & 12 deletions docs/contents/API/deprecated.rst

This file was deleted.

12 changes: 12 additions & 0 deletions docs/contents/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,18 @@ Changelog
=====================================
The source code is hosted and maintained on `github <https://github.com/dschenck/easytree/>`_.

Version 1.0.0 (2024-11-12)
--------------------------
- removed deprecated :code:`easytree.Tree` class
- removed deprecated :code:`easytree.Node` class alias
- removed deprecated :code:`easytree.new` function
- removed deprecated :code:`easytree.load` function
- removed deprecated :code:`easytree.loads` function
- removed deprecated :code:`easytree.dump` function
- removed deprecated :code:`easytree.dumps` function
- removed deprecated :code:`easytree.serialize` function
- fixed bug on :code:`easytree.undefined.get`

Version 0.2.4 (2023-11-25)
--------------------------
- fixed a bug where :code:`dict.setdefault` would never set the default value
Expand Down
28 changes: 14 additions & 14 deletions docs/contents/getting-started.rst
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,15 @@ Inheritence
Setting or assigning values
---------------------------

Instead of raising an :code:`AttributeError`, reading a new attribute on an :code:`easytree.dict` creates and returns a new child :code:`Node`.
Instead of raising an :code:`AttributeError`, reading a new attribute on an :code:`easytree.dict` returns a new :code:`undefined` node.

.. code-block::

>>> tree = easytree.dict()
>>> tree.address # new undefined node
<Node 'address'>
>>> tree.address # undefined node
<undefined 'address'>

Reading or setting an attribute on such child node dynamically *casts* it as an :code:`easytree.dict`.
Reading or setting an attribute on such child node dynamically *casts* it as an :code:`easytree.dict` and assigns it to its parent.

.. code-block::

Expand All @@ -63,11 +63,11 @@ Alternatively, using a list method such as :code:`append` dynamically *casts* th
.. code-block::

>>> tree = easytree.dict()
>>> tree.address
<Node 'address'>
>>> tree.address # undefined node
<undefined 'address'>

>>> tree.address.country.append("United States")
>>> tree.address
>>> tree.address # now a dict
{"country": ["United States"]}


Expand All @@ -85,7 +85,7 @@ Of course, you can use the dot or bracket notation interchangeably, both to read
"bar"

.. note::
The bracket notation remains necessary if the key is not a valid attribute identifier name.
The bracket notation remains necessary if the key is not a valid attribute identifier name, or if the key is identical to a :code:`dict` method name.

.. code-block::

Expand Down Expand Up @@ -119,15 +119,15 @@ Dictionaries assigned to an :code:`easytree.dict` or added to an :code:`easytree
]


Lists assigned to an :code:`easytree.dict` are *cast* as :code:`easytree.list` instances.
Lists assigned to an :code:`easytree.dict` are also *cast* as :code:`easytree.list` instances.

.. code-block::

>>> tree = easytree.dict({"numbers": [1,3,5]})
>>> isinstance(tree.numbers, easytree.list)
True

Tuple values assigned to an :code:`easytree.dict` are also *cast*.
Tuple values assigned to an :code:`easytree.dict` are also *cast* as tuples of :code:`easytree` objects.

.. code-block::

Expand Down Expand Up @@ -206,15 +206,15 @@ Because the :code:`append` method returns a reference to the last appended item,

The undefined node
------------------
An :code:`undefined` node object created when an undefined attribute is read from an :code:`easytree.dict` node.
An :code:`undefined` node object is returned when an undefined attribute is read from an :code:`easytree.dict` node. This falsy object contains a reference to its parent object, as well as the key from which this object was returned.

.. code-block::

>>> person = easytree.dict()
>>> person.address
<Node 'address'>
<undefined 'address'>

Assigning or reading an attribute from an :code:`undefined` node *casts* it as a dictionary.
Assigning or reading an attribute from an :code:`undefined` node *casts* it as a dictionary. This is possible since the :code:`undefined` object keeps a reference to its parent and the key from which it was returned.

.. code-block::

Expand Down Expand Up @@ -249,7 +249,7 @@ By definition, and unless an easytree is sealed or frozen, reading an undefined

>>> profile = easytree.dict({"firstname":"David"})
>>> profile.firstnam #typo
<Node 'firstnam'>
<undefined 'firstnam'>

Using a numeric key on an undefined node will cast the node as a dictionary, not a list.

Expand Down
9 changes: 5 additions & 4 deletions docs/contents/sealing-freezing.rst
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
Sealing and freezing
=====================================
.. note::

New with version 0.1.8

While :code:`easytree` makes it easy to create deeply-nested trees, it can also make it error prone when reading back properties.
Sealing and freezing allow to protect trees by restricting some or all mutations to a tree.

Expand Down Expand Up @@ -43,3 +39,8 @@ Freezing a tree prevents the user from accidentally creating new nodes or changi
AttributeError: cannot set attribute 'city' on frozen node

You can :code:`freeze` and :code:`unfreeze` a tree with the dedicated root-level functions. These functions return a *new* tree (i.e. these functions are not in-place).
::

>>> person = easytree.freeze({"name":"Bob", "address":{"city":"New York"}})
>>> person.address.city = "Los Angeles"
AttributeError: cannot set attribute 'city' on frozen node
2 changes: 1 addition & 1 deletion docs/contents/subclassing.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Subclassing
-----------
Starting with version 0.2.1., subclassing :code:`easytree.dict` and :code:`easytree.list` classes is possible.
Subclassing an :code:`easytree.dict` or an :code:`easytree.list` class is possible.

.. attention::
The only requirement is to keep the signature of the :code:`__init__` method unchanged in your subclass. You may amend the actual method, but the signature should remain the same.
Expand Down
30 changes: 14 additions & 16 deletions easytree/__init__.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,24 @@
# metadata
__version__ = "0.2.4"

from easytree.tree import (
Node,
serialize,
)
__version__ = "1.0.0"

from easytree.utils import (
new,
load,
loads,
dump,
dumps,
frozen,
freeze,
unfreeze,
sealed,
frozen,
seal,
unseal,
sealed,
)

from easytree.types import dict, list, undefined

# export Node as Tree
Tree = Node
__all__ = [
"dict",
"freeze",
"frozen",
"list",
"seal",
"sealed",
"undefined",
"unfreeze",
"unseal",
]
Loading