xenfra 0.3.5__tar.gz → 0.3.6__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,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: xenfra
3
- Version: 0.3.5
3
+ Version: 0.3.6
4
4
  Summary: A 'Zen Mode' infrastructure engine for Python developers.
5
5
  Author: xenfra-cloud
6
6
  Author-email: xenfra-cloud <xenfracloud@gmail.com>
@@ -24,6 +24,7 @@ Requires-Dist: keyring>=25.7.0
24
24
  Requires-Dist: keyrings-alt>=5.0.2
25
25
  Requires-Dist: tenacity>=8.2.3
26
26
  Requires-Dist: cryptography>=43.0.0
27
+ Requires-Dist: toml>=0.10.2
27
28
  Requires-Dist: pytest>=8.0.0 ; extra == 'test'
28
29
  Requires-Dist: pytest-mock>=3.12.0 ; extra == 'test'
29
30
  Requires-Python: >=3.13
@@ -1,55 +1,56 @@
1
- [project]
2
- name = "xenfra"
3
- version = "0.3.5"
4
- description = "A 'Zen Mode' infrastructure engine for Python developers."
5
- readme = "README.md"
6
- authors = [
7
- { name = "xenfra-cloud", email = "xenfracloud@gmail.com" }
8
- ]
9
-
10
- classifiers = [
11
- "Programming Language :: Python :: 3",
12
- "License :: OSI Approved :: MIT License",
13
- "Operating System :: OS Independent",
14
- "Development Status :: 3 - Alpha",
15
- "Intended Audience :: Developers",
16
- "Topic :: Software Development :: Build Tools",
17
- "Topic :: System :: Systems Administration",
18
- ]
19
-
20
- dependencies = [
21
- "click>=8.1.7",
22
- "rich>=14.2.0",
23
- "sqlmodel>=0.0.16",
24
- "python-digitalocean>=1.17.0",
25
- "python-dotenv>=1.2.1",
26
- "pyyaml>=6.0.1",
27
- "fabric>=3.2.2",
28
- "xenfra-sdk",
29
- "httpx>=0.27.0",
30
- "keyring>=25.7.0",
31
- "keyrings.alt>=5.0.2",
32
- "tenacity>=8.2.3", # For retry logic
33
- "cryptography>=43.0.0", # For encrypted file-based token storage
34
- ]
35
- requires-python = ">=3.13"
36
-
37
- [tool.uv.sources]
38
- xenfra-sdk = { workspace = true }
39
-
40
- [project.urls]
41
- Homepage = "https://github.com/xenfra-cloud/xenfra"
42
- Issues = "https://github.com/xenfra-cloud/xenfra/issues"
43
-
44
- [project.optional-dependencies]
45
- test = [
46
- "pytest>=8.0.0",
47
- "pytest-mock>=3.12.0",
48
- ]
49
-
50
- [project.scripts]
51
- xenfra = "xenfra.main:main"
52
-
53
- [build-system]
54
- requires = ["uv_build>=0.9.18,<0.10.0"]
55
- build-backend = "uv_build"
1
+ [project]
2
+ name = "xenfra"
3
+ version = "0.3.6"
4
+ description = "A 'Zen Mode' infrastructure engine for Python developers."
5
+ readme = "README.md"
6
+ authors = [
7
+ { name = "xenfra-cloud", email = "xenfracloud@gmail.com" }
8
+ ]
9
+
10
+ classifiers = [
11
+ "Programming Language :: Python :: 3",
12
+ "License :: OSI Approved :: MIT License",
13
+ "Operating System :: OS Independent",
14
+ "Development Status :: 3 - Alpha",
15
+ "Intended Audience :: Developers",
16
+ "Topic :: Software Development :: Build Tools",
17
+ "Topic :: System :: Systems Administration",
18
+ ]
19
+
20
+ dependencies = [
21
+ "click>=8.1.7",
22
+ "rich>=14.2.0",
23
+ "sqlmodel>=0.0.16",
24
+ "python-digitalocean>=1.17.0",
25
+ "python-dotenv>=1.2.1",
26
+ "pyyaml>=6.0.1",
27
+ "fabric>=3.2.2",
28
+ "xenfra-sdk",
29
+ "httpx>=0.27.0",
30
+ "keyring>=25.7.0",
31
+ "keyrings.alt>=5.0.2",
32
+ "tenacity>=8.2.3", # For retry logic
33
+ "cryptography>=43.0.0", # For encrypted file-based token storage
34
+ "toml>=0.10.2",
35
+ ]
36
+ requires-python = ">=3.13"
37
+
38
+ [tool.uv.sources]
39
+ xenfra-sdk = { workspace = true }
40
+
41
+ [project.urls]
42
+ Homepage = "https://github.com/xenfra-cloud/xenfra"
43
+ Issues = "https://github.com/xenfra-cloud/xenfra/issues"
44
+
45
+ [project.optional-dependencies]
46
+ test = [
47
+ "pytest>=8.0.0",
48
+ "pytest-mock>=3.12.0",
49
+ ]
50
+
51
+ [project.scripts]
52
+ xenfra = "xenfra.main:main"
53
+
54
+ [build-system]
55
+ requires = ["uv_build>=0.9.18,<0.10.0"]
56
+ build-backend = "uv_build"
@@ -280,6 +280,68 @@ def apply_patch(patch: dict, target_file: str = None, create_backup_file: bool =
280
280
  # Replace entire file
281
281
  with open(file_to_patch, "w") as f:
282
282
  f.write(str(value))
283
+
284
+ # For TOML files (pyproject.toml)
285
+ elif file_to_patch.endswith(".toml"):
286
+ import toml
287
+
288
+ with open(file_to_patch, "r") as f:
289
+ config_data = toml.load(f)
290
+
291
+ operation = patch.get("operation")
292
+ path = patch.get("path", "").strip("/")
293
+ value = patch.get("value")
294
+
295
+ if operation == "add":
296
+ # Special case for pyproject.toml dependencies
297
+ is_pyproject = os.path.basename(file_to_patch) == "pyproject.toml"
298
+ if is_pyproject and (not path or path == "project/dependencies"):
299
+ # Ensure project and dependencies exist
300
+ if "project" not in config_data:
301
+ config_data["project"] = {}
302
+ if "dependencies" not in config_data["project"]:
303
+ config_data["project"]["dependencies"] = []
304
+
305
+ # Add value if not already present
306
+ if value not in config_data["project"]["dependencies"]:
307
+ config_data["project"]["dependencies"].append(value)
308
+ elif path:
309
+ path_parts = path.split("/")
310
+ current = config_data
311
+ for part in path_parts[:-1]:
312
+ if part not in current:
313
+ current[part] = {}
314
+ current = current[part]
315
+
316
+ # If target is a list (like dependencies), append
317
+ target_key = path_parts[-1]
318
+ if target_key in current and isinstance(current[target_key], list):
319
+ if value not in current[target_key]:
320
+ current[target_key].append(value)
321
+ else:
322
+ current[target_key] = value
323
+ else:
324
+ # Root level add
325
+ if isinstance(value, dict):
326
+ config_data.update(value)
327
+ else:
328
+ # Ignore root-level non-dict adds for structured files
329
+ # to prevent overwriting the entire config with a string
330
+ pass
331
+
332
+ elif operation == "replace":
333
+ if path:
334
+ path_parts = path.split("/")
335
+ current = config_data
336
+ for part in path_parts[:-1]:
337
+ current = current[part]
338
+ current[path_parts[-1]] = value
339
+ else:
340
+ config_data = value
341
+
342
+ # Write back
343
+ with open(file_to_patch, "w") as f:
344
+ toml.dump(config_data, f)
283
345
  else:
284
346
  # Design decision: Only support auto-patching for common dependency files
285
347
  # Other file types should be manually edited to avoid data loss
File without changes
File without changes
File without changes
File without changes