-
-

Welcome to pynodes’s documentation!

+
+

Welcome to nodestack’s documentation!

Note

This project is under active development.

@@ -80,7 +80,7 @@
@@ -88,16 +88,20 @@

Installation:

-
(venv) $ git clone https://gitea.lutix.org/ftg/nodes.git
+
(venv) $ git clone https://gitea.lutix.org/ftg/nodestack.git
 
-

Source code is hosted on my own instance of gitea.

+

or

+
(venv) $ pip install nodestack
+
+
+

Source code is hosted on my own instance of gitea.

Basic Usage:

-
import pynodes
+
import nodestack
 
-class Person(pynodes.Node):
+class Person(nodestack.Node):
     pass
 
 bob = Person('Bob')
diff --git a/docs/build/html/objects.inv b/docs/build/html/objects.inv
index e081bc40fe466d99ee763394c5aaf2e0a2c94342..62a4a4df2e54877b80dd19de80170583a4a9dfaf 100644
GIT binary patch
delta 328
zcmV-O0k{6C1FHj&C<$(FWMy-7VPk8NFGzo}PQx$|hW9*$5v-|T?Z(&vREdExy4t7M
zs$*NeD!sl~Sk-@qI
zkI39NA)11CBhqmB47@(w<#qhmTlx^hYOA~y^;{E=`(4$dGfv_A2v|6z7!xwhW^OkO
zs~J15vmjp4O5dSiFMj&_`uHS~&{H&*q6RkJ-BjtH|6{k%*Ha-c_mm%tyzioVMcel&
aFn4JaLX`Sa%yZd!$@P7D5UOuPIHSlLouobh

delta 326
zcmV-M0lEIG1E~X$CbR7>P}<02Z6M|3MP4WnZ@tkL_yDDv0Gyx?+)6k0%O=;Ae*;j}
zbQ6zypT-*s6^di-5WrSQJWo7T2Q~^07T7a*(
   
   
-  Python Module Index — pynodes 0.1 documentation
+  Python Module Index — nodestack 0.1 documentation
       
       
 
@@ -36,7 +36,7 @@
           
           
           
-            pynodes
+            nodestack
           
 
@@ -56,7 +56,7 @@
@@ -77,17 +77,17 @@

Python Module Index

- p + n
- +
 
- p
+ n
- pynodes + nodestack
diff --git a/docs/build/html/search.html b/docs/build/html/search.html index 5528c86..4c52c1f 100644 --- a/docs/build/html/search.html +++ b/docs/build/html/search.html @@ -3,7 +3,7 @@ - Search — pynodes 0.1 documentation + Search — nodestack 0.1 documentation @@ -32,7 +32,7 @@ - pynodes + nodestack
@@ -52,7 +52,7 @@
diff --git a/docs/build/html/searchindex.js b/docs/build/html/searchindex.js index ee8532b..dab3efb 100644 --- a/docs/build/html/searchindex.js +++ b/docs/build/html/searchindex.js @@ -1 +1 @@ -Search.setIndex({"docnames": ["api", "index"], "filenames": ["api.rst", "index.rst"], "titles": ["API", "Welcome to pynodes\u2019s documentation!"], "terms": {"i": [0, 1], "python": 0, "librari": 0, "manag": 0, "node": [0, 1], "class": [0, 1], "A": 0, "an": [0, 1], "object": 0, "which": 0, "relat": 0, "other": 0, "given": 0, "tree": 0, "chart": 0, "venv": 1, "pip": [], "instal": [], "import": 1, "name": 0, "str": 0, "parent": [0, 1], "none": 0, "sourc": [0, 1], "should": 0, "subclass": 0, "onli": 0, "add_child": [0, 1], "child": 0, "add": 0, "new": 0, "current": 0, "instanc": [0, 1], "static": 0, "check_lineag": 0, "list": 0, "bool": 0, "check": 0, "straight": 0, "lineag": 0, "1": 0, "ancestor": 0, "2": 0, "3": 0, "n": 0, "grand": 0, "children": 0, "classmethod": 0, "create_random_nod": 0, "type_": 0, "cmd": 0, "depth": 0, "int": 0, "0": 0, "creat": 0, "random": 0, "test": 0, "purpos": 0, "properti": 0, "path": 0, "return": 0, "represent": 0, "self": 0, "pretty_print": [0, 1], "print": 0, "from": 0, "reset_stat": 0, "reset": 0, "all": 0, "classvar": 0, "member": 0, "index": [], "modul": [], "search": [], "page": [], "level": 0, "sibl": 0, "get_child": 0, "find": 0, "specifi": 0, "noth": 0, "found": 0, "get_sibl": 0, "has_children": 0, "ha": 0, "one": 0, "least": 0, "has_par": 0, "has_sibl": 0, "is_child": 0, "is_sibl": 0, "code": 1, "host": 1, "my": 1, "own": 1, "gitea": 1, "link": [], "text": [], "usag": [], "basic": [], "pynod": 0, "api": 1, "thi": 1, "project": 1, "under": 1, "activ": 1, "develop": 1, "person": 1, "pass": 1, "bob": 1, "ev": 1, "alic": 1, "pretti": [], "alice_again": 1, "rais": 1, "error": 1, "cool": [], "bit": [], "some": [], "option": 0, "default": 0, "git": 1, "clone": 1, "http": 1, "lutix": 1, "org": 1, "ftg": 1, "paramet": 0, "param": [], "compar": 0, "cookbook": [], "crawl": [], "web": [], "The": [], "most": [], "simpl": [], "wai": [], "us": [], "our": [], "program": [], "argument": [], "simpli": [], "run": [], "main": [], "py": [], "u": [], "url": [], "webpag": [], "slowli": [], "To": [], "delai": [], "your": [], "crawler": [], "d": [], "10": [], "wait": [], "second": [], "between": [], "fetch": [], "blog": [], "you": [], "want": [], "flag": [], "while": [], "ignor": [], "match": [], "regex": [], "contain": []}, "objects": {"": [[0, 0, 0, "-", "pynodes"]], "pynodes": [[0, 1, 1, "", "Node"]], "pynodes.Node": [[0, 2, 1, "", "add_child"], [0, 2, 1, "", "check_lineage"], [0, 2, 1, "", "create_random_nodes"], [0, 2, 1, "", "get_child"], [0, 2, 1, "", "get_sibling"], [0, 2, 1, "", "has_children"], [0, 2, 1, "", "has_parent"], [0, 2, 1, "", "has_siblings"], [0, 2, 1, "", "is_child"], [0, 2, 1, "", "is_sibling"], [0, 3, 1, "", "level"], [0, 3, 1, "", "parents"], [0, 3, 1, "", "path"], [0, 2, 1, "", "pretty_print"], [0, 2, 1, "", "reset_stats"], [0, 3, 1, "", "siblings"]]}, "objtypes": {"0": "py:module", "1": "py:class", "2": "py:method", "3": "py:property"}, "objnames": {"0": ["py", "module", "Python module"], "1": ["py", "class", "Python class"], "2": ["py", "method", "Python method"], "3": ["py", "property", "Python property"]}, "titleterms": {"welcom": 1, "pynod": 1, "": 1, "document": 1, "basic": 1, "usag": 1, "indic": [], "tabl": [], "instal": 1, "api": 0, "content": 1}, "envversion": {"sphinx.domains.c": 3, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 9, "sphinx.domains.index": 1, "sphinx.domains.javascript": 3, "sphinx.domains.math": 2, "sphinx.domains.python": 4, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx.ext.viewcode": 1, "sphinx": 60}, "alltitles": {"Welcome to pynodes\u2019s documentation!": [[1, "welcome-to-pynodes-s-documentation"]], "Content:": [[1, "content"]], "Installation:": [[1, "installation"]], "Basic Usage:": [[1, "basic-usage"]], "API": [[0, "api"]]}, "indexentries": {"node (class in pynodes)": [[0, "pynodes.Node"]], "add_child() (pynodes.node method)": [[0, "pynodes.Node.add_child"]], "check_lineage() (pynodes.node static method)": [[0, "pynodes.Node.check_lineage"]], "create_random_nodes() (pynodes.node class method)": [[0, "pynodes.Node.create_random_nodes"]], "get_child() (pynodes.node method)": [[0, "pynodes.Node.get_child"]], "get_sibling() (pynodes.node method)": [[0, "pynodes.Node.get_sibling"]], "has_children() (pynodes.node method)": [[0, "pynodes.Node.has_children"]], "has_parent() (pynodes.node method)": [[0, "pynodes.Node.has_parent"]], "has_siblings() (pynodes.node method)": [[0, "pynodes.Node.has_siblings"]], "is_child() (pynodes.node method)": [[0, "pynodes.Node.is_child"]], "is_sibling() (pynodes.node method)": [[0, "pynodes.Node.is_sibling"]], "level (pynodes.node property)": [[0, "pynodes.Node.level"]], "module": [[0, "module-pynodes"]], "parents (pynodes.node property)": [[0, "pynodes.Node.parents"]], "path (pynodes.node property)": [[0, "pynodes.Node.path"]], "pretty_print() (pynodes.node method)": [[0, "pynodes.Node.pretty_print"]], "pynodes": [[0, "module-pynodes"]], "reset_stats() (pynodes.node class method)": [[0, "pynodes.Node.reset_stats"]], "siblings (pynodes.node property)": [[0, "pynodes.Node.siblings"]]}}) \ No newline at end of file +Search.setIndex({"docnames": ["api", "index"], "filenames": ["api.rst", "index.rst"], "titles": ["API", "Welcome to nodestack\u2019s documentation!"], "terms": {"i": [0, 1], "python": 0, "librari": 0, "manag": 0, "node": [0, 1], "class": [0, 1], "A": 0, "an": [0, 1], "object": 0, "which": 0, "relat": 0, "other": 0, "given": 0, "tree": 0, "chart": 0, "venv": 1, "pip": 1, "instal": [], "import": 1, "name": 0, "str": 0, "parent": [0, 1], "none": 0, "sourc": [0, 1], "should": 0, "subclass": 0, "onli": 0, "add_child": [0, 1], "child": 0, "add": 0, "new": 0, "current": 0, "instanc": [0, 1], "static": 0, "check_lineag": 0, "list": 0, "bool": 0, "check": 0, "straight": 0, "lineag": 0, "1": 0, "ancestor": 0, "2": 0, "3": 0, "n": 0, "grand": 0, "children": 0, "classmethod": 0, "create_random_nod": 0, "type_": 0, "cmd": 0, "depth": 0, "int": 0, "0": 0, "creat": 0, "random": 0, "test": 0, "purpos": 0, "properti": 0, "path": 0, "return": 0, "represent": 0, "self": 0, "pretty_print": [0, 1], "print": 0, "from": 0, "reset_stat": 0, "reset": 0, "all": 0, "classvar": 0, "member": 0, "index": [], "modul": [], "search": [], "page": [], "level": 0, "sibl": 0, "get_child": 0, "find": 0, "specifi": 0, "noth": 0, "found": 0, "get_sibl": 0, "has_children": 0, "ha": 0, "one": 0, "least": 0, "has_par": 0, "has_sibl": 0, "is_child": 0, "is_sibl": 0, "code": 1, "host": 1, "my": 1, "own": 1, "gitea": 1, "link": [], "text": [], "usag": [], "basic": [], "pynod": [], "api": 1, "thi": 1, "project": 1, "under": 1, "activ": 1, "develop": 1, "person": 1, "pass": 1, "bob": 1, "ev": 1, "alic": 1, "pretti": [], "alice_again": 1, "rais": 1, "error": 1, "cool": [], "bit": [], "some": [], "option": 0, "default": 0, "git": 1, "clone": 1, "http": 1, "lutix": 1, "org": 1, "ftg": 1, "paramet": 0, "param": [], "compar": 0, "cookbook": [], "crawl": [], "web": [], "The": [], "most": [], "simpl": [], "wai": [], "us": [], "our": [], "program": [], "argument": [], "simpli": [], "run": [], "main": [], "py": [], "u": [], "url": [], "webpag": [], "slowli": [], "To": [], "delai": [], "your": [], "crawler": [], "d": [], "10": [], "wait": [], "second": [], "between": [], "fetch": [], "blog": [], "you": [], "want": [], "flag": [], "while": [], "ignor": [], "match": [], "regex": [], "contain": [], "nodestack": 0}, "objects": {"": [[0, 0, 0, "-", "nodestack"]], "nodestack": [[0, 1, 1, "", "Node"]], "nodestack.Node": [[0, 2, 1, "", "add_child"], [0, 2, 1, "", "check_lineage"], [0, 2, 1, "", "create_random_nodes"], [0, 2, 1, "", "get_child"], [0, 2, 1, "", "get_sibling"], [0, 2, 1, "", "has_children"], [0, 2, 1, "", "has_parent"], [0, 2, 1, "", "has_siblings"], [0, 2, 1, "", "is_child"], [0, 2, 1, "", "is_sibling"], [0, 3, 1, "", "level"], [0, 3, 1, "", "parents"], [0, 3, 1, "", "path"], [0, 2, 1, "", "pretty_print"], [0, 2, 1, "", "reset_stats"], [0, 3, 1, "", "siblings"]]}, "objtypes": {"0": "py:module", "1": "py:class", "2": "py:method", "3": "py:property"}, "objnames": {"0": ["py", "module", "Python module"], "1": ["py", "class", "Python class"], "2": ["py", "method", "Python method"], "3": ["py", "property", "Python property"]}, "titleterms": {"welcom": 1, "pynod": [], "": 1, "document": 1, "basic": 1, "usag": 1, "indic": [], "tabl": [], "instal": 1, "api": 0, "content": 1, "nodestack": 1}, "envversion": {"sphinx.domains.c": 3, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 9, "sphinx.domains.index": 1, "sphinx.domains.javascript": 3, "sphinx.domains.math": 2, "sphinx.domains.python": 4, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx.ext.viewcode": 1, "sphinx": 60}, "alltitles": {"API": [[0, "api"]], "Welcome to nodestack\u2019s documentation!": [[1, "welcome-to-nodestack-s-documentation"]], "Content:": [[1, "content"]], "Installation:": [[1, "installation"]], "Basic Usage:": [[1, "basic-usage"]]}, "indexentries": {}}) \ No newline at end of file diff --git a/docs/source/api.rst b/docs/source/api.rst index bb2c8f9..21ff1ce 100644 --- a/docs/source/api.rst +++ b/docs/source/api.rst @@ -1,8 +1,8 @@ API ===== -**pynodes** is a Python library to manage Nodes classes. +**nodestack** is a Python library to manage Nodes classes. A node is an object which is related to other nodes given a tree chart. -.. automodule:: pynodes +.. automodule:: nodestack :members: diff --git a/docs/source/conf.py b/docs/source/conf.py index aa92acb..079faaa 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -13,13 +13,13 @@ import os import sys sys.path.insert(0, os.path.abspath('../..')) -import pynodes +import nodestack import sphinx_rtd_theme # -- Project information ----------------------------------------------------- -project = 'pynodes' +project = 'nodestack' copyright = '2024, fabthegreat' author = 'fabthegreat' diff --git a/docs/source/index.rst b/docs/source/index.rst index 91d0d40..5174bf4 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -1,10 +1,10 @@ -.. pynodes documentation master file, created by +.. nodestack documentation master file, created by sphinx-quickstart on Sat Mar 30 18:38:12 2024. You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. -Welcome to pynodes's documentation! -=================================== +Welcome to nodestack's documentation! +===================================== .. note:: @@ -22,18 +22,24 @@ Installation: ------------- .. code-block:: console - (venv) $ git clone https://gitea.lutix.org/ftg/nodes.git + (venv) $ git clone https://gitea.lutix.org/ftg/nodestack.git -Source code is hosted on my own instance of `gitea `_. +or + +.. code-block:: console + + (venv) $ pip install nodestack + +Source code is hosted on my own instance of `gitea `_. Basic Usage: ------------ .. code-block:: python - import pynodes + import nodestack - class Person(pynodes.Node): + class Person(nodestack.Node): pass bob = Person('Bob') diff --git a/pynodes.py b/pynodes.py deleted file mode 100644 index e36326d..0000000 --- a/pynodes.py +++ /dev/null @@ -1,235 +0,0 @@ -from __future__ import annotations # for Class forward reference -import random -import uuid - -from typing import ClassVar - -class Node: - """ - Should be subclassed only - """ - # Class Var for statistics - deepest_level: ClassVar[int] = 0 - largest_sibling_number: ClassVar[int] = 0 - all_nodes: ClassVar[list[Node]] = [] - - def __init_subclass__(cls): - """ each subclass must define its own ClassVar """ - # TODO to be renamed for clarity - super().__init_subclass__() - cls.deepest_level: ClassVar[int] = 0 - cls.largest_sibling_number: ClassVar[int] = 0 - cls.all_nodes: ClassVar[list[Node]] = [] - return cls - - def __new__(cls, name: str, parent: Node | None = None) -> None: - """ - prevent the user to set the same name for 2 nodes - ??? better to do it with uuid? - """ - for n in cls.all_nodes: - if name == n.name: - raise AttributeError('Node with this name already exists') - else: - return super().__new__(cls) - - def __init__(self, name: str, parent: Node | None = None) -> None: - self.name = name - self.parent = parent # is set with add_child - self.children: list[Node] = [] - self.id = uuid.uuid4() - type(self).all_nodes.append(self) - - def add_child(self, child: Node) -> None: - """ - Add new child node to current instance - - :param child: Node object - """ - child.parent = self - if child.name not in [c.name for c in self.children]: - self.children.append(child) - if child.level > type(self).deepest_level: - type(self).deepest_level = child.level - if len(self.children) > type(self).largest_sibling_number: - type(self).largest_sibling_number = len(self.children) - else: - raise Exception('Child with same name already exists') - - @property - def siblings(self) -> list[Node]: - """ - Returns all the siblings of the Node object - """ - if self.has_siblings(): - return self.parent.children - - @property - def parents(self) -> list[Node]: - """ - Returns all the ancestors of the Node object - """ - parents = [] - p = self - while p.has_parent(): - p = p.parent - parents.append(p) - return parents - - @property - def level(self) -> int: - """ - Returns the level of the Node object - """ - level = 0 - p = self - while p.has_parent(): - level += 1 - p = p.parent - return level - - @property - def path(self) -> str: - """ - Returns a representation of the ancestor lineage of self - """ - path = '' - for p in reversed(self.parents): - path += p.name+'.' - path += self.name - return path - - def is_sibling(self, other: str) -> bool: - """ - Check if Node object is a sibling of the other Node object - - :param other: Other Node object to be compared with - """ - if other in [s.name for s in self.siblings]: - return True - else: - return False - - def is_child(self, other: str) -> bool: - """ - Check if Node object is a child of the other Node object - """ - if other in [s.name for s in self.children]: - return True - else: - return False - - def pretty_print(self, option: str = 'default') -> None: - """ - Print children tree from current instance - """ - dashes = ' '*self.level+'|'+'--'*self.level+' ' - if option == 'id': - dashes += f'[{self.id}] ' - print(f'{dashes}{self.name}') - for c in self.children: - c.pretty_print(option) - - def has_parent(self) -> bool: - """ check if Node object has a parent or not """ - if self.parent is not None: - return True - return False - - def has_children(self) -> bool: - """ check if Node object has one child at least """ - if self.children is not None: - return True - return False - - def has_siblings(self) -> bool: - """ check if Node object has one sibling at least """ - if self.has_parent() and self.parent.has_children() \ - and len(self.parent.children) > 0: - return True - return False - - def get_child(self, name: str) -> Node | None: - """ find and returns a child with specified name. None if nothing found """ - for c in self.children: - if c.name == name: - return c - return None - - def get_sibling(self, name: str) -> Node | None: - """ find and returns a sibling with specified name. None if nothing - found """ - for c in self.siblings: - if c.name == name: - return c - return None - - def get_children(self, name: str) -> list[Node]: - # refactoring, recursion is not good - results = [] - if self.name == name: - results.append(self) - for c in self.children: - results += c.get_children(name) - return results - - @staticmethod - def check_lineage(nodes: list[Node]) -> bool: - """ - check if the list of nodes is a straight lineage: - node 1 (ancestor) -> node 2 -> node 3 -> ... -> node n (grand - children) - - """ - for i in range(1, len(nodes)): - if nodes[i].parent != nodes[i-1]: - return False - - return True - - @classmethod - def reset_stats(cls) -> None: - """ - reset all the ClassVar members - """ - cls.deepest_level = 0 - cls.largest_sibling_number = 0 - cls.all_nodes = [] - - @classmethod - def create_random_nodes(cls, type_: str = 'cmd', depth: int = 0) -> Node: - """ - Creates random tree of nodes for testing purpose - """ - def create_node(level, i): - id_ = len(cls.all_nodes) + 1 - return cls(f'{type_}_'+str(id_)) - def create_node_list(level: int, width: int = 5): - return [create_node(level, i) - for i in range(random.randint(1, width))] - def create_arg_tree(arg: cls): - if arg.level < depth: - for a in create_node_list(arg.level): - arg.add_child(a) - create_arg_tree(a) - return arg - arg = cls('parser') - return create_arg_tree(arg) - - def __lt__(self, other): - return self.level < other.level - - def __gt__(self, other): - return self.level > other.level - - def __le__(self, other): - return self.level <= other.level - - def __ge__(self, other): - return self.level >= other.level - - def __str__(self) -> str: - return self.name - -if __name__ == "__main__": - pass diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..0c782bc --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,25 @@ +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[tool.hatch.build] +exclude = ["venv"] + +[project] +name = "nodestack" +version = "0.0.1" +authors = [ + { name="fabthegreat", email="nodestack@lutix.org" }, +] +description = "A simple tree objects library" +readme = "README.md" +requires-python = ">=3.8" +classifiers = [ + "Programming Language :: Python :: 3", + "License :: OSI Approved :: MIT License", + "Operating System :: OS Independent", +] + +[project.urls] +Homepage = "https://gitea.lutix.org/ftg/nodestack" +Issues = "https://gitea.lutix.org/ftg/nodestack/issues" diff --git a/tests/.test_nodes.py.swp b/tests/.test_nodes.py.swp deleted file mode 100644 index c5de6e4b0128d3b87627954b575fe2ee6c7b4822..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12288 zcmeI2L2DC16vtn^w~ErUPXi`7WE0y8p%BDkQ9&ga1@$mYva`+TW@p%)7IIPAFW?98 zYv||jtaw)N19u!>JL z4k1xl)27Wft!&e2s>TzWr?D68F&6cwiIE#E5)Hl=t=U$*I1syxk!4+^ zjPeyKYSaz(2-uR+sjjZG_={UcMyqseK-o*OL>8H>EGDvB@T9B)hCr?|-8-X)u{ zQiYxxrFekvQ);Shp;U7hcj-$v<@(Ay+o^YD;8;df&8o!fFiEucrbt^=C|g6UTS{d% whgTcvh`gQvzQMt`$3C3fQG^iJ^E>raw?TutJzV3aIv$(QZ|8u?4gdfE