supernova-photon 0.1.1__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.
@@ -0,0 +1,5 @@
1
+ from . import v5
2
+
3
+ __version__ = "0.1.0"
4
+
5
+ __all__ = ["v5"]
@@ -0,0 +1,95 @@
1
+ import sys
2
+ from .v5 import photon
3
+
4
+
5
+ def main():
6
+
7
+ print("=" * 60)
8
+ print("SUPERNOVA PHOTON-1 V5 — TERMINAL")
9
+ print("=" * 60)
10
+
11
+ try:
12
+ engine = photon()
13
+ except Exception as exc:
14
+ print("Initialization failed:", exc)
15
+ return
16
+
17
+ print("\nEnter 'exit' to quit.")
18
+ print("Example target: speed")
19
+ print("Example input: distance=100 m")
20
+ print("Example input: time=10 s")
21
+
22
+ while True:
23
+
24
+ try:
25
+ target = input("\nTarget variable: ").strip()
26
+
27
+ if target.lower() in ("exit", "quit"):
28
+ break
29
+
30
+ known = {}
31
+
32
+ print("Enter known values.")
33
+ print("Leave variable name empty when finished.")
34
+
35
+ while True:
36
+
37
+ name = input("Variable: ").strip()
38
+
39
+ if not name:
40
+ break
41
+
42
+ raw = input("Value and unit (e.g. 100 m): ").strip()
43
+
44
+ parts = raw.split()
45
+
46
+ if len(parts) != 2:
47
+ print("Use format: value unit")
48
+ continue
49
+
50
+ known[name] = (
51
+ float(parts[0]),
52
+ parts[1]
53
+ )
54
+
55
+ output_unit = input(
56
+ "Output unit (Enter for SI): "
57
+ ).strip() or None
58
+
59
+ equation = input(
60
+ "Equation name (Enter for automatic): "
61
+ ).strip() or None
62
+
63
+ result = engine.solve(
64
+ target,
65
+ known,
66
+ equation_name=equation,
67
+ target_unit=output_unit
68
+ )
69
+
70
+ print("\nRESULT")
71
+ print("-" * 40)
72
+ print("Equation:", result["equation"])
73
+ print("Formula:", result["formula"])
74
+ print(
75
+ "Answer:",
76
+ result["result"],
77
+ result["unit"]
78
+ )
79
+ print(
80
+ "Validation probability:",
81
+ result["validation_probability"]
82
+ )
83
+ print("-" * 40)
84
+
85
+ except KeyboardInterrupt:
86
+ break
87
+
88
+ except Exception as exc:
89
+ print("Error:", exc)
90
+
91
+ print("Photon-1 V5 terminated.")
92
+
93
+
94
+ if __name__ == "__main__":
95
+ main()
@@ -0,0 +1,606 @@
1
+ import math
2
+ import os
3
+ import numpy as np
4
+
5
+
6
+ HF_REPO_ID = "Supernova11c/Supernova-Photon-1-V5"
7
+ HF_FILENAME = "photon1_v5.pt"
8
+
9
+
10
+ ALIASES = {
11
+ "e": "energy",
12
+ "energy": "energy",
13
+ "m": "mass",
14
+ "mass": "mass",
15
+ "c": "speed",
16
+ "v": "speed",
17
+ "speed": "speed",
18
+ "d": "distance",
19
+ "distance": "distance",
20
+ "t": "time",
21
+ "time": "time",
22
+ "rho": "density",
23
+ "ρ": "density",
24
+ "density": "density",
25
+ "volume": "volume",
26
+ "f": "force",
27
+ "force": "force",
28
+ "a": "acceleration",
29
+ "acceleration": "acceleration",
30
+ "w": "work",
31
+ "work": "work",
32
+ "p": "power",
33
+ "power": "power",
34
+ }
35
+
36
+
37
+ UNIT_TABLE = {
38
+ "energy": {"J": 1.0, "kJ": 1000.0},
39
+ "mass": {"kg": 1.0, "g": 0.001},
40
+ "speed": {
41
+ "m/s": 1.0,
42
+ "km/s": 1000.0,
43
+ "km/h": 1 / 3.6
44
+ },
45
+ "distance": {
46
+ "m": 1.0,
47
+ "cm": 0.01,
48
+ "km": 1000.0
49
+ },
50
+ "time": {
51
+ "s": 1.0,
52
+ "min": 60.0,
53
+ "h": 3600.0
54
+ },
55
+ "density": {
56
+ "kg/m3": 1.0,
57
+ "g/cm3": 1000.0
58
+ },
59
+ "volume": {
60
+ "m3": 1.0,
61
+ "L": 0.001,
62
+ "cm3": 1e-6
63
+ },
64
+ "force": {"N": 1.0, "kN": 1000.0},
65
+ "acceleration": {
66
+ "m/s2": 1.0,
67
+ "cm/s2": 0.01
68
+ },
69
+ "work": {"J": 1.0, "kJ": 1000.0},
70
+ "power": {"W": 1.0, "kW": 1000.0}
71
+ }
72
+
73
+
74
+ DEFAULT_UNITS = {
75
+ "energy": "J",
76
+ "mass": "kg",
77
+ "speed": "m/s",
78
+ "distance": "m",
79
+ "time": "s",
80
+ "density": "kg/m3",
81
+ "volume": "m3",
82
+ "force": "N",
83
+ "acceleration": "m/s2",
84
+ "work": "J",
85
+ "power": "W"
86
+ }
87
+
88
+
89
+ FORMULAS = {
90
+ "einstein": "E = mc²",
91
+ "speed": "v = d/t",
92
+ "density": "ρ = m/V",
93
+ "newton": "F = ma",
94
+ "work": "W = Fd",
95
+ "power": "P = W/t"
96
+ }
97
+
98
+
99
+ def normalize_variable(name):
100
+ key = str(name).strip().lower()
101
+
102
+ if key not in ALIASES:
103
+ raise ValueError(f"Unknown variable: {name}")
104
+
105
+ return ALIASES[key]
106
+
107
+
108
+ def to_si(variable, value, unit):
109
+ variable = normalize_variable(variable)
110
+
111
+ if unit not in UNIT_TABLE[variable]:
112
+ raise ValueError(
113
+ f"Invalid unit {unit!r} for {variable}"
114
+ )
115
+
116
+ value = float(value)
117
+
118
+ if not math.isfinite(value):
119
+ raise ValueError("Input must be finite")
120
+
121
+ return value * UNIT_TABLE[variable][unit]
122
+
123
+
124
+ def from_si(variable, value, unit):
125
+ variable = normalize_variable(variable)
126
+
127
+ if unit not in UNIT_TABLE[variable]:
128
+ raise ValueError(
129
+ f"Invalid output unit {unit!r} for {variable}"
130
+ )
131
+
132
+ return value / UNIT_TABLE[variable][unit]
133
+
134
+
135
+ def safe_divide(a, b):
136
+ if b == 0:
137
+ raise ValueError("Division by zero")
138
+
139
+ return a / b
140
+
141
+
142
+ # ============================================================
143
+ # EQUATION REGISTRY
144
+ # ============================================================
145
+
146
+ EQUATIONS = {
147
+
148
+ "einstein": {
149
+ "variables": {"energy", "mass", "speed"},
150
+ "solvers": {
151
+ "energy": lambda x: x["mass"] * x["speed"]**2,
152
+ "mass": lambda x: safe_divide(
153
+ x["energy"], x["speed"]**2
154
+ ),
155
+ "speed": lambda x: math.sqrt(
156
+ safe_divide(x["energy"], x["mass"])
157
+ )
158
+ }
159
+ },
160
+
161
+ "speed": {
162
+ "variables": {"speed", "distance", "time"},
163
+ "solvers": {
164
+ "speed": lambda x: safe_divide(
165
+ x["distance"], x["time"]
166
+ ),
167
+ "distance": lambda x: x["speed"] * x["time"],
168
+ "time": lambda x: safe_divide(
169
+ x["distance"], x["speed"]
170
+ )
171
+ }
172
+ },
173
+
174
+ "density": {
175
+ "variables": {"density", "mass", "volume"},
176
+ "solvers": {
177
+ "density": lambda x: safe_divide(
178
+ x["mass"], x["volume"]
179
+ ),
180
+ "mass": lambda x: x["density"] * x["volume"],
181
+ "volume": lambda x: safe_divide(
182
+ x["mass"], x["density"]
183
+ )
184
+ }
185
+ },
186
+
187
+ "newton": {
188
+ "variables": {"force", "mass", "acceleration"},
189
+ "solvers": {
190
+ "force": lambda x: x["mass"] * x["acceleration"],
191
+ "mass": lambda x: safe_divide(
192
+ x["force"], x["acceleration"]
193
+ ),
194
+ "acceleration": lambda x: safe_divide(
195
+ x["force"], x["mass"]
196
+ )
197
+ }
198
+ },
199
+
200
+ "work": {
201
+ "variables": {"work", "force", "distance"},
202
+ "solvers": {
203
+ "work": lambda x: x["force"] * x["distance"],
204
+ "force": lambda x: safe_divide(
205
+ x["work"], x["distance"]
206
+ ),
207
+ "distance": lambda x: safe_divide(
208
+ x["work"], x["force"]
209
+ )
210
+ }
211
+ },
212
+
213
+ "power": {
214
+ "variables": {"power", "work", "time"},
215
+ "solvers": {
216
+ "power": lambda x: safe_divide(
217
+ x["work"], x["time"]
218
+ ),
219
+ "work": lambda x: x["power"] * x["time"],
220
+ "time": lambda x: safe_divide(
221
+ x["work"], x["power"]
222
+ )
223
+ }
224
+ }
225
+ }
226
+
227
+
228
+ # ============================================================
229
+ # ADAPTIVE TOLERANCE
230
+ # ============================================================
231
+
232
+ class AdaptiveTolerance:
233
+
234
+ def __init__(self, tolerance=1e-6):
235
+ tolerance = float(tolerance)
236
+
237
+ if not math.isfinite(tolerance) or tolerance <= 0:
238
+ raise ValueError("Invalid adaptive tolerance")
239
+
240
+ self.log_tolerance = math.log(tolerance)
241
+ self.temperature = 0.5
242
+
243
+ @property
244
+ def tolerance(self):
245
+ return math.exp(self.log_tolerance)
246
+
247
+ def probability_valid(self, residual):
248
+
249
+ residual = float(residual)
250
+
251
+ if not math.isfinite(residual) or residual < 0:
252
+ return 0.0
253
+
254
+ residual = max(residual, 1e-16)
255
+
256
+ z = (
257
+ self.log_tolerance - math.log(residual)
258
+ ) / self.temperature
259
+
260
+ z = max(-60, min(60, z))
261
+
262
+ return 1.0 / (1.0 + math.exp(-z))
263
+
264
+
265
+ # ============================================================
266
+ # EQUATION SELECTION
267
+ # ============================================================
268
+
269
+ def select_equation(target, known_variables, equation_name=None):
270
+
271
+ target = normalize_variable(target)
272
+
273
+ known_variables = {
274
+ normalize_variable(x)
275
+ for x in known_variables
276
+ }
277
+
278
+ if equation_name is not None:
279
+
280
+ if equation_name not in EQUATIONS:
281
+ raise ValueError("Unknown equation")
282
+
283
+ equation = EQUATIONS[equation_name]
284
+
285
+ if target not in equation["solvers"]:
286
+ raise ValueError("Unsupported target")
287
+
288
+ expected = equation["variables"] - {target}
289
+
290
+ if known_variables != expected:
291
+ raise ValueError("Incompatible equation inputs")
292
+
293
+ return equation_name
294
+
295
+ matches = []
296
+
297
+ for name, equation in EQUATIONS.items():
298
+
299
+ expected = equation["variables"] - {target}
300
+
301
+ if (
302
+ target in equation["solvers"]
303
+ and known_variables == expected
304
+ ):
305
+ matches.append(name)
306
+
307
+ if len(matches) != 1:
308
+ raise ValueError(
309
+ "No unique compatible equation found"
310
+ )
311
+
312
+ return matches[0]
313
+
314
+
315
+ # ============================================================
316
+ # NUMERICAL RESIDUAL
317
+ # ============================================================
318
+
319
+ def equation_residual(name, values):
320
+
321
+ if name == "einstein":
322
+ lhs = values["energy"]
323
+ rhs = values["mass"] * values["speed"]**2
324
+
325
+ elif name == "speed":
326
+ lhs = values["speed"]
327
+ rhs = safe_divide(
328
+ values["distance"], values["time"]
329
+ )
330
+
331
+ elif name == "density":
332
+ lhs = values["density"]
333
+ rhs = safe_divide(
334
+ values["mass"], values["volume"]
335
+ )
336
+
337
+ elif name == "newton":
338
+ lhs = values["force"]
339
+ rhs = values["mass"] * values["acceleration"]
340
+
341
+ elif name == "work":
342
+ lhs = values["work"]
343
+ rhs = values["force"] * values["distance"]
344
+
345
+ elif name == "power":
346
+ lhs = values["power"]
347
+ rhs = safe_divide(
348
+ values["work"], values["time"]
349
+ )
350
+
351
+ else:
352
+ raise ValueError("Unknown equation")
353
+
354
+ scale = max(abs(lhs), abs(rhs), 1e-300)
355
+
356
+ return abs(lhs - rhs) / scale
357
+
358
+
359
+ # ============================================================
360
+ # MAIN PHOTON ENGINE
361
+ # ============================================================
362
+
363
+ class PhotonCoreV5:
364
+
365
+ def __init__(
366
+ self,
367
+ adaptive_model,
368
+ checkpoint=None
369
+ ):
370
+ self.adaptive_model = adaptive_model
371
+ self.checkpoint = checkpoint
372
+
373
+ def validate_result(self, equation_name, values):
374
+
375
+ residual = equation_residual(
376
+ equation_name, values
377
+ )
378
+
379
+ probability = (
380
+ self.adaptive_model.probability_valid(residual)
381
+ )
382
+
383
+ return {
384
+ "accepted": probability >= 0.5,
385
+ "residual": residual,
386
+ "tolerance": self.adaptive_model.tolerance,
387
+ "probability": probability
388
+ }
389
+
390
+ def solve(
391
+ self,
392
+ target,
393
+ known_values,
394
+ equation_name=None,
395
+ target_unit=None
396
+ ):
397
+
398
+ target = normalize_variable(target)
399
+
400
+ if not isinstance(known_values, dict) or not known_values:
401
+ raise ValueError("Provide a non-empty dictionary")
402
+
403
+ values = {}
404
+
405
+ for name, item in known_values.items():
406
+
407
+ variable = normalize_variable(name)
408
+
409
+ if variable in values:
410
+ raise ValueError("Duplicate variable")
411
+
412
+ if not isinstance(item, (tuple, list)) or len(item) != 2:
413
+ raise ValueError(
414
+ f"{variable} must be (value, unit)"
415
+ )
416
+
417
+ value, unit = item
418
+
419
+ values[variable] = to_si(
420
+ variable, value, unit
421
+ )
422
+
423
+ if target in values:
424
+ raise ValueError("Target already supplied")
425
+
426
+ selected = select_equation(
427
+ target,
428
+ values.keys(),
429
+ equation_name
430
+ )
431
+
432
+ nonnegative = {
433
+ "energy", "mass", "speed", "distance",
434
+ "time", "density", "volume", "force",
435
+ "work", "power"
436
+ }
437
+
438
+ for variable, value in values.items():
439
+
440
+ if variable in nonnegative and value < 0:
441
+ raise ValueError(
442
+ f"{variable} cannot be negative"
443
+ )
444
+
445
+ result_si = EQUATIONS[selected]["solvers"][target](
446
+ values
447
+ )
448
+
449
+ if not math.isfinite(result_si):
450
+ raise ValueError("Non-finite calculation result")
451
+
452
+ if target in nonnegative and result_si < 0:
453
+ raise ValueError("Negative result is invalid")
454
+
455
+ complete = dict(values)
456
+ complete[target] = result_si
457
+
458
+ validation = self.validate_result(
459
+ selected, complete
460
+ )
461
+
462
+ if not validation["accepted"]:
463
+ raise ArithmeticError(
464
+ "Numerical validation failed"
465
+ )
466
+
467
+ unit = target_unit or DEFAULT_UNITS[target]
468
+
469
+ result = from_si(target, result_si, unit)
470
+
471
+ return {
472
+ "equation": selected,
473
+ "formula": FORMULAS[selected],
474
+ "target": target,
475
+ "result": result,
476
+ "unit": unit,
477
+ "si_result": result_si,
478
+ "residual": validation["residual"],
479
+ "adaptive_tolerance": validation["tolerance"],
480
+ "validation_probability": validation["probability"]
481
+ }
482
+
483
+ def convert(self, variable, value, input_unit, output_unit):
484
+
485
+ si = to_si(variable, value, input_unit)
486
+
487
+ return from_si(variable, si, output_unit)
488
+
489
+
490
+ # ============================================================
491
+ # HUGGING FACE CHECKPOINT INITIALIZATION
492
+ # ============================================================
493
+
494
+ def load_checkpoint(
495
+ repo_id=HF_REPO_ID,
496
+ filename=HF_FILENAME,
497
+ local_path=None
498
+ ):
499
+
500
+ if local_path is None:
501
+
502
+ from huggingface_hub import hf_hub_download
503
+
504
+ print("[PHOTON] Downloading checkpoint...")
505
+
506
+ local_path = hf_hub_download(
507
+ repo_id=repo_id,
508
+ filename=filename,
509
+ repo_type="model"
510
+ )
511
+
512
+ if not os.path.isfile(local_path):
513
+ raise FileNotFoundError(local_path)
514
+
515
+ import torch
516
+
517
+ try:
518
+ checkpoint = torch.load(
519
+ local_path,
520
+ map_location="cpu",
521
+ weights_only=True
522
+ )
523
+ except Exception as exc:
524
+ raise RuntimeError(
525
+ "Checkpoint could not be safely loaded. "
526
+ "Check the checkpoint format."
527
+ ) from exc
528
+
529
+ if not isinstance(checkpoint, dict):
530
+ raise ValueError("Invalid checkpoint structure")
531
+
532
+ required = {
533
+ "version",
534
+ "equations",
535
+ "solving_directions",
536
+ "learned_tolerance"
537
+ }
538
+
539
+ if not required.issubset(checkpoint):
540
+ raise ValueError("Checkpoint metadata is incomplete")
541
+
542
+ if checkpoint["version"] != "V5":
543
+ raise ValueError("Incorrect Photon checkpoint version")
544
+
545
+ if set(checkpoint["equations"]) != set(EQUATIONS):
546
+ raise ValueError("Equation registry mismatch")
547
+
548
+ if checkpoint["solving_directions"] != 18:
549
+ raise ValueError("Incorrect solving direction count")
550
+
551
+ tolerance = float(checkpoint["learned_tolerance"])
552
+
553
+ if not math.isfinite(tolerance) or tolerance <= 0:
554
+ raise ValueError("Invalid saved tolerance")
555
+
556
+ print("[PHOTON] Checkpoint verified.")
557
+ print("[PHOTON] Saved tolerance:", tolerance)
558
+
559
+ return checkpoint
560
+
561
+
562
+ # ============================================================
563
+ # PUBLIC INITIALIZATION
564
+ # ============================================================
565
+
566
+ def initialize(
567
+ download_checkpoint=True,
568
+ checkpoint_path=None,
569
+ repo_id=HF_REPO_ID
570
+ ):
571
+
572
+ checkpoint = None
573
+
574
+ if download_checkpoint:
575
+
576
+ checkpoint = load_checkpoint(
577
+ repo_id=repo_id,
578
+ local_path=checkpoint_path
579
+ )
580
+
581
+ tolerance = float(
582
+ checkpoint["learned_tolerance"]
583
+ )
584
+
585
+ else:
586
+ tolerance = 1e-6
587
+
588
+ adaptive_model = AdaptiveTolerance(tolerance)
589
+
590
+ photon = PhotonCoreV5(
591
+ adaptive_model,
592
+ checkpoint=checkpoint
593
+ )
594
+
595
+ print("=" * 60)
596
+ print("SUPERNOVA TERAILLM — PHOTON-1 V5")
597
+ print("=" * 60)
598
+ print("Initialization: SUCCESS")
599
+ print("Equations:", len(EQUATIONS))
600
+ print("Solving directions:", 18)
601
+ print("Adaptive parameters:", 1)
602
+ print("Checkpoint loaded:", checkpoint is not None)
603
+ print("Execution: LOCAL")
604
+ print("=" * 60)
605
+
606
+ return photon
Supernova_photon/v5.py ADDED
@@ -0,0 +1,21 @@
1
+ from .engine import initialize, PhotonCoreV5
2
+
3
+ def photon(
4
+ download_checkpoint=True,
5
+ checkpoint_path=None,
6
+ repo_id="Supernova11c/Supernova-Photon-1-V5"
7
+ ):
8
+ """
9
+ Initialize Photon-1 V5.
10
+
11
+ Downloads and verifies the Hugging Face checkpoint
12
+ by default. Calculations run locally.
13
+ """
14
+
15
+ return initialize(
16
+ download_checkpoint=download_checkpoint,
17
+ checkpoint_path=checkpoint_path,
18
+ repo_id=repo_id
19
+ )
20
+
21
+ __all__ = ["photon", "PhotonCoreV5"]
@@ -0,0 +1,60 @@
1
+ Metadata-Version: 2.4
2
+ Name: supernova-photon
3
+ Version: 0.1.1
4
+ Summary: Supernova Photon-1 V5 mathematical computing engine
5
+ License: MIT
6
+ Classifier: Programming Language :: Python :: 3
7
+ Classifier: Programming Language :: Python :: 3 :: Only
8
+ Classifier: Operating System :: OS Independent
9
+ Requires-Python: >=3.9
10
+ Description-Content-Type: text/markdown
11
+ Requires-Dist: numpy>=1.24
12
+ Requires-Dist: huggingface-hub>=0.23
13
+ Requires-Dist: torch>=2.0
14
+
15
+ # Supernova Photon-1 V5
16
+
17
+ A local mathematical computation library developed by Supernova.
18
+
19
+ ## Installation
20
+
21
+ ```bash
22
+ pip install supernova-photon
23
+ ```
24
+
25
+ ## Initialization
26
+
27
+ ```python
28
+ from Supernova_photon import v5
29
+
30
+ photon = v5.photon()
31
+ ```
32
+
33
+ ## Example
34
+
35
+ ```python
36
+ result = photon.solve(
37
+ "speed",
38
+ {
39
+ "distance": (100, "m"),
40
+ "time": (10, "s")
41
+ }
42
+ )
43
+
44
+ print(result)
45
+ ```
46
+
47
+ ## Supported equations
48
+
49
+ - Einstein: E = mc²
50
+ - Speed: v = d/t
51
+ - Density: rho = m/V
52
+ - Newton: F = ma
53
+ - Work: W = Fd
54
+ - Power: P = W/t
55
+
56
+ The checkpoint is downloaded from Hugging Face during
57
+ initialization. Calculations are performed locally.
58
+
59
+ The checkpoint provides saved calibration and metadata.
60
+ It is not an executable neural arithmetic model.
@@ -0,0 +1,9 @@
1
+ Supernova_photon/__init__.py,sha256=mVqILiW0BwbPq4vtJxhDdghxOLQw_vvXeFZFGqPPaWs,58
2
+ Supernova_photon/cli.py,sha256=torVaBfxrXeC6frNlY7IA-2pTGPjlVg-NOI0Xeel87w,2222
3
+ Supernova_photon/engine.py,sha256=2hcp8V3cC_sfeLP-3D1tiswKAH7Q45LC_toEEm485o0,14537
4
+ Supernova_photon/v5.py,sha256=6iLau3-XAfv2YwH6QZJFsOZ4R7E3Is5ZARBlrCJnv5g,490
5
+ supernova_photon-0.1.1.dist-info/METADATA,sha256=KoLxYMeU2jJMs1diFZ_DPZlPmuY_WIbHu5EeG6MNGHw,1172
6
+ supernova_photon-0.1.1.dist-info/WHEEL,sha256=mOdXR9C3wMVov7cSY8PY-XCzo3SmmWCHvGQr5csJoao,91
7
+ supernova_photon-0.1.1.dist-info/entry_points.txt,sha256=wdekc2K9yCdcrgiUSuxCNLx4ydZRbjHD1hHCMTL2W8U,53
8
+ supernova_photon-0.1.1.dist-info/top_level.txt,sha256=Rb0AFGSma0VsuGV8NqMrj5UKuYdu4zNXoMVQk3mmgn0,17
9
+ supernova_photon-0.1.1.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (84.2.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ photon = Supernova_photon.cli:main
@@ -0,0 +1 @@
1
+ Supernova_photon