consync 2.2.1__tar.gz → 2.2.3__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.
Files changed (73) hide show
  1. {consync-2.2.1 → consync-2.2.3}/PKG-INFO +1 -1
  2. {consync-2.2.1 → consync-2.2.3}/consync/cli.py +3 -3
  3. {consync-2.2.1 → consync-2.2.3}/consync/config.py +16 -4
  4. {consync-2.2.1 → consync-2.2.3}/consync/hooks.py +2 -2
  5. {consync-2.2.1 → consync-2.2.3}/consync/lock.py +2 -2
  6. {consync-2.2.1 → consync-2.2.3}/consync/state.py +2 -2
  7. {consync-2.2.1 → consync-2.2.3}/pyproject.toml +1 -1
  8. {consync-2.2.1 → consync-2.2.3}/.github/CODEOWNERS +0 -0
  9. {consync-2.2.1 → consync-2.2.3}/.github/copilot-instructions.md +0 -0
  10. {consync-2.2.1 → consync-2.2.3}/.github/dependabot.yml +0 -0
  11. {consync-2.2.1 → consync-2.2.3}/.github/workflows/ci.yml +0 -0
  12. {consync-2.2.1 → consync-2.2.3}/.github/workflows/codeql.yml +0 -0
  13. {consync-2.2.1 → consync-2.2.3}/.github/workflows/publish.yml +0 -0
  14. {consync-2.2.1 → consync-2.2.3}/.github/workflows/release.yml +0 -0
  15. {consync-2.2.1 → consync-2.2.3}/.gitignore +0 -0
  16. {consync-2.2.1 → consync-2.2.3}/CLAUDE.md +0 -0
  17. {consync-2.2.1 → consync-2.2.3}/CONTRIBUTING.md +0 -0
  18. {consync-2.2.1 → consync-2.2.3}/FAQ.md +0 -0
  19. {consync-2.2.1 → consync-2.2.3}/LICENSE +0 -0
  20. {consync-2.2.1 → consync-2.2.3}/README.md +0 -0
  21. {consync-2.2.1 → consync-2.2.3}/SECURITY.md +0 -0
  22. {consync-2.2.1 → consync-2.2.3}/TODO.md +0 -0
  23. {consync-2.2.1 → consync-2.2.3}/assets/demo.gif +0 -0
  24. {consync-2.2.1 → consync-2.2.3}/assets/demo.tape +0 -0
  25. {consync-2.2.1 → consync-2.2.3}/consync/__init__.py +0 -0
  26. {consync-2.2.1 → consync-2.2.3}/consync/backup.py +0 -0
  27. {consync-2.2.1 → consync-2.2.3}/consync/logging_config.py +0 -0
  28. {consync-2.2.1 → consync-2.2.3}/consync/models.py +0 -0
  29. {consync-2.2.1 → consync-2.2.3}/consync/parsers/__init__.py +0 -0
  30. {consync-2.2.1 → consync-2.2.3}/consync/parsers/c_header.py +0 -0
  31. {consync-2.2.1 → consync-2.2.3}/consync/parsers/c_struct_table.py +0 -0
  32. {consync-2.2.1 → consync-2.2.3}/consync/parsers/csv_parser.py +0 -0
  33. {consync-2.2.1 → consync-2.2.3}/consync/parsers/json_parser.py +0 -0
  34. {consync-2.2.1 → consync-2.2.3}/consync/parsers/toml_parser.py +0 -0
  35. {consync-2.2.1 → consync-2.2.3}/consync/parsers/xlsx.py +0 -0
  36. {consync-2.2.1 → consync-2.2.3}/consync/precision.py +0 -0
  37. {consync-2.2.1 → consync-2.2.3}/consync/renderers/__init__.py +0 -0
  38. {consync-2.2.1 → consync-2.2.3}/consync/renderers/c_header.py +0 -0
  39. {consync-2.2.1 → consync-2.2.3}/consync/renderers/c_struct_table.py +0 -0
  40. {consync-2.2.1 → consync-2.2.3}/consync/renderers/csharp.py +0 -0
  41. {consync-2.2.1 → consync-2.2.3}/consync/renderers/csv_renderer.py +0 -0
  42. {consync-2.2.1 → consync-2.2.3}/consync/renderers/json_renderer.py +0 -0
  43. {consync-2.2.1 → consync-2.2.3}/consync/renderers/python_const.py +0 -0
  44. {consync-2.2.1 → consync-2.2.3}/consync/renderers/rust_const.py +0 -0
  45. {consync-2.2.1 → consync-2.2.3}/consync/renderers/verilog.py +0 -0
  46. {consync-2.2.1 → consync-2.2.3}/consync/renderers/vhdl.py +0 -0
  47. {consync-2.2.1 → consync-2.2.3}/consync/sync.py +0 -0
  48. {consync-2.2.1 → consync-2.2.3}/consync/validators.py +0 -0
  49. {consync-2.2.1 → consync-2.2.3}/consync/watcher.py +0 -0
  50. {consync-2.2.1 → consync-2.2.3}/examples/fpga/.consync.yaml +0 -0
  51. {consync-2.2.1 → consync-2.2.3}/examples/fpga/design_params.csv +0 -0
  52. {consync-2.2.1 → consync-2.2.3}/examples/hardware/.consync.yaml +0 -0
  53. {consync-2.2.1 → consync-2.2.3}/examples/hardware/constants.csv +0 -0
  54. {consync-2.2.1 → consync-2.2.3}/examples/multilang/.consync.yaml +0 -0
  55. {consync-2.2.1 → consync-2.2.3}/examples/multilang/constants.json +0 -0
  56. {consync-2.2.1 → consync-2.2.3}/npm/.npmrc +0 -0
  57. {consync-2.2.1 → consync-2.2.3}/npm/LICENSE +0 -0
  58. {consync-2.2.1 → consync-2.2.3}/npm/README.md +0 -0
  59. {consync-2.2.1 → consync-2.2.3}/npm/bin/consync.js +0 -0
  60. {consync-2.2.1 → consync-2.2.3}/npm/package.json +0 -0
  61. {consync-2.2.1 → consync-2.2.3}/npm/scripts/install.js +0 -0
  62. {consync-2.2.1 → consync-2.2.3}/tests/__init__.py +0 -0
  63. {consync-2.2.1 → consync-2.2.3}/tests/test_arrays.py +0 -0
  64. {consync-2.2.1 → consync-2.2.3}/tests/test_bidirectional.py +0 -0
  65. {consync-2.2.1 → consync-2.2.3}/tests/test_c_struct_table.py +0 -0
  66. {consync-2.2.1 → consync-2.2.3}/tests/test_cli.py +0 -0
  67. {consync-2.2.1 → consync-2.2.3}/tests/test_comprehensive_sync.py +0 -0
  68. {consync-2.2.1 → consync-2.2.3}/tests/test_embedded.py +0 -0
  69. {consync-2.2.1 → consync-2.2.3}/tests/test_parsers.py +0 -0
  70. {consync-2.2.1 → consync-2.2.3}/tests/test_precision.py +0 -0
  71. {consync-2.2.1 → consync-2.2.3}/tests/test_renderers.py +0 -0
  72. {consync-2.2.1 → consync-2.2.3}/tests/test_safety.py +0 -0
  73. {consync-2.2.1 → consync-2.2.3}/tests/test_sync.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: consync
3
- Version: 2.2.1
3
+ Version: 2.2.3
4
4
  Summary: Bidirectional sync between spreadsheets and source code constants — with full decimal precision.
5
5
  Project-URL: Homepage, https://github.com/naveenkumarbaskaran/consync
6
6
  Project-URL: Repository, https://github.com/naveenkumarbaskaran/consync
@@ -46,7 +46,7 @@ def init(path: str):
46
46
  click.echo(f"⚠️ {target} already exists. Delete it first to regenerate.")
47
47
  sys.exit(1)
48
48
 
49
- target.write_text(generate_default_config())
49
+ target.write_text(generate_default_config(), encoding="utf-8")
50
50
  click.echo(f"✅ Created {target}")
51
51
  click.echo(" Edit it to configure your source ↔ target mappings.")
52
52
  click.echo(" Then run: consync sync")
@@ -329,13 +329,13 @@ def diff_cmd(config_path: str | None, from_side: str | None, color: bool):
329
329
 
330
330
  try:
331
331
  _render_file(constants, tmp_path, mapping.target_format if direction == "source" else mapping.source_format, mapping)
332
- new_content = tmp_path.read_text().splitlines(keepends=True)
332
+ new_content = tmp_path.read_text(encoding="utf-8").splitlines(keepends=True)
333
333
  finally:
334
334
  tmp_path.unlink(missing_ok=True)
335
335
 
336
336
  # Get current content
337
337
  if dest_path.exists():
338
- old_content = dest_path.read_text().splitlines(keepends=True)
338
+ old_content = dest_path.read_text(encoding="utf-8").splitlines(keepends=True)
339
339
  else:
340
340
  old_content = []
341
341
 
@@ -132,6 +132,14 @@ def _parse_mapping(raw: dict[str, Any], config_dir: Path) -> MappingConfig:
132
132
 
133
133
  direction = _parse_direction(raw.get("direction", "source_to_target"))
134
134
 
135
+ # Normalize parser_options — handle None (empty YAML value) and promote
136
+ # common parser keys (variant, table_var, fields) from mapping level
137
+ parser_options = raw.get("parser_options") or {}
138
+ _PROMOTABLE_PARSER_KEYS = ("variant", "table_var", "fields")
139
+ for key in _PROMOTABLE_PARSER_KEYS:
140
+ if key not in parser_options and key in raw:
141
+ parser_options[key] = raw[key]
142
+
135
143
  return MappingConfig(
136
144
  source=source,
137
145
  target=target,
@@ -147,9 +155,9 @@ def _parse_mapping(raw: dict[str, Any], config_dir: Path) -> MappingConfig:
147
155
  output_style=raw.get("output_style", "const"),
148
156
  static_const=raw.get("static_const", False),
149
157
  typed_ints=raw.get("typed_ints", True),
150
- parser_options=raw.get("parser_options", {}),
151
- renderer_options=raw.get("renderer_options", {}),
152
- validators=raw.get("validators", {}),
158
+ parser_options=parser_options,
159
+ renderer_options=raw.get("renderer_options") or {},
160
+ validators=raw.get("validators") or {},
153
161
  )
154
162
 
155
163
 
@@ -223,7 +231,11 @@ mappings:
223
231
  # target: MotorParams.xlsx # Excel generated from C (created if missing)
224
232
  # direction: both # Edit either side, sync keeps them matched
225
233
  # format: c_struct_table # Parser for #if/#elif struct arrays
226
- # precision: 17
234
+ # variant: all # Extract ALL #if/#elif variants (one sheet each)
235
+ # # table_var: MyStructLUT # Optional: struct array name (auto-detected)
236
+ # # fields: [R_Phase, L_d, Psi] # Optional: field names (auto-detected)
237
+ # # parser_options: # Alternative: nest parser keys here
238
+ # # variant: all
227
239
 
228
240
  # ─── Pattern 3: Code → Spreadsheet (bootstrap) ───
229
241
  # - source: params.csv # Will be created from your existing code
@@ -49,7 +49,7 @@ def install_git_hook(hook_type: str = "pre-commit"):
49
49
 
50
50
  # Check for existing hook
51
51
  if hook_file.exists():
52
- existing = hook_file.read_text()
52
+ existing = hook_file.read_text(encoding="utf-8")
53
53
  if "consync" in existing:
54
54
  click.echo(f"✔️ consync hook already installed in .git/hooks/{hook_type}")
55
55
  return
@@ -61,7 +61,7 @@ def install_git_hook(hook_type: str = "pre-commit"):
61
61
  f.write(HOOK_TEMPLATE.format(hook_type=hook_type, git_cmd=git_cmd))
62
62
  else:
63
63
  # Create new hook
64
- hook_file.write_text(HOOK_TEMPLATE.format(hook_type=hook_type, git_cmd=git_cmd))
64
+ hook_file.write_text(HOOK_TEMPLATE.format(hook_type=hook_type, git_cmd=git_cmd), encoding="utf-8")
65
65
 
66
66
  hook_file.chmod(0o755)
67
67
  click.echo(f"✅ Installed consync check in .git/hooks/{hook_type}")
@@ -66,7 +66,7 @@ class SyncLock:
66
66
  "created": datetime.now(timezone.utc).isoformat(timespec="seconds"),
67
67
  "hostname": platform.node(),
68
68
  }
69
- self.lock_path.write_text(json.dumps(lock_info, indent=2))
69
+ self.lock_path.write_text(json.dumps(lock_info, indent=2), encoding="utf-8")
70
70
  self._acquired = True
71
71
  logger.debug("Lock acquired: %s", self.lock_path)
72
72
 
@@ -80,7 +80,7 @@ class SyncLock:
80
80
  def _read_lock(self) -> dict | None:
81
81
  """Read lock file contents."""
82
82
  try:
83
- return json.loads(self.lock_path.read_text())
83
+ return json.loads(self.lock_path.read_text(encoding="utf-8"))
84
84
  except (json.JSONDecodeError, OSError):
85
85
  return None
86
86
 
@@ -43,14 +43,14 @@ class SyncState:
43
43
  def _load(self):
44
44
  if self.state_file.exists():
45
45
  try:
46
- self._data = json.loads(self.state_file.read_text())
46
+ self._data = json.loads(self.state_file.read_text(encoding="utf-8"))
47
47
  except (json.JSONDecodeError, OSError):
48
48
  self._data = {}
49
49
  else:
50
50
  self._data = {}
51
51
 
52
52
  def _save(self):
53
- self.state_file.write_text(json.dumps(self._data, indent=2) + "\n")
53
+ self.state_file.write_text(json.dumps(self._data, indent=2) + "\n", encoding="utf-8")
54
54
 
55
55
  def get_hash(self, mapping_key: str, side: str) -> str | None:
56
56
  """Get the stored hash for a mapping side ('source' or 'target')."""
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "consync"
7
- version = "2.2.1"
7
+ version = "2.2.3"
8
8
  description = "Bidirectional sync between spreadsheets and source code constants — with full decimal precision."
9
9
  readme = "README.md"
10
10
  license = {text = "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
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