halib 0.1.67__py3-none-any.whl → 0.1.73__py3-none-any.whl

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.
@@ -0,0 +1,100 @@
1
+ import os
2
+ from rich.pretty import pprint
3
+ from abc import ABC, abstractmethod
4
+ from dataclass_wizard import YAMLWizard
5
+
6
+
7
+ class NamedConfig(ABC):
8
+ """
9
+ Base class for named configurations.
10
+ All configurations should have a name.
11
+ """
12
+
13
+ @abstractmethod
14
+ def get_name(self):
15
+ """
16
+ Get the name of the configuration.
17
+ This method should be implemented in subclasses.
18
+ """
19
+ pass
20
+
21
+
22
+ class ExpBaseConfig(ABC, YAMLWizard):
23
+ """
24
+ Base class for configuration objects.
25
+ What a cfg class must have:
26
+ 1 - a dataset cfg
27
+ 2 - a metric cfg
28
+ 3 - a method cfg
29
+ """
30
+
31
+ # Save to yaml fil
32
+ def save_to_outdir(
33
+ self, filename: str = "config.yaml", outdir=None, override: bool = False
34
+ ) -> None:
35
+ """
36
+ Save the configuration to the output directory.
37
+ """
38
+ if outdir is not None:
39
+ output_dir = outdir
40
+ else:
41
+ output_dir = self.get_outdir()
42
+ os.makedirs(output_dir, exist_ok=True)
43
+ assert (output_dir is not None) and (
44
+ os.path.isdir(output_dir)
45
+ ), f"Output directory '{output_dir}' does not exist or is not a directory."
46
+ file_path = os.path.join(output_dir, filename)
47
+ if os.path.exists(file_path) and not override:
48
+ pprint(
49
+ f"File '{file_path}' already exists. Use 'override=True' to overwrite."
50
+ )
51
+ else:
52
+ # method of YAMLWizard to_yaml_file
53
+ self.to_yaml_file(file_path)
54
+
55
+ @classmethod
56
+ @abstractmethod
57
+ # load from a custom YAML file
58
+ def from_custom_yaml_file(cls, yaml_file: str):
59
+ """Load a configuration from a custom YAML file."""
60
+ pass
61
+
62
+ @abstractmethod
63
+ def get_cfg_name(self):
64
+ """
65
+ Get the name of the configuration.
66
+ This method should be implemented in subclasses.
67
+ """
68
+ pass
69
+
70
+ @abstractmethod
71
+ def get_outdir(self):
72
+ """
73
+ Get the output directory for the configuration.
74
+ This method should be implemented in subclasses.
75
+ """
76
+ return None
77
+
78
+ @abstractmethod
79
+ def get_general_cfg(self):
80
+ """
81
+ Get the general configuration like output directory, log settings, SEED, etc.
82
+ This method should be implemented in subclasses.
83
+ """
84
+ pass
85
+
86
+ @abstractmethod
87
+ def get_dataset_cfg(self) -> NamedConfig:
88
+ """
89
+ Get the dataset configuration.
90
+ This method should be implemented in subclasses.
91
+ """
92
+ pass
93
+
94
+ @abstractmethod
95
+ def get_metric_cfg(self) -> NamedConfig:
96
+ """
97
+ Get the metric configuration.
98
+ This method should be implemented in subclasses.
99
+ """
100
+ pass
@@ -0,0 +1,99 @@
1
+ from abc import ABC, abstractmethod
2
+
3
+ from ..research.base_config import ExpBaseConfig
4
+ from ..research.perfcalc import PerfCalc
5
+ from ..research.metrics import MetricsBackend
6
+
7
+ # ! SEE https://github.com/hahv/base_exp for sample usage
8
+ class BaseExperiment(PerfCalc, ABC):
9
+ """
10
+ Base class for experiments.
11
+ Orchestrates the experiment pipeline using a pluggable metrics backend.
12
+ """
13
+
14
+ def __init__(self, config: ExpBaseConfig):
15
+ self.config = config
16
+ self.metric_backend = None
17
+
18
+ # -----------------------
19
+ # PerfCalc Required Methods
20
+ # -----------------------
21
+ def get_dataset_name(self):
22
+ return self.config.get_dataset_cfg().get_name()
23
+
24
+ def get_experiment_name(self):
25
+ return self.config.get_cfg_name()
26
+
27
+ def get_metric_backend(self):
28
+ if not self.metric_backend:
29
+ self.metric_backend = self.prepare_metrics(self.config.get_metric_cfg())
30
+ return self.metric_backend
31
+
32
+ # -----------------------
33
+ # Abstract Experiment Steps
34
+ # -----------------------
35
+ @abstractmethod
36
+ def init_general(self, general_cfg):
37
+ """Setup general settings like SEED, logging, env variables."""
38
+ pass
39
+
40
+ @abstractmethod
41
+ def prepare_dataset(self, dataset_cfg):
42
+ """Load/prepare dataset."""
43
+ pass
44
+
45
+ @abstractmethod
46
+ def prepare_metrics(self, metric_cfg) -> MetricsBackend:
47
+ """
48
+ Prepare the metrics for the experiment.
49
+ This method should be implemented in subclasses.
50
+ """
51
+ pass
52
+
53
+ @abstractmethod
54
+ def exec_exp(self, *args, **kwargs):
55
+ """Run experiment process, e.g.: training/evaluation loop.
56
+ Return: raw_metrics_data, and extra_data as input for calc_and_save_exp_perfs
57
+ """
58
+ pass
59
+
60
+ def eval_exp(self):
61
+ """Optional: re-run evaluation from saved results."""
62
+ pass
63
+
64
+ # -----------------------
65
+ # Main Experiment Runner
66
+ # -----------------------
67
+ def run_exp(self, do_calc_metrics=True, *args, **kwargs):
68
+ """
69
+ Run the whole experiment pipeline.
70
+ Params:
71
+ + 'outfile' to save csv file results,
72
+ + 'outdir' to set output directory for experiment results.
73
+ + 'return_df' to return a DataFrame of results instead of a dictionary.
74
+
75
+ Full pipeline:
76
+ 1. Init
77
+ 2. Dataset
78
+ 3. Metrics Preparation
79
+ 4. Save Config
80
+ 5. Execute
81
+ 6. Calculate & Save Metrics
82
+ """
83
+ self.init_general(self.config.get_general_cfg())
84
+ self.prepare_dataset(self.config.get_dataset_cfg())
85
+
86
+ # Save config before running
87
+ self.config.save_to_outdir()
88
+
89
+ # Execute experiment
90
+ results = self.exec_exp(*args, **kwargs)
91
+ if do_calc_metrics:
92
+ metrics_data, extra_data = results
93
+ # Calculate & Save metrics
94
+ perf_results = self.calc_and_save_exp_perfs(
95
+ raw_metrics_data=metrics_data, extra_data=extra_data, *args, **kwargs
96
+ )
97
+ return perf_results
98
+ else:
99
+ return results
@@ -1,190 +1,189 @@
1
- Metadata-Version: 2.4
2
- Name: halib
3
- Version: 0.1.67
4
- Summary: Small library for common tasks
5
- Author: Hoang Van Ha
6
- Author-email: hoangvanhauit@gmail.com
7
- Classifier: Programming Language :: Python :: 3
8
- Classifier: License :: OSI Approved :: MIT License
9
- Classifier: Operating System :: OS Independent
10
- Requires-Python: >=3.8
11
- Description-Content-Type: text/markdown
12
- License-File: LICENSE.txt
13
- Requires-Dist: arrow
14
- Requires-Dist: click
15
- Requires-Dist: enlighten
16
- Requires-Dist: kaleido==0.1.*
17
- Requires-Dist: loguru
18
- Requires-Dist: more-itertools
19
- Requires-Dist: moviepy
20
- Requires-Dist: networkx
21
- Requires-Dist: numpy
22
- Requires-Dist: omegaconf
23
- Requires-Dist: opencv-python
24
- Requires-Dist: pandas
25
- Requires-Dist: Pillow
26
- Requires-Dist: Pyarrow
27
- Requires-Dist: pycurl
28
- Requires-Dist: python-telegram-bot
29
- Requires-Dist: requests
30
- Requires-Dist: rich
31
- Requires-Dist: scikit-learn
32
- Requires-Dist: matplotlib
33
- Requires-Dist: seaborn
34
- Requires-Dist: plotly
35
- Requires-Dist: pygwalker
36
- Requires-Dist: tabulate
37
- Requires-Dist: itables
38
- Requires-Dist: timebudget
39
- Requires-Dist: tqdm
40
- Requires-Dist: tube_dl
41
- Requires-Dist: wandb
42
- Requires-Dist: dataclass-wizard
43
- Dynamic: author
44
- Dynamic: author-email
45
- Dynamic: classifier
46
- Dynamic: description
47
- Dynamic: description-content-type
48
- Dynamic: license-file
49
- Dynamic: requires-dist
50
- Dynamic: requires-python
51
- Dynamic: summary
52
-
53
- Helper package for coding and automation
54
-
55
- **Version 0.1.67**
56
-
57
- + now use `uv` for venv management
58
- + `research/perfcalc`: support both torchmetrics and custom metrics for performance calculation
59
-
60
- **Version 0.1.61**
61
-
62
- + add `util/video`: add `VideoUtils` class to handle common video-related tasks
63
- + add `util/gpu_mon`: add `GPUMonitor` class to monitor GPU usage and performance
64
-
65
- **Version 0.1.59**
66
-
67
- + add `util/perfcalc`: abstract class for performance calculation. This class need to be inherited and implemented with specific performance calculation logic.
68
-
69
- **Version 0.1.55**
70
-
71
- + add `util/dataclass_util` to help dynamically create `dataclass` classes from dictionary or YAML file, including support for nested dataclasses. From there, we can use `dataclass_wizard` to create a list of `dataclass` classes with the help from ChatGPT.
72
-
73
- **Version 0.1.52**
74
-
75
- + add `research/perftb` module to allow creating and managing performance tables for experiments, including filtering by datasets, metrics, and experiments.
76
-
77
- **Version 0.1.50**
78
-
79
- + add `pprint_local_path` to print local path (file/directory) in clickable link (as file URI)
80
-
81
- + add `research` package to help with research tasks, including `benchquery` for benchmarking queries from dataframe
82
- + add `wandb` module to allow easy sync offline data to Weights & Biases (wandb) and batch clear wandb runs.
83
-
84
- **Version 0.1.47**
85
- + add `pprint_box` to print object/string in a box frame (like in `inspect`)
86
-
87
- **Version 0.1.46**
88
- + filter the warning message of `UserWarning: Unable to import Axes3D.`
89
- + auto_wrap_text for `fn_display_df` to avoid long text in the table
90
-
91
- **Version 0.1.42**
92
- + add <rich_color.py>: add basic color list (for easy usage)
93
-
94
- **Version 0.1.41**
95
- + add <rich_color.py> to display rich color information in <rich> python package (rcolor_str, rcolor_pallet_all, etc.)
96
-
97
- **Version 0.1.40**
98
-
99
- + update <csvfile.py> to use `itables` and `pygwalker` to display dataframe in jupyter notebook.
100
-
101
- **Version 0.1.38**
102
-
103
- + add <torchloader.py> to search for best cfg for torch dataloader (num_workers, batch_size, pin_memory, et.)
104
-
105
- **Version 0.1.37**
106
-
107
- + add <dataset.py> to help split classification dataset into train/val(test)
108
- ---
109
- **Version 0.1.33**
110
-
111
- + add `plot.py` module to plot DL model training history (with columlns: epoch, train_accuracy, val_accuracy, train_loss, val_loss) using `seaborn` and `matplotlib`
112
- ---
113
- **Version 0.1.29**
114
-
115
- + for `tele_noti` module, `kaleido==0.1.*` is required for plotly since `kaleido 0.2.*` is not working (taking for ever to generate image)
116
- ---
117
- **Version 0.1.24**
118
-
119
- + rename `sys` to `system` to avoid conflict with built-in `sys` module
120
- + add `tele_noti` module to send notification to telegram after a specific interval for training progress monitoring
121
- ---
122
- **Version 0.1.22**
123
-
124
- + add `cuda.py` module to check CUDA availability (for both pytorch and tensorflow)
125
- ---
126
- **Version 0.1.21**
127
-
128
- + using `networkx` and `omegaconf` to allow yaml file inheritance and override
129
- ---
130
- **Version 0.1.15**
131
-
132
- + `__init__.py`: add common logging library; also `console_log` decorator to log function (start and end)
133
-
134
- ---
135
-
136
- **Version 0.1.10**
137
-
138
- + filesys: fix typo on "is_exit" to "is_exist"
139
- + gdrive: now support uploading file to folder and return direct link (shareable link)
140
-
141
- **Version 0.1.9**
142
-
143
- + add dependencies requirement.txt
144
-
145
- **Version 0.1.8**
146
-
147
- Fix bugs:
148
-
149
- + [performance] instead of inserting directly new rows into table dataframe, first insert it into in-memory `row_pool_dict`, that fill data in that dict into the actual dataframe when needed.
150
-
151
- ---
152
-
153
- **Version 0.1.7**
154
-
155
- Fix bugs:
156
-
157
- + fix insert into table so slow by allowing insert multiple rows at once
158
-
159
- ---
160
-
161
- **Version 0.1.6**
162
-
163
- New features:
164
-
165
- + add DFCreator for manipulating table (DataFrame) - create, insert row, display, write to file
166
-
167
- ---
168
-
169
- **Version 0.1.5**
170
-
171
- New Features
172
-
173
- + add cmd module
174
- + new package structure
175
-
176
- ---
177
-
178
- **Version 0.1.4**
179
-
180
- New Features
181
-
182
- + add support to create Bitbucket Project from template
183
-
184
- ---
185
-
186
- **Version 0.1.2**
187
-
188
- New Features
189
-
190
- + add support to upload local to google drive.
1
+ Metadata-Version: 2.1
2
+ Name: halib
3
+ Version: 0.1.73
4
+ Summary: Small library for common tasks
5
+ Author: Hoang Van Ha
6
+ Author-email: hoangvanhauit@gmail.com
7
+ License: UNKNOWN
8
+ Platform: UNKNOWN
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Operating System :: OS Independent
12
+ Requires-Python: >=3.8
13
+ Description-Content-Type: text/markdown
14
+ License-File: LICENSE.txt
15
+ Requires-Dist: arrow
16
+ Requires-Dist: click
17
+ Requires-Dist: enlighten
18
+ Requires-Dist: kaleido (==0.1.*)
19
+ Requires-Dist: loguru
20
+ Requires-Dist: more-itertools
21
+ Requires-Dist: moviepy
22
+ Requires-Dist: networkx
23
+ Requires-Dist: numpy
24
+ Requires-Dist: omegaconf
25
+ Requires-Dist: opencv-python
26
+ Requires-Dist: pandas
27
+ Requires-Dist: Pillow
28
+ Requires-Dist: Pyarrow
29
+ Requires-Dist: pycurl
30
+ Requires-Dist: python-telegram-bot
31
+ Requires-Dist: requests
32
+ Requires-Dist: rich
33
+ Requires-Dist: scikit-learn
34
+ Requires-Dist: matplotlib
35
+ Requires-Dist: seaborn
36
+ Requires-Dist: plotly
37
+ Requires-Dist: pygwalker
38
+ Requires-Dist: tabulate
39
+ Requires-Dist: itables
40
+ Requires-Dist: timebudget
41
+ Requires-Dist: tqdm
42
+ Requires-Dist: tube-dl
43
+ Requires-Dist: wandb
44
+ Requires-Dist: dataclass-wizard
45
+
46
+ Helper package for coding and automation
47
+
48
+ **Version 0.1.73**
49
+
50
+ + `research/base_exp`: add base experiment class to handle common experiment tasks, including performance calculation and saving results.
51
+
52
+ **Version 0.1.67**
53
+
54
+ + now use `uv` for venv management
55
+ + `research/perfcalc`: support both torchmetrics and custom metrics for performance calculation
56
+
57
+ **Version 0.1.61**
58
+
59
+ + add `util/video`: add `VideoUtils` class to handle common video-related tasks
60
+ + add `util/gpu_mon`: add `GPUMonitor` class to monitor GPU usage and performance
61
+
62
+ **Version 0.1.59**
63
+
64
+ + add `util/perfcalc`: abstract class for performance calculation. This class need to be inherited and implemented with specific performance calculation logic.
65
+
66
+ **Version 0.1.55**
67
+
68
+ + add `util/dataclass_util` to help dynamically create `dataclass` classes from dictionary or YAML file, including support for nested dataclasses. From there, we can use `dataclass_wizard` to create a list of `dataclass` classes with the help from ChatGPT.
69
+
70
+ **Version 0.1.52**
71
+
72
+ + add `research/perftb` module to allow creating and managing performance tables for experiments, including filtering by datasets, metrics, and experiments.
73
+
74
+ **Version 0.1.50**
75
+
76
+ + add `pprint_local_path` to print local path (file/directory) in clickable link (as file URI)
77
+
78
+ + add `research` package to help with research tasks, including `benchquery` for benchmarking queries from dataframe
79
+ + add `wandb` module to allow easy sync offline data to Weights & Biases (wandb) and batch clear wandb runs.
80
+
81
+ **Version 0.1.47**
82
+ + add `pprint_box` to print object/string in a box frame (like in `inspect`)
83
+
84
+ **Version 0.1.46**
85
+ + filter the warning message of `UserWarning: Unable to import Axes3D.`
86
+ + auto_wrap_text for `fn_display_df` to avoid long text in the table
87
+
88
+ **Version 0.1.42**
89
+ + add <rich_color.py>: add basic color list (for easy usage)
90
+
91
+ **Version 0.1.41**
92
+ + add <rich_color.py> to display rich color information in <rich> python package (rcolor_str, rcolor_pallet_all, etc.)
93
+
94
+ **Version 0.1.40**
95
+
96
+ + update <csvfile.py> to use `itables` and `pygwalker` to display dataframe in jupyter notebook.
97
+
98
+ **Version 0.1.38**
99
+
100
+ + add <torchloader.py> to search for best cfg for torch dataloader (num_workers, batch_size, pin_memory, et.)
101
+
102
+ **Version 0.1.37**
103
+
104
+ + add <dataset.py> to help split classification dataset into train/val(test)
105
+ ---
106
+ **Version 0.1.33**
107
+
108
+ + add `plot.py` module to plot DL model training history (with columlns: epoch, train_accuracy, val_accuracy, train_loss, val_loss) using `seaborn` and `matplotlib`
109
+ ---
110
+ **Version 0.1.29**
111
+
112
+ + for `tele_noti` module, `kaleido==0.1.*` is required for plotly since `kaleido 0.2.*` is not working (taking for ever to generate image)
113
+ ---
114
+ **Version 0.1.24**
115
+
116
+ + rename `sys` to `system` to avoid conflict with built-in `sys` module
117
+ + add `tele_noti` module to send notification to telegram after a specific interval for training progress monitoring
118
+ ---
119
+ **Version 0.1.22**
120
+
121
+ + add `cuda.py` module to check CUDA availability (for both pytorch and tensorflow)
122
+ ---
123
+ **Version 0.1.21**
124
+
125
+ + using `networkx` and `omegaconf` to allow yaml file inheritance and override
126
+ ---
127
+ **Version 0.1.15**
128
+
129
+ + `__init__.py`: add common logging library; also `console_log` decorator to log function (start and end)
130
+
131
+ ---
132
+
133
+ **Version 0.1.10**
134
+
135
+ + filesys: fix typo on "is_exit" to "is_exist"
136
+ + gdrive: now support uploading file to folder and return direct link (shareable link)
137
+
138
+ **Version 0.1.9**
139
+
140
+ + add dependencies requirement.txt
141
+
142
+ **Version 0.1.8**
143
+
144
+ Fix bugs:
145
+
146
+ + [performance] instead of inserting directly new rows into table dataframe, first insert it into in-memory `row_pool_dict`, that fill data in that dict into the actual dataframe when needed.
147
+
148
+ ---
149
+
150
+ **Version 0.1.7**
151
+
152
+ Fix bugs:
153
+
154
+ + fix insert into table so slow by allowing insert multiple rows at once
155
+
156
+ ---
157
+
158
+ **Version 0.1.6**
159
+
160
+ New features:
161
+
162
+ + add DFCreator for manipulating table (DataFrame) - create, insert row, display, write to file
163
+
164
+ ---
165
+
166
+ **Version 0.1.5**
167
+
168
+ New Features
169
+
170
+ + add cmd module
171
+ + new package structure
172
+
173
+ ---
174
+
175
+ **Version 0.1.4**
176
+
177
+ New Features
178
+
179
+ + add support to create Bitbucket Project from template
180
+
181
+ ---
182
+
183
+ **Version 0.1.2**
184
+
185
+ New Features
186
+
187
+ + add support to upload local to google drive.
188
+
189
+
@@ -28,6 +28,8 @@ halib/online/gdrive_mkdir.py,sha256=wSJkQMJCDuS1gxQ2lHQHq_IrJ4xR_SEoPSo9n_2WNFU,
28
28
  halib/online/gdrive_test.py,sha256=hMWzz4RqZwETHp4GG4WwVNFfYvFQhp2Boz5t-DqwMo0,1342
29
29
  halib/online/projectmake.py,sha256=Zrs96WgXvO4nIrwxnCOletL4aTBge-EoF0r7hpKO1w8,4034
30
30
  halib/research/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
31
+ halib/research/base_config.py,sha256=AIjVzl2ZJ9b8yIGb2X5EZwLmyGJ_9wNWqrib1nU3Wj0,2831
32
+ halib/research/base_exp.py,sha256=tz03FF2XMI9b6Ram4ZJBjKo053Vb7T8yTTCH0jeLvp4,3218
31
33
  halib/research/benchquery.py,sha256=FuKnbWQtCEoRRtJAfN-zaN-jPiO_EzsakmTOMiqi7GQ,4626
32
34
  halib/research/dataset.py,sha256=QU0Hr5QFb8_XlvnOMgC9QJGIpwXAZ9lDd0RdQi_QRec,6743
33
35
  halib/research/metrics.py,sha256=Xgv0GUGo-o-RJaBOmkRCRpQJaYijF_1xeKkyYU_Bv4U,5249
@@ -49,8 +51,8 @@ halib/utils/gpu_mon.py,sha256=vD41_ZnmPLKguuq9X44SB_vwd9JrblO4BDzHLXZhhFY,2233
49
51
  halib/utils/listop.py,sha256=Vpa8_2fI0wySpB2-8sfTBkyi_A4FhoFVVvFiuvW8N64,339
50
52
  halib/utils/tele_noti.py,sha256=-4WXZelCA4W9BroapkRyIdUu9cUVrcJJhegnMs_WpGU,5928
51
53
  halib/utils/video.py,sha256=ZqzNVPgc1RZr_T0OlHvZ6SzyBpL7O27LtB86JMbBuR0,3059
52
- halib-0.1.67.dist-info/licenses/LICENSE.txt,sha256=qZssdna4aETiR8znYsShUjidu-U4jUT9Q-EWNlZ9yBQ,1100
53
- halib-0.1.67.dist-info/METADATA,sha256=Zk22ct5W95qBzGkz0tNepuAdfUwPJTbVO7Nb4L_hFTQ,5541
54
- halib-0.1.67.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
55
- halib-0.1.67.dist-info/top_level.txt,sha256=7AD6PLaQTreE0Fn44mdZsoHBe_Zdd7GUmjsWPyQ7I-k,6
56
- halib-0.1.67.dist-info/RECORD,,
54
+ halib-0.1.73.dist-info/LICENSE.txt,sha256=qZssdna4aETiR8znYsShUjidu-U4jUT9Q-EWNlZ9yBQ,1100
55
+ halib-0.1.73.dist-info/METADATA,sha256=rbQYLf3CgTFzNtQ66v6OCEHpE9yjNfT2Qf7LDd-II-g,5350
56
+ halib-0.1.73.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
57
+ halib-0.1.73.dist-info/top_level.txt,sha256=7AD6PLaQTreE0Fn44mdZsoHBe_Zdd7GUmjsWPyQ7I-k,6
58
+ halib-0.1.73.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.9.0)
2
+ Generator: bdist_wheel (0.37.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5