FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

GitHub Viewer

""" Encoding-aware file operations with automatic encoding detection for reading and configurable encoding for writing. Provides safe_open() as a drop-in replacement for built-in open() that handles encoding intelligently on reads, smart_read() for direct file reading with fallback encoding detection via charset_normalizer, and safe_write() for writing files with a configurable default encoding. The module-level DEFAULT_ENCODING variable can be overridden at runtime (e.g., from main.py) to set the preferred encoding for write operations. """ import charset_normalizer # Global encoding setting used by safe_open() and safe_write() for write # operations. Can be overridden at runtime from main.py or elsewhere. DEFAULT_ENCODING = "utf-8" def smart_read(filepath): """ Read a text file, automatically detecting the encoding if not UTF-8. Attempts a fast UTF-8 decode first using Python's optimized native decoder. Falls back to charset_normalizer for legacy encodings (e.g. GBK, Latin-1, Shift-JIS) when a UnicodeDecodeError is raised. Args: filepath: Path to the file to read. Returns: The file contents as a string. Raises: ValueError: If the encoding cannot be determined. FileNotFoundError: If the file does not exist. """ try: # FAST PATH: Try standard UTF-8 first using Python's optimized # native decoder — this handles the vast majority of modern files. with open(filepath, "r", encoding="utf-8") as f: return f.read() except UnicodeDecodeError: # SLOW PATH: A decode error means this is likely a legacy encoding. # Let the library read the raw bytes and guess the correct encoding. results = charset_normalizer.from_path(filepath) match = results.best() if match is None: raise ValueError(f"Could not determine text encoding for {filepath}") return str(match) def safe_write(filepath, content, encoding=None): """ Write string content to a file using the specified or default encoding. Args: filepath: Path to the file to write. content: The string content to write. encoding: Encoding to use. Defaults to the module-level DEFAULT_ENCODING if not provided. Returns: The content that was written (for convenience / chaining). """ if encoding is None: encoding = DEFAULT_ENCODING with open(filepath, "w", encoding=encoding) as f: f.write(content) return content def safe_open(filepath, mode="r", encoding=None, **kwargs): """ Open a file with intelligent encoding handling. """ # Binary modes — pass through to built-in open() unchanged. if "b" in mode: return open(filepath, mode, **kwargs) # If the user explicitly provided an encoding, respect it unconditionally. if encoding is not None: return open(filepath, mode, encoding=encoding, **kwargs) # Write / append modes (with no explicit encoding) — use DEFAULT_ENCODING. # Note: We don't check for "r+" here because if a file is being read, # we must detect its existing encoding first so we don't corrupt it. if "w" in mode or "a" in mode or "x" in mode: return open(filepath, mode, encoding=DEFAULT_ENCODING, **kwargs) # Read modes (and read/write "r+" modes) — Auto-detect the encoding. try: # FAST PATH: Try UTF-8 first by opening and reading a tiny chunk with open(filepath, mode, encoding="utf-8", **kwargs) as f: f.read(1) # Test if it raises a DecodeError # If we got here, UTF-8 is valid. Return a fresh file object. return open(filepath, mode, encoding="utf-8", **kwargs) except UnicodeDecodeError: # SLOW PATH: Detect encoding using charset_normalizer results = charset_normalizer.from_path(filepath) match = results.best() if match is None: raise ValueError(f"Could not determine text encoding for {filepath}") # Return a real file object using the detected encoding return open(filepath, mode, encoding=match.encoding, **kwargs)

Back | FazBrowse Home | New Git URL