pygitpub 0.0.59__tar.gz → 0.0.60__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.
@@ -1,8 +1,6 @@
1
1
  # generated
2
- /build/
3
2
  /toolchain/
4
3
  /dist/
5
- /target/
6
4
  /out/
7
5
  /debug/
8
6
  /download/
@@ -64,7 +62,7 @@ modules.order
64
62
 
65
63
  # sphinx
66
64
  /docs/_build/
67
- /docs/.doctrees/environment.pickle
65
+ /docs/.doctrees/
68
66
 
69
67
  # mdBook build output
70
68
  /docs/book/
@@ -77,8 +75,6 @@ modules.order
77
75
  # python
78
76
  __pycache__/
79
77
  *.py[oc]
80
- *.pyc
81
- *.pyo
82
78
  /wheel/
83
79
  /.venv/
84
80
  .coverage
@@ -87,7 +83,10 @@ coverage.xml
87
83
  *.egg-info/
88
84
 
89
85
  # mine
90
- /.pydmt.build.errors
86
+ # error files left by the bashy prompt plugins (.uv.sync.errors,
87
+ # .pydmt.build.errors, ...); unanchored because a sub-project's
88
+ # pyproject root can sit below the git root
89
+ .*.errors
91
90
  /.pydmt/
92
91
  *.stamp
93
92
  *.stamp.*
@@ -147,10 +146,13 @@ build/
147
146
  .ipynb_checkpoints/
148
147
 
149
148
  # c#
149
+ # **/obj/ and **/bin/ match at any depth, which is what .NET output needs
150
+ # (src/<proj>/bin, src/<proj>/obj). The un-globbed [Oo]bj/ and [Bb]in/ that
151
+ # used to follow were redundant with these two and are gone.
150
152
  **/obj/
151
153
  **/bin/
152
- [Oo]bj/
153
- [Bb]in/
154
+ # perl-meta keeps real Perl sources under perl/bin/Meta/, not build output.
155
+ !/perl/bin/
154
156
 
155
157
  # flash/air
156
158
  *.swf
@@ -175,7 +177,6 @@ bin-release/
175
177
  .project
176
178
  .project.xml
177
179
  .idea/
178
- /.idea/
179
180
  build.properties
180
181
 
181
182
  # spark
@@ -186,24 +187,26 @@ spark-warehouse/
186
187
  /.terraform/
187
188
  terraform.tfstate
188
189
  terraform.tfstate.backup
189
- /terraform.tfstate
190
- /terraform.tfstate.backup
191
190
  /terraform.lock.hcl
192
191
 
193
192
  # scala
194
- target/
195
- project/
193
+ # Anchored: sbt's build dir is at the repo root. Unanchored, this also
194
+ # swallowed source directories named project/ nested under src/.
195
+ /project/
196
196
 
197
197
  # rust
198
198
  **/*.rs.bk
199
199
  **/mutants.out*/
200
200
  *.pdb
201
- debug
201
+ # Anchored: this is the root debug build dir. Unanchored (and without a
202
+ # trailing slash) it matched any file or directory named debug at any depth,
203
+ # including authored example content.
204
+ /debug/
202
205
  /.rsconstruct_cache.json
203
206
 
204
207
  # claude
205
208
  /.claude/
206
- claude/
209
+ /claude/
207
210
  .claude/projects/
208
211
  .claude/settings.local.json
209
212
 
@@ -242,3 +245,36 @@ creds.txt
242
245
 
243
246
  # rsconstruct
244
247
  /.rsconstruct/
248
+
249
+ # generated website pieces (built into the Pages artifact by CI)
250
+ /docs/output/
251
+ /docs/index.html
252
+ # sphinx html output: the 14 py* repos render docs/ from sphinx/ and publish
253
+ # it as the Pages artifact, so none of it is committed. Listed path by path
254
+ # rather than as /docs/ because the rs* repos keep hand-written mdBook
255
+ # sources there, and several others keep authored html.
256
+ /docs/_modules/
257
+ /docs/_sources/
258
+ /docs/_static/
259
+ /docs/.buildinfo
260
+ /docs/objects.inv
261
+ /docs/searchindex.js
262
+ /docs/.nojekyll
263
+ # sphinx's top-level html. Not a blanket /docs/*.html: js-jschess and the
264
+ # site-personal-* repos keep hand-authored html under docs/. The fixed pages
265
+ # (genindex, modules, search) and the authored-rst pages some repos render
266
+ # (architecture, notes, ...) are listed by name; the one-page-per-module
267
+ # output is /docs/py*.html, since every package here is named py*.
268
+ /docs/architecture.html
269
+ /docs/cli-reference.html
270
+ /docs/development.html
271
+ /docs/genindex.html
272
+ /docs/modules.html
273
+ /docs/notes.html
274
+ /docs/overview.html
275
+ /docs/py*.html
276
+ /docs/quota-guide.html
277
+ /docs/search.html
278
+
279
+ # per-machine tool resolution cache (absolute paths, not portable)
280
+ /.tools.versions
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: pygitpub
3
- Version: 0.0.59
3
+ Version: 0.0.60
4
4
  Summary: Pygitpub will help you work with github
5
5
  Project-URL: Homepage, https://github.com/veltzer/pygitpub
6
6
  Project-URL: Bug Tracker, https://github.com/veltzer/pygitpub/issues
@@ -19,9 +19,10 @@ Classifier: Operating System :: OS Independent
19
19
  Classifier: Programming Language :: Python
20
20
  Classifier: Programming Language :: Python :: 3
21
21
  Classifier: Programming Language :: Python :: 3 :: Only
22
- Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.14
23
23
  Classifier: Topic :: Utilities
24
- Requires-Python: >=3.12
24
+ Requires-Python: >=3.14
25
+ Requires-Dist: lupa
25
26
  Requires-Dist: pyapikey
26
27
  Requires-Dist: pygithub
27
28
  Requires-Dist: pylogconf
@@ -29,6 +30,9 @@ Requires-Dist: pytconf
29
30
  Requires-Dist: pyyaml
30
31
  Description-Content-Type: text/markdown
31
32
 
33
+ <!-- This file is generated. Do not edit it by hand: your changes will be
34
+ lost on the next build. Edit the template it is rendered from, or the
35
+ values that template reads, and build again. -->
32
36
  # *pygitpub* project by Mark Veltzer
33
37
 
34
38
  description: Pygitpub will help you work with github
@@ -37,7 +41,7 @@ project website: https://veltzer.github.io/pygitpub
37
41
 
38
42
  author: Mark Veltzer
39
43
 
40
- version: 0.0.59
44
+ version: 0.0.60
41
45
 
42
46
  ![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)
43
47
 
@@ -66,7 +70,6 @@ version: 0.0.59
66
70
  ## contact me
67
71
 
68
72
  [mailto](mailto:mark.veltzer@gmail.com)
69
- ![gitter](https://img.shields.io/gitter/room/veltzer/mark.veltzer)
70
73
  ![discord](https://img.shields.io/discord/719336281624281119)
71
74
  ![discord](https://img.shields.io/discord/719336282194444302)
72
75
 
@@ -1,3 +1,6 @@
1
+ <!-- This file is generated. Do not edit it by hand: your changes will be
2
+ lost on the next build. Edit the template it is rendered from, or the
3
+ values that template reads, and build again. -->
1
4
  # *pygitpub* project by Mark Veltzer
2
5
 
3
6
  description: Pygitpub will help you work with github
@@ -6,7 +9,7 @@ project website: https://veltzer.github.io/pygitpub
6
9
 
7
10
  author: Mark Veltzer
8
11
 
9
- version: 0.0.59
12
+ version: 0.0.60
10
13
 
11
14
  ![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)
12
15
 
@@ -35,7 +38,6 @@ version: 0.0.59
35
38
  ## contact me
36
39
 
37
40
  [mailto](mailto:mark.veltzer@gmail.com)
38
- ![gitter](https://img.shields.io/gitter/room/veltzer/mark.veltzer)
39
41
  ![discord](https://img.shields.io/discord/719336281624281119)
40
42
  ![discord](https://img.shields.io/discord/719336282194444302)
41
43
 
@@ -4,8 +4,8 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "pygitpub"
7
- version = "0.0.59"
8
- requires-python = ">=3.12"
7
+ version = "0.0.60"
8
+ requires-python = ">=3.14"
9
9
  authors = [
10
10
  { name = "Mark Veltzer", email = "mark.veltzer@gmail.com" }
11
11
  ]
@@ -26,7 +26,7 @@ classifiers = [
26
26
  "Programming Language :: Python",
27
27
  "Programming Language :: Python :: 3",
28
28
  "Programming Language :: Python :: 3 :: Only",
29
- "Programming Language :: Python :: 3.12",
29
+ "Programming Language :: Python :: 3.14",
30
30
  "Topic :: Utilities",
31
31
  "License :: OSI Approved :: MIT License",
32
32
  ]
@@ -36,6 +36,16 @@ dependencies = [
36
36
  "PyGithub",
37
37
  "pyapikey",
38
38
  "pyyaml",
39
+ "lupa",
40
+ ]
41
+
42
+ [dependency-groups]
43
+ dev = [
44
+ "mypy",
45
+ "pylint",
46
+ "pytest",
47
+ "ruff",
48
+ "sphinx",
39
49
  ]
40
50
 
41
51
  [project.urls]
@@ -74,10 +84,23 @@ exclude = [
74
84
  ]
75
85
 
76
86
  [tool.mypy]
77
- python_version = "3.12"
87
+ python_version = "3.14"
78
88
  warn_return_any = true
79
89
  warn_unused_configs = true
90
+ mypy_path = "src:python:scripts"
91
+ explicit_package_bases = true
92
+ namespace_packages = true
80
93
 
94
+ # Third-party libraries without type stubs; `foo.*` also matches `foo` itself.
95
+ [[tool.mypy.overrides]]
96
+ module = [
97
+ "github.*",
98
+ "lupa.*",
99
+ "pyapikey.*",
100
+ "pylogconf.*",
101
+ "pytconf.*",
102
+ ]
103
+ ignore_missing_imports = true
81
104
  [tool.hatch.envs.default]
82
105
  installer = "uv"
83
106
 
@@ -16,12 +16,13 @@ from pytconf.registry import the_registry
16
16
 
17
17
  import pygitpub.static
18
18
  from pygitpub.configs import AFFILIATIONS, ConfigAlgo, ConfigGithub, ConfigOutput
19
- from pygitpub.utils.importlib import import_file
19
+ from pygitpub.utils.lua import config_path, load_lua_file
20
20
  from pygitpub.utils.misc import delete, get_all_git_repos
21
21
 
22
22
 
23
23
  def get_base_dir() -> str:
24
- return os.path.expanduser(ConfigAlgo.base_dir)
24
+ base_dir: str = ConfigAlgo.base_dir
25
+ return os.path.expanduser(base_dir)
25
26
 
26
27
 
27
28
  def get_repo_folder(repo) -> str:
@@ -84,25 +85,25 @@ def fix_metadata() -> None:
84
85
  continue
85
86
  os.chdir(folder)
86
87
  # print(f"doing [{folder}]...")
87
- file_path = "config/project.py"
88
+ file_path = config_path("project")
88
89
  if not os.path.isfile(file_path):
89
90
  os.chdir(orig_folder)
90
91
  continue
91
- mod = import_file(file_path)
92
- if not hasattr(mod, "description_short"):
92
+ project = load_lua_file(file_path)
93
+ if "DESCRIPTION_SHORT" not in project:
93
94
  os.chdir(orig_folder)
94
95
  continue
95
- description_short = mod.description_short
96
+ description_short = project["DESCRIPTION_SHORT"]
96
97
  if description_short != repo.description:
97
98
  print(f"in {folder}...")
98
99
  print(f"description_short is [{description_short}]")
99
100
  print(f"repo.description is [{repo.description}]")
100
101
  repo.edit(description=description_short)
101
- if not hasattr(mod, "keywords"):
102
+ if "KEYWORDS" not in project:
102
103
  print(f"{folder} no keywords")
103
104
  os.chdir(orig_folder)
104
105
  continue
105
- keywords = mod.keywords
106
+ keywords = project["KEYWORDS"]
106
107
  if set(keywords) != set(repo.get_topics()):
107
108
  print(f"in {folder}...")
108
109
  print(f"keywords is [{keywords}]")
@@ -1,5 +1,5 @@
1
1
  """ version which can be consumed from within the module """
2
- VERSION_STR = "0.0.59"
2
+ VERSION_STR = "0.0.60"
3
3
  DESCRIPTION = "Pygitpub will help you work with github"
4
4
  APP_NAME = "pygitpub"
5
5
  LOGGER_NAME = "pygitpub"
@@ -0,0 +1,68 @@
1
+ """
2
+ Load "config/*.lua" data files.
3
+
4
+ The config files used to be python modules loaded via importlib; they are now
5
+ lua data files (config/project.lua and friends). A file is run in a fresh lua
6
+ runtime and the globals it declares are returned as a plain dict.
7
+ """
8
+
9
+ import os.path
10
+ from typing import Any
11
+
12
+ # lupa exposes LuaRuntime through a module level __getattr__ that points at the
13
+ # bundled lua version (lupa.lua54, lupa.lua55, ...), so it cannot be imported
14
+ # by name. Going through the package attribute works for any bundled version.
15
+ import lupa
16
+
17
+ CONFIG_FOLDER = "config"
18
+
19
+
20
+ def lua_to_python(value: Any) -> Any:
21
+ """
22
+ Recursively convert a lua value into its python equivalent.
23
+
24
+ Lua has a single table type, so a table is a list if its keys are exactly
25
+ 1..n and a dict otherwise. An empty table becomes an empty list, which
26
+ matches how the config files use them.
27
+ """
28
+ if not hasattr(value, "values"):
29
+ return value
30
+ keys = list(value.keys())
31
+ if keys == list(range(1, len(keys) + 1)):
32
+ return [lua_to_python(x) for x in value.values()]
33
+ return {k: lua_to_python(value[k]) for k in keys}
34
+
35
+
36
+ def config_path(name: str) -> str:
37
+ """ return the path of a config file by its short name ("project") """
38
+ return os.path.join(CONFIG_FOLDER, f"{name}.lua")
39
+
40
+
41
+ def load_lua_file(path: str) -> dict[str, Any]:
42
+ """
43
+ Run a lua file and return the globals it declared as a dict.
44
+
45
+ Raises FileNotFoundError if the file does not exist.
46
+ """
47
+ if not os.path.isfile(path):
48
+ raise FileNotFoundError(path)
49
+ runtime = lupa.LuaRuntime()
50
+ with open(path, encoding="utf-8") as stream:
51
+ runtime.execute(stream.read())
52
+ globals_table = runtime.globals()
53
+ values = {}
54
+ for key in globals_table:
55
+ # skip the lua standard library, we only want what the file declared
56
+ if key in _LUA_BUILTINS:
57
+ continue
58
+ values[key] = lua_to_python(globals_table[key])
59
+ return values
60
+
61
+
62
+ _LUA_BUILTINS = frozenset({
63
+ "_G", "_VERSION", "assert", "collectgarbage", "coroutine", "debug", "dofile",
64
+ "error", "getmetatable", "io", "ipairs", "load", "loadfile", "math", "next",
65
+ "os", "package", "pairs", "pcall", "print", "python", "rawequal", "rawget",
66
+ "rawlen", "rawset", "require", "select", "setmetatable", "string", "table",
67
+ "tonumber", "tostring", "type", "utf8", "warn", "xpcall",
68
+ })
@@ -1,16 +0,0 @@
1
- """ importlib.py """
2
-
3
- import importlib.util
4
-
5
-
6
- def module_exists(module_name):
7
- """ return if a module exists or not """
8
- spec = importlib.util.find_spec(module_name)
9
- return spec is not None
10
-
11
-
12
- def import_file(file_path):
13
- spec = importlib.util.spec_from_file_location("foo", file_path)
14
- mod = importlib.util.module_from_spec(spec)
15
- spec.loader.exec_module(mod)
16
- return mod
File without changes