{"id":21905046,"url":"https://github.com/kenjyco/fs-helper","last_synced_at":"2026-01-27T20:37:56.140Z","repository":{"id":54609202,"uuid":"113215961","full_name":"kenjyco/fs-helper","owner":"kenjyco","description":"CLI helpers for filesystem and logging tasks","archived":false,"fork":false,"pushed_at":"2024-11-30T16:58:31.000Z","size":17,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-29T02:34:21.218Z","etag":null,"topics":["filesystem","kenjyco","logging","python"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kenjyco.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-12-05T18:03:28.000Z","updated_at":"2024-11-30T16:58:35.000Z","dependencies_parsed_at":"2022-08-13T21:20:44.813Z","dependency_job_id":null,"html_url":"https://github.com/kenjyco/fs-helper","commit_stats":null,"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kenjyco%2Ffs-helper","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kenjyco%2Ffs-helper/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kenjyco%2Ffs-helper/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kenjyco%2Ffs-helper/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kenjyco","download_url":"https://codeload.github.com/kenjyco/fs-helper/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248602316,"owners_count":21131616,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["filesystem","kenjyco","logging","python"],"created_at":"2024-11-28T16:27:56.287Z","updated_at":"2026-01-27T20:37:56.135Z","avatar_url":"https://github.com/kenjyco.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"A collection of essential filesystem and logging utilities designed to eliminate daily friction in Python development. `fs-helper` provides production-grade implementations of fundamental operations that developers need constantly but often implement inconsistently across projects.\n\nThis library embodies a philosophy of **invisible infrastructure** becoming so reliable and predictable that you forget you're using it. Every function is designed to solve a problem completely on first invocation, with zero-configuration defaults that work in production immediately while providing comprehensive control when needed.\n\n**Who benefits from this:**\n- **DevOps engineers** automating deployment and monitoring workflows\n- **Python developers** building command-line tools and scripts\n- **Data scientists** managing file-based workflows and logging\n- **Anyone** tired of reimplementing the same filesystem and logging patterns across projects\n\n**How it fits into your toolchain:**\n`fs-helper` serves as foundational infrastructure that other tools can depend on. It's designed to compose naturally with shell scripts, provide REPL-friendly exploration, and integrate seamlessly into existing Python projects without imposing architectural constraints.\n\n## Install\n\n```\npip install fs-helper\n```\n\n## QuickStart\n\n```python\nimport fs_helper as fh\n\n# Production-ready logging in one line\nlogger = fh.get_logger(__name__)\nlogger.info(\"Application started\")\n\n# Safe path handling that works everywhere\nlog_dir = fh.abspath(\"~/logs\")\n\n# Convert any text to a safe filename\nsafe_name = fh.lazy_filename(\"User Data: Report (2024)\")\n# Returns: \"User-Data--Report-2024\"\n\n# Git-aware path resolution\nrepo_root = fh.repopath()  # Returns None if not in a git repo\nif repo_root:\n    print(f\"Working in repository: {repo_root}\")\n\n# File monitoring for automation workflows\nfh.wait_for_write_age(\"output.log\", age=5, verbose=True)\nprint(\"Log file has been stable for 5 seconds, proceeding...\")\n```\n\n**What you gain:** Immediate access to bulletproof implementations of common operations with comprehensive error handling, cross-platform compatibility, and zero configuration overhead. Functions gracefully handle edge cases (missing directories, permission issues, invalid paths) so your code can focus on domain logic rather than infrastructure concerns.\n\n## API Overview\n\n### Core Path Operations\n\n- **`abspath(filepath)`** - Enhanced path normalization with tilde expansion\n  - `filepath`: Path string to normalize\n  - Returns: Absolute path as string\n  - Internal calls: None\n\n- **`strip_extension(filepath)`** - Remove file extension from path\n  - `filepath`: Path string\n  - Returns: Path without extension\n  - Internal calls: None\n\n- **`get_extension(filepath)`** - Extract file extension from path\n  - `filepath`: Path string\n  - Returns: Extension without leading dot\n  - Internal calls: None\n\n- **`repopath(filepath='')`** - Find git repository root for given path\n  - `filepath`: Path to check (defaults to current directory)\n  - Returns: Repository root path or `None` if not in a git repo\n  - Internal calls: `abspath()`\n\n### Production Logging\n\n- **`get_logger(module_name, logdir=DEFAULT_LOG_DIR, file_format='%(asctime)s - %(levelname)s - %(funcName)s: %(message)s', stream_format='%(asctime)s: %(message)s', file_level=logging.DEBUG, stream_level=logging.INFO)`** - Create production-ready logger with file and console output\n  - `module_name`: Logger identifier (typically `__name__`)\n  - `logdir`: Directory for log files (defaults to `~/logs`, falls back to `/tmp/logs`)\n  - `file_format`: Log format for file output (set to empty string to disable)\n  - `stream_format`: Log format for console output (set to empty string to disable)\n  - `file_level`: Logging level for file (accepts strings like 'info' or integers)\n  - `stream_level`: Logging level for console\n  - Returns: Configured logger instance with automatic directory creation and fallback strategies\n  - Internal calls: `abspath()`\n\n- **`get_logfile_from_logger(logger)`** - Extract log file path from logger instance\n  - `logger`: Logger object\n  - Returns: Path to log file or `None` if no file handler\n  - Internal calls: None\n\n- **`get_logger_filenames(logger)`** - Get all log file paths from logger\n  - `logger`: Logger object\n  - Returns: List of log file paths\n  - Internal calls: None\n\n### File Utilities\n\n- **`lazy_filename(text, ext='')`** - Convert arbitrary text to safe filenames\n  - `text`: Input text to convert (URLs, user input, API responses)\n  - `ext`: Optional extension to append\n  - Returns: Safe filename string with unsafe characters removed\n  - Internal calls: None\n\n- **`sha256sum(filepath)`** - Calculate SHA256 checksum of file\n  - `filepath`: Path to file\n  - Returns: Hexadecimal SHA256 digest\n  - Internal calls: `abspath()`\n\n### Package Analysis\n\n- **`get_local_package_info(dirpath, exception=True)`** - Extract packaging information from Python project directory\n  - `dirpath`: Path to project directory\n  - `exception`: If True, raise exception for non-Python projects\n  - Returns: Dictionary with keys: `setup.py_path`, `setup.py_content`, `pyproject.toml_path`, `pyproject.toml_content`\n  - Internal calls: `abspath()`\n\n### Monitoring and Coordination\n\n- **`wait_for_write_age(filepath, age=10, sleeptime=1, verbose=False)`** - Wait until file hasn't been modified for specified duration\n  - `filepath`: File to monitor\n  - `age`: Seconds since last write required\n  - `sleeptime`: Polling interval in seconds\n  - `verbose`: If True, print status messages\n  - Returns: `True` when condition met\n  - Internal calls: `abspath()`\n\n- **`wait_for_empty_directory(dirpath, sleeptime=1, verbose=False)`** - Wait until directory contains no files\n  - `dirpath`: Directory to monitor\n  - `sleeptime`: Polling interval in seconds\n  - `verbose`: If True, print status messages\n  - Returns: `True` when directory is empty\n  - Internal calls: `abspath()`\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkenjyco%2Ffs-helper","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkenjyco%2Ffs-helper","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkenjyco%2Ffs-helper/lists"}