funkshway 2026.5.2__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.
funkshway/__init__.py ADDED
@@ -0,0 +1,2 @@
1
+ def hello() -> str:
2
+ return "Hello from funkshway!"
funkshway/core.py ADDED
@@ -0,0 +1,73 @@
1
+ import libcst as cst
2
+ import libcst.matchers as m
3
+
4
+ class UnrecognizedBlockError(Exception):
5
+ pass
6
+
7
+ class FunkshwayTransformer(cst.CSTTransformer):
8
+ """
9
+ Initial transformer for funkshway.
10
+ Currently just performs an idempotent round-trip.
11
+ """
12
+ pass
13
+
14
+ def is_constant_assignment(node: cst.CSTNode) -> bool:
15
+ if m.matches(node, m.SimpleStatementLine(body=[m.Assign(targets=[m.AssignTarget(target=m.Name(value=m.MatchRegex(r"^[A-Z_][A-Z0-9_]*$")))])])):
16
+ return True
17
+ return False
18
+
19
+ def is_main_block(node: cst.CSTNode) -> bool:
20
+ if m.matches(node, m.If(test=m.Comparison(left=m.Name(value="__name__"), comparisons=[m.ComparisonTarget(operator=m.Equal(), comparator=m.SimpleString(value='"__main__"'))]))):
21
+ return True
22
+ if m.matches(node, m.If(test=m.Comparison(left=m.Name(value="__name__"), comparisons=[m.ComparisonTarget(operator=m.Equal(), comparator=m.SimpleString(value="'__main__'"))]))):
23
+ return True
24
+ return False
25
+
26
+ def check_for_unrecognized_blocks(module: cst.Module):
27
+ """
28
+ Checks if there are any blocks at the top level that are not supported.
29
+ """
30
+ for statement in module.body:
31
+ # Ignore empty lines and comments at top level if they are just standalone?
32
+ # Actually, comments should be associated with blocks.
33
+
34
+ # Supported:
35
+ # 1. Imports
36
+ if m.matches(statement, m.SimpleStatementLine(body=[m.Import() | m.ImportFrom()])):
37
+ continue
38
+
39
+ # 2. Constants
40
+ if is_constant_assignment(statement):
41
+ continue
42
+
43
+ # 3. Classes
44
+ if m.matches(statement, m.ClassDef()):
45
+ continue
46
+
47
+ # 4. Functions
48
+ if m.matches(statement, m.FunctionDef()):
49
+ continue
50
+
51
+ # 5. Main block
52
+ if is_main_block(statement):
53
+ continue
54
+
55
+ # 6. Standalone comments/docstrings might be tricky.
56
+ # For Phase 1, let's be strict.
57
+ if m.matches(statement, m.SimpleStatementLine(body=[m.Expr(value=m.SimpleString())])):
58
+ # Docstring
59
+ continue
60
+
61
+ raise UnrecognizedBlockError(f"Unrecognized block at top level: {statement}")
62
+
63
+ def format_code(source_code: str) -> str:
64
+ """
65
+ Parses source code, applies transformations, and returns formatted code.
66
+ """
67
+ module = cst.parse_module(source_code)
68
+
69
+ check_for_unrecognized_blocks(module)
70
+
71
+ # Phase 1: Just idempotent round-trip
72
+ transformed_module = module.visit(FunkshwayTransformer())
73
+ return transformed_module.code
funkshway/main.py ADDED
@@ -0,0 +1,25 @@
1
+ import argparse
2
+ import sys
3
+ from funkshway.core import format_code, UnrecognizedBlockError
4
+
5
+ def main():
6
+ parser = argparse.ArgumentParser(description="funkshway: Opinionated Python code reordering")
7
+ parser.add_argument("file", help="Python file to format")
8
+ args = parser.parse_args()
9
+
10
+ try:
11
+ with open(args.file, "r") as f:
12
+ source_code = f.read()
13
+
14
+ formatted_code = format_code(source_code)
15
+ print(formatted_code, end="")
16
+
17
+ except UnrecognizedBlockError as e:
18
+ print(f"Refusal: {e}", file=sys.stderr)
19
+ sys.exit(1)
20
+ except Exception as e:
21
+ print(f"Error: {e}", file=sys.stderr)
22
+ sys.exit(1)
23
+
24
+ if __name__ == "__main__":
25
+ main()
funkshway/py.typed ADDED
File without changes
@@ -0,0 +1,39 @@
1
+ Metadata-Version: 2.4
2
+ Name: funkshway
3
+ Version: 2026.5.2
4
+ Summary: CLI to move code blocks in a Python file into an opinionated, idempotent order
5
+ Author-email: David Seaward <72779-lofidevops@users.noreply.gitlab.com>
6
+ Requires-Python: >=3.12
7
+ Requires-Dist: libcst>=1.3.1
8
+ Description-Content-Type: text/markdown
9
+
10
+ # funkshway 🕺
11
+
12
+ CLI to move code blocks in a Python file into an opinionated, idempotent order.
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ uv tool install funkshway
18
+ ```
19
+
20
+ ## Usage
21
+
22
+ ```bash
23
+ funkshway path/to/file.py
24
+ ```
25
+
26
+ Idempotent round-trip guaranteed for supported blocks.
27
+ Unrecognized code at top-level will cause the tool to refuse formatting.
28
+
29
+ ## Release
30
+
31
+ ```shell
32
+ git tag -a 2.0.0 -m "Version 2.0.0"
33
+ uv build
34
+ uv publish # uses tag for version number
35
+ ```
36
+
37
+ ## Colophon
38
+
39
+ Building almost exclusively with Junie using AGENTS.md, specification.toml and PLAN.md
@@ -0,0 +1,8 @@
1
+ funkshway/__init__.py,sha256=imkavrY7QF6kURhae7tbS664tPadwehGUmmpEuXtt6U,55
2
+ funkshway/core.py,sha256=utT4ngCAbNtOW0Ct_VCIlf1p-XAuO_if6l6cG4NlW2w,2593
3
+ funkshway/main.py,sha256=mLYcgs1FL2Q1ajPdOz7DQwo4O8rqaIHvQjSAgmv8mAE,725
4
+ funkshway/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ funkshway-2026.5.2.dist-info/METADATA,sha256=T2KR6xQxoahK31L3zHYEplIQg2zEqLR15bvgUnlpYzY,856
6
+ funkshway-2026.5.2.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
7
+ funkshway-2026.5.2.dist-info/entry_points.txt,sha256=o2qWzHStUsUChbkvDH_tKvTmVsdTIGZoM1LdqaIn00Q,50
8
+ funkshway-2026.5.2.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.29.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ funkshway = funkshway.main:main