crcutil 2.0.2__tar.gz → 2.0.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 (52) hide show
  1. {crcutil-2.0.2/src/crcutil.egg-info → crcutil-2.0.3}/PKG-INFO +1 -1
  2. {crcutil-2.0.2 → crcutil-2.0.3}/pyproject.toml +1 -1
  3. {crcutil-2.0.2 → crcutil-2.0.3}/src/crcutil/core/checksum.py +96 -1
  4. {crcutil-2.0.2 → crcutil-2.0.3/src/crcutil.egg-info}/PKG-INFO +1 -1
  5. {crcutil-2.0.2 → crcutil-2.0.3}/.github/workflows/python-publish.yml +0 -0
  6. {crcutil-2.0.2 → crcutil-2.0.3}/.gitignore +0 -0
  7. {crcutil-2.0.2 → crcutil-2.0.3}/LICENSE +0 -0
  8. {crcutil-2.0.2 → crcutil-2.0.3}/README.md +0 -0
  9. {crcutil-2.0.2 → crcutil-2.0.3}/__init__.py +0 -0
  10. {crcutil-2.0.2 → crcutil-2.0.3}/git-hooks/commit-msg +0 -0
  11. {crcutil-2.0.2 → crcutil-2.0.3}/git-hooks/pre-commit +0 -0
  12. {crcutil-2.0.2 → crcutil-2.0.3}/init.sh +0 -0
  13. {crcutil-2.0.2 → crcutil-2.0.3}/requirements.txt +0 -0
  14. {crcutil-2.0.2 → crcutil-2.0.3}/ruff.toml +0 -0
  15. {crcutil-2.0.2 → crcutil-2.0.3}/setup.cfg +0 -0
  16. {crcutil-2.0.2 → crcutil-2.0.3}/src/crcutil/__init__.py +0 -0
  17. {crcutil-2.0.2 → crcutil-2.0.3}/src/crcutil/__main__.py +0 -0
  18. {crcutil-2.0.2 → crcutil-2.0.3}/src/crcutil/config/log_config.yaml +0 -0
  19. {crcutil-2.0.2 → crcutil-2.0.3}/src/crcutil/core/__init__.py +0 -0
  20. {crcutil-2.0.2 → crcutil-2.0.3}/src/crcutil/core/checksum_manager.py +0 -0
  21. {crcutil-2.0.2 → crcutil-2.0.3}/src/crcutil/core/keyboard_monitor.py +0 -0
  22. {crcutil-2.0.2 → crcutil-2.0.3}/src/crcutil/core/keyboard_monitor_factory.py +0 -0
  23. {crcutil-2.0.2 → crcutil-2.0.3}/src/crcutil/core/keyboard_monitor_wayland.py +0 -0
  24. {crcutil-2.0.2 → crcutil-2.0.3}/src/crcutil/core/keyboard_monitor_windows.py +0 -0
  25. {crcutil-2.0.2 → crcutil-2.0.3}/src/crcutil/core/keyboard_monitor_x11.py +0 -0
  26. {crcutil-2.0.2 → crcutil-2.0.3}/src/crcutil/core/prompt.py +0 -0
  27. {crcutil-2.0.2 → crcutil-2.0.3}/src/crcutil/dto/__init__.py +0 -0
  28. {crcutil-2.0.2 → crcutil-2.0.3}/src/crcutil/dto/bootstrap_paths_dto.py +0 -0
  29. {crcutil-2.0.2 → crcutil-2.0.3}/src/crcutil/dto/checksum_dto.py +0 -0
  30. {crcutil-2.0.2 → crcutil-2.0.3}/src/crcutil/dto/crc_diff_report_dto.py +0 -0
  31. {crcutil-2.0.2 → crcutil-2.0.3}/src/crcutil/dto/user_instructions_dto.py +0 -0
  32. {crcutil-2.0.2 → crcutil-2.0.3}/src/crcutil/enums/__init__.py +0 -0
  33. {crcutil-2.0.2 → crcutil-2.0.3}/src/crcutil/enums/user_request.py +0 -0
  34. {crcutil-2.0.2 → crcutil-2.0.3}/src/crcutil/exception/__init__.py +0 -0
  35. {crcutil-2.0.2 → crcutil-2.0.3}/src/crcutil/exception/bootstrap_error.py +0 -0
  36. {crcutil-2.0.2 → crcutil-2.0.3}/src/crcutil/exception/corrupt_crc_error.py +0 -0
  37. {crcutil-2.0.2 → crcutil-2.0.3}/src/crcutil/exception/device_error.py +0 -0
  38. {crcutil-2.0.2 → crcutil-2.0.3}/src/crcutil/exception/unexpected_argument_error.py +0 -0
  39. {crcutil-2.0.2 → crcutil-2.0.3}/src/crcutil/exception/user_error.py +0 -0
  40. {crcutil-2.0.2 → crcutil-2.0.3}/src/crcutil/serializer/__init__.py +0 -0
  41. {crcutil-2.0.2 → crcutil-2.0.3}/src/crcutil/serializer/checksum_serializer.py +0 -0
  42. {crcutil-2.0.2 → crcutil-2.0.3}/src/crcutil/serializer/crc_diff_report_serializer.py +0 -0
  43. {crcutil-2.0.2 → crcutil-2.0.3}/src/crcutil/util/__init__.py +0 -0
  44. {crcutil-2.0.2 → crcutil-2.0.3}/src/crcutil/util/crcutil_logger.py +0 -0
  45. {crcutil-2.0.2 → crcutil-2.0.3}/src/crcutil/util/file_importer.py +0 -0
  46. {crcutil-2.0.2 → crcutil-2.0.3}/src/crcutil/util/path_ops.py +0 -0
  47. {crcutil-2.0.2 → crcutil-2.0.3}/src/crcutil/util/static.py +0 -0
  48. {crcutil-2.0.2 → crcutil-2.0.3}/src/crcutil.egg-info/SOURCES.txt +0 -0
  49. {crcutil-2.0.2 → crcutil-2.0.3}/src/crcutil.egg-info/dependency_links.txt +0 -0
  50. {crcutil-2.0.2 → crcutil-2.0.3}/src/crcutil.egg-info/entry_points.txt +0 -0
  51. {crcutil-2.0.2 → crcutil-2.0.3}/src/crcutil.egg-info/requires.txt +0 -0
  52. {crcutil-2.0.2 → crcutil-2.0.3}/src/crcutil.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: crcutil
3
- Version: 2.0.2
3
+ Version: 2.0.3
4
4
  Author-email: Carlos Florez <carlos@florez.co.uk>
5
5
  Maintainer-email: Carlos Florez <carlos@florez.co.uk>
6
6
  License: MIT License
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "crcutil"
7
- version = "2.0.2"
7
+ version = "2.0.3"
8
8
  requires-python = ">=3.12.10"
9
9
  authors = [
10
10
  {name = "Carlos Florez", email = "carlos@florez.co.uk"}
@@ -3,6 +3,10 @@ import zlib
3
3
  from collections.abc import Callable
4
4
  from pathlib import Path
5
5
 
6
+ from crcutil.util.crcutil_logger import CrcutilLogger
7
+
8
+ CHUNK_SIZE = 64 * 1024
9
+
6
10
 
7
11
  class Checksum:
8
12
  def __init__(self, location: Path, root_location: Path) -> None:
@@ -95,6 +99,8 @@ class Checksum:
95
99
  and updating the CRC32 value incrementally. The result is
96
100
  masked to ensure it's treated as an unsigned 32-bit integer.
97
101
 
102
+ Text files with dos line endings are normalized to unix
103
+
98
104
  Args:
99
105
  location (pathlib.Path): The path to evaluate
100
106
 
@@ -102,7 +108,96 @@ class Checksum:
102
108
  bytes: 4-byte little-endian representation of the CRC32 checksum
103
109
  """
104
110
  file_checksum = 0
111
+
112
+ # Known text extensions to consider for line ending normalization
113
+ text_extensions = {
114
+ ".txt",
115
+ ".md",
116
+ ".rst",
117
+ ".html",
118
+ ".htm",
119
+ ".xml",
120
+ ".json",
121
+ ".yaml",
122
+ ".yml",
123
+ ".csv",
124
+ ".tsv",
125
+ ".ini",
126
+ ".cfg",
127
+ ".conf",
128
+ ".py",
129
+ ".js",
130
+ ".java",
131
+ ".c",
132
+ ".cpp",
133
+ ".h",
134
+ ".hpp",
135
+ ".php",
136
+ ".rb",
137
+ ".go",
138
+ ".rs",
139
+ ".ts",
140
+ ".css",
141
+ ".scss",
142
+ ".sql",
143
+ ".sh",
144
+ ".bash",
145
+ ".zsh",
146
+ ".ps1",
147
+ ".bat",
148
+ ".cmd",
149
+ ".log",
150
+ }
151
+
152
+ extension = location.suffix.lower()
153
+ is_text_file = self.__is_likely_text_file(location)
154
+
155
+ if extension in text_extensions and is_text_file:
156
+ try:
157
+ with location.open("r", encoding="utf-8") as f:
158
+ content = f.read().replace("\r\n", "\n")
159
+ content_bytes = content.encode("utf-8")
160
+ file_checksum = zlib.crc32(content_bytes) & 0xFFFFFFFF
161
+ return file_checksum.to_bytes(4, "little", signed=False)
162
+ except UnicodeDecodeError:
163
+ description = (
164
+ f"Understood as text file: {location!s} "
165
+ "but encountered decoding error. Proceeding w/ binary"
166
+ )
167
+ CrcutilLogger.get_logger().debug(description)
168
+
105
169
  with location.open("rb") as f:
106
- for chunk in iter(lambda: f.read(4096), b""):
170
+ for chunk in iter(lambda: f.read(CHUNK_SIZE), b""):
107
171
  file_checksum = zlib.crc32(chunk, file_checksum) & 0xFFFFFFFF
172
+
108
173
  return file_checksum.to_bytes(4, "little", signed=False)
174
+
175
+ def __is_likely_text_file(self, location: Path) -> bool:
176
+ """
177
+ Check if a file is likely to be text by sampling the beginning.
178
+ """
179
+ # Only read a sample
180
+ with location.open("rb") as f:
181
+ sample = f.read(CHUNK_SIZE)
182
+
183
+ # Empty file, treat as empty text
184
+ if not sample:
185
+ return True
186
+
187
+ # Null byte presence, likely a binary file
188
+ if b"\0" in sample:
189
+ return False
190
+
191
+ ascii_lower_range = 32
192
+ ascii_upper_range = 126
193
+ tab = 9
194
+ line_feed = 10
195
+ carriage_return = 13
196
+ printable_count = sum(
197
+ 1
198
+ for byte in sample
199
+ if ascii_lower_range <= byte <= ascii_upper_range
200
+ or byte in (tab, line_feed, carriage_return)
201
+ )
202
+ printable_character_treshold = 0.8
203
+ return (printable_count / len(sample)) > printable_character_treshold
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: crcutil
3
- Version: 2.0.2
3
+ Version: 2.0.3
4
4
  Author-email: Carlos Florez <carlos@florez.co.uk>
5
5
  Maintainer-email: Carlos Florez <carlos@florez.co.uk>
6
6
  License: MIT License
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