pelutils 4.3.1__tar.gz → 4.5.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.
Files changed (72) hide show
  1. pelutils-4.5.0/LICENSE.txt +19 -0
  2. {pelutils-4.3.1 → pelutils-4.5.0}/PKG-INFO +55 -24
  3. {pelutils-4.3.1 → pelutils-4.5.0}/README.md +37 -15
  4. pelutils-4.5.0/pelutils/__init__.py +5 -0
  5. pelutils-4.5.0/pelutils/array/_unique.pyi +80 -0
  6. {pelutils-4.3.1 → pelutils-4.5.0}/pelutils/logging/_rich_string.py +3 -11
  7. {pelutils-4.3.1 → pelutils-4.5.0}/pelutils/misc/__init__.py +1 -1
  8. {pelutils-4.3.1 → pelutils-4.5.0}/pelutils/misc/_table.py +45 -15
  9. {pelutils-4.3.1 → pelutils-4.5.0}/pelutils/serialization/_universal_json_model.py +15 -6
  10. {pelutils-4.3.1 → pelutils-4.5.0}/pelutils/ticktock/__init__.py +2 -2
  11. {pelutils-4.3.1 → pelutils-4.5.0}/pelutils/ticktock/_ticktock.py +67 -9
  12. {pelutils-4.3.1 → pelutils-4.5.0}/pelutils.egg-info/PKG-INFO +55 -24
  13. {pelutils-4.3.1 → pelutils-4.5.0}/pelutils.egg-info/SOURCES.txt +3 -1
  14. pelutils-4.5.0/pelutils.egg-info/requires.txt +10 -0
  15. pelutils-4.5.0/pyproject.toml +86 -0
  16. pelutils-4.5.0/setup.py +17 -0
  17. pelutils-4.3.1/pelutils/__init__.py +0 -3
  18. pelutils-4.3.1/pelutils/__version__.py +0 -2
  19. pelutils-4.3.1/pelutils.egg-info/requires.txt +0 -33
  20. pelutils-4.3.1/setup.py +0 -95
  21. {pelutils-4.3.1 → pelutils-4.5.0}/MANIFEST.in +0 -0
  22. {pelutils-4.3.1 → pelutils-4.5.0}/pelutils/_c/__init__.py +0 -0
  23. {pelutils-4.3.1 → pelutils-4.5.0}/pelutils/_c/array/blob.c +0 -0
  24. {pelutils-4.3.1 → pelutils-4.5.0}/pelutils/_c/array/blob.h +0 -0
  25. {pelutils-4.3.1 → pelutils-4.5.0}/pelutils/_c/array/unique.c +0 -0
  26. {pelutils-4.3.1 → pelutils-4.5.0}/pelutils/_c/array/unique.h +0 -0
  27. {pelutils-4.3.1 → pelutils-4.5.0}/pelutils/_c/deque/deque.c +0 -0
  28. {pelutils-4.3.1 → pelutils-4.5.0}/pelutils/_c/deque/deque.h +0 -0
  29. {pelutils-4.3.1 → pelutils-4.5.0}/pelutils/_c/hashmap/LICENSE +0 -0
  30. {pelutils-4.3.1 → pelutils-4.5.0}/pelutils/_c/hashmap/hashmap.c +0 -0
  31. {pelutils-4.3.1 → pelutils-4.5.0}/pelutils/_c/hashmap/hashmap.h +0 -0
  32. {pelutils-4.3.1 → pelutils-4.5.0}/pelutils/_c/pelutils.c +0 -0
  33. {pelutils-4.3.1 → pelutils-4.5.0}/pelutils/_c/types.h +0 -0
  34. {pelutils-4.3.1 → pelutils-4.5.0}/pelutils/_entry_points/__init__.py +0 -0
  35. {pelutils-4.3.1 → pelutils-4.5.0}/pelutils/_entry_points/linecounter.py +0 -0
  36. {pelutils-4.3.1 → pelutils-4.5.0}/pelutils/array/__init__.py +0 -0
  37. {pelutils-4.3.1 → pelutils-4.5.0}/pelutils/array/_blob.py +0 -0
  38. {pelutils-4.3.1 → pelutils-4.5.0}/pelutils/array/_unique.py +0 -0
  39. {pelutils-4.3.1 → pelutils-4.5.0}/pelutils/array/_utils.py +0 -0
  40. {pelutils-4.3.1 → pelutils-4.5.0}/pelutils/job_parser/__init__.py +0 -0
  41. {pelutils-4.3.1 → pelutils-4.5.0}/pelutils/job_parser/_job_parser.py +0 -0
  42. {pelutils-4.3.1 → pelutils-4.5.0}/pelutils/job_parser/_structs.py +0 -0
  43. {pelutils-4.3.1 → pelutils-4.5.0}/pelutils/legacy/__init__.py +0 -0
  44. {pelutils-4.3.1 → pelutils-4.5.0}/pelutils/legacy/v3/__init__.py +0 -0
  45. {pelutils-4.3.1 → pelutils-4.5.0}/pelutils/legacy/v3/_datastorage.py +0 -0
  46. {pelutils-4.3.1 → pelutils-4.5.0}/pelutils/logging/__init__.py +0 -0
  47. {pelutils-4.3.1 → pelutils-4.5.0}/pelutils/logging/_logger.py +0 -0
  48. {pelutils-4.3.1 → pelutils-4.5.0}/pelutils/logging/_rotate.py +0 -0
  49. {pelutils-4.3.1 → pelutils-4.5.0}/pelutils/misc/_conditional_import.py +0 -0
  50. {pelutils-4.3.1 → pelutils-4.5.0}/pelutils/misc/_files.py +0 -0
  51. {pelutils-4.3.1 → pelutils-4.5.0}/pelutils/misc/_git.py +0 -0
  52. {pelutils-4.3.1 → pelutils-4.5.0}/pelutils/misc/_misc.py +0 -0
  53. {pelutils-4.3.1 → pelutils-4.5.0}/pelutils/misc/_platform.py +0 -0
  54. {pelutils-4.3.1 → pelutils-4.5.0}/pelutils/plots/__init__.py +0 -0
  55. {pelutils-4.3.1 → pelutils-4.5.0}/pelutils/plots/_figure.py +0 -0
  56. {pelutils-4.3.1 → pelutils-4.5.0}/pelutils/plots/_histogram.py +0 -0
  57. {pelutils-4.3.1 → pelutils-4.5.0}/pelutils/plots/_utils.py +0 -0
  58. {pelutils-4.3.1 → pelutils-4.5.0}/pelutils/py.typed +0 -0
  59. {pelutils-4.3.1 → pelutils-4.5.0}/pelutils/serialization/__init__.py +0 -0
  60. {pelutils-4.3.1 → pelutils-4.5.0}/pelutils/serialization/_jsonl.py +0 -0
  61. {pelutils-4.3.1 → pelutils-4.5.0}/pelutils/serialization/_pretty_json.py +0 -0
  62. {pelutils-4.3.1 → pelutils-4.5.0}/pelutils/stats/__init__.py +0 -0
  63. {pelutils-4.3.1 → pelutils-4.5.0}/pelutils/stats/_distributions.py +0 -0
  64. {pelutils-4.3.1 → pelutils-4.5.0}/pelutils/stats/_stats.py +0 -0
  65. {pelutils-4.3.1 → pelutils-4.5.0}/pelutils/tests/__init__.py +0 -0
  66. {pelutils-4.3.1 → pelutils-4.5.0}/pelutils/tests/_tests.py +0 -0
  67. {pelutils-4.3.1 → pelutils-4.5.0}/pelutils/types/__init__.py +0 -0
  68. {pelutils-4.3.1 → pelutils-4.5.0}/pelutils/types/_types.py +0 -0
  69. {pelutils-4.3.1 → pelutils-4.5.0}/pelutils.egg-info/dependency_links.txt +0 -0
  70. {pelutils-4.3.1 → pelutils-4.5.0}/pelutils.egg-info/entry_points.txt +0 -0
  71. {pelutils-4.3.1 → pelutils-4.5.0}/pelutils.egg-info/top_level.txt +0 -0
  72. {pelutils-4.3.1 → pelutils-4.5.0}/setup.cfg +0 -0
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2022 Asger Laurits Schultz and Søren Winkel Holm
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ SOFTWARE.
@@ -1,12 +1,11 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: pelutils
3
- Version: 4.3.1
3
+ Version: 4.5.0
4
4
  Summary: The Swiss army knife of Python projects
5
- Home-page: https://github.com/peleiden/pelutils
6
- Download-URL: https://pypi.org/project/pelutils/
7
- Author: Asger Laurits Schultz, Søren Winkel Holm
8
- Author-email: asger.s@protonmail.com, swholm@protonmail.com
9
- License: MIT
5
+ Author-email: Asger Laurits Schultz <asger.s@protonmail.com>, Søren Winkel Holm <swholm@protonmail.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/peleiden/pelutils
8
+ Project-URL: Download, https://pypi.org/project/pelutils/
10
9
  Keywords: utility,logger,parser,profiling,plotting
11
10
  Classifier: Intended Audience :: Developers
12
11
  Classifier: Operating System :: OS Independent
@@ -20,9 +19,19 @@ Classifier: Programming Language :: Python :: 3.14
20
19
  Classifier: Programming Language :: Python :: 3.15
21
20
  Requires-Python: >=3.11
22
21
  Description-Content-Type: text/markdown
23
- Provides-Extra: dev
24
- Provides-Extra: docs
22
+ License-File: LICENSE.txt
25
23
  License-File: pelutils/_c/hashmap/LICENSE
24
+ Requires-Dist: numpy>=2.0
25
+ Requires-Dist: gitpython>=3.1.0
26
+ Requires-Dist: rich>=10.0.0
27
+ Requires-Dist: py-cpuinfo>=8.0.0
28
+ Requires-Dist: psutil>=5.8.0
29
+ Requires-Dist: matplotlib>=3.3
30
+ Requires-Dist: scipy>=1.6
31
+ Requires-Dist: tqdm>=4.55
32
+ Requires-Dist: pydantic>=2
33
+ Requires-Dist: typing_extensions>=4.6
34
+ Dynamic: license-file
26
35
 
27
36
  # pelutils
28
37
 
@@ -314,7 +323,7 @@ def process(features: FloatArray, labels: IntArray, mask: BoolArray): ...
314
323
 
315
324
  ## Also included
316
325
 
317
- - `pelutils.misc.Table` — build aligned text tables which can also be easily export to LaTeX with `Table.to_latex()`.
326
+ - `pelutils.misc.Table` — build aligned text tables which can be exported to LaTeX with `Table.to_latex()` or Markdown with `Table.to_markdown()`.
318
327
  - `pelutils.misc.hardware_info` / `OS` — describe the machine the code runs on.
319
328
  - `pelutils.misc.git_repo_info` — the repo and commit the code is executing in.
320
329
  - Assorted file and dict helpers (`reverse_line_iterator`, `except_keys`, ...).
@@ -329,25 +338,47 @@ If no wheel matches, `pip` builds from source which requires `<Python.h>` — in
329
338
  32-bit systems are not fully supported.
330
339
  Most of the library is Python-only and should work but using any C-dependent code (namely `unique` and `SparseGridBlobDetection`) is likely to end in a segfault.
331
340
 
332
- ## Updating and releasing
341
+ ## Development
333
342
 
334
- `pelutils` uses the `master` branch as a stable development branch.
335
- The `release` branch contains the latest version on PyPI.
336
- New features should be made in feature branches from `master` that can be merged into `master` once ready.
337
- When a new release is ready, update `pelutils/__version__.py` and rebase `master` onto `release`.
338
- Then push a new tag from `release` named `vX.Y.Z`.
343
+ Use [uv](https://docs.astral.sh/uv/) for dependency management, builds, and running
344
+ development tools. Install uv, then from the repository root sync the development
345
+ environment (a C compiler and Python headers are required to build the native extension):
346
+
347
+ ```sh
348
+ uv sync --python 3.11 --group dev
349
+ ```
350
+
351
+ The `dev` dependency group includes CPU-only PyTorch and documentation tools.
352
+
353
+ Run checks and tools through `uv run`:
339
354
 
340
- When new code is merged into `master`, a number of checks are run.
341
- These can be tested locally with the following commands.
342
355
  ```sh
343
356
  # Linting and formatting
344
- ruff format pelutils tests
345
- ruff check pelutils tests
357
+ uv run --python 3.11 ruff format pelutils tests
358
+ uv run --python 3.11 ruff check pelutils tests
346
359
  # Type checking
347
- basedpyright pelutils
360
+ uv run --python 3.11 basedpyright pelutils
348
361
  # Unit tests
349
- python -m pytest tests --cov pelutils
362
+ uv run --python 3.11 pytest tests --cov pelutils
350
363
  # Build docs
351
- # Once build, open docs/build/html/index.html in your browser to see them
352
- make -C docs html
364
+ uv run --python 3.11 make -C docs html
365
+ # Preview at docs/build/html/index.html
353
366
  ```
367
+
368
+ After changing C sources, rebuild the extension with
369
+ `uv sync --python 3.11 --group dev --reinstall-package pelutils`.
370
+
371
+ The wheel-build CI tests each built wheel in a cibuildwheel environment provisioned
372
+ from the locked `dev` group with uv; pytest runs against the installed wheel. Read the
373
+ Docs also syncs that group through uv.
374
+
375
+ ## Updating and releasing
376
+
377
+ `pelutils` uses the `master` branch as a stable development branch.
378
+ The `release` branch contains the latest version on PyPI.
379
+ New features should be made in feature branches from `master` that can be merged into `master` once ready.
380
+ When a new release is ready, update `pyproject.toml` and rebase `master` onto `release`.
381
+ Then push a new tag from `release` named `vX.Y.Z`.
382
+
383
+ When new code is merged into `master`, the checks listed above are run.
384
+ To build distribution artifacts locally, use `uv build --python 3.11`.
@@ -288,7 +288,7 @@ def process(features: FloatArray, labels: IntArray, mask: BoolArray): ...
288
288
 
289
289
  ## Also included
290
290
 
291
- - `pelutils.misc.Table` — build aligned text tables which can also be easily export to LaTeX with `Table.to_latex()`.
291
+ - `pelutils.misc.Table` — build aligned text tables which can be exported to LaTeX with `Table.to_latex()` or Markdown with `Table.to_markdown()`.
292
292
  - `pelutils.misc.hardware_info` / `OS` — describe the machine the code runs on.
293
293
  - `pelutils.misc.git_repo_info` — the repo and commit the code is executing in.
294
294
  - Assorted file and dict helpers (`reverse_line_iterator`, `except_keys`, ...).
@@ -303,25 +303,47 @@ If no wheel matches, `pip` builds from source which requires `<Python.h>` — in
303
303
  32-bit systems are not fully supported.
304
304
  Most of the library is Python-only and should work but using any C-dependent code (namely `unique` and `SparseGridBlobDetection`) is likely to end in a segfault.
305
305
 
306
- ## Updating and releasing
306
+ ## Development
307
307
 
308
- `pelutils` uses the `master` branch as a stable development branch.
309
- The `release` branch contains the latest version on PyPI.
310
- New features should be made in feature branches from `master` that can be merged into `master` once ready.
311
- When a new release is ready, update `pelutils/__version__.py` and rebase `master` onto `release`.
312
- Then push a new tag from `release` named `vX.Y.Z`.
308
+ Use [uv](https://docs.astral.sh/uv/) for dependency management, builds, and running
309
+ development tools. Install uv, then from the repository root sync the development
310
+ environment (a C compiler and Python headers are required to build the native extension):
311
+
312
+ ```sh
313
+ uv sync --python 3.11 --group dev
314
+ ```
315
+
316
+ The `dev` dependency group includes CPU-only PyTorch and documentation tools.
317
+
318
+ Run checks and tools through `uv run`:
313
319
 
314
- When new code is merged into `master`, a number of checks are run.
315
- These can be tested locally with the following commands.
316
320
  ```sh
317
321
  # Linting and formatting
318
- ruff format pelutils tests
319
- ruff check pelutils tests
322
+ uv run --python 3.11 ruff format pelutils tests
323
+ uv run --python 3.11 ruff check pelutils tests
320
324
  # Type checking
321
- basedpyright pelutils
325
+ uv run --python 3.11 basedpyright pelutils
322
326
  # Unit tests
323
- python -m pytest tests --cov pelutils
327
+ uv run --python 3.11 pytest tests --cov pelutils
324
328
  # Build docs
325
- # Once build, open docs/build/html/index.html in your browser to see them
326
- make -C docs html
329
+ uv run --python 3.11 make -C docs html
330
+ # Preview at docs/build/html/index.html
327
331
  ```
332
+
333
+ After changing C sources, rebuild the extension with
334
+ `uv sync --python 3.11 --group dev --reinstall-package pelutils`.
335
+
336
+ The wheel-build CI tests each built wheel in a cibuildwheel environment provisioned
337
+ from the locked `dev` group with uv; pytest runs against the installed wheel. Read the
338
+ Docs also syncs that group through uv.
339
+
340
+ ## Updating and releasing
341
+
342
+ `pelutils` uses the `master` branch as a stable development branch.
343
+ The `release` branch contains the latest version on PyPI.
344
+ New features should be made in feature branches from `master` that can be merged into `master` once ready.
345
+ When a new release is ready, update `pyproject.toml` and rebase `master` onto `release`.
346
+ Then push a new tag from `release` named `vX.Y.Z`.
347
+
348
+ When new code is merged into `master`, the checks listed above are run.
349
+ To build distribution artifacts locally, use `uv build --python 3.11`.
@@ -0,0 +1,5 @@
1
+ from importlib.metadata import version as _get_distribution_version
2
+
3
+ __version__ = _get_distribution_version("pelutils")
4
+
5
+ __all__ = ("__version__",)
@@ -0,0 +1,80 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Literal, overload
4
+
5
+ import numpy.typing as npt
6
+
7
+ from pelutils.types import AnyArray, IntArray
8
+
9
+ @overload
10
+ def unique(
11
+ array: npt.ArrayLike,
12
+ *,
13
+ return_index: Literal[False] = False,
14
+ return_inverse: Literal[False] = False,
15
+ return_counts: Literal[False] = False,
16
+ axis: int = 0,
17
+ ) -> AnyArray: ...
18
+ @overload
19
+ def unique(
20
+ array: npt.ArrayLike,
21
+ *,
22
+ return_index: Literal[True],
23
+ return_inverse: Literal[False] = False,
24
+ return_counts: Literal[False] = False,
25
+ axis: int = 0,
26
+ ) -> tuple[AnyArray, IntArray]: ...
27
+ @overload
28
+ def unique(
29
+ array: npt.ArrayLike,
30
+ *,
31
+ return_index: Literal[False] = False,
32
+ return_inverse: Literal[True],
33
+ return_counts: Literal[False] = False,
34
+ axis: int = 0,
35
+ ) -> tuple[AnyArray, IntArray]: ...
36
+ @overload
37
+ def unique(
38
+ array: npt.ArrayLike,
39
+ *,
40
+ return_index: Literal[True],
41
+ return_inverse: Literal[True],
42
+ return_counts: Literal[False] = False,
43
+ axis: int = 0,
44
+ ) -> tuple[AnyArray, IntArray, IntArray]: ...
45
+ @overload
46
+ def unique(
47
+ array: npt.ArrayLike,
48
+ *,
49
+ return_index: Literal[False] = False,
50
+ return_inverse: Literal[False] = False,
51
+ return_counts: Literal[True],
52
+ axis: int = 0,
53
+ ) -> tuple[AnyArray, IntArray]: ...
54
+ @overload
55
+ def unique(
56
+ array: npt.ArrayLike,
57
+ *,
58
+ return_index: Literal[True],
59
+ return_inverse: Literal[False] = False,
60
+ return_counts: Literal[True],
61
+ axis: int = 0,
62
+ ) -> tuple[AnyArray, IntArray, IntArray]: ...
63
+ @overload
64
+ def unique(
65
+ array: npt.ArrayLike,
66
+ *,
67
+ return_index: Literal[False] = False,
68
+ return_inverse: Literal[True],
69
+ return_counts: Literal[True],
70
+ axis: int = 0,
71
+ ) -> tuple[AnyArray, IntArray, IntArray]: ...
72
+ @overload
73
+ def unique(
74
+ array: npt.ArrayLike,
75
+ *,
76
+ return_index: Literal[True],
77
+ return_inverse: Literal[True],
78
+ return_counts: Literal[True],
79
+ axis: int = 0,
80
+ ) -> tuple[AnyArray, IntArray, IntArray, IntArray]: ...
@@ -1,7 +1,5 @@
1
- import re
2
-
3
- from rich.color import ANSI_COLOR_NAMES
4
1
  from rich.console import Console
2
+ from rich.markup import escape
5
3
  from typing_extensions import override
6
4
 
7
5
  _stdout_console = Console(highlight=False)
@@ -14,10 +12,6 @@ class RichString:
14
12
  This allows for printing and logging without rich syntax causing issues.
15
13
  """
16
14
 
17
- _open_tag_regex = re.compile("(%s)" % "|".join(r"\[" + c + r"\]" for c in ANSI_COLOR_NAMES)) # noqa: UP031
18
- _close_tag_regex_1 = re.compile(r"\\(\[\/.*\])")
19
- _close_tag_regex_2 = re.compile(r"(\[\/.*\])")
20
-
21
15
  def __init__(self, stderr: bool = False):
22
16
  self.strings: list[str] = list() # Normal strings
23
17
  self.riches: list[str] = list() # Corresponding strings with rich syntax
@@ -26,10 +20,8 @@ class RichString:
26
20
  def add_string(self, s: str, rich: str | None = None):
27
21
  """Add a new string and optionally a rich string equivalent."""
28
22
  if rich is None:
29
- # Escape beginning brackets to prevent accidental formatting when printing
30
- rich = re.sub(self._open_tag_regex, r"\\\1", s)
31
- rich = re.sub(self._close_tag_regex_1, r"\1", rich)
32
- rich = re.sub(self._close_tag_regex_2, r"\\\1", rich)
23
+ # Escape all markup so plain text cannot be mistaken for Rich formatting.
24
+ rich = escape(s)
33
25
  self.strings.append(s)
34
26
  self.riches.append(rich)
35
27
 
@@ -6,7 +6,7 @@ and rewriting them each time is tedious and error-prone. This module is the grab
6
6
  those: each helper is self-contained and useful on its own, so import only what you need.
7
7
 
8
8
  Main inclusions are :class:`Table` for aligned text tables that also export to LaTeX via
9
- :meth:`Table.to_latex`; :class:`OS` and :data:`hardware_info` for describing the machine
9
+ :meth:`Table.to_latex` and Markdown via :meth:`Table.to_markdown`; :class:`OS` and :data:`hardware_info` for describing the machine
10
10
  the code runs on; :func:`git_repo_info` for the repository and commit currently executing;
11
11
  :func:`array_bytes`/:func:`array_ptr` for low-level array introspection; and small file
12
12
  and dict helpers such as :func:`reverse_line_iterator` and :func:`except_keys`.
@@ -1,16 +1,17 @@
1
- import re
2
1
  from collections.abc import Sequence
3
2
  from typing import Any
4
3
 
4
+ from rich.cells import cell_len
5
5
  from typing_extensions import override
6
6
 
7
7
 
8
8
  class Table:
9
- """Build aligned, human-readable text tables that can also be exported to LaTeX.
9
+ """Build aligned, human-readable text tables that can also be exported to LaTeX and Markdown.
10
10
 
11
11
  Add an optional header, then rows, and render with ``str(table)``; column widths are
12
12
  computed automatically. :meth:`add_hline` inserts a horizontal rule and
13
- :meth:`to_latex` produces ``booktabs``-style LaTeX.
13
+ :meth:`to_latex` produces ``booktabs``-style LaTeX, and :meth:`to_markdown`
14
+ produces a Markdown pipe table.
14
15
 
15
16
  Example
16
17
  -------
@@ -67,29 +68,58 @@ class Table:
67
68
  self._hlines.add(len(self._rows) - 1)
68
69
 
69
70
  def to_latex(self) -> str:
70
- """Produce LaTeX code for the table to included in a tabular environment.
71
+ """Produce LaTeX code for the table to include in a tabular environment.
71
72
 
72
73
  It assumes the booktabs package is used.
73
74
  """
74
- formatted = str(self)
75
- lines = formatted.splitlines()
76
- lines.insert(0, r"\toprule")
75
+ assert self._width is not None
76
+ all_rows = [self._header, *self._rows] if self._header else self._rows
77
+ widths = [max(cell_len(row[j]) for row in all_rows) for j in range(self._width)]
78
+
79
+ lines = [r"\toprule"]
80
+ if self._header:
81
+ header = (self._format_element(cell, width, True) for cell, width in zip(self._header, widths, strict=True))
82
+ lines.append(" & ".join(header) + r" \\")
83
+ lines.append(r"\midrule")
84
+
85
+ for i, (row, left_align) in enumerate(zip(self._rows, self._left_aligns, strict=True)):
86
+ cells = (self._format_element(cell, width, align) for cell, width, align in zip(row, widths, left_align, strict=True))
87
+ lines.append(" & ".join(cells) + r" \\")
88
+ if i in self._hlines:
89
+ lines.append(r"\midrule")
90
+
77
91
  lines.append(r"\bottomrule")
92
+ return "\n".join(lines)
78
93
 
79
- for i, line in enumerate(lines):
80
- if re.match(r"^(-+\+)+-+$", line):
81
- lines[i] = r"\midrule"
82
- elif re.match(r"^(.+\|)+.+$", line):
83
- lines[i] = line.replace("|", "&") + r" \\"
94
+ def to_markdown(self) -> str:
95
+ """Produce a Markdown pipe table.
84
96
 
97
+ Markdown requires a header row, so a table without an explicit header gets a
98
+ blank one. Column alignment follows the first data row (or is left-aligned
99
+ when there are no data rows). Markdown has no syntax for horizontal rules
100
+ between body rows, so markers added with :meth:`add_hline` are omitted.
101
+ """
102
+ assert self._width is not None
103
+ header = self._header or ("",) * self._width
104
+ aligns = self._left_aligns[0] if self._left_aligns else (True,) * self._width
105
+ lines = [
106
+ "| " + " | ".join(self._escape_markdown_cell(cell) for cell in header) + " |",
107
+ "| " + " | ".join(":---" if align else "---:" for align in aligns) + " |",
108
+ ]
109
+ lines.extend("| " + " | ".join(self._escape_markdown_cell(cell) for cell in row) + " |" for row in self._rows)
85
110
  return "\n".join(lines)
86
111
 
112
+ @staticmethod
113
+ def _escape_markdown_cell(cell: str) -> str:
114
+ return cell.replace("\\", "\\\\").replace("|", r"\|").replace("\r\n", "\n").replace("\r", "\n").replace("\n", "<br>")
115
+
87
116
  @staticmethod
88
117
  def _format_element(element: str, width: int, left_align: bool) -> str:
118
+ padding = width - cell_len(element)
89
119
  if left_align:
90
- return element + " " * (width - len(element))
120
+ return element + " " * padding
91
121
  else:
92
- return " " * (width - len(element)) + element
122
+ return " " * padding + element
93
123
 
94
124
  @override
95
125
  def __repr__(self) -> str:
@@ -99,7 +129,7 @@ class Table:
99
129
  def __str__(self) -> str:
100
130
  assert self._width is not None
101
131
  all_rows = [self._header, *self._rows] if self._header else self._rows
102
- widths = [max(len(all_rows[i][j]) for i in range(len(all_rows))) for j in range(self._width)]
132
+ widths = [max(cell_len(all_rows[i][j]) for i in range(len(all_rows))) for j in range(self._width)]
103
133
  hline = "+".join("-" * (width + 1 + (0 < i < self._width - 1)) for i, width in enumerate(widths))
104
134
  strs = list()
105
135
  if self._header:
@@ -22,15 +22,24 @@ class UniversalJsonModel(BaseModel):
22
22
 
23
23
  model_config = ConfigDict(arbitrary_types_allowed=True)
24
24
 
25
- def to_json_dict(self) -> dict[str, Any]: # pyright: ignore[reportExplicitAny]
26
- """Return a JSON-compatible dictionary, pickle-encoding unsupported values."""
27
- return self.model_dump(mode="json", fallback=pickle_encode)
25
+ def to_json_dict(self, **model_dump_kwargs: Any) -> dict[str, Any]: # pyright: ignore[reportExplicitAny]
26
+ """Return a JSON-compatible dictionary, pickle-encoding unsupported values.
27
+
28
+ Keyword arguments are forwarded to :meth:`pydantic.BaseModel.model_dump`, except
29
+ ``mode`` and ``fallback``, which are fixed to preserve this method's JSON format.
30
+ """
31
+ if {"mode", "fallback"} & model_dump_kwargs.keys():
32
+ raise TypeError("'mode' and 'fallback' are fixed by to_json_dict()")
33
+ return self.model_dump(mode="json", fallback=pickle_encode, **model_dump_kwargs)
28
34
 
29
35
  @classmethod
30
- def from_json_dict(cls: type[Self], json_dict: dict[str, Any]) -> Self: # pyright: ignore[reportExplicitAny]
31
- """Build a model from :meth:`to_json_dict` output. Do not load untrusted data."""
36
+ def from_json_dict(cls: type[Self], json_dict: dict[str, Any], **model_validate_kwargs: Any) -> Self: # pyright: ignore[reportExplicitAny]
37
+ """Build a model from :meth:`to_json_dict` output. Do not load untrusted data.
38
+
39
+ Keyword arguments are forwarded to :meth:`pydantic.BaseModel.model_validate`.
40
+ """
32
41
  self_dict = from_safe_json(json_dict)
33
- return cls.model_validate(self_dict)
42
+ return cls.model_validate(self_dict, **model_validate_kwargs)
34
43
 
35
44
  def save(self, path: str | Path, *, max_line_length: int = 140, indent: int = 2, encoding: str = "utf-8"):
36
45
  """Save the model to ``path`` as human-readable JSON, creating parent directories as needed."""
@@ -37,6 +37,6 @@ periodic tasks, and ``fuse``/``fuse_multiple`` for combining results across
37
37
  processes.
38
38
  """
39
39
 
40
- from ._ticktock import TT, Profile, TickTock, TickTockException
40
+ from ._ticktock import TT, Profile, TickTock, TickTockException, get_active_ticktock
41
41
 
42
- __all__ = ("TT", "Profile", "TickTock", "TickTockException")
42
+ __all__ = ("TT", "Profile", "TickTock", "TickTockException", "get_active_ticktock")
@@ -1,8 +1,9 @@
1
+ import itertools
2
+ import threading
1
3
  import warnings
2
4
  from collections.abc import Hashable, Iterable, Iterator, Sequence
3
5
  from contextlib import contextmanager
4
6
  from copy import deepcopy
5
- from threading import current_thread
6
7
  from time import perf_counter
7
8
  from typing import TypeAlias, TypeVar, cast
8
9
 
@@ -23,6 +24,20 @@ _time_units: tuple[_TimeUnit, ...] = (
23
24
 
24
25
  T = TypeVar("T")
25
26
 
27
+ _lock = threading.RLock()
28
+ _active_ticktocks: "dict[int, TickTock]" = dict()
29
+ _ids = itertools.count()
30
+ _ids_lock = threading.RLock()
31
+ _local_thread = threading.local()
32
+
33
+
34
+ def _get_thread_uid() -> int:
35
+ """Return a stable, program-lifetime-unique ID for the calling thread."""
36
+ if not hasattr(_local_thread, "__ticktock_uid__"):
37
+ with _ids_lock:
38
+ _local_thread.__ticktock_uid__ = next(_ids)
39
+ return _local_thread.__ticktock_uid__
40
+
26
41
 
27
42
  def _get_smallest_suitable_unit(duration_s: float) -> _TimeUnit:
28
43
  """Return the smallest unit for which the duration is at least the same size as the unit."""
@@ -160,8 +175,8 @@ class TickTock:
160
175
  self._profile_stack: list[Profile] = list() # LIFO stack of active profiles
161
176
  self._root_profiles: list[Profile] = list() # Top level profiles
162
177
 
163
- self._thread_name = current_thread().name
164
- self._thread_id = id(current_thread())
178
+ self._thread_name = threading.current_thread().name
179
+ self._thread_id = _get_thread_uid()
165
180
 
166
181
  def tick(self, key: Hashable = None):
167
182
  """Start a timer identified by an optional hashable key."""
@@ -244,10 +259,10 @@ class TickTock:
244
259
  self._end_profile()
245
260
 
246
261
  def _warn_if_wrong_thread(self, *, stacklevel: int):
247
- if self._thread_id != id(current_thread()):
262
+ if self._thread_id != _get_thread_uid():
248
263
  warnings.warn(
249
264
  f"This TickTock instance was created in the {self._thread_name} thread but profiling was started in "
250
- + f"{current_thread().name}. Profiling is NOT designed to deal with multiple threads. Instead, create a "
265
+ + f"{threading.current_thread().name}. Profiling is NOT designed to deal with multiple threads. Instead, create a "
251
266
  + "TickTock instance for each thread requiring profiling.",
252
267
  stacklevel=stacklevel,
253
268
  )
@@ -332,13 +347,23 @@ class TickTock:
332
347
  profile.parent.children.remove(profile)
333
348
 
334
349
  def reset(self):
335
- """Stop all timing and profiling and clear all profiles and measurements."""
350
+ """Stop all timing and profiling and clear all profiles and measurements.
351
+
352
+ Resetting is allowed while this instance is registered by :meth:`as_active`; the
353
+ active registration remains until that context exits. Resetting while a profile
354
+ context is in progress raises :class:`TickTockException` without changing state.
355
+ """
336
356
  if self._profile_stack:
337
357
  raise TickTockException("Cannot reset TickTock while profiling is active")
338
358
  self.__init__()
339
359
 
340
360
  def reset_profiles(self):
341
- """Similar to ``reset`` but only reset profiles, leaving ``tick``/``tock`` timers intact."""
361
+ """Reset profiles while leaving ``tick``/``tock`` timers intact.
362
+
363
+ The same restrictions as :meth:`reset` apply: this is allowed while registered
364
+ by :meth:`as_active`, but raises :class:`TickTockException` during a profile
365
+ context.
366
+ """
342
367
  tick_starts = self._tick_starts
343
368
  self.reset()
344
369
  self._tick_starts = tick_starts
@@ -393,8 +418,8 @@ class TickTock:
393
418
  raise ValueError("Some TickTocks are the same instance, which is not allowed")
394
419
  for tt in tts[1:]:
395
420
  ticktock.fuse(tt)
396
- ticktock._thread_name = current_thread().name
397
- ticktock._thread_id = id(current_thread())
421
+ ticktock._thread_name = threading.current_thread().name
422
+ ticktock._thread_id = _get_thread_uid()
398
423
  return ticktock
399
424
 
400
425
  @staticmethod
@@ -446,5 +471,38 @@ class TickTock:
446
471
  """Return True if any profiling has been performed."""
447
472
  return len(self._root_profiles) > 0
448
473
 
474
+ @contextmanager
475
+ def as_active(self):
476
+ """Set the ``TickTock`` instance as the active instance in the current thread.
477
+
478
+ It can then be retrieved with :func:`get_active_ticktock`.
479
+ Calling :meth:`reset` or :meth:`reset_profiles` inside this context does not
480
+ unset the active instance. Those methods still raise if a profile context is
481
+ currently in progress.
482
+ """
483
+ current_thread_id = _get_thread_uid()
484
+ with _lock:
485
+ if current_thread_id in _active_ticktocks:
486
+ raise TickTockException(f"An active TickTock instance has already been set in thread {threading.current_thread().name}")
487
+ _active_ticktocks[current_thread_id] = self
488
+ try:
489
+ yield
490
+ finally:
491
+ with _lock:
492
+ del _active_ticktocks[current_thread_id]
493
+
494
+
495
+ def get_active_ticktock() -> TickTock:
496
+ """Return the active ``TickTock`` instance in the current thread (as set by :meth:`TickTock.as_active`).
497
+
498
+ If no active ``TickTock`` is set, a new ``TickTock`` instance is returned.
499
+ This allows normal profiling usage without having to care if it's actually used or not.
500
+ """
501
+ with _lock:
502
+ ticktock = _active_ticktocks.get(_get_thread_uid())
503
+ return ticktock if ticktock is not None else TickTock()
504
+
449
505
 
506
+ # Globally accessible default instance
507
+ # It suffices to use this for most cases
450
508
  TT = TickTock()
@@ -1,12 +1,11 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: pelutils
3
- Version: 4.3.1
3
+ Version: 4.5.0
4
4
  Summary: The Swiss army knife of Python projects
5
- Home-page: https://github.com/peleiden/pelutils
6
- Download-URL: https://pypi.org/project/pelutils/
7
- Author: Asger Laurits Schultz, Søren Winkel Holm
8
- Author-email: asger.s@protonmail.com, swholm@protonmail.com
9
- License: MIT
5
+ Author-email: Asger Laurits Schultz <asger.s@protonmail.com>, Søren Winkel Holm <swholm@protonmail.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/peleiden/pelutils
8
+ Project-URL: Download, https://pypi.org/project/pelutils/
10
9
  Keywords: utility,logger,parser,profiling,plotting
11
10
  Classifier: Intended Audience :: Developers
12
11
  Classifier: Operating System :: OS Independent
@@ -20,9 +19,19 @@ Classifier: Programming Language :: Python :: 3.14
20
19
  Classifier: Programming Language :: Python :: 3.15
21
20
  Requires-Python: >=3.11
22
21
  Description-Content-Type: text/markdown
23
- Provides-Extra: dev
24
- Provides-Extra: docs
22
+ License-File: LICENSE.txt
25
23
  License-File: pelutils/_c/hashmap/LICENSE
24
+ Requires-Dist: numpy>=2.0
25
+ Requires-Dist: gitpython>=3.1.0
26
+ Requires-Dist: rich>=10.0.0
27
+ Requires-Dist: py-cpuinfo>=8.0.0
28
+ Requires-Dist: psutil>=5.8.0
29
+ Requires-Dist: matplotlib>=3.3
30
+ Requires-Dist: scipy>=1.6
31
+ Requires-Dist: tqdm>=4.55
32
+ Requires-Dist: pydantic>=2
33
+ Requires-Dist: typing_extensions>=4.6
34
+ Dynamic: license-file
26
35
 
27
36
  # pelutils
28
37
 
@@ -314,7 +323,7 @@ def process(features: FloatArray, labels: IntArray, mask: BoolArray): ...
314
323
 
315
324
  ## Also included
316
325
 
317
- - `pelutils.misc.Table` — build aligned text tables which can also be easily export to LaTeX with `Table.to_latex()`.
326
+ - `pelutils.misc.Table` — build aligned text tables which can be exported to LaTeX with `Table.to_latex()` or Markdown with `Table.to_markdown()`.
318
327
  - `pelutils.misc.hardware_info` / `OS` — describe the machine the code runs on.
319
328
  - `pelutils.misc.git_repo_info` — the repo and commit the code is executing in.
320
329
  - Assorted file and dict helpers (`reverse_line_iterator`, `except_keys`, ...).
@@ -329,25 +338,47 @@ If no wheel matches, `pip` builds from source which requires `<Python.h>` — in
329
338
  32-bit systems are not fully supported.
330
339
  Most of the library is Python-only and should work but using any C-dependent code (namely `unique` and `SparseGridBlobDetection`) is likely to end in a segfault.
331
340
 
332
- ## Updating and releasing
341
+ ## Development
333
342
 
334
- `pelutils` uses the `master` branch as a stable development branch.
335
- The `release` branch contains the latest version on PyPI.
336
- New features should be made in feature branches from `master` that can be merged into `master` once ready.
337
- When a new release is ready, update `pelutils/__version__.py` and rebase `master` onto `release`.
338
- Then push a new tag from `release` named `vX.Y.Z`.
343
+ Use [uv](https://docs.astral.sh/uv/) for dependency management, builds, and running
344
+ development tools. Install uv, then from the repository root sync the development
345
+ environment (a C compiler and Python headers are required to build the native extension):
346
+
347
+ ```sh
348
+ uv sync --python 3.11 --group dev
349
+ ```
350
+
351
+ The `dev` dependency group includes CPU-only PyTorch and documentation tools.
352
+
353
+ Run checks and tools through `uv run`:
339
354
 
340
- When new code is merged into `master`, a number of checks are run.
341
- These can be tested locally with the following commands.
342
355
  ```sh
343
356
  # Linting and formatting
344
- ruff format pelutils tests
345
- ruff check pelutils tests
357
+ uv run --python 3.11 ruff format pelutils tests
358
+ uv run --python 3.11 ruff check pelutils tests
346
359
  # Type checking
347
- basedpyright pelutils
360
+ uv run --python 3.11 basedpyright pelutils
348
361
  # Unit tests
349
- python -m pytest tests --cov pelutils
362
+ uv run --python 3.11 pytest tests --cov pelutils
350
363
  # Build docs
351
- # Once build, open docs/build/html/index.html in your browser to see them
352
- make -C docs html
364
+ uv run --python 3.11 make -C docs html
365
+ # Preview at docs/build/html/index.html
353
366
  ```
367
+
368
+ After changing C sources, rebuild the extension with
369
+ `uv sync --python 3.11 --group dev --reinstall-package pelutils`.
370
+
371
+ The wheel-build CI tests each built wheel in a cibuildwheel environment provisioned
372
+ from the locked `dev` group with uv; pytest runs against the installed wheel. Read the
373
+ Docs also syncs that group through uv.
374
+
375
+ ## Updating and releasing
376
+
377
+ `pelutils` uses the `master` branch as a stable development branch.
378
+ The `release` branch contains the latest version on PyPI.
379
+ New features should be made in feature branches from `master` that can be merged into `master` once ready.
380
+ When a new release is ready, update `pyproject.toml` and rebase `master` onto `release`.
381
+ Then push a new tag from `release` named `vX.Y.Z`.
382
+
383
+ When new code is merged into `master`, the checks listed above are run.
384
+ To build distribution artifacts locally, use `uv build --python 3.11`.
@@ -1,8 +1,9 @@
1
+ LICENSE.txt
1
2
  MANIFEST.in
2
3
  README.md
4
+ pyproject.toml
3
5
  setup.py
4
6
  pelutils/__init__.py
5
- pelutils/__version__.py
6
7
  pelutils/py.typed
7
8
  pelutils.egg-info/PKG-INFO
8
9
  pelutils.egg-info/SOURCES.txt
@@ -27,6 +28,7 @@ pelutils/_entry_points/linecounter.py
27
28
  pelutils/array/__init__.py
28
29
  pelutils/array/_blob.py
29
30
  pelutils/array/_unique.py
31
+ pelutils/array/_unique.pyi
30
32
  pelutils/array/_utils.py
31
33
  pelutils/job_parser/__init__.py
32
34
  pelutils/job_parser/_job_parser.py
@@ -0,0 +1,10 @@
1
+ numpy>=2.0
2
+ gitpython>=3.1.0
3
+ rich>=10.0.0
4
+ py-cpuinfo>=8.0.0
5
+ psutil>=5.8.0
6
+ matplotlib>=3.3
7
+ scipy>=1.6
8
+ tqdm>=4.55
9
+ pydantic>=2
10
+ typing_extensions>=4.6
@@ -0,0 +1,86 @@
1
+ # uv_build does not support the native C extension; uv uses this PEP 517 backend.
2
+ [build-system]
3
+ requires = ["setuptools>=77", "wheel"]
4
+ build-backend = "setuptools.build_meta"
5
+
6
+ [project]
7
+ name = "pelutils"
8
+ version = "4.5.0"
9
+ description = "The Swiss army knife of Python projects"
10
+ readme = "README.md"
11
+ requires-python = ">=3.11"
12
+ license = "MIT"
13
+ license-files = ["LICENSE.txt", "pelutils/_c/hashmap/LICENSE"]
14
+ authors = [
15
+ { name = "Asger Laurits Schultz", email = "asger.s@protonmail.com" },
16
+ { name = "Søren Winkel Holm", email = "swholm@protonmail.com" },
17
+ ]
18
+ keywords = ["utility", "logger", "parser", "profiling", "plotting"]
19
+ classifiers = [
20
+ "Intended Audience :: Developers",
21
+ "Operating System :: OS Independent",
22
+ "Programming Language :: Python",
23
+ "Programming Language :: Python :: 3 :: Only",
24
+ "Programming Language :: Python :: Free Threading :: 3 - Stable",
25
+ "Programming Language :: Python :: 3.11",
26
+ "Programming Language :: Python :: 3.12",
27
+ "Programming Language :: Python :: 3.13",
28
+ "Programming Language :: Python :: 3.14",
29
+ "Programming Language :: Python :: 3.15",
30
+ ]
31
+ dependencies = [
32
+ "numpy>=2.0",
33
+ "gitpython>=3.1.0",
34
+ "rich>=10.0.0",
35
+ "py-cpuinfo>=8.0.0",
36
+ "psutil>=5.8.0",
37
+ "matplotlib>=3.3",
38
+ "scipy>=1.6",
39
+ "tqdm>=4.55",
40
+ "pydantic>=2",
41
+ "typing_extensions>=4.6",
42
+ ]
43
+
44
+ [dependency-groups]
45
+ dev = [
46
+ "torch>=2",
47
+ "pytest==8.4.2",
48
+ "pytest-cov==7.0.0",
49
+ "coveralls>=4.0.0",
50
+ "coverage==7.10.7",
51
+ "wheel",
52
+ "setuptools>=60.0.0",
53
+ "ruff==0.15.8",
54
+ "basedpyright==1.39.0",
55
+ "freezegun>=1.5",
56
+ "ipdb",
57
+ "sphinx",
58
+ "sphinx-autobuild",
59
+ "furo",
60
+ "myst-parser",
61
+ ]
62
+
63
+ [project.scripts]
64
+ linecounter = "pelutils._entry_points.linecounter:run"
65
+
66
+ [project.urls]
67
+ Homepage = "https://github.com/peleiden/pelutils"
68
+ Download = "https://pypi.org/project/pelutils/"
69
+
70
+ [tool.setuptools]
71
+ include-package-data = true
72
+
73
+ [tool.setuptools.packages.find]
74
+ exclude = ["tests", "tests.*"]
75
+ namespaces = false
76
+
77
+ [tool.setuptools.package-data]
78
+ pelutils = ["py.typed"]
79
+
80
+ [[tool.uv.index]]
81
+ name = "pytorch"
82
+ url = "https://download.pytorch.org/whl/cpu"
83
+ explicit = true
84
+
85
+ [tool.uv.sources]
86
+ torch = { index = "pytorch" }
@@ -0,0 +1,17 @@
1
+ import os
2
+ import sys
3
+
4
+ from setuptools import setup
5
+ from setuptools.extension import Extension
6
+
7
+ c_files = [os.path.join(root, filename) for root, _, files in os.walk("pelutils/_c") for filename in files if filename.endswith(".c")]
8
+
9
+ setup(
10
+ ext_modules=[
11
+ Extension(
12
+ name="_pelutils_c",
13
+ sources=c_files,
14
+ extra_compile_args=["-DMS_WIN64"] if sys.platform == "win32" else [],
15
+ )
16
+ ]
17
+ )
@@ -1,3 +0,0 @@
1
- from .__version__ import __version__
2
-
3
- __all__ = ("__version__",)
@@ -1,2 +0,0 @@
1
- # Do not put anything else in this file
2
- __version__ = "4.3.1"
@@ -1,33 +0,0 @@
1
- gitpython>=3.1.0
2
- matplotlib>=3.3
3
- numpy>=2.0
4
- psutil>=5.8.0
5
- py-cpuinfo>=8.0.0
6
- pydantic>=2
7
- rich>=10.0.0
8
- scipy>=1.6
9
- tqdm>=4.55
10
- typing_extensions>=4.6
11
-
12
- [dev]
13
- basedpyright==1.39.0
14
- coverage==7.10.7
15
- coveralls>=4.0.0
16
- freezegun>=1.5
17
- furo
18
- ipdb
19
- myst-parser
20
- pytest-cov==7.0.0
21
- pytest==8.4.2
22
- ruff==0.15.8
23
- setuptools>=60.0.0
24
- sphinx
25
- sphinx-autobuild
26
- torch>=2
27
- wheel
28
-
29
- [docs]
30
- furo
31
- myst-parser
32
- sphinx
33
- sphinx-autobuild
pelutils-4.3.1/setup.py DELETED
@@ -1,95 +0,0 @@
1
- import os
2
- import sys
3
- from glob import glob as glob # glob
4
-
5
- from setuptools import find_packages, setup
6
- from setuptools.extension import Extension
7
-
8
- sys.path.append("pelutils")
9
- from __version__ import __version__
10
-
11
- requirements = [
12
- "numpy>=2.0",
13
- "gitpython>=3.1.0",
14
- "rich>=10.0.0",
15
- "py-cpuinfo>=8.0.0",
16
- "psutil>=5.8.0",
17
- "matplotlib>=3.3",
18
- "scipy>=1.6",
19
- "tqdm>=4.55",
20
- "pydantic>=2",
21
- "typing_extensions>=4.6",
22
- ]
23
- requirements_dev = [
24
- "torch>=2",
25
- "pytest==8.4.2",
26
- "pytest-cov==7.0.0",
27
- "coveralls>=4.0.0",
28
- "coverage==7.10.7",
29
- "wheel",
30
- "setuptools>=60.0.0",
31
- "ruff==0.15.8",
32
- "basedpyright==1.39.0",
33
- "freezegun>=1.5",
34
- "ipdb",
35
- ]
36
- requirements_docs = [
37
- "sphinx",
38
- "sphinx-autobuild",
39
- "furo",
40
- "myst-parser",
41
- ]
42
-
43
- with open("README.md") as readme_file:
44
- README = readme_file.read()
45
-
46
- c_files = list()
47
- for root, __, files in os.walk("pelutils/_c"):
48
- c_files += [os.path.join(root, f) for f in files if f.endswith(".c")]
49
-
50
- setup_args = dict(
51
- name="pelutils",
52
- version=__version__,
53
- description="The Swiss army knife of Python projects",
54
- long_description_content_type="text/markdown",
55
- long_description=README,
56
- license="MIT",
57
- packages=find_packages(exclude=("tests", "tests.*")),
58
- package_data={"pelutils": ["py.typed"]},
59
- author="Asger Laurits Schultz, Søren Winkel Holm",
60
- author_email="asger.s@protonmail.com, swholm@protonmail.com",
61
- keywords=["utility", "logger", "parser", "profiling", "plotting"],
62
- url="https://github.com/peleiden/pelutils",
63
- download_url="https://pypi.org/project/pelutils/",
64
- install_requires=requirements,
65
- extras_require={"docs": requirements_docs, "dev": requirements_dev + requirements_docs},
66
- entry_points={
67
- "console_scripts": [
68
- "linecounter = pelutils._entry_points.linecounter:run",
69
- ]
70
- },
71
- ext_modules=[
72
- Extension(
73
- name="_pelutils_c",
74
- sources=c_files,
75
- extra_compile_args=["-DMS_WIN64"] if sys.platform == "win32" else [],
76
- )
77
- ],
78
- license_files=[os.path.join("pelutils", "_c", "hashmap", "LICENSE")],
79
- python_requires=">=3.11",
80
- classifiers=[
81
- "Intended Audience :: Developers",
82
- "Operating System :: OS Independent",
83
- "Programming Language :: Python",
84
- "Programming Language :: Python :: 3 :: Only",
85
- "Programming Language :: Python :: Free Threading :: 3 - Stable",
86
- "Programming Language :: Python :: 3.11",
87
- "Programming Language :: Python :: 3.12",
88
- "Programming Language :: Python :: 3.13",
89
- "Programming Language :: Python :: 3.14",
90
- "Programming Language :: Python :: 3.15",
91
- ],
92
- )
93
-
94
- if __name__ == "__main__":
95
- setup(**setup_args)
File without changes
File without changes
File without changes
File without changes
File without changes