diff --git a/docs/jupyter/tutorial.ipynb b/docs/jupyter/tutorial.ipynb new file mode 100644 index 0000000..390428c --- /dev/null +++ b/docs/jupyter/tutorial.ipynb @@ -0,0 +1,310 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Nutree Tutorial" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Nutree organizes arbitrary object instances in an unobtrusive way.
\n", + "That means, we can add existing objects without havin to derrive from a common \n", + "base class or having them implement a specific protocol." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Setup some sample classes and objects" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": {}, + "outputs": [], + "source": [ + "import uuid\n", + "\n", + "\n", + "class Department:\n", + " def __init__(self, name: str):\n", + " self.guid = uuid.uuid4()\n", + " self.name = name\n", + "\n", + " def __str__(self):\n", + " return f\"Department<{self.name}>\"\n", + "\n", + "\n", + "class Person:\n", + " def __init__(self, name: str, age: int):\n", + " self.guid = uuid.uuid4()\n", + " self.name = name\n", + " self.age = age\n", + "\n", + " def __str__(self):\n", + " return f\"Person<{self.name} ({self.age})>\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now create some instances" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": {}, + "outputs": [], + "source": [ + "development_dep = Department(\"Development\")\n", + "test__dep = Department(\"Test\")\n", + "marketing_dep = Department(\"Marketing\")\n", + "\n", + "alice = Person(\"Alice\", 25)\n", + "bob = Person(\"Bob\", 35)\n", + "claire = Person(\"Claire\", 45)\n", + "dave = Person(\"Dave\", 55)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's organize these objects in a hierarchical structure:" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Tree<'Organization'>\n", + "├── <__main__.Department object at 0x111f04e00>\n", + "│ ├── <__main__.Department object at 0x111b89f70>\n", + "│ │ ╰── <__main__.Person object at 0x111f05520>\n", + "│ ╰── <__main__.Person object at 0x111f04da0>\n", + "├── <__main__.Department object at 0x111edac90>\n", + "│ ╰── <__main__.Person object at 0x111f06a50>\n", + "╰── <__main__.Person object at 0x111ed9880>\n" + ] + } + ], + "source": [ + "from nutree import Tree\n", + "\n", + "tree = Tree(\"Organization\")\n", + "\n", + "dev_node = tree.add(development_dep)\n", + "test_node = dev_node.add(test__dep)\n", + "mkt_node = tree.add(marketing_dep)\n", + "\n", + "tree.add(alice)\n", + "dev_node.add(bob)\n", + "test_node.add(claire)\n", + "mkt_node.add(dave)\n", + "\n", + "tree.print()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Tree nodes store a reference to the object in the `node.data` attribute.\n", + "\n", + "The nodes are formatted by the object's `__repr__` implementation by default.
\n", + "We can overide ths by passing an f-string as `repr` argument:" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Tree<'Organization'>\n", + "├── Department\n", + "│ ├── Department\n", + "│ │ ╰── Person\n", + "│ ╰── Person\n", + "├── Department\n", + "│ ╰── Person\n", + "╰── Person\n" + ] + } + ], + "source": [ + "tree.print(repr=\"{node.data}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Iteration and Searching" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Mutation" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Data IDs and Clones" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Node<'Department', data_id=287245536>\n", + "├── Node<'Department', data_id=287017463>\n", + "│ ╰── Node<'Person', data_id=287245650>\n", + "╰── Node<'Person', data_id=287245530>\n", + "Node<'Department', data_id=287234761>\n", + "╰── Node<'Person', data_id=287245989>\n", + "Node<'Person', data_id=287234440>\n" + ] + } + ], + "source": [ + "tree.print(repr=\"{node}\", title=False)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Serialization" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[{'data': 'Department',\n", + " 'children': [{'data': 'Department',\n", + " 'children': [{'data': 'Person'}]},\n", + " {'data': 'Person'}]},\n", + " {'data': 'Department',\n", + " 'children': [{'data': 'Person'}]},\n", + " {'data': 'Person'}]" + ] + }, + "execution_count": 36, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tree.to_dict_list()" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[(0, {}), (1, {}), (2, {}), (1, {}), (0, {}), (5, {}), (0, {})]" + ] + }, + "execution_count": 37, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "list(tree.to_list_iter())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Tree<'4595934048'>\n", + "╰── 'A'\n" + ] + } + ], + "source": [ + "t = Tree._from_list([(0, \"A\")])\n", + "print(t.format())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.6" + }, + "orig_nbformat": 4 + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/tutorial.ipynb b/docs/tutorial.ipynb deleted file mode 100644 index 787c2cd..0000000 --- a/docs/tutorial.ipynb +++ /dev/null @@ -1,157 +0,0 @@ -{ - "cells": [ - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Nutree Tutorial" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Start by creating an instance of the `Tree` class:" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Tree<'Demo'>\n", - "╰── 'A'\n", - " ├── 'a'\n", - " ╰── 'b'\n" - ] - } - ], - "source": [ - "from nutree import Tree\n", - "\n", - "tree = Tree(\"Demo\")\n", - "\n", - "node_a = tree.add(\"A\")\n", - "node_a.add(\"a\")\n", - "node_a.add(\"b\")\n", - "tree.print()\n" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[{'data': 'A', 'children': [{'data': 'a'}, {'data': 'b'}]}]" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "tree.to_dict_list()\n" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[(0, 'A'), (1, 'a'), (1, 'b')]" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "list(tree.to_list_iter())\n" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Node<'A', data_id=-6155505832273219541>\n", - "├── Node<'a', data_id=1939327296338879458>\n", - "╰── Node<'b', data_id=6853019497100189332>\n" - ] - } - ], - "source": [ - "print(tree.format(repr=\"{node}\", title=False))\n" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Tree<'4407606288'>\n", - "╰── 'A'\n" - ] - } - ], - "source": [ - "t = Tree._from_list([(0, \"A\")])\n", - "print(t.format())\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "interpreter": { - "hash": "f600cddd0c1baa98c0960b46a2f454b2dd6263de5ae4ff509241484089717206" - }, - "kernelspec": { - "display_name": "Python 3.9.1 64-bit ('nutree-usdBtVUd': pipenv)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.1" - }, - "orig_nbformat": 4 - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/pyproject.toml b/pyproject.toml index 2b172f9..f61843a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,6 +20,12 @@ ignore = [ "E721", # Do not compare types, use `isinstance()` ] +[tool.ruff.lint.per-file-ignores] +"*.ipynb" = [ # Jupyter Notebooks + "T20", # print statement + "E402", # module level import not at top of file +] + # [tool.ruff.lint.isort] # case-sensitive = true diff --git a/tox.ini b/tox.ini index 9d64302..cfcbd0a 100644 --- a/tox.ini +++ b/tox.ini @@ -66,8 +66,8 @@ deps = ruff commands = ruff -V - ruff check nutree tests setup.py - ruff format --check nutree tests setup.py + ruff check nutree tests docs/jupyter setup.py + ruff format --check nutree tests docs/jupyter setup.py [testenv:format] @@ -77,8 +77,8 @@ deps = ruff changedir = {toxinidir} commands = - ruff check --fix nutree tests setup.py - ruff format nutree tests setup.py + ruff check --fix nutree tests docs/jupyter setup.py + ruff format nutree tests docs/jupyter setup.py {[testenv:lint]commands}