beyondbabel 0.3.0__tar.gz → 0.4.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.
- {beyondbabel-0.3.0 → beyondbabel-0.4.0}/PKG-INFO +37 -28
- {beyondbabel-0.3.0 → beyondbabel-0.4.0}/README.md +36 -27
- {beyondbabel-0.3.0 → beyondbabel-0.4.0}/bb.py +89 -20
- {beyondbabel-0.3.0 → beyondbabel-0.4.0}/beyondbabel.egg-info/PKG-INFO +37 -28
- {beyondbabel-0.3.0 → beyondbabel-0.4.0}/pyproject.toml +1 -1
- {beyondbabel-0.3.0 → beyondbabel-0.4.0}/beyondbabel.egg-info/SOURCES.txt +0 -0
- {beyondbabel-0.3.0 → beyondbabel-0.4.0}/beyondbabel.egg-info/dependency_links.txt +0 -0
- {beyondbabel-0.3.0 → beyondbabel-0.4.0}/beyondbabel.egg-info/entry_points.txt +0 -0
- {beyondbabel-0.3.0 → beyondbabel-0.4.0}/beyondbabel.egg-info/requires.txt +0 -0
- {beyondbabel-0.3.0 → beyondbabel-0.4.0}/beyondbabel.egg-info/top_level.txt +0 -0
- {beyondbabel-0.3.0 → beyondbabel-0.4.0}/setup.cfg +0 -0
- {beyondbabel-0.3.0 → beyondbabel-0.4.0}/tests/test_compile.py +0 -0
- {beyondbabel-0.3.0 → beyondbabel-0.4.0}/tests/test_edit_file.py +0 -0
- {beyondbabel-0.3.0 → beyondbabel-0.4.0}/tests/test_edit_new.py +0 -0
- {beyondbabel-0.3.0 → beyondbabel-0.4.0}/tests/test_edit_refactor.py +0 -0
- {beyondbabel-0.3.0 → beyondbabel-0.4.0}/tests/test_import_by_name.py +0 -0
- {beyondbabel-0.3.0 → beyondbabel-0.4.0}/tests/test_internals.py +0 -0
- {beyondbabel-0.3.0 → beyondbabel-0.4.0}/tests/test_lineage_v2.py +0 -0
- {beyondbabel-0.3.0 → beyondbabel-0.4.0}/tests/test_pool_refs.py +0 -0
- {beyondbabel-0.3.0 → beyondbabel-0.4.0}/tests/test_positional.py +0 -0
- {beyondbabel-0.3.0 → beyondbabel-0.4.0}/tests/test_refactor_stale.py +0 -0
- {beyondbabel-0.3.0 → beyondbabel-0.4.0}/tests/test_restore.py +0 -0
- {beyondbabel-0.3.0 → beyondbabel-0.4.0}/tests/test_scratchpad.py +0 -0
- {beyondbabel-0.3.0 → beyondbabel-0.4.0}/tests/test_storage.py +0 -0
- {beyondbabel-0.3.0 → beyondbabel-0.4.0}/tests/test_translate_file.py +0 -0
- {beyondbabel-0.3.0 → beyondbabel-0.4.0}/tests/test_translate_tree.py +0 -0
- {beyondbabel-0.3.0 → beyondbabel-0.4.0}/tests/test_undefined_names.py +0 -0
- {beyondbabel-0.3.0 → beyondbabel-0.4.0}/tests/test_update.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: beyondbabel
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: A function pool manager for Python that enables multilingual function sharing through AST normalization
|
|
5
5
|
Author: Amirouche Boubekki
|
|
6
6
|
License-Expression: MIT
|
|
@@ -28,50 +28,53 @@ Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
|
|
|
28
28
|
|
|
29
29
|

|
|
30
30
|
|
|
31
|
-
**
|
|
31
|
+
**Diversity as strength, made verifiable.**
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
Every programmer who thinks in Wolof, Tamil, Vietnamese, or Tamazight and codes in English pays a cognitive tax. Every variable named in a second language is a thought translated before it's expressed. This overhead is invisible to the people who don't pay it — and universal for everyone who does.
|
|
33
|
+
Write a function in your language; if someone else, human or machine, had the same thought, the hash will show it.
|
|
36
34
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
Content-addressing gives every function a unique fingerprint. Authorship is preserved. Lineage is traceable. Knowledge is shared without losing track of who made what.
|
|
35
|
+
> **Experimental**: This is research software under active development.
|
|
40
36
|
|
|
41
|
-
|
|
37
|
+
Convergence is detected, divergence is preserved. When two minds write the same logic, they get the same hash, and no shared language was needed to find each other. When they write different logic, they get different hashes, and both are kept. Nothing is flattened into a single English version.
|
|
42
38
|
|
|
43
39
|
```python
|
|
44
|
-
#
|
|
45
|
-
def
|
|
46
|
-
"""
|
|
47
|
-
|
|
48
|
-
return
|
|
40
|
+
# Français
|
|
41
|
+
def additionner(premier, second):
|
|
42
|
+
"""Additionner deux nombres."""
|
|
43
|
+
somme = premier + second
|
|
44
|
+
return somme
|
|
49
45
|
```
|
|
50
46
|
|
|
51
47
|
```python
|
|
52
|
-
#
|
|
53
|
-
def
|
|
54
|
-
"""
|
|
55
|
-
|
|
56
|
-
return
|
|
48
|
+
# العربية
|
|
49
|
+
def اجمع(الأول, الثاني):
|
|
50
|
+
"""اجمع عددين."""
|
|
51
|
+
الناتج = الأول + الثاني
|
|
52
|
+
return الناتج
|
|
57
53
|
```
|
|
58
54
|
|
|
59
55
|
```python
|
|
60
56
|
# Español
|
|
61
|
-
def
|
|
62
|
-
"""
|
|
63
|
-
|
|
64
|
-
return
|
|
57
|
+
def sumar(primero, segundo):
|
|
58
|
+
"""Sumar dos números."""
|
|
59
|
+
suma = primero + segundo
|
|
60
|
+
return suma
|
|
65
61
|
```
|
|
66
62
|
|
|
67
63
|
```bash
|
|
68
|
-
bb
|
|
69
|
-
bb add
|
|
70
|
-
bb add
|
|
71
|
-
bb add example_simple_spanish.py@spa # → 9f86d0... ← same hash again
|
|
64
|
+
bb add additionner.py@fra # → one hash
|
|
65
|
+
bb add اجمع.py@ara # → the same hash
|
|
66
|
+
bb add sumar.py@spa # → the same hash again
|
|
72
67
|
```
|
|
73
68
|
|
|
74
|
-
Three
|
|
69
|
+
Three people, or two people and a model prompted in Arabic. Nobody translated; each wrote an original. The names and the docstring stay in their own language, and the hash is computed from the logic alone.
|
|
70
|
+
|
|
71
|
+
## Why
|
|
72
|
+
|
|
73
|
+
Students learn to code in English while thinking in their own language, and every name they choose is a thought translated before it is written. Languages in Arabic script also tend to cost more tokens on LLMs for the same meaning, a quiet tax on the people who already pay one.
|
|
74
|
+
|
|
75
|
+
The machine side is the same question seen from outside. When several LLM agents work on one problem, someone has to know whether two of them really agree, or only sound alike. A shared hash is a cheap, honest answer for the case where the logic is identical, and an honest "no" when it is not.
|
|
76
|
+
|
|
77
|
+
The project is early. Exact matching is the foundation; near-matches are still a research question (see `LIMITS.md`).
|
|
75
78
|
|
|
76
79
|
## What it enables
|
|
77
80
|
|
|
@@ -108,6 +111,12 @@ uv tool install git+https://github.com/amirouche/bb.py.git
|
|
|
108
111
|
|
|
109
112
|
Requires Python 3.11+. No runtime dependencies.
|
|
110
113
|
|
|
114
|
+
## About
|
|
115
|
+
|
|
116
|
+
Nurturing a society that recognizes diversity as strength through verifiable knowledge sharing.
|
|
117
|
+
|
|
118
|
+
Content-addressing gives every function a fingerprint. Authorship is preserved. Lineage is traceable. Knowledge is shared without losing track of who made what.
|
|
119
|
+
|
|
111
120
|
## Vision
|
|
112
121
|
|
|
113
122
|
bb.py is a step toward Möbius — a content-addressed language where timestamps make lineage visible, and names are views into a multilingual registry. Who made what, who built on whom, who absorbed whose work without credit. The mirror doesn't prescribe norms or enforce justice. It refuses amnesia.
|
|
@@ -2,50 +2,53 @@
|
|
|
2
2
|
|
|
3
3
|

|
|
4
4
|
|
|
5
|
-
**
|
|
5
|
+
**Diversity as strength, made verifiable.**
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
Every programmer who thinks in Wolof, Tamil, Vietnamese, or Tamazight and codes in English pays a cognitive tax. Every variable named in a second language is a thought translated before it's expressed. This overhead is invisible to the people who don't pay it — and universal for everyone who does.
|
|
7
|
+
Write a function in your language; if someone else, human or machine, had the same thought, the hash will show it.
|
|
10
8
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
Content-addressing gives every function a unique fingerprint. Authorship is preserved. Lineage is traceable. Knowledge is shared without losing track of who made what.
|
|
9
|
+
> **Experimental**: This is research software under active development.
|
|
14
10
|
|
|
15
|
-
|
|
11
|
+
Convergence is detected, divergence is preserved. When two minds write the same logic, they get the same hash, and no shared language was needed to find each other. When they write different logic, they get different hashes, and both are kept. Nothing is flattened into a single English version.
|
|
16
12
|
|
|
17
13
|
```python
|
|
18
|
-
#
|
|
19
|
-
def
|
|
20
|
-
"""
|
|
21
|
-
|
|
22
|
-
return
|
|
14
|
+
# Français
|
|
15
|
+
def additionner(premier, second):
|
|
16
|
+
"""Additionner deux nombres."""
|
|
17
|
+
somme = premier + second
|
|
18
|
+
return somme
|
|
23
19
|
```
|
|
24
20
|
|
|
25
21
|
```python
|
|
26
|
-
#
|
|
27
|
-
def
|
|
28
|
-
"""
|
|
29
|
-
|
|
30
|
-
return
|
|
22
|
+
# العربية
|
|
23
|
+
def اجمع(الأول, الثاني):
|
|
24
|
+
"""اجمع عددين."""
|
|
25
|
+
الناتج = الأول + الثاني
|
|
26
|
+
return الناتج
|
|
31
27
|
```
|
|
32
28
|
|
|
33
29
|
```python
|
|
34
30
|
# Español
|
|
35
|
-
def
|
|
36
|
-
"""
|
|
37
|
-
|
|
38
|
-
return
|
|
31
|
+
def sumar(primero, segundo):
|
|
32
|
+
"""Sumar dos números."""
|
|
33
|
+
suma = primero + segundo
|
|
34
|
+
return suma
|
|
39
35
|
```
|
|
40
36
|
|
|
41
37
|
```bash
|
|
42
|
-
bb
|
|
43
|
-
bb add
|
|
44
|
-
bb add
|
|
45
|
-
bb add example_simple_spanish.py@spa # → 9f86d0... ← same hash again
|
|
38
|
+
bb add additionner.py@fra # → one hash
|
|
39
|
+
bb add اجمع.py@ara # → the same hash
|
|
40
|
+
bb add sumar.py@spa # → the same hash again
|
|
46
41
|
```
|
|
47
42
|
|
|
48
|
-
Three
|
|
43
|
+
Three people, or two people and a model prompted in Arabic. Nobody translated; each wrote an original. The names and the docstring stay in their own language, and the hash is computed from the logic alone.
|
|
44
|
+
|
|
45
|
+
## Why
|
|
46
|
+
|
|
47
|
+
Students learn to code in English while thinking in their own language, and every name they choose is a thought translated before it is written. Languages in Arabic script also tend to cost more tokens on LLMs for the same meaning, a quiet tax on the people who already pay one.
|
|
48
|
+
|
|
49
|
+
The machine side is the same question seen from outside. When several LLM agents work on one problem, someone has to know whether two of them really agree, or only sound alike. A shared hash is a cheap, honest answer for the case where the logic is identical, and an honest "no" when it is not.
|
|
50
|
+
|
|
51
|
+
The project is early. Exact matching is the foundation; near-matches are still a research question (see `LIMITS.md`).
|
|
49
52
|
|
|
50
53
|
## What it enables
|
|
51
54
|
|
|
@@ -82,6 +85,12 @@ uv tool install git+https://github.com/amirouche/bb.py.git
|
|
|
82
85
|
|
|
83
86
|
Requires Python 3.11+. No runtime dependencies.
|
|
84
87
|
|
|
88
|
+
## About
|
|
89
|
+
|
|
90
|
+
Nurturing a society that recognizes diversity as strength through verifiable knowledge sharing.
|
|
91
|
+
|
|
92
|
+
Content-addressing gives every function a fingerprint. Authorship is preserved. Lineage is traceable. Knowledge is shared without losing track of who made what.
|
|
93
|
+
|
|
85
94
|
## Vision
|
|
86
95
|
|
|
87
96
|
bb.py is a step toward Möbius — a content-addressed language where timestamps make lineage visible, and names are views into a multilingual registry. Who made what, who built on whom, who absorbed whose work without credit. The mirror doesn't prescribe norms or enforce justice. It refuses amnesia.
|
|
@@ -70,7 +70,10 @@ Writing functions for the pool:
|
|
|
70
70
|
`bb edit name@lang --refactor app@lang` saves the change and updates
|
|
71
71
|
everything between app and it, and lists what it rewrote (or run
|
|
72
72
|
`bb update app@lang` later: it brings app and everything it uses to
|
|
73
|
-
their current versions in one step, keeping pins).
|
|
73
|
+
their current versions in one step, keeping pins). An update is saved
|
|
74
|
+
only when the checks of what it rewrites pass, as in bb edit: one that
|
|
75
|
+
fails stays on its version, the rest is updated, the failure is printed
|
|
76
|
+
and the exit status is 1.
|
|
74
77
|
- Finding functions: `bb search` alone lists every current function;
|
|
75
78
|
`bb search WORDS` searches names, docs and code; `bb latest
|
|
76
79
|
name@lang --hash` prints only the current hash (for scripts); `bb log`
|
|
@@ -6319,14 +6322,16 @@ def code_load_refs(tree: ast.AST, cache: Dict[str, Callable]) -> types.SimpleNam
|
|
|
6319
6322
|
return types.SimpleNamespace(ref=loaded.__getitem__)
|
|
6320
6323
|
|
|
6321
6324
|
|
|
6322
|
-
def code_load_normalized(func_hash: str, cache: Dict[str, Callable] = None
|
|
6325
|
+
def code_load_normalized(func_hash: str, cache: Dict[str, Callable] = None,
|
|
6326
|
+
source: str = None, like: str = None) -> Callable:
|
|
6323
6327
|
"""
|
|
6324
6328
|
Load a pool function from its normalized code, exactly as hashed.
|
|
6325
6329
|
|
|
6326
6330
|
No language mapping is applied, so what runs is the code that was
|
|
6327
6331
|
hashed and reviewed, whatever names a mapping displays. Each function
|
|
6328
6332
|
runs in its own namespace, with its bb imports bound to their own
|
|
6329
|
-
loaded functions.
|
|
6333
|
+
loaded functions. With source (and like, the function it rewrites),
|
|
6334
|
+
code that is not in the pool yet is loaded under func_hash.
|
|
6330
6335
|
|
|
6331
6336
|
Raises:
|
|
6332
6337
|
ValueError: If the function or a dependency is missing or fails to load
|
|
@@ -6336,12 +6341,16 @@ def code_load_normalized(func_hash: str, cache: Dict[str, Callable] = None) -> C
|
|
|
6336
6341
|
if func_hash in cache:
|
|
6337
6342
|
return cache[func_hash]
|
|
6338
6343
|
|
|
6339
|
-
if
|
|
6340
|
-
|
|
6341
|
-
|
|
6342
|
-
|
|
6344
|
+
if source is None:
|
|
6345
|
+
if code_detect_schema(func_hash) is None:
|
|
6346
|
+
raise ValueError(f"Function not in the local pool: {func_hash}")
|
|
6347
|
+
data = object_load(func_hash)
|
|
6348
|
+
source, like = data['normalized_code'], func_hash
|
|
6349
|
+
else:
|
|
6350
|
+
data = object_load(like) # a version not saved yet, loaded like the one it rewrites
|
|
6351
|
+
tree = ast.parse(source)
|
|
6343
6352
|
if data.get('normalization', 1) < 2:
|
|
6344
|
-
code_restore_inner_imports(tree,
|
|
6353
|
+
code_restore_inner_imports(tree, like)
|
|
6345
6354
|
|
|
6346
6355
|
namespace: Dict[str, Any] = {'bb': code_load_refs(tree, cache)}
|
|
6347
6356
|
body = []
|
|
@@ -6389,14 +6398,25 @@ def check_run_reviewed(func_hash: str, reviewed: set) -> Tuple[Optional[List[Tup
|
|
|
6389
6398
|
if missing:
|
|
6390
6399
|
return None, missing
|
|
6391
6400
|
|
|
6401
|
+
return check_run_all(func_hash, object_load_checks(func_hash)), []
|
|
6402
|
+
|
|
6403
|
+
|
|
6404
|
+
def check_run_all(func_hash: str, checks: List[str], source: str = None,
|
|
6405
|
+
like: str = None) -> List[Tuple[str, str, str]]:
|
|
6406
|
+
"""
|
|
6407
|
+
Run checks against a function, already approved: results for check_report.
|
|
6408
|
+
|
|
6409
|
+
With source and like, the function is code not saved yet (see
|
|
6410
|
+
code_load_normalized). Callers make sure everything that runs was approved.
|
|
6411
|
+
"""
|
|
6392
6412
|
cache: Dict[str, Callable] = {}
|
|
6393
6413
|
try:
|
|
6394
|
-
implementation = code_load_normalized(func_hash, cache)
|
|
6414
|
+
implementation = code_load_normalized(func_hash, cache, source=source, like=like)
|
|
6395
6415
|
except ValueError as e:
|
|
6396
|
-
return [('ERROR', helper_function_label(func_hash), str(e))]
|
|
6416
|
+
return [('ERROR', helper_function_label(like or func_hash), str(e))]
|
|
6397
6417
|
|
|
6398
6418
|
results = []
|
|
6399
|
-
for check_hash in
|
|
6419
|
+
for check_hash in checks:
|
|
6400
6420
|
name = helper_function_label(check_hash)
|
|
6401
6421
|
try:
|
|
6402
6422
|
check = code_load_normalized(check_hash, cache)
|
|
@@ -6407,7 +6427,7 @@ def check_run_reviewed(func_hash: str, reviewed: set) -> Tuple[Optional[List[Tup
|
|
|
6407
6427
|
results.append((status, name, detail))
|
|
6408
6428
|
|
|
6409
6429
|
results.sort(key=lambda r: r[1])
|
|
6410
|
-
return results
|
|
6430
|
+
return results
|
|
6411
6431
|
|
|
6412
6432
|
|
|
6413
6433
|
def command_validate_checks(identifier: str = None, unreviewed: bool = False):
|
|
@@ -7229,7 +7249,7 @@ def command_scratchpad(identifiers: List[str], file: str, comment: str = None, t
|
|
|
7229
7249
|
finally:
|
|
7230
7250
|
shutil.rmtree(work, ignore_errors=True)
|
|
7231
7251
|
if refactor:
|
|
7232
|
-
command_update(refactor, comment)
|
|
7252
|
+
command_update(refactor, comment, unreviewed)
|
|
7233
7253
|
|
|
7234
7254
|
|
|
7235
7255
|
def refactor_save(old_hash: str, new_hash: str, new_code: str, checks: List[str], comment: str,
|
|
@@ -7269,7 +7289,29 @@ def code_hash_rewritten(new_code: str, checks: List[str]) -> str:
|
|
|
7269
7289
|
raise ValueError("no function in code")
|
|
7270
7290
|
|
|
7271
7291
|
|
|
7272
|
-
def
|
|
7292
|
+
def update_check_rewritten(base: str, new_hash: str, new_code: str, checks: List[str],
|
|
7293
|
+
unreviewed: bool = False) -> List[str]:
|
|
7294
|
+
"""
|
|
7295
|
+
Run the checks of a rewrite before it is saved; the failures, one line each.
|
|
7296
|
+
|
|
7297
|
+
Like bb edit, nothing runs that you have not approved: the rewrite
|
|
7298
|
+
imports pool functions and so do its checks. Those not approved are
|
|
7299
|
+
reported as failures (bb review them), unless unreviewed.
|
|
7300
|
+
"""
|
|
7301
|
+
needed = set()
|
|
7302
|
+
for dep in code_extract_dependencies(new_code):
|
|
7303
|
+
needed.update(code_resolve_dependencies(dep))
|
|
7304
|
+
for check_hash in checks:
|
|
7305
|
+
needed.update(code_resolve_dependencies(check_hash))
|
|
7306
|
+
missing = sorted(needed - review_approvals(list(needed)) - review_load_authored())
|
|
7307
|
+
if missing and not unreviewed:
|
|
7308
|
+
return ["not run, review first: " + ', '.join(f"bb review {h}" for h in missing)]
|
|
7309
|
+
results = check_run_all(new_hash, checks, source=new_code, like=base)
|
|
7310
|
+
return [f"{status} {name}: {detail}" if detail else f"{status} {name}"
|
|
7311
|
+
for status, name, detail in results if status != 'PASS']
|
|
7312
|
+
|
|
7313
|
+
|
|
7314
|
+
def command_update(identifier: str, comment: str = None, unreviewed: bool = False):
|
|
7273
7315
|
"""
|
|
7274
7316
|
Bring a function and everything it uses up to date, in one step.
|
|
7275
7317
|
|
|
@@ -7282,6 +7324,12 @@ def command_update(identifier: str, comment: str = None):
|
|
|
7282
7324
|
(written as bb.ref) are kept. A fork (several current versions) is
|
|
7283
7325
|
left as it is, with a warning. One comment goes on every new version.
|
|
7284
7326
|
|
|
7327
|
+
Like bb edit, a rewrite is saved only when the checks of the function
|
|
7328
|
+
pass with the new versions it uses. One that fails is not saved: it
|
|
7329
|
+
stays on the version it has, its callers stay as they were, and the
|
|
7330
|
+
rest is updated anyway. What failed is printed, and bb update exits
|
|
7331
|
+
with status 1; bb edit the function to adapt it, then update again.
|
|
7332
|
+
|
|
7285
7333
|
```
|
|
7286
7334
|
bb update app@eng -m "use the new layout everywhere"
|
|
7287
7335
|
```
|
|
@@ -7295,6 +7343,7 @@ def command_update(identifier: str, comment: str = None):
|
|
|
7295
7343
|
comment = ""
|
|
7296
7344
|
done: Dict[Tuple[str, Optional[str]], str] = {}
|
|
7297
7345
|
rewritten: List[Tuple[str, str]] = []
|
|
7346
|
+
failed: List[Tuple[str, str, List[str]]] = []
|
|
7298
7347
|
|
|
7299
7348
|
def update(func_hash: str, name: Optional[str], stack: Tuple[str, ...] = ()) -> str:
|
|
7300
7349
|
"""The up-to-date hash for func_hash, used by name (itself when nothing changes)."""
|
|
@@ -7323,6 +7372,11 @@ def command_update(identifier: str, comment: str = None):
|
|
|
7323
7372
|
checks = object_load_checks(base)
|
|
7324
7373
|
result = code_hash_rewritten(new_code, checks)
|
|
7325
7374
|
followed = {dep: lineage_name_for(dep, lang, aliases.get(dep)) for dep in swaps}
|
|
7375
|
+
problems = update_check_rewritten(base, result, new_code, checks, unreviewed) if checks else []
|
|
7376
|
+
if problems and result != base:
|
|
7377
|
+
failed.append((base, result, problems))
|
|
7378
|
+
done[(func_hash, name)] = done[(base, name)] = base
|
|
7379
|
+
return base
|
|
7326
7380
|
|
|
7327
7381
|
def keep(record):
|
|
7328
7382
|
"""Names of base that use the swapped functions by other names stay (two names, one code)."""
|
|
@@ -7339,14 +7393,27 @@ def command_update(identifier: str, comment: str = None):
|
|
|
7339
7393
|
return result
|
|
7340
7394
|
|
|
7341
7395
|
new_root = update(root, helper_identifier_name(identifier) or lineage_name_for(root, lang))
|
|
7342
|
-
if not rewritten:
|
|
7396
|
+
if not rewritten and not failed:
|
|
7343
7397
|
print(f"{helper_function_label(root)} is up to date: nothing to save")
|
|
7344
7398
|
return
|
|
7345
|
-
|
|
7346
|
-
|
|
7347
|
-
|
|
7348
|
-
|
|
7399
|
+
if rewritten:
|
|
7400
|
+
print(f"Updated {len(rewritten)} function(s), deepest first:")
|
|
7401
|
+
for old, new in rewritten:
|
|
7402
|
+
print(f" {helper_function_label(new)}: {old[:12]}... -> {new[:12]}...")
|
|
7403
|
+
print("Drafts open on these functions are now stale: write them again.")
|
|
7404
|
+
else:
|
|
7405
|
+
print("Nothing updated.")
|
|
7349
7406
|
print(f"Hash: {new_root}")
|
|
7407
|
+
if failed:
|
|
7408
|
+
sys.stdout.flush() # what was updated comes before what was not
|
|
7409
|
+
print(f"Not updated, a check failed ({len(failed)}):", file=sys.stderr)
|
|
7410
|
+
for old, new, problems in failed:
|
|
7411
|
+
print(f" {helper_function_label(old)}: {old[:12]}... stays; its update would be {new[:12]}...",
|
|
7412
|
+
file=sys.stderr)
|
|
7413
|
+
for problem in problems:
|
|
7414
|
+
print(f" {problem}", file=sys.stderr)
|
|
7415
|
+
print("Edit them to adapt (bb edit NAME@lang), then update again.", file=sys.stderr)
|
|
7416
|
+
sys.exit(1)
|
|
7350
7417
|
|
|
7351
7418
|
|
|
7352
7419
|
def command_refactor(what_hash: str, from_hash: str, to_hash: str, at_hash: str = None, comment: str = None):
|
|
@@ -8439,6 +8506,8 @@ def _build_parser():
|
|
|
8439
8506
|
update_parser = subparsers.add_parser('update', help='Bring a function and everything it uses up to date')
|
|
8440
8507
|
update_parser.add_argument('identifier', help='Function to update (name@lang or hash)')
|
|
8441
8508
|
update_parser.add_argument('--comment', '-m', default=None, help='Comment for the new versions (asked when omitted)')
|
|
8509
|
+
update_parser.add_argument('--dangerously-unreviewed', action='store_true',
|
|
8510
|
+
help='Run checks even on unreviewed functions they import')
|
|
8442
8511
|
|
|
8443
8512
|
refactor_parser = subparsers.add_parser('refactor', help='Replace a dependency in a function')
|
|
8444
8513
|
refactor_parser.add_argument('what', help='Function hash to modify')
|
|
@@ -8583,7 +8652,7 @@ def main():
|
|
|
8583
8652
|
elif args.command == 'tree':
|
|
8584
8653
|
command_tree(args.identifier, as_json=args.as_json)
|
|
8585
8654
|
elif args.command == 'update':
|
|
8586
|
-
command_update(args.identifier, comment=args.comment)
|
|
8655
|
+
command_update(args.identifier, comment=args.comment, unreviewed=args.dangerously_unreviewed)
|
|
8587
8656
|
elif args.command == 'refactor':
|
|
8588
8657
|
command_refactor(args.what, args.from_hash, args.to_hash, args.at_hash if hasattr(args, 'at_hash') else None,
|
|
8589
8658
|
comment=args.comment)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: beyondbabel
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: A function pool manager for Python that enables multilingual function sharing through AST normalization
|
|
5
5
|
Author: Amirouche Boubekki
|
|
6
6
|
License-Expression: MIT
|
|
@@ -28,50 +28,53 @@ Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
|
|
|
28
28
|
|
|
29
29
|

|
|
30
30
|
|
|
31
|
-
**
|
|
31
|
+
**Diversity as strength, made verifiable.**
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
Every programmer who thinks in Wolof, Tamil, Vietnamese, or Tamazight and codes in English pays a cognitive tax. Every variable named in a second language is a thought translated before it's expressed. This overhead is invisible to the people who don't pay it — and universal for everyone who does.
|
|
33
|
+
Write a function in your language; if someone else, human or machine, had the same thought, the hash will show it.
|
|
36
34
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
Content-addressing gives every function a unique fingerprint. Authorship is preserved. Lineage is traceable. Knowledge is shared without losing track of who made what.
|
|
35
|
+
> **Experimental**: This is research software under active development.
|
|
40
36
|
|
|
41
|
-
|
|
37
|
+
Convergence is detected, divergence is preserved. When two minds write the same logic, they get the same hash, and no shared language was needed to find each other. When they write different logic, they get different hashes, and both are kept. Nothing is flattened into a single English version.
|
|
42
38
|
|
|
43
39
|
```python
|
|
44
|
-
#
|
|
45
|
-
def
|
|
46
|
-
"""
|
|
47
|
-
|
|
48
|
-
return
|
|
40
|
+
# Français
|
|
41
|
+
def additionner(premier, second):
|
|
42
|
+
"""Additionner deux nombres."""
|
|
43
|
+
somme = premier + second
|
|
44
|
+
return somme
|
|
49
45
|
```
|
|
50
46
|
|
|
51
47
|
```python
|
|
52
|
-
#
|
|
53
|
-
def
|
|
54
|
-
"""
|
|
55
|
-
|
|
56
|
-
return
|
|
48
|
+
# العربية
|
|
49
|
+
def اجمع(الأول, الثاني):
|
|
50
|
+
"""اجمع عددين."""
|
|
51
|
+
الناتج = الأول + الثاني
|
|
52
|
+
return الناتج
|
|
57
53
|
```
|
|
58
54
|
|
|
59
55
|
```python
|
|
60
56
|
# Español
|
|
61
|
-
def
|
|
62
|
-
"""
|
|
63
|
-
|
|
64
|
-
return
|
|
57
|
+
def sumar(primero, segundo):
|
|
58
|
+
"""Sumar dos números."""
|
|
59
|
+
suma = primero + segundo
|
|
60
|
+
return suma
|
|
65
61
|
```
|
|
66
62
|
|
|
67
63
|
```bash
|
|
68
|
-
bb
|
|
69
|
-
bb add
|
|
70
|
-
bb add
|
|
71
|
-
bb add example_simple_spanish.py@spa # → 9f86d0... ← same hash again
|
|
64
|
+
bb add additionner.py@fra # → one hash
|
|
65
|
+
bb add اجمع.py@ara # → the same hash
|
|
66
|
+
bb add sumar.py@spa # → the same hash again
|
|
72
67
|
```
|
|
73
68
|
|
|
74
|
-
Three
|
|
69
|
+
Three people, or two people and a model prompted in Arabic. Nobody translated; each wrote an original. The names and the docstring stay in their own language, and the hash is computed from the logic alone.
|
|
70
|
+
|
|
71
|
+
## Why
|
|
72
|
+
|
|
73
|
+
Students learn to code in English while thinking in their own language, and every name they choose is a thought translated before it is written. Languages in Arabic script also tend to cost more tokens on LLMs for the same meaning, a quiet tax on the people who already pay one.
|
|
74
|
+
|
|
75
|
+
The machine side is the same question seen from outside. When several LLM agents work on one problem, someone has to know whether two of them really agree, or only sound alike. A shared hash is a cheap, honest answer for the case where the logic is identical, and an honest "no" when it is not.
|
|
76
|
+
|
|
77
|
+
The project is early. Exact matching is the foundation; near-matches are still a research question (see `LIMITS.md`).
|
|
75
78
|
|
|
76
79
|
## What it enables
|
|
77
80
|
|
|
@@ -108,6 +111,12 @@ uv tool install git+https://github.com/amirouche/bb.py.git
|
|
|
108
111
|
|
|
109
112
|
Requires Python 3.11+. No runtime dependencies.
|
|
110
113
|
|
|
114
|
+
## About
|
|
115
|
+
|
|
116
|
+
Nurturing a society that recognizes diversity as strength through verifiable knowledge sharing.
|
|
117
|
+
|
|
118
|
+
Content-addressing gives every function a fingerprint. Authorship is preserved. Lineage is traceable. Knowledge is shared without losing track of who made what.
|
|
119
|
+
|
|
111
120
|
## Vision
|
|
112
121
|
|
|
113
122
|
bb.py is a step toward Möbius — a content-addressed language where timestamps make lineage visible, and names are views into a multilingual registry. Who made what, who built on whom, who absorbed whose work without credit. The mirror doesn't prescribe norms or enforce justice. It refuses amnesia.
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "beyondbabel"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.4.0"
|
|
8
8
|
description = "A function pool manager for Python that enables multilingual function sharing through AST normalization"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|