ipctools 0.0.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.
ipctools-0.0.0/LICENSE ADDED
@@ -0,0 +1,15 @@
1
+ Inter-process communication tools.
2
+ Copyright (C) 2026 Narvin Singh
3
+
4
+ This program is free software: you can redistribute it and/or modify
5
+ it under the terms of the GNU General Public License as published by
6
+ the Free Software Foundation, either version 3 of the License, or
7
+ (at your option) any later version.
8
+
9
+ This program is distributed in the hope that it will be useful,
10
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ GNU General Public License for more details.
13
+
14
+ You should have received a copy of the GNU General Public License
15
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
@@ -0,0 +1,85 @@
1
+ Metadata-Version: 2.3
2
+ Name: ipctools
3
+ Version: 0.0.0
4
+ Summary: Inter-process communication tools.
5
+ Author: Narvin Singh
6
+ Author-email: Narvin Singh <Narvin.A.Singh@gmail.com>
7
+ License: Inter-process communication tools.
8
+ Copyright (C) 2026 Narvin Singh
9
+
10
+ This program is free software: you can redistribute it and/or modify
11
+ it under the terms of the GNU General Public License as published by
12
+ the Free Software Foundation, either version 3 of the License, or
13
+ (at your option) any later version.
14
+
15
+ This program is distributed in the hope that it will be useful,
16
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
17
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
+ GNU General Public License for more details.
19
+
20
+ You should have received a copy of the GNU General Public License
21
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
22
+ Classifier: Programming Language :: Python :: 3
23
+ Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
24
+ Classifier: Operating System :: OS Independent
25
+ Requires-Dist: python-docs-theme~=2025.12 ; extra == 'doc'
26
+ Requires-Dist: sphinx~=9.1 ; extra == 'doc'
27
+ Requires-Python: >=3.12
28
+ Project-URL: Homepage, https://gitlab.com/narvin/ipctools
29
+ Project-URL: Repository, https://gitlab.com/narvin/ipctools
30
+ Project-URL: Bug Tracker, https://gitlab.com/narvin/ipctools/-/issues
31
+ Provides-Extra: doc
32
+ Description-Content-Type: text/x-rst
33
+
34
+ Ipctools
35
+ ########
36
+
37
+ Inter-process communication tools.
38
+
39
+ This is a template project that can be used to publish a package to `PyPI
40
+ <https://pypi.org/>`__.
41
+
42
+ Installation
43
+ ************
44
+
45
+ Create a ``.env`` file in the project directory with your `PyPI token
46
+ <https://pypi.org/help/#apitoken>`__ so you can publish packages.
47
+
48
+ .. code-block:: shell
49
+
50
+ echo "PYPI_TOKEN=<your token>" > .env
51
+
52
+ ``git`` and ``uv`` should be installed on your system. ``uv`` may be installed
53
+ by running ``make uv``.
54
+
55
+ Unless you use the ``unsafe`` option, then you must set ``GIT_PATH`` and
56
+ ``UV_PATH`` to the location of these tools on your system. You may also set
57
+ these in the ``.env`` file.
58
+
59
+ Usage
60
+ *****
61
+
62
+ Apply data to the template.
63
+
64
+ .. code-block:: shell
65
+
66
+ uv run -m src.pypireg apply -n "<project name>" -d "<project description>"
67
+
68
+ The project will be customized with the data, and files and directories will be
69
+ renamed. You may copy, and rename the project directory, then begin working on
70
+ the customized project. There are ``make`` recipes to install the project,
71
+ build documentation, perform code quality checks, run unit tests, and build and
72
+ publish the package to PyPI. The first thing you may want to do is attempt to
73
+ publish your new package in order to reserve the name if it is available.
74
+
75
+ Restore the project to its original state.
76
+
77
+ .. note::
78
+
79
+ Since the package directory has been renamed, instead of ``src.pypireg``,
80
+ you must reference the package by its new name.
81
+
82
+ .. code-block:: shell
83
+
84
+ uv run -m src.<project name> restore
85
+
@@ -0,0 +1,52 @@
1
+ Ipctools
2
+ ########
3
+
4
+ Inter-process communication tools.
5
+
6
+ This is a template project that can be used to publish a package to `PyPI
7
+ <https://pypi.org/>`__.
8
+
9
+ Installation
10
+ ************
11
+
12
+ Create a ``.env`` file in the project directory with your `PyPI token
13
+ <https://pypi.org/help/#apitoken>`__ so you can publish packages.
14
+
15
+ .. code-block:: shell
16
+
17
+ echo "PYPI_TOKEN=<your token>" > .env
18
+
19
+ ``git`` and ``uv`` should be installed on your system. ``uv`` may be installed
20
+ by running ``make uv``.
21
+
22
+ Unless you use the ``unsafe`` option, then you must set ``GIT_PATH`` and
23
+ ``UV_PATH`` to the location of these tools on your system. You may also set
24
+ these in the ``.env`` file.
25
+
26
+ Usage
27
+ *****
28
+
29
+ Apply data to the template.
30
+
31
+ .. code-block:: shell
32
+
33
+ uv run -m src.pypireg apply -n "<project name>" -d "<project description>"
34
+
35
+ The project will be customized with the data, and files and directories will be
36
+ renamed. You may copy, and rename the project directory, then begin working on
37
+ the customized project. There are ``make`` recipes to install the project,
38
+ build documentation, perform code quality checks, run unit tests, and build and
39
+ publish the package to PyPI. The first thing you may want to do is attempt to
40
+ publish your new package in order to reserve the name if it is available.
41
+
42
+ Restore the project to its original state.
43
+
44
+ .. note::
45
+
46
+ Since the package directory has been renamed, instead of ``src.pypireg``,
47
+ you must reference the package by its new name.
48
+
49
+ .. code-block:: shell
50
+
51
+ uv run -m src.<project name> restore
52
+
@@ -0,0 +1,101 @@
1
+ [project]
2
+ name = "ipctools"
3
+ version = "0.0.0"
4
+ authors = [
5
+ {name = "Narvin Singh", email = "Narvin.A.Singh@gmail.com"}
6
+ ]
7
+ classifiers = [
8
+ "Programming Language :: Python :: 3",
9
+ "License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)",
10
+ "Operating System :: OS Independent"
11
+ ]
12
+ description = "Inter-process communication tools."
13
+ readme = "README.rst"
14
+ license = {file = "LICENSE"}
15
+ requires-python = ">=3.12"
16
+
17
+ dependencies = []
18
+
19
+ [project.optional-dependencies]
20
+ doc = [
21
+ "python-docs-theme~=2025.12",
22
+ "sphinx~=9.1",
23
+ ]
24
+
25
+ [dependency-groups]
26
+ dev = [
27
+ "mypy~=1.19",
28
+ "pre-commit~=4.5",
29
+ "pytest~=9.0",
30
+ "ruff~=0.15.1",
31
+ "sphinx-lint~=1.0",
32
+ "yamllint~=1.38",
33
+ ]
34
+
35
+ [project.urls]
36
+ Homepage = "https://gitlab.com/narvin/ipctools"
37
+ Repository = "https://gitlab.com/narvin/ipctools"
38
+ "Bug Tracker" = "https://gitlab.com/narvin/ipctools/-/issues"
39
+
40
+ [build-system]
41
+ requires = ["uv_build>=0.10.2,<0.11.0"]
42
+ build-backend = "uv_build"
43
+
44
+ [tool.mypy]
45
+ python_version = "3.14"
46
+ strict = true
47
+
48
+ [tool.ruff]
49
+ line-length = 100
50
+ target-version = "py314"
51
+
52
+ [tool.ruff.format]
53
+ skip-magic-trailing-comma = true
54
+
55
+ [tool.ruff.lint]
56
+ select = ["ALL"]
57
+ ignore = [
58
+ # flake8-commas
59
+ "COM812", # Trailing comma missing
60
+
61
+ # pydocstyle
62
+ "D203", # 1 blank line required before class docstring
63
+ "D205", # 1 blank line required between summary line and description
64
+ "D212", # Multi-line docstring summary should start at the first line
65
+ "D400", # First line should end with a period
66
+ "D415", # First line should end with a period, question mark, or exclamation point
67
+
68
+ # Error
69
+ "E501", # Line too long ({width} > {limit})
70
+ "E731", # Do not assign a lambda expression, use a def
71
+
72
+ # eradicate
73
+ "ERA001", # Found commented-out code
74
+
75
+ # flake8-fixme
76
+ "FIX002", # Line contains TODO, consider resolving the issue
77
+
78
+ # flake8-implicit-str-concat
79
+ "ISC001", # Implicitly concatenated string literals on one line
80
+
81
+ # flake8-pytest-style
82
+ "PT009", # Use a regular assert instead of unittest-style {assertion}
83
+ "PT027", # Use pytest.raises instead of unittest-style {assertion}
84
+
85
+ # flake8-todos
86
+ "TD003", # Missing issue link on the line following this TODO
87
+ ]
88
+ fixable = [
89
+ "F401", # unused import
90
+ "F541", # f-string without any placeholders
91
+
92
+ # isort
93
+ "I001", # Import block is un-sorted or un-formatted
94
+
95
+ # Ruff-specific rules
96
+ "RUF022", # `__all__` is not sorted
97
+ "RUF100", # Unused noqa directive
98
+ ]
99
+ isort.split-on-trailing-comma = false
100
+ pydocstyle.convention = "google"
101
+
@@ -0,0 +1,8 @@
1
+ """The main package."""
2
+
3
+ from importlib import metadata
4
+
5
+ __project__ = "Ipctools"
6
+ __distribution__ = "ipctools"
7
+ __version__ = metadata.version("ipctools")
8
+ __authors__ = ["Narvin Singh"]
@@ -0,0 +1,59 @@
1
+ """The package entry point."""
2
+
3
+ import argparse
4
+ import logging
5
+
6
+ from . import ipctools
7
+
8
+
9
+ def apply_name(name: str, desc: str, author: list[str] | None, *, unsafe: bool) -> None:
10
+ """Stub for apply"""
11
+ logging.getLogger(__name__).debug("applying name: %s and description: %s", name, desc)
12
+ ipctools.apply(name, desc, authors=author, unsafe=unsafe)
13
+
14
+
15
+ def revert_apply_name(*, unsafe: bool) -> None:
16
+ """Stub for revert_apply_name"""
17
+ logging.getLogger(__name__).debug("restoring project")
18
+ ipctools.restore(unsafe=unsafe)
19
+
20
+
21
+ def main() -> int:
22
+ """The entry point function."""
23
+ parser = argparse.ArgumentParser(prog="{{PROJECT}}", description="{{DESCRIPTION}}")
24
+ parser_common = argparse.ArgumentParser(add_help=False)
25
+ parser_common.add_argument(
26
+ "-l",
27
+ "--log-level",
28
+ choices=logging.getLevelNamesMapping().keys(),
29
+ default="DEBUG",
30
+ help="The logging level",
31
+ )
32
+ parser_common.add_argument(
33
+ "-u",
34
+ "--unsafe",
35
+ action="store_true",
36
+ help="If not set, then environment variables with tool paths must be defined",
37
+ )
38
+ subparsers = parser.add_subparsers(title="commands")
39
+ parser_apply = subparsers.add_parser(
40
+ "apply", parents=[parser_common], help="Apply data to the project"
41
+ )
42
+ parser_apply.add_argument("-n", "--name", required=True, help="The project name")
43
+ parser_apply.add_argument("-d", "--desc", required=True, help="The project description")
44
+ parser_apply.add_argument("-a", "--author", action="append", help="A project author")
45
+ parser_apply.set_defaults(func=apply_name)
46
+ parser_restore = subparsers.add_parser(
47
+ "restore", parents=[parser_common], help="Restore the pypireg project to its original state"
48
+ )
49
+ parser_restore.set_defaults(func=revert_apply_name)
50
+ args = parser.parse_args()
51
+ logging.basicConfig(level=args.log_level)
52
+ logger = logging.getLogger(__name__)
53
+ logger.debug("args: %s", args)
54
+ args.func(**{k: v for k, v in args.__dict__.items() if k not in {"func", "log_level"}})
55
+ return 0
56
+
57
+
58
+ if __name__ == "__main__":
59
+ raise SystemExit(main())
@@ -0,0 +1,150 @@
1
+ """The main module."""
2
+
3
+ import configparser
4
+ import functools
5
+ import json
6
+ import os
7
+ import pathlib
8
+ import shutil
9
+ import subprocess
10
+ import tomllib
11
+ from typing import TYPE_CHECKING
12
+
13
+ if TYPE_CHECKING:
14
+ from collections.abc import Mapping
15
+
16
+
17
+ @functools.lru_cache(1)
18
+ def _projroot() -> pathlib.Path:
19
+ return pathlib.Path(__file__).parent.parent.parent
20
+
21
+
22
+ @functools.lru_cache(1)
23
+ def _load_env() -> configparser.ConfigParser:
24
+ parser = configparser.ConfigParser(allow_unnamed_section=True)
25
+ parser.read(_projroot() / ".env")
26
+ return parser
27
+
28
+
29
+ def _tool_path(tool: str, default: str | None) -> str:
30
+ _load_env()
31
+ key = f"{tool.upper()}_PATH"
32
+ msg = f"set the environment variable `{key}`, or add it to your `.env` file"
33
+ path = os.getenv(key)
34
+ if not path:
35
+ parser = _load_env()
36
+ try:
37
+ path = parser.get(configparser.UNNAMED_SECTION, key)
38
+ except configparser.NoOptionError as exc:
39
+ raise RuntimeError(msg) from exc
40
+ if path:
41
+ return path
42
+ if default is None:
43
+ raise RuntimeError(msg)
44
+ return default
45
+
46
+
47
+ @functools.lru_cache(2)
48
+ def _git_path(*, unsafe: bool) -> str:
49
+ return _tool_path("git", "git" if unsafe else None)
50
+
51
+
52
+ @functools.lru_cache(2)
53
+ def _uv_path(*, unsafe: bool) -> str:
54
+ return _tool_path("uv", "uv" if unsafe else None)
55
+
56
+
57
+ def _update_file_raw(path: pathlib.Path, spec: Mapping[str, str]) -> None:
58
+ with path.open("r+") as f:
59
+ template = f.read()
60
+ f.seek(0)
61
+ content = functools.reduce(
62
+ lambda acc, curr: acc.replace(curr[0], curr[1]), spec.items(), template
63
+ )
64
+ f.write(content)
65
+ f.truncate()
66
+
67
+
68
+ def _update_file(path: pathlib.Path, spec: Mapping[str, str]) -> None:
69
+ _update_file_raw(path, {f"{{{{{k.upper()}}}}}": v for k, v in spec.items()})
70
+
71
+
72
+ def _rename_file(path: pathlib.Path, name: str) -> None:
73
+ path.rename(path.parent / name)
74
+
75
+
76
+ def _get_authors_str(authors: list[str] | None, *, unsafe: bool) -> str | None:
77
+ match authors:
78
+ case [] | None:
79
+ git = _git_path(unsafe=unsafe)
80
+ res = subprocess.run( # noqa: S603
81
+ [git, "config", "get", "user.name"], capture_output=True, check=False
82
+ )
83
+ author = res.stdout.decode().strip()
84
+ return json.dumps([author]) or None
85
+ case _:
86
+ return json.dumps(authors)
87
+
88
+
89
+ def apply(
90
+ name: str, description: str, *, authors: list[str] | None = None, unsafe: bool = False
91
+ ) -> None:
92
+ """Apply data to the project."""
93
+ uv = _uv_path(unsafe=unsafe)
94
+ authors_str = _get_authors_str(authors, unsafe=unsafe)
95
+ projroot = _projroot()
96
+ proper_name = name.title()
97
+ _update_file(projroot / "LICENSE", {"description": description})
98
+ _update_file(projroot / "pyproject.toml", {"project": name, "description": description})
99
+ _update_file_raw(projroot / "pyproject.toml", {'name = "pypireg"': f'name = "{name}"'})
100
+ _update_file(
101
+ projroot / "README.rst",
102
+ {
103
+ "project": proper_name,
104
+ "project_underline": "#" * len(proper_name),
105
+ "description": description,
106
+ },
107
+ )
108
+ _update_file(projroot / "doc" / "conf.py", {"project": name})
109
+ _update_file(projroot / "doc" / "index.rst", {"project": name})
110
+ _update_file(
111
+ projroot / "src" / "pypireg" / "__init__.py",
112
+ {
113
+ "project": proper_name,
114
+ "distribution": name,
115
+ "authors": json.dumps(authors) if authors is not None else "None",
116
+ },
117
+ )
118
+ _update_file_raw(
119
+ projroot / "src" / "pypireg" / "__init__.py",
120
+ {
121
+ '__version__ = metadata.version("pypireg")': f'__version__ = metadata.version("{name}")',
122
+ "__authors__ = None": f"__authors__ = {authors_str}",
123
+ },
124
+ )
125
+ _update_file_raw(
126
+ projroot / "src" / "pypireg" / "__main__.py",
127
+ {"from . import pypireg": f"from . import {name}", "pypireg.": f"{name}."},
128
+ )
129
+ _rename_file(projroot / "src" / "pypireg" / "pypireg.py", f"{name}.py")
130
+ _rename_file(projroot / "src" / "pypireg", name)
131
+ _rename_file(projroot / "test" / "pypireg", name)
132
+ shutil.rmtree(projroot / ".venv")
133
+ subprocess.run([uv, "sync"], cwd=projroot, check=False) # noqa: S603
134
+ subprocess.run([uv, "run", "ruff", "format"], cwd=projroot, check=False) # noqa: S603
135
+
136
+
137
+ def restore(*, unsafe: bool = False) -> None:
138
+ """Restore the project to its original state."""
139
+ git = _git_path(unsafe=unsafe)
140
+ uv = _uv_path(unsafe=unsafe)
141
+ projroot = _projroot()
142
+ with pathlib.Path(projroot / "pyproject.toml").open("rb") as f:
143
+ pyproj = tomllib.load(f)
144
+ name = pyproj["project"]["name"]
145
+ _rename_file(projroot / "src" / name / f"{name}.py", "pypireg.py")
146
+ _rename_file(projroot / "src" / name, "pypireg")
147
+ _rename_file(projroot / "test" / name, "pypireg")
148
+ subprocess.run([git, "restore", "."], cwd=projroot, check=False) # noqa: S603
149
+ shutil.rmtree(projroot / ".venv")
150
+ subprocess.run([uv, "sync"], cwd=projroot, check=False) # noqa: S603
File without changes