jtil 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
jtil-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,6 @@
1
+ Metadata-Version: 2.4
2
+ Name: jtil
3
+ Version: 0.1.0
4
+ Summary: Util package for Jensen.
5
+ Requires-Python: >=3.11
6
+ Description-Content-Type: text/markdown
jtil-0.1.0/README.md ADDED
File without changes
@@ -0,0 +1,7 @@
1
+ [project]
2
+ name = "jtil"
3
+ version = "0.1.0"
4
+ description = "Util package for Jensen."
5
+ readme = "README.md"
6
+ requires-python = ">=3.11"
7
+ dependencies = []
jtil-0.1.0/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
File without changes
@@ -0,0 +1,71 @@
1
+ """
2
+ Install editable package `util` with `uv pip install -e .` command.
3
+
4
+ We have setup the pyproject.toml for you, you can use:
5
+
6
+ ```shell
7
+ cd Python-Package-Tutorial
8
+ uv pip install -e .
9
+ ```
10
+
11
+ to install editable package `util` and all its subpackages, otherwise you won't be able to use the `Separator` class in the `separator.py` module in other module like `import_tutorial_d/import_tutorial.py`.
12
+
13
+ The essential code of the `pyproject.toml` file is:
14
+
15
+ ```toml
16
+ [build-system]
17
+ requires = ["setuptools"]
18
+ build-backend = "setuptools.build_meta"
19
+
20
+ [tool.setuptools.packages.find]
21
+ # tell Python to find the packages in the current directory
22
+ where = ["."]
23
+ # tell Python to find the util package specifically
24
+ include = ["util*"] # `*` means also include all subpackages in the util package
25
+ ```
26
+ """
27
+
28
+ from enum import Enum
29
+
30
+
31
+ class BColors(Enum):
32
+ """text color for terminal font"""
33
+
34
+ BOLD = "\033[1m"
35
+ UNDERLINE = "\033[4m"
36
+
37
+ ENDC = "\033[0m"
38
+ BLACK = "\033[30m"
39
+ RED = "\033[31m"
40
+ GREEN = "\033[32m"
41
+ YELLOW = "\033[33m"
42
+ BLUE = "\033[34m"
43
+ MAGENTA = "\033[35m"
44
+ CYAN = "\033[36m"
45
+ WHITE = "\033[37m"
46
+
47
+
48
+ class Separator:
49
+ """Separator in the terminal"""
50
+
51
+ def __init__(self, title: str, level: int = 3, color: BColors = BColors.GREEN):
52
+ assert level >= 1 and level <= 6, "Level must be between 1 and 6"
53
+ n_symbol = (6 - level) * 2 # 6 levels in total as in markdown
54
+ space = " " if level != 6 else ""
55
+ print(
56
+ f"{color.value}{'=' * n_symbol}{space}{title}{space}{'=' * n_symbol}{BColors.ENDC.value}",
57
+ )
58
+
59
+
60
+ def cprint(*value: object, color: BColors = BColors.GREEN, **kwargs) -> None:
61
+ """Print text with color."""
62
+ print(color.value, end="")
63
+ print(*value, **kwargs)
64
+ print(BColors.ENDC.value, end="")
65
+
66
+
67
+ if __name__ == "__main__":
68
+ Separator("Test Separator", color=BColors.RED)
69
+ Separator("Test Separator", level=1)
70
+ Separator("Test Separator", level=6)
71
+ Separator("Test Separator", level=5, color=BColors.BLUE)
@@ -0,0 +1,157 @@
1
+ def list_tree(
2
+ obj, name=None, prefix="", is_last=True, formatter: dict[type, callable] = None
3
+ ):
4
+ """
5
+ Recursively print nested lists and tuples in a tree-like structure.
6
+ Groups consecutive elements of the same type and displays their index.
7
+
8
+ Args:
9
+ obj: The object to print.
10
+ name: The key or index name of the current node.
11
+ prefix: String used for structural indentation.
12
+ is_last: Boolean flag indicating if it's the last child in a branch.
13
+ formatter: Dictionary of type -> lambda or function taking `obj` as input.
14
+ It should return a custom string for specific types, or None to fallback to repr().
15
+ """
16
+ # Determine the string representation of the current node's type
17
+ obj_type = type(obj).__name__
18
+
19
+ # Build the node label
20
+ label_parts = []
21
+ if name:
22
+ label_parts.append(f"{name}:")
23
+ label_parts.append(f"<{obj_type}>")
24
+
25
+ # Display length for containers, or truncated value for basic data types
26
+ if isinstance(obj, (list, tuple)):
27
+ label_parts.append(f"(len={len(obj)})")
28
+ else:
29
+ # Apply custom formatter if provided
30
+ val_str = None
31
+
32
+ if formatter is not None:
33
+ format_fn = formatter.get(type(obj))
34
+ if format_fn is not None:
35
+ try:
36
+ # Attempt to use the lambda/function to format the object
37
+ val_str = format_fn(obj)
38
+ except Exception as e:
39
+ print(e)
40
+
41
+ # Fallback to standard __repr__ if formatter returns None or fails
42
+ if val_str is None:
43
+ val_str = repr(obj)
44
+
45
+ # Truncate excessively long strings for better terminal visualization
46
+ if len(val_str) > 50:
47
+ val_str = val_str[:47] + "..."
48
+ label_parts.append(val_str)
49
+
50
+ node_label = " ".join(label_parts)
51
+
52
+ # Print the current node with appropriate tree branches
53
+ if not prefix:
54
+ print(node_label)
55
+ else:
56
+ connector = "└── " if is_last else "├── "
57
+ print(f"{prefix}{connector}{node_label}")
58
+
59
+ # Recursively process children if the current object is a list or tuple
60
+ if isinstance(obj, (list, tuple)):
61
+ # Calculate the prefix for the next depth level
62
+ child_prefix = prefix + (" " if is_last else "│ ")
63
+
64
+ # Group consecutive child elements by their data type
65
+ groups = []
66
+ for idx, item in enumerate(obj):
67
+ item_type = type(item)
68
+ if not groups:
69
+ groups.append(
70
+ {
71
+ "type": item_type,
72
+ "first_item": item,
73
+ "count": 1,
74
+ "start_idx": idx,
75
+ }
76
+ )
77
+ elif groups[-1]["type"] == item_type:
78
+ groups[-1]["count"] += 1
79
+ else:
80
+ groups.append(
81
+ {
82
+ "type": item_type,
83
+ "first_item": item,
84
+ "count": 1,
85
+ "start_idx": idx,
86
+ }
87
+ )
88
+
89
+ # Iterate and print the grouped children
90
+ for i, group in enumerate(groups):
91
+ is_last_group = i == len(groups) - 1
92
+ start_idx = group["start_idx"]
93
+
94
+ if group["count"] == 1:
95
+ # Only one element of this type, print single element with its exact index
96
+ list_tree(
97
+ group["first_item"],
98
+ name=f"[{start_idx}]",
99
+ prefix=child_prefix,
100
+ is_last=is_last_group,
101
+ formatter=formatter,
102
+ )
103
+ else:
104
+ # Print the first element of the group. It is explicitly NOT the last branch,
105
+ # because we still need to append the "... + n more" summary node below it.
106
+ list_tree(
107
+ group["first_item"],
108
+ name=f"[{start_idx}]",
109
+ prefix=child_prefix,
110
+ is_last=False,
111
+ formatter=formatter,
112
+ )
113
+
114
+ # Calculate the index range for the folded elements
115
+ next_idx = start_idx + 1
116
+ end_idx = start_idx + group["count"] - 1
117
+
118
+ # Format the summary index label (e.g., [1] or [1..3])
119
+ if next_idx == end_idx:
120
+ summary_idx_label = f"[{next_idx}]"
121
+ else:
122
+ summary_idx_label = f"[{next_idx}..{end_idx}]"
123
+
124
+ # Print the summary node for the remaining identical types
125
+ summary_connector = "└── " if is_last_group else "├── "
126
+ summary_label = f"{summary_idx_label} ... +{group['count'] - 1} more <{group['type'].__name__}>"
127
+ print(f"{child_prefix}{summary_connector}{summary_label}")
128
+
129
+
130
+ if __name__ == "__main__":
131
+ from separator import Separator
132
+
133
+ Separator("Basic Test")
134
+ list_tree(1)
135
+ list_tree([1, 2, 3])
136
+ list_tree([1, [41, 42]])
137
+
138
+ Separator("Param Test")
139
+ list_tree([1, [41, 42]], name="AAA")
140
+ list_tree([1, [41, 42]], prefix="@")
141
+ list_tree([1, [41, 42]], name="AAA", prefix="@")
142
+
143
+ Separator("Class Type Test")
144
+
145
+ class TestData:
146
+ def __init__(self, data: int, shape=(1,)):
147
+ self.data = data
148
+ self.shape = shape
149
+
150
+ def __repr__(self):
151
+ return f"A TestData Object: {self.data}"
152
+
153
+ list_tree([TestData(42), 2])
154
+ list_tree(
155
+ [(99, 100), TestData(43, shape=(2, 2)), (101, 102), 2, 3, 4],
156
+ formatter={TestData: lambda x: f"TestData(shape={x.shape})"},
157
+ )
@@ -0,0 +1,6 @@
1
+ Metadata-Version: 2.4
2
+ Name: jtil
3
+ Version: 0.1.0
4
+ Summary: Util package for Jensen.
5
+ Requires-Python: >=3.11
6
+ Description-Content-Type: text/markdown
@@ -0,0 +1,9 @@
1
+ README.md
2
+ pyproject.toml
3
+ src/jtil/__init__.py
4
+ src/jtil/separator.py
5
+ src/jtil/visualize.py
6
+ src/jtil.egg-info/PKG-INFO
7
+ src/jtil.egg-info/SOURCES.txt
8
+ src/jtil.egg-info/dependency_links.txt
9
+ src/jtil.egg-info/top_level.txt
@@ -0,0 +1 @@
1
+ jtil