rosetta-cli 3.0.6__tar.gz → 3.0.7__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 (33) hide show
  1. {rosetta_cli-3.0.6/rosetta_cli.egg-info → rosetta_cli-3.0.7}/PKG-INFO +1 -1
  2. {rosetta_cli-3.0.6 → rosetta_cli-3.0.7}/pyproject.toml +1 -1
  3. {rosetta_cli-3.0.6 → rosetta_cli-3.0.7}/rosetta_cli/rosetta_publisher.py +53 -21
  4. {rosetta_cli-3.0.6 → rosetta_cli-3.0.7}/rosetta_cli/services/document_data.py +10 -3
  5. {rosetta_cli-3.0.6 → rosetta_cli-3.0.7/rosetta_cli.egg-info}/PKG-INFO +1 -1
  6. {rosetta_cli-3.0.6 → rosetta_cli-3.0.7}/MANIFEST.in +0 -0
  7. {rosetta_cli-3.0.6 → rosetta_cli-3.0.7}/README.md +0 -0
  8. {rosetta_cli-3.0.6 → rosetta_cli-3.0.7}/env.template +0 -0
  9. {rosetta_cli-3.0.6 → rosetta_cli-3.0.7}/rosetta_cli/__init__.py +0 -0
  10. {rosetta_cli-3.0.6 → rosetta_cli-3.0.7}/rosetta_cli/__main__.py +0 -0
  11. {rosetta_cli-3.0.6 → rosetta_cli-3.0.7}/rosetta_cli/cli.py +0 -0
  12. {rosetta_cli-3.0.6 → rosetta_cli-3.0.7}/rosetta_cli/commands/__init__.py +0 -0
  13. {rosetta_cli-3.0.6 → rosetta_cli-3.0.7}/rosetta_cli/commands/base_command.py +0 -0
  14. {rosetta_cli-3.0.6 → rosetta_cli-3.0.7}/rosetta_cli/commands/cleanup_command.py +0 -0
  15. {rosetta_cli-3.0.6 → rosetta_cli-3.0.7}/rosetta_cli/commands/list_command.py +0 -0
  16. {rosetta_cli-3.0.6 → rosetta_cli-3.0.7}/rosetta_cli/commands/parse_command.py +0 -0
  17. {rosetta_cli-3.0.6 → rosetta_cli-3.0.7}/rosetta_cli/commands/publish_command.py +0 -0
  18. {rosetta_cli-3.0.6 → rosetta_cli-3.0.7}/rosetta_cli/commands/verify_command.py +0 -0
  19. {rosetta_cli-3.0.6 → rosetta_cli-3.0.7}/rosetta_cli/ragflow_client.py +0 -0
  20. {rosetta_cli-3.0.6 → rosetta_cli-3.0.7}/rosetta_cli/rosetta_auth.py +0 -0
  21. {rosetta_cli-3.0.6 → rosetta_cli-3.0.7}/rosetta_cli/rosetta_config.py +0 -0
  22. {rosetta_cli-3.0.6 → rosetta_cli-3.0.7}/rosetta_cli/rosetta_utils.py +0 -0
  23. {rosetta_cli-3.0.6 → rosetta_cli-3.0.7}/rosetta_cli/services/__init__.py +0 -0
  24. {rosetta_cli-3.0.6 → rosetta_cli-3.0.7}/rosetta_cli/services/auth_service.py +0 -0
  25. {rosetta_cli-3.0.6 → rosetta_cli-3.0.7}/rosetta_cli/services/dataset_service.py +0 -0
  26. {rosetta_cli-3.0.6 → rosetta_cli-3.0.7}/rosetta_cli/services/document_service.py +0 -0
  27. {rosetta_cli-3.0.6 → rosetta_cli-3.0.7}/rosetta_cli/typing_utils.py +0 -0
  28. {rosetta_cli-3.0.6 → rosetta_cli-3.0.7}/rosetta_cli.egg-info/SOURCES.txt +0 -0
  29. {rosetta_cli-3.0.6 → rosetta_cli-3.0.7}/rosetta_cli.egg-info/dependency_links.txt +0 -0
  30. {rosetta_cli-3.0.6 → rosetta_cli-3.0.7}/rosetta_cli.egg-info/entry_points.txt +0 -0
  31. {rosetta_cli-3.0.6 → rosetta_cli-3.0.7}/rosetta_cli.egg-info/requires.txt +0 -0
  32. {rosetta_cli-3.0.6 → rosetta_cli-3.0.7}/rosetta_cli.egg-info/top_level.txt +0 -0
  33. {rosetta_cli-3.0.6 → rosetta_cli-3.0.7}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rosetta-cli
3
- Version: 3.0.6
3
+ Version: 3.0.7
4
4
  Summary: Rosetta CLI for publishing knowledge base content to RAGFlow
5
5
  Author-email: Rosetta Team <rosetta-support@griddynamics.com>
6
6
  License-Expression: Apache-2.0
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "rosetta-cli"
7
- version = "3.0.6"
7
+ version = "3.0.7"
8
8
  description = "Rosetta CLI for publishing knowledge base content to RAGFlow"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.12"
@@ -23,7 +23,7 @@ from pathlib import Path
23
23
  from typing import cast
24
24
 
25
25
  from .services.document_service import DocumentService
26
- from .services.document_data import DocumentData
26
+ from .services.document_data import DocumentData, InvalidTextEncodingError
27
27
  from .ragflow_client import DocumentMetadata, RAGFlowClient, RAGFlowClientError
28
28
  from .rosetta_config import DEFAULT_PARSE_TIMEOUT
29
29
  from .typing_utils import DocumentLike, JsonDict
@@ -171,6 +171,7 @@ class ContentPublisher:
171
171
  print("Reading files...")
172
172
  all_caches = [] # ALL successfully read caches (for cleanup/orphan detection)
173
173
  results = []
174
+ read_failures: list[Path] = []
174
175
 
175
176
  for file in files:
176
177
  try:
@@ -178,17 +179,32 @@ class ContentPublisher:
178
179
  cache = DocumentData.from_file(
179
180
  file,
180
181
  self.workspace_root,
181
- self.file_extensions,
182
182
  publish_root=folder,
183
183
  )
184
184
  all_caches.append(cache)
185
185
 
186
186
  except Exception as e:
187
+ read_failures.append(file)
187
188
  print(f"✗ Error reading {file.name}: {e}")
188
- continue
189
-
190
- # Duplicate cleanup: remove stale server copies of the same file (before publish)
191
- self._cleanup_duplicates(all_caches, dry_run)
189
+ results.append(PublishResult(
190
+ success=False,
191
+ document_id="",
192
+ file_path=str(file),
193
+ tags=[],
194
+ error=str(e),
195
+ ))
196
+
197
+ # Destructive cleanup requires a complete local inventory. If even one
198
+ # file could not be read, preserve remote documents until a full run can
199
+ # determine which paths are truly stale.
200
+ if read_failures:
201
+ print(
202
+ "\nDuplicate cleanup skipped "
203
+ f"({len(read_failures)} local file(s) could not be read)"
204
+ )
205
+ else:
206
+ # Remove stale server copies of the same file before publishing.
207
+ self._cleanup_duplicates(all_caches, dry_run)
192
208
 
193
209
  # Check for changes after cleanup so skip decisions reflect current server state.
194
210
  doc_caches = [] # Only changed caches (for publishing)
@@ -271,15 +287,23 @@ class ContentPublisher:
271
287
  # docs — running orphan detection would delete everything else.
272
288
  is_full_publish = folder.name == "instructions" or folder.parent == self.workspace_root
273
289
  if is_full_publish:
274
- managed_domains_by_dataset: dict[str, set[str]] = {}
275
- for cache in all_caches:
276
- dataset_name = self._resolve_dataset_name({"release": cache.release})
277
- managed_domains_by_dataset.setdefault(dataset_name, set()).add(cache.domain)
278
- self._cleanup_orphans(
279
- all_caches,
280
- dry_run,
281
- managed_domains_by_dataset=managed_domains_by_dataset,
282
- )
290
+ if read_failures:
291
+ # The local inventory is incomplete, so a failed read must not
292
+ # make an existing server document look like an orphan.
293
+ print(
294
+ "\nOrphan detection skipped "
295
+ f"({len(read_failures)} local file(s) could not be read)"
296
+ )
297
+ else:
298
+ managed_domains_by_dataset: dict[str, set[str]] = {}
299
+ for cache in all_caches:
300
+ dataset_name = self._resolve_dataset_name({"release": cache.release})
301
+ managed_domains_by_dataset.setdefault(dataset_name, set()).add(cache.domain)
302
+ self._cleanup_orphans(
303
+ all_caches,
304
+ dry_run,
305
+ managed_domains_by_dataset=managed_domains_by_dataset,
306
+ )
283
307
  else:
284
308
  print("\nOrphan detection skipped (subfolder publish)")
285
309
 
@@ -347,12 +371,20 @@ class ContentPublisher:
347
371
  )
348
372
 
349
373
  # Create cache on-the-fly (still better than reading multiple times)
350
- cache = DocumentData.from_file(
351
- file,
352
- self.workspace_root,
353
- self.file_extensions,
354
- publish_root=file.parent,
355
- )
374
+ try:
375
+ cache = DocumentData.from_file(
376
+ file,
377
+ self.workspace_root,
378
+ publish_root=file.parent,
379
+ )
380
+ except InvalidTextEncodingError as e:
381
+ return PublishResult(
382
+ success=False,
383
+ document_id="",
384
+ file_path=str(file),
385
+ tags=[],
386
+ error=str(e),
387
+ )
356
388
 
357
389
  ims_doc_id = cache.ims_doc_id
358
390
  content = cache.content
@@ -18,6 +18,13 @@ except Exception: # pragma: no cover - guarded at runtime
18
18
  frontmatter = None
19
19
 
20
20
 
21
+ class InvalidTextEncodingError(ValueError):
22
+ """Raised when a text-suffix file cannot be decoded as UTF-8."""
23
+
24
+ def __init__(self, file_path: Path):
25
+ super().__init__(f"{file_path} is not valid UTF-8")
26
+
27
+
21
28
  def _is_r2_or_later(release: str) -> bool:
22
29
  """Check if release is r2 or later (r2, r3, r2.5, etc.)."""
23
30
  if not release or not release.startswith("r"):
@@ -85,8 +92,8 @@ class DocumentData:
85
92
  if is_text:
86
93
  try:
87
94
  content_str = content.decode("utf-8")
88
- except UnicodeDecodeError:
89
- content_str = content.decode("utf-8", errors="ignore")
95
+ except UnicodeDecodeError as error:
96
+ raise InvalidTextEncodingError(file_path) from error
90
97
 
91
98
  # Count lines platform-independently: \r\n, \n\r, \r, \n all count as separators
92
99
  line_count = None
@@ -111,7 +118,7 @@ class DocumentData:
111
118
  doc_title = cls._compute_doc_title(parsed_path, file_path.name)
112
119
 
113
120
  content_hash = cls._calculate_hash(
114
- content_str if content_str is not None else str(len(content)),
121
+ content_str if content_str is not None else hashlib.sha256(content).hexdigest(),
115
122
  tags,
116
123
  domain,
117
124
  release,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rosetta-cli
3
- Version: 3.0.6
3
+ Version: 3.0.7
4
4
  Summary: Rosetta CLI for publishing knowledge base content to RAGFlow
5
5
  Author-email: Rosetta Team <rosetta-support@griddynamics.com>
6
6
  License-Expression: Apache-2.0
File without changes
File without changes
File without changes
File without changes