48 Commits
Author SHA1 Message Date
xixu-me e0cf05dea0 Fix release workflow runners and Node 24 readiness
CI/CD / test (macos-latest, 3.12) (push) Waiting to run
CI/CD / test (macos-latest, 3.13) (push) Waiting to run
CI/CD / test (ubuntu-latest, 3.12) (push) Waiting to run
CI/CD / test (ubuntu-latest, 3.13) (push) Waiting to run
CI/CD / test (windows-latest, 3.12) (push) Waiting to run
CI/CD / test (windows-latest, 3.13) (push) Waiting to run
2026-03-17 17:10:36 +08:00
xixu-me a3350b1a27 Fix macOS CI path assertions for JSON output 2026-03-17 17:00:56 +08:00
xixu-me 0c52a51a15 Add machine-readable CLI output for desktop clients 2026-03-17 16:29:09 +08:00
xixu-me 96a13fd29a Merge pull request #20 from xixu-me/dependabot/github_actions/actions/upload-artifact-7
Bump actions/upload-artifact from 6 to 7
2026-03-01 13:54:11 +08:00
xixu-me 6ae689d945 Merge pull request #21 from xixu-me/dependabot/github_actions/actions/download-artifact-8
Bump actions/download-artifact from 7 to 8
2026-03-01 13:53:27 +08:00
dependabot[bot] 7ac5b57496 Bump actions/download-artifact from 7 to 8
Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 7 to 8.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/v7...v8)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-version: '8'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-01 04:56:40 +00:00
dependabot[bot] 4e0f04e10a Bump actions/upload-artifact from 6 to 7
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 6 to 7.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-01 04:56:35 +00:00
xixu-me cc98287944 Merge pull request #19 from xixu-me/dependabot/github_actions/actions/cache-5
Bump actions/cache from 4 to 5
2026-01-01 12:42:16 +08:00
xixu-me fa82ed95bb Merge pull request #18 from xixu-me/dependabot/github_actions/actions/upload-artifact-6
Bump actions/upload-artifact from 5 to 6
2026-01-01 12:41:27 +08:00
xixu-me 1878584aa0 Merge pull request #17 from xixu-me/dependabot/github_actions/actions/download-artifact-7
Bump actions/download-artifact from 6 to 7
2026-01-01 12:40:34 +08:00
dependabot[bot] 8048393440 Bump actions/cache from 4 to 5
Bumps [actions/cache](https://github.com/actions/cache) from 4 to 5.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-01-01 04:16:16 +00:00
dependabot[bot] 750fb36643 Bump actions/upload-artifact from 5 to 6
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 5 to 6.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-01-01 04:16:13 +00:00
dependabot[bot] 879c1166b4 Bump actions/download-artifact from 6 to 7
Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 6 to 7.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-01-01 04:16:07 +00:00
xixu-me aa1b218d4a Remove copyright year in cli.py 2026-01-01 11:44:30 +08:00
xixu-me 96fc060aeb Merge pull request #16 from xixu-me/docs-remove-copyright-year-5183375226831100009
Remove year from copyright info in READMEs and docs
2026-01-01 01:25:19 +08:00
google-labs-jules[bot] e2fca92d4b docs: remove year from copyright info in READMEs and docs
Removes the year "2025" from the copyright section in all README files (all languages) and docs/index.md, as requested. The copyright line now reads "Copyright (c) [Author]..." without a specific year.
2025-12-31 17:24:55 +00:00
xixu-me 08e3bdc849 Rename publish_docs.yml to publish-docs.yml 2026-01-01 01:10:33 +08:00
xixu-me a48631159f Merge pull request #15 from xixu-me/update-docs-and-copyright-11831253178374946146
Update docs copyright and sync installation instructions
2026-01-01 01:06:11 +08:00
google-labs-jules[bot] 1f4b77ffc7 Update copyright year to be dynamic and sync docs with README
- Update `docs/conf.py` to use `datetime` for dynamic copyright year.
- Update `docs/quickstart.md` to match installation instructions from `README.md`.
- Remove redundant installation details from `docs/index.md` and link to `quickstart`.
2025-12-31 17:05:26 +00:00
xixu-me 66fbe5852b Merge pull request #14 from xixu-me/dependabot/github_actions/actions/checkout-6
Bump actions/checkout from 5 to 6
2025-12-01 12:58:23 +08:00
dependabot[bot] 0eb219965a Bump actions/checkout from 5 to 6
Bumps [actions/checkout](https://github.com/actions/checkout) from 5 to 6.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-01 04:54:33 +00:00
xixu-me 13f14c847a Merge pull request #13 from xixu-me/claude/enhance-doc-seo-011CV4B1p2pxajncAxBbuMDb
Improve Documentation Search Engine Optimization
2025-11-12 23:23:22 +08:00
Claude 40c7724bcb Remove SEO_ENHANCEMENTS.md documentation file
- Delete SEO_ENHANCEMENTS.md to keep docs directory clean
- Remove from exclude_patterns in conf.py
- SEO enhancements remain in place and functional
2025-11-12 15:18:52 +00:00
Claude a316a8ac2e Fix documentation build: exclude SEO_ENHANCEMENTS.md and clean template formatting
- Add SEO_ENHANCEMENTS.md to exclude_patterns to prevent Sphinx warnings
- Clean up layout.html template formatting for better compatibility
- Split template tags across multiple lines for readability
2025-11-12 15:16:43 +00:00
Claude 9e741b6f8f Enhance documentation SEO with comprehensive optimizations
This commit implements extensive SEO improvements for the tzst documentation:

## Key Enhancements:

### 1. Sitemap & Crawling
- Add sphinx-sitemap extension for automatic XML sitemap generation
- Create robots.txt with crawler guidelines and sitemap reference
- Configure html_baseurl for proper sitemap generation

### 2. Structured Data (Schema.org)
- Add SoftwareApplication schema with detailed metadata
- Implement BreadcrumbList schema for all pages
- Add TechArticle schema for documentation pages
- Create FAQPage schema for quickstart with 5 common Q&As
- Add HowTo schema for examples page with step-by-step guide

### 3. Enhanced Meta Tags
- Add comprehensive Open Graph tags (og:site_name, og:locale)
- Enhance Twitter Card tags (twitter:site, twitter:creator)
- Add article meta tags for proper attribution
- Include rating and revisit-after tags

### 4. Page-Specific Optimization
- Add SEO meta tags to development.md
- Enhance all existing page meta tags
- Implement page-specific canonical URLs
- Add unique descriptions and keywords per page

### 5. Performance Optimization
- Add preconnect hints for external domains
- Add dns-prefetch for frequently accessed domains
- Configure html_copy_source=False to reduce duplicate content
- Hide unnecessary Sphinx links and branding

### 6. Documentation
- Create comprehensive SEO_ENHANCEMENTS.md documenting all changes
- Include best practices and monitoring recommendations
- Provide verification steps and future enhancement ideas

## Benefits:
- Improved search engine visibility and indexing
- Rich snippets in search results
- Better social media sharing previews
- Enhanced click-through rates
- Faster page discovery
- Professional appearance

## Files Modified:
- docs/conf.py - Sitemap config, meta tags, SEO settings
- docs/requirements.txt - Add sphinx-sitemap dependency
- docs/_templates/layout.html - Structured data, schemas
- docs/development.md - Add page-specific meta tags
- docs/_static/robots.txt - New file for crawler guidance
- docs/SEO_ENHANCEMENTS.md - New comprehensive documentation
2025-11-12 14:48:58 +00:00
xixu-me 988cdc0306 Update PyPI downloads badge links to PyPIStats
Changed the PyPI downloads badge links in all README translations and documentation from pypi.org to pypistats.org for more accurate download statistics.
2025-11-12 17:59:36 +08:00
xixu-me c872ca623a Add link to in-depth technical article in all READMEs
A link to the technical analysis article 'Deep Dive into tzst: A Modern Python Archiving Library Based on Zstandard' has been added to the introduction section of all language README files to provide readers with more detailed information about the project.
2025-11-09 20:00:02 +08:00
xixu-me d82f82bd5d Update install instructions and remove CLI notes
Added uv as a recommended installation method alongside pip in all README translations. Removed the note about downloading standalone binaries and using uvx for command line usage for brevity and consistency.
2025-11-05 12:24:19 +08:00
xixu-me 20cfb855c8 Merge pull request #10 from xixu-me/dependabot/github_actions/actions/upload-artifact-5
Bump actions/upload-artifact from 4 to 5
2025-11-01 12:37:47 +08:00
xixu-me 662d84da27 Merge pull request #11 from xixu-me/dependabot/github_actions/actions/download-artifact-6
Bump actions/download-artifact from 5 to 6
2025-11-01 12:37:31 +08:00
xixu-me 81c92e3a33 Merge pull request #12 from xixu-me/dependabot/github_actions/stefanzweifel/git-auto-commit-action-7
Bump stefanzweifel/git-auto-commit-action from 6 to 7
2025-11-01 12:37:14 +08:00
dependabot[bot] 37103bf869 Bump stefanzweifel/git-auto-commit-action from 6 to 7
Bumps [stefanzweifel/git-auto-commit-action](https://github.com/stefanzweifel/git-auto-commit-action) from 6 to 7.
- [Release notes](https://github.com/stefanzweifel/git-auto-commit-action/releases)
- [Changelog](https://github.com/stefanzweifel/git-auto-commit-action/blob/master/CHANGELOG.md)
- [Commits](https://github.com/stefanzweifel/git-auto-commit-action/compare/v6...v7)

---
updated-dependencies:
- dependency-name: stefanzweifel/git-auto-commit-action
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-01 04:15:14 +00:00
dependabot[bot] 7c4459dc5a Bump actions/download-artifact from 5 to 6
Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 5 to 6.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-01 04:15:12 +00:00
dependabot[bot] 1f3e9ef76e Bump actions/upload-artifact from 4 to 5
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4 to 5.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-01 04:15:09 +00:00
xixu-me 5ecb10411f Update compression level error message in test
Adjusted the expected error message in the test for invalid compression level to match the new format, specifying that the value must be an integer between 1 and 22.
2025-10-04 20:36:23 +08:00
xixu-me 2cb2b9eaa7 Fix regex in compression level validation test
Updated the regex pattern in the compression level validation test to escape the dot character, ensuring correct matching of invalid input '1.5'.
2025-10-03 22:05:22 +08:00
xixu-me e5ad0336f3 Add CLAUDE.md with contributor guidance
Introduces CLAUDE.md to provide architecture overview, development commands, code quality checks, build instructions, key features, and testing patterns for the tzst Python library. This file is intended to guide contributors and AI assistants working with the repository.
2025-10-03 21:37:44 +08:00
xixu-me 6442ba91f3 Merge pull request #9 from xixu-me/dependabot/github_actions/actions/setup-python-6
Bump actions/setup-python from 5 to 6
2025-10-03 12:26:45 +08:00
dependabot[bot] e5f6fd2bc4 Bump actions/setup-python from 5 to 6
Bumps [actions/setup-python](https://github.com/actions/setup-python) from 5 to 6.
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](https://github.com/actions/setup-python/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/setup-python
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-01 04:19:18 +00:00
xixu-me ff6c321f0d Merge pull request #8 from xixu-me/dependabot/github_actions/actions/download-artifact-5
Bump actions/download-artifact from 4 to 5
2025-09-01 18:51:25 +08:00
xixu-me 1fc8a85c64 Merge pull request #7 from xixu-me/dependabot/github_actions/actions/checkout-5
Bump actions/checkout from 4 to 5
2025-09-01 18:50:40 +08:00
dependabot[bot] 0aae913613 Bump actions/download-artifact from 4 to 5
Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 4 to 5.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-01 09:55:01 +00:00
dependabot[bot] 4987bcd468 Bump actions/checkout from 4 to 5
Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 5.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-01 09:32:46 +00:00
xixu-me fd11edd877 Add funding options to FUNDING.yml 2025-08-24 17:44:18 +08:00
xixu-me aca7b5f42c Merge pull request #6 from xixu-me/dependabot/github_actions/stefanzweifel/git-auto-commit-action-6
Bump stefanzweifel/git-auto-commit-action from 5 to 6
2025-07-04 17:17:06 +08:00
dependabot[bot] e454f79e18 Bump stefanzweifel/git-auto-commit-action from 5 to 6
Bumps [stefanzweifel/git-auto-commit-action](https://github.com/stefanzweifel/git-auto-commit-action) from 5 to 6.
- [Release notes](https://github.com/stefanzweifel/git-auto-commit-action/releases)
- [Changelog](https://github.com/stefanzweifel/git-auto-commit-action/blob/master/CHANGELOG.md)
- [Commits](https://github.com/stefanzweifel/git-auto-commit-action/compare/v5...v6)

---
updated-dependencies:
- dependency-name: stefanzweifel/git-auto-commit-action
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-01 07:25:41 +00:00
xixu-me bcfb299bfb Add SECURITY.md with security policy and best practices
Introduces a SECURITY.md file detailing supported versions, security features, best practices for safe archive extraction, vulnerability reporting procedures, and development security practices for the tzst project.
2025-06-17 21:16:31 +08:00
xixu-me 171c00c8ce Create CODE_OF_CONDUCT.md 2025-06-17 21:04:08 +08:00
26 changed files with 1351 additions and 238 deletions

No files matched your search

+1
View File
@@ -1 +1,2 @@
custom: https://xi-xu.me/#sponsorships
buy_me_a_coffee: xixu
+21 -17
View File
@@ -1,5 +1,8 @@
name: CI/CD
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
on:
push:
branches: [main, develop]
@@ -31,10 +34,10 @@ jobs:
python-version: ["3.12", "3.13"]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}
@@ -68,10 +71,10 @@ jobs:
contents: read
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Set up Python
uses: actions/setup-python@v5
uses: actions/setup-python@v6
with:
python-version: "3.12"
@@ -87,7 +90,7 @@ jobs:
run: twine check dist/*
- name: Upload build artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: dist
path: dist/
@@ -104,7 +107,7 @@ jobs:
steps:
- name: Download build artifacts
uses: actions/download-artifact@v4
uses: actions/download-artifact@v8
with:
name: dist
path: dist/
@@ -141,21 +144,21 @@ jobs:
python-version: "3.12"
cross_compile: true
# macOS architectures
- os: macos-13 # Intel-based runner
- os: macos-15-intel # Intel-based runner
os_name: darwin
arch: amd64
python-version: "3.12"
- os: macos-14 # ARM-based runner (M1/M2)
- os: macos-15 # ARM-based runner (M1/M2)
os_name: darwin
arch: arm64
python-version: "3.12"
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}
@@ -194,7 +197,7 @@ jobs:
}
- name: Build binary for ARM64 on macOS
if: matrix.os == 'macos-14' && matrix.arch == 'arm64'
if: matrix.os_name == 'darwin' && matrix.arch == 'arm64'
run: |
python -m PyInstaller --onefile --name tzst --console --target-arch arm64 --icon docs/_static/favicon.ico src/main.py
@@ -245,7 +248,7 @@ jobs:
Compress-Archive -Path * -DestinationPath ../tzst-${{ steps.version.outputs.version }}-${{ matrix.os_name }}-${{ matrix.arch }}.zip
- name: Upload binary artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: binary-${{ matrix.os_name }}-${{ matrix.arch }}
path: tzst-${{ steps.version.outputs.version }}-${{ matrix.os_name }}-${{ matrix.arch }}.zip
@@ -258,7 +261,7 @@ jobs:
contents: write
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Extract version from tag
id: version
@@ -267,7 +270,7 @@ jobs:
echo "version=$VERSION" >> $GITHUB_OUTPUT
- name: Download all binary artifacts
uses: actions/download-artifact@v4
uses: actions/download-artifact@v8
with:
pattern: binary-*
merge-multiple: true
@@ -311,12 +314,13 @@ jobs:
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
with:
fetch-depth: 0
ref: main
- name: Set up Python
uses: actions/setup-python@v5
uses: actions/setup-python@v6
with:
python-version: "3.12"
@@ -351,7 +355,7 @@ jobs:
git config --local user.name "GitHub Action"
- name: Commit and push changes
uses: stefanzweifel/git-auto-commit-action@v5
uses: stefanzweifel/git-auto-commit-action@v7
with:
commit_message: "Update badges [skip ci]"
file_pattern: README.md
@@ -26,17 +26,17 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Set up Python
uses: actions/setup-python@v5
uses: actions/setup-python@v6
with:
python-version: "3.12"
- name: Cache pip dependencies
uses: actions/cache@v4
uses: actions/cache@v5
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-docs-${{ hashFiles('docs/requirements.txt') }}
@@ -56,7 +56,7 @@ jobs:
python -m sphinx -b html . _build -W --keep-going
- name: Upload documentation artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: documentation
path: docs/_build/
@@ -80,10 +80,10 @@ jobs:
contents: read
steps:
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Set up Python
uses: actions/setup-python@v5
uses: actions/setup-python@v6
with:
python-version: "3.12"
+75
View File
@@ -0,0 +1,75 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Overview
tzst is a next-generation Python library for modern archive management using Zstandard compression. It provides both a Python API and a command-line interface for creating, extracting, listing, and testing .tzst/.tar.zst archives. The library focuses on performance, security, and reliability with features like atomic operations, streaming mode for large archives, and security filtering for extraction.
## Architecture
The codebase is structured as follows:
- `src/tzst/core.py` - Core implementation containing the `TzstArchive` class and convenience functions
- `src/tzst/cli.py` - Command-line interface built with argparse
- `src/tzst/exceptions.py` - Custom exception classes
- `src/tzst/__init__.py` - Public API exports
The library wraps Python's tarfile module with Zstandard compression/decompression streams. It supports both buffered and streaming modes for memory efficiency with large archives.
## Commands
### Development Environment
```bash
# Development installation with dev dependencies
pip install -e .[dev]
# Run tests
pytest
pytest --cov=tzst --cov-report=html # with coverage
```
### Code Quality
```bash
# Check code quality
ruff check src tests
# Format code
ruff format src tests
```
### Building and Distribution
```bash
# Build package
python -m build
# Upload to PyPI (requires credentials)
python -m twine upload dist/*
```
## Key Features to Consider
1. **Streaming Mode**: For archives >100MB, always recommend using streaming mode to reduce memory usage
2. **Security Filters**: Use 'data' filter by default for extraction to prevent path traversal attacks
3. **Atomic Operations**: Archive creation uses temporary files by default for safety
4. **Conflict Resolution**: During extraction, implement proper file conflict resolution strategies
5. **Compression Levels**: Default to level 3 unless the user has specific performance/size requirements
## Testing Patterns
The project uses pytest with comprehensive test coverage including:
- Unit tests in `tests/unit/`
- Integration tests in `tests/integration/`
- CLI-specific tests in `tests/cli/`
- Edge case handling in `tests/test_core_edge_cases.py`
## Common Tasks
- To add functionality: work in `src/tzst/core.py` following existing patterns
- To modify CLI behavior: update `src/tzst/cli.py` and adjust argument parsing as needed
- To add new command: extend `create_parser()` in cli.py and add appropriate handler function
- For error handling: use appropriate TzstError subclasses from exceptions.py
+128
View File
@@ -0,0 +1,128 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
i@xi-xu.me.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.
+12 -4
View File
@@ -6,7 +6,7 @@
[![CodeQL](https://github.com/xixu-me/tzst/actions/workflows/github-code-scanning/codeql/badge.svg)](https://github.com/xixu-me/tzst/actions/workflows/github-code-scanning/codeql)
[![CI/CD](https://github.com/xixu-me/tzst/actions/workflows/ci.yml/badge.svg)](https://github.com/xixu-me/tzst/actions/workflows/ci.yml)
[![PyPI - Version](https://img.shields.io/pypi/v/tzst)](https://pypi.org/project/tzst/)
[![PyPI - Downloads](https://img.shields.io/pypi/dm/tzst)](https://pypi.org/project/tzst/)
[![PyPI - Downloads](https://img.shields.io/pypi/dm/tzst)](https://pypistats.org/packages/tzst)
[![GitHub License](https://img.shields.io/github/license/xixu-me/tzst)](LICENSE)
[![Sponsor](https://img.shields.io/badge/Sponsor-violet)](https://xi-xu.me/#sponsorships)
[![Documentation](https://img.shields.io/badge/Documentation-blue)](https://tzst.xi-xu.me)
@@ -17,6 +17,8 @@
**tzst** هي مكتبة Python من الجيل التالي مُطورة لإدارة الأرشيف الحديث، تستفيد من ضغط Zstandard المتطور لتقديم أداء وأمان وموثوقية فائقة. مبنية حصرياً لـ Python 3.12+، هذا الحل على مستوى المؤسسة يدمج العمليات الذرية وكفاءة التدفق ووواجهة برمجة التطبيقات المصممة بعناية فائقة لإعادة تعريف كيفية تعامل المطورين مع أرشيف `.tzst`/`.tar.zst` في بيئات الإنتاج. 🚀
تم نشر مقال التحليل الفني المتعمق: **[Deep Dive into tzst: A Modern Python Archiving Library Based on Zstandard](https://blog.xi-xu.me/2025/11/01/deep-dive-into-tzst-en.html)**.
## ✨ الميزات
- **🗜️ ضغط عالي**: ضغط Zstandard لنسب ضغط وسرعة ممتازة
@@ -65,10 +67,18 @@
### 📦 من PyPI
استخدام pip:
```bash
pip install tzst
```
أو استخدام uv (موصى به):
```bash
uv tool install tzst
```
### 🔧 من المصدر
```bash
@@ -91,8 +101,6 @@ pip install -e .[dev]
### 💻 استخدام سطر الأوامر
> **ملاحظة**: تحميل [الملف الثنائي المستقل](#من-إصدارات-github) للحصول على أفضل أداء وعدم الاعتماد على Python. بدلاً من ذلك، استخدم `uvx tzst` للتشغيل دون تثبيت. راجع [وثائق uv](https://docs.astral.sh/uv/) للتفاصيل.
```bash
# 📁 إنشاء أرشيف
tzst a archive.tzst file1.txt file2.txt directory/
@@ -514,7 +522,7 @@ python -m pytest tests/
## 📄 الترخيص
حقوق النشر &copy; 2025 [شي شو](https://xi-xu.me). جميع الحقوق محفوظة.
حقوق النشر &copy; [شي شو](https://xi-xu.me). جميع الحقوق محفوظة.
مرخص تحت ترخيص [BSD 3-Clause](LICENSE).
+12 -4
View File
@@ -6,7 +6,7 @@
[![CodeQL](https://github.com/xixu-me/tzst/actions/workflows/github-code-scanning/codeql/badge.svg)](https://github.com/xixu-me/tzst/actions/workflows/github-code-scanning/codeql)
[![CI/CD](https://github.com/xixu-me/tzst/actions/workflows/ci.yml/badge.svg)](https://github.com/xixu-me/tzst/actions/workflows/ci.yml)
[![PyPI - Version](https://img.shields.io/pypi/v/tzst)](https://pypi.org/project/tzst/)
[![PyPI - Downloads](https://img.shields.io/pypi/dm/tzst)](https://pypi.org/project/tzst/)
[![PyPI - Downloads](https://img.shields.io/pypi/dm/tzst)](https://pypistats.org/packages/tzst)
[![GitHub License](https://img.shields.io/github/license/xixu-me/tzst)](LICENSE)
[![Sponsor](https://img.shields.io/badge/Sponsor-violet)](https://xi-xu.me/#sponsorships)
[![Documentation](https://img.shields.io/badge/Documentation-blue)](https://tzst.xi-xu.me)
@@ -15,6 +15,8 @@
**tzst** ist eine Python-Bibliothek der nächsten Generation, die für modernes Archivmanagement entwickelt wurde und hochmoderne Zstandard-Komprimierung nutzt, um überlegene Leistung, Sicherheit und Zuverlässigkeit zu bieten. Ausschließlich für Python 3.12+ entwickelt, kombiniert diese Unternehmenslösung atomare Operationen, Streaming-Effizienz und eine sorgfältig erstellte API, um die Art und Weise neu zu definieren, wie Entwickler mit `.tzst`/`.tar.zst`-Archiven in Produktionsumgebungen umgehen. 🚀
Veröffentlichter ausführlicher technischer Analyseartikel: **[Deep Dive into tzst: A Modern Python Archiving Library Based on Zstandard](https://blog.xi-xu.me/2025/11/01/deep-dive-into-tzst-en.html)**.
## ✨ Funktionen
- **🗜️ Hohe Komprimierung**: Zstandard-Komprimierung für ausgezeichnete Komprimierungsraten und Geschwindigkeit
@@ -63,10 +65,18 @@ Lade eigenständige ausführbare Dateien herunter, die keine Python-Installation
### 📦 Von PyPI
Mit pip:
```bash
pip install tzst
```
Oder mit uv (empfohlen):
```bash
uv tool install tzst
```
### 🔧 Aus dem Quellcode
```bash
@@ -89,8 +99,6 @@ pip install -e .[dev]
### 💻 Kommandozeilennutzung
> **Hinweis**: Lade die [eigenständige Binärdatei](#von-github-releases) für beste Leistung und keine Python-Abhängigkeit herunter. Alternativ verwende `uvx tzst` für die Ausführung ohne Installation. Siehe [uv-Dokumentation](https://docs.astral.sh/uv/) für Details.
```bash
# 📁 Archiv erstellen
tzst a archive.tzst file1.txt file2.txt directory/
@@ -512,6 +520,6 @@ python -m pytest tests/
## 📄 Lizenz
Urheberrecht &copy; 2025 [Xi Xu](https://xi-xu.me). Alle Rechte vorbehalten.
Urheberrecht &copy; [Xi Xu](https://xi-xu.me). Alle Rechte vorbehalten.
Lizenziert unter der [BSD 3-Clause](LICENSE) Lizenz.
+12 -4
View File
@@ -6,7 +6,7 @@
[![CodeQL](https://github.com/xixu-me/tzst/actions/workflows/github-code-scanning/codeql/badge.svg)](https://github.com/xixu-me/tzst/actions/workflows/github-code-scanning/codeql)
[![CI/CD](https://github.com/xixu-me/tzst/actions/workflows/ci.yml/badge.svg)](https://github.com/xixu-me/tzst/actions/workflows/ci.yml)
[![PyPI - Version](https://img.shields.io/pypi/v/tzst)](https://pypi.org/project/tzst/)
[![PyPI - Downloads](https://img.shields.io/pypi/dm/tzst)](https://pypi.org/project/tzst/)
[![PyPI - Downloads](https://img.shields.io/pypi/dm/tzst)](https://pypistats.org/packages/tzst)
[![GitHub License](https://img.shields.io/github/license/xixu-me/tzst)](LICENSE)
[![Sponsor](https://img.shields.io/badge/Sponsor-violet)](https://xi-xu.me/#sponsorships)
[![Documentation](https://img.shields.io/badge/Documentation-blue)](https://tzst.xi-xu.me)
@@ -15,6 +15,8 @@
**tzst** es una biblioteca de Python de próxima generación diseñada para la gestión moderna de archivos, aprovechando la compresión Zstandard de vanguardia para ofrecer un rendimiento, seguridad y fiabilidad superiores. Construida exclusivamente para Python 3.12+, esta solución de nivel empresarial combina operaciones atómicas, eficiencia de transmisión (streaming) y una API meticulosamente elaborada para redefinir cómo los desarrolladores manejan los archivos `.tzst`/`.tar.zst` en entornos de producción. 🚀
Artículo de análisis técnico en profundidad publicado: **[Deep Dive into tzst: A Modern Python Archiving Library Based on Zstandard](https://blog.xi-xu.me/2025/11/01/deep-dive-into-tzst-en.html)**.
## ✨ Características
- **🗜️ Alta Compresión**: Compresión Zstandard para excelentes ratios de compresión y velocidad.
@@ -63,10 +65,18 @@ Descarga ejecutables independientes que no requieren instalación de Python:
### 📦 Desde PyPI
Usando pip:
```
pip install tzst
```
O usando uv (recomendado):
```
uv tool install tzst
```
### 🔧 Desde el Código Fuente
```
@@ -89,8 +99,6 @@ pip install -e .[dev]
### 💻 Uso desde la Línea de Comandos
> **Nota**: Descarga el [binario independiente](#desde-los-lanzamientos-de-github) para obtener el mejor rendimiento y no depender de Python. Alternativamente, usa `uvx tzst` para ejecutar sin instalación. Consulta la [documentación de uv](https://docs.astral.sh/uv/) para más detalles.
```
# 📁 Crear un archivo
tzst a archivo.tzst archivo1.txt archivo2.txt directorio/
@@ -512,6 +520,6 @@ python -m pytest tests/
## 📄 Licencia
Copyright &copy; 2025 [Xi Xu](https://xi-xu.me). Todos los derechos reservados.
Copyright &copy; [Xi Xu](https://xi-xu.me). Todos los derechos reservados.
Licenciado bajo la licencia [BSD 3-Clause](LICENSE).
+12 -4
View File
@@ -6,7 +6,7 @@
[![CodeQL](https://github.com/xixu-me/tzst/actions/workflows/github-code-scanning/codeql/badge.svg)](https://github.com/xixu-me/tzst/actions/workflows/github-code-scanning/codeql)
[![CI/CD](https://github.com/xixu-me/tzst/actions/workflows/ci.yml/badge.svg)](https://github.com/xixu-me/tzst/actions/workflows/ci.yml)
[![PyPI - Version](https://img.shields.io/pypi/v/tzst)](https://pypi.org/project/tzst/)
[![PyPI - Downloads](https://img.shields.io/pypi/dm/tzst)](https://pypi.org/project/tzst/)
[![PyPI - Downloads](https://img.shields.io/pypi/dm/tzst)](https://pypistats.org/packages/tzst)
[![GitHub License](https://img.shields.io/github/license/xixu-me/tzst)](LICENSE)
[![Sponsor](https://img.shields.io/badge/Sponsor-violet)](https://xi-xu.me/#sponsorships)
[![Documentation](https://img.shields.io/badge/Documentation-blue)](https://tzst.xi-xu.me)
@@ -15,6 +15,8 @@
**tzst** est une bibliothèque Python de nouvelle génération conçue pour la gestion moderne d'archives, exploitant la compression Zstandard de pointe pour offrir des performances, une sécurité et une fiabilité supérieures. Construite exclusivement pour Python 3.12+, cette solution de niveau entreprise combine des opérations atomiques, l'efficacité du streaming et une API méticuleusement conçue pour redéfinir la façon dont les développeurs gèrent les archives `.tzst`/`.tar.zst` dans les environnements de production. 🚀
Article d'analyse technique approfondie publié : **[Deep Dive into tzst: A Modern Python Archiving Library Based on Zstandard](https://blog.xi-xu.me/2025/11/01/deep-dive-into-tzst-en.html)**.
## ✨ Fonctionnalités
- **🗜️ Compression élevée** : Compression Zstandard pour d'excellents taux de compression et une vitesse remarquable
@@ -63,10 +65,18 @@ Téléchargez des exécutables autonomes qui ne nécessitent pas d'installation
### 📦 Depuis PyPI
Avec pip :
```bash
pip install tzst
```
Ou avec uv (recommandé) :
```bash
uv tool install tzst
```
### 🔧 Depuis le code source
```bash
@@ -89,8 +99,6 @@ pip install -e .[dev]
### 💻 Utilisation en ligne de commande
> **Note** : Téléchargez le [binaire autonome](#depuis-les-releases-github) pour les meilleures performances et aucune dépendance Python. Alternativement, utilisez `uvx tzst` pour exécuter sans installation. Voir la [documentation uv](https://docs.astral.sh/uv/) pour les détails.
```bash
# 📁 Créer une archive
tzst a archive.tzst file1.txt file2.txt directory/
@@ -512,6 +520,6 @@ python -m pytest tests/
## 📄 Licence
Droits d'auteur &copy; 2025 [Xi Xu](https://xi-xu.me). Tous droits réservés.
Droits d'auteur &copy; [Xi Xu](https://xi-xu.me). Tous droits réservés.
Sous licence [BSD 3-Clause](LICENSE).
+12 -4
View File
@@ -6,7 +6,7 @@
[![CodeQL](https://github.com/xixu-me/tzst/actions/workflows/github-code-scanning/codeql/badge.svg)](https://github.com/xixu-me/tzst/actions/workflows/github-code-scanning/codeql)
[![CI/CD](https://github.com/xixu-me/tzst/actions/workflows/ci.yml/badge.svg)](https://github.com/xixu-me/tzst/actions/workflows/ci.yml)
[![PyPI - Version](https://img.shields.io/pypi/v/tzst)](https://pypi.org/project/tzst/)
[![PyPI - Downloads](https://img.shields.io/pypi/dm/tzst)](https://pypi.org/project/tzst/)
[![PyPI - Downloads](https://img.shields.io/pypi/dm/tzst)](https://pypistats.org/packages/tzst)
[![GitHub License](https://img.shields.io/github/license/xixu-me/tzst)](LICENSE)
[![Sponsor](https://img.shields.io/badge/Sponsor-violet)](https://xi-xu.me/#sponsorships)
[![Documentation](https://img.shields.io/badge/Documentation-blue)](https://tzst.xi-xu.me)
@@ -15,6 +15,8 @@
**tzst** は、最新の Zstandard 圧縮技術を活用した次世代 Python ライブラリで、優れたパフォーマンス、セキュリティ、信頼性を提供するモダンなアーカイブ管理を実現します。 Python 3.12+ 専用に構築されたこのエンタープライズグレードのソリューションは、アトミック操作、ストリーミング効率、厳密に設計された API を組み合わせ、本番環境における `.tzst` / `.tar.zst` アーカイブの扱い方を再定義します。 🚀
技術詳細分析記事が公開されました: **[Deep Dive into tzst: A Modern Python Archiving Library Based on Zstandard](https://blog.xi-xu.me/2025/11/01/deep-dive-into-tzst-en.html)**。
## ✨ 特徴
- **🗜️ 高圧縮率**: Zstandard 圧縮による優れた圧縮率と速度
@@ -63,10 +65,18 @@ Python インストール不要のスタンドアロン実行ファイルをダ
### 📦 PyPI から
pip を使用:
```bash
pip install tzst
```
または uv を使用(推奨):
```bash
uv tool install tzst
```
### 🔧 ソースから
```bash
@@ -89,8 +99,6 @@ pip install -e .[dev]
### 💻 コマンドラインの使い方
> **注**: 最高のパフォーマンスと Python 依存なしを実現するには[スタンドアロンバイナリ](#github-リリースから)をダウンロードしてください。または、インストールなしで実行するには `uvx tzst` を使用します。詳細は [uv ドキュメント](https://docs.astral.sh/uv/)を参照。
```bash
# 📁 アーカイブ作成
tzst a archive.tzst file1.txt file2.txt directory/
@@ -512,6 +520,6 @@ python -m pytest tests/
## 📄 ライセンス
著作権 &copy; 2025 [Xi Xu](https://xi-xu.me)。全著作権を保留します。
著作権 &copy; [Xi Xu](https://xi-xu.me)。全著作権を保留します。
[BSD 3-Clause](LICENSE) ライセンスのもとで公開されています。
+12 -4
View File
@@ -6,7 +6,7 @@
[![CodeQL](https://github.com/xixu-me/tzst/actions/workflows/github-code-scanning/codeql/badge.svg)](https://github.com/xixu-me/tzst/actions/workflows/github-code-scanning/codeql)
[![CI/CD](https://github.com/xixu-me/tzst/actions/workflows/ci.yml/badge.svg)](https://github.com/xixu-me/tzst/actions/workflows/ci.yml)
[![PyPI - Version](https://img.shields.io/pypi/v/tzst)](https://pypi.org/project/tzst/)
[![PyPI - Downloads](https://img.shields.io/pypi/dm/tzst)](https://pypi.org/project/tzst/)
[![PyPI - Downloads](https://img.shields.io/pypi/dm/tzst)](https://pypistats.org/packages/tzst)
[![GitHub License](https://img.shields.io/github/license/xixu-me/tzst)](LICENSE)
[![Sponsor](https://img.shields.io/badge/Sponsor-violet)](https://xi-xu.me/#sponsorships)
[![Documentation](https://img.shields.io/badge/Documentation-blue)](https://tzst.xi-xu.me)
@@ -15,6 +15,8 @@
**tzst**는 최신 Zstandard 압축 기술을 활용하여 우수한 성능, 보안 및 신뢰성을 제공하는 차세대 Python 라이브러리입니다. Python 3.12+ 전용으로 제작된 이 엔터프라이즈급 솔루션은 원자적 작업, 스트리밍 효율성 및 정교하게 설계된 API를 결합하여 `.tzst`/`.tar.zst` 아카이브를 프로덕션 환경에서 처리하는 방식을 재정의합니다. 🚀
심층 기술 분석 기사가 게시되었습니다: **[Deep Dive into tzst: A Modern Python Archiving Library Based on Zstandard](https://blog.xi-xu.me/2025/11/01/deep-dive-into-tzst-en.html)**.
## ✨ 기능
- **🗜️ 고압축률**: 우수한 압축률과 속도를 위한 Zstandard 압축
@@ -63,10 +65,18 @@ Python 설치가 필요 없는 독립형 실행 파일 다운로드:
### 📦 PyPI에서
pip 사용:
```bash
pip install tzst
```
또는 uv 사용 (권장):
```bash
uv tool install tzst
```
### 🔧 소스에서
```bash
@@ -89,8 +99,6 @@ pip install -e .[dev]
### 💻 명령줄 사용법
> **참고**: 최상의 성능과 Python 의존성 없이 사용하려면 [독립형 바이너리](#github-릴리스에서)를 다운로드하세요. 또는 설치 없이 실행하려면 `uvx tzst`를 사용하세요. 자세한 내용은 [uv 문서](https://docs.astral.sh/uv/) 참조.
```bash
# 📁 아카이브 생성
tzst a archive.tzst file1.txt file2.txt directory/
@@ -512,6 +520,6 @@ python -m pytest tests/
## 📄 라이선스
저작권 &copy; 2025 [시 쉬](https://xi-xu.me). 모든 권리 보유.
저작권 &copy; [시 쉬](https://xi-xu.me). 모든 권리 보유.
[BSD 3-Clause](LICENSE) 라이선스로 사용이 허가되었습니다.
+12 -4
View File
@@ -6,7 +6,7 @@
[![CodeQL](https://github.com/xixu-me/tzst/actions/workflows/github-code-scanning/codeql/badge.svg)](https://github.com/xixu-me/tzst/actions/workflows/github-code-scanning/codeql)
[![CI/CD](https://github.com/xixu-me/tzst/actions/workflows/ci.yml/badge.svg)](https://github.com/xixu-me/tzst/actions/workflows/ci.yml)
[![PyPI - Version](https://img.shields.io/pypi/v/tzst)](https://pypi.org/project/tzst/)
[![PyPI - Downloads](https://img.shields.io/pypi/dm/tzst)](https://pypi.org/project/tzst/)
[![PyPI - Downloads](https://img.shields.io/pypi/dm/tzst)](https://pypistats.org/packages/tzst)
[![GitHub License](https://img.shields.io/github/license/xixu-me/tzst)](LICENSE)
[![Sponsor](https://img.shields.io/badge/Sponsor-violet)](https://xi-xu.me/#sponsorships)
[![Documentation](https://img.shields.io/badge/Documentation-blue)](https://tzst.xi-xu.me)
@@ -15,6 +15,8 @@
**tzst** is a next-generation Python library engineered for modern archive management, leveraging cutting-edge Zstandard compression to deliver superior performance, security, and reliability. Built exclusively for Python 3.12+, this enterprise-grade solution combines atomic operations, streaming efficiency, and a meticulously crafted API to redefine how developers handle `.tzst`/`.tar.zst` archives in production environments. 🚀
In-depth technical analysis article published: **[Deep Dive into tzst: A Modern Python Archiving Library Based on Zstandard](https://blog.xi-xu.me/2025/11/01/deep-dive-into-tzst-en.html)**.
## ✨ Features
- **🗜️ High Compression**: Zstandard compression for excellent compression ratios and speed
@@ -63,10 +65,18 @@ Download standalone executables that don't require Python installation:
### 📦 From PyPI
Using pip:
```bash
pip install tzst
```
Or using uv (recommended):
```bash
uv tool install tzst
```
### 🔧 From Source
```bash
@@ -89,8 +99,6 @@ pip install -e .[dev]
### 💻 Command Line Usage
> **Note**: Download the [standalone binary](#from-github-releases) for the best performance and no Python dependency. Alternatively, use `uvx tzst` for running without installation. See [uv documentation](https://docs.astral.sh/uv/) for details.
```bash
# 📁 Create an archive
tzst a archive.tzst file1.txt file2.txt directory/
@@ -512,6 +520,6 @@ python -m pytest tests/
## 📄 License
Copyright &copy; 2025 [Xi Xu](https://xi-xu.me). All rights reserved.
Copyright &copy; [Xi Xu](https://xi-xu.me). All rights reserved.
Licensed under the [BSD 3-Clause](LICENSE) license.
+12 -4
View File
@@ -6,7 +6,7 @@
[![CodeQL](https://github.com/xixu-me/tzst/actions/workflows/github-code-scanning/codeql/badge.svg)](https://github.com/xixu-me/tzst/actions/workflows/github-code-scanning/codeql)
[![CI/CD](https://github.com/xixu-me/tzst/actions/workflows/ci.yml/badge.svg)](https://github.com/xixu-me/tzst/actions/workflows/ci.yml)
[![PyPI - Version](https://img.shields.io/pypi/v/tzst)](https://pypi.org/project/tzst/)
[![PyPI - Downloads](https://img.shields.io/pypi/dm/tzst)](https://pypi.org/project/tzst/)
[![PyPI - Downloads](https://img.shields.io/pypi/dm/tzst)](https://pypistats.org/packages/tzst)
[![GitHub License](https://img.shields.io/github/license/xixu-me/tzst)](LICENSE)
[![Sponsor](https://img.shields.io/badge/Sponsor-violet)](https://xi-xu.me/#sponsorships)
[![Documentation](https://img.shields.io/badge/Documentation-blue)](https://tzst.xi-xu.me)
@@ -15,6 +15,8 @@
**tzst** é uma biblioteca Python de próxima geração projetada para gerenciamento moderno de arquivos, aproveitando a compressão Zstandard de ponta para oferecer desempenho, segurança e confiabilidade superiores. Construída exclusivamente para Python 3.12+, esta solução corporativa combina operações atômicas, eficiência de streaming e uma API meticulosamente elaborada para redefinir como os desenvolvedores lidam com arquivos `.tzst`/`.tar.zst` em ambientes de produção. 🚀
Artigo de análise técnica aprofundada publicado: **[Deep Dive into tzst: A Modern Python Archiving Library Based on Zstandard](https://blog.xi-xu.me/2025/11/01/deep-dive-into-tzst-en.html)**.
## ✨ Recursos
- **🗜️ Alta Compressão**: Compressão Zstandard para excelentes taxas de compressão e velocidade
@@ -63,10 +65,18 @@ Baixe executáveis independentes que não requerem instalação do Python:
### 📦 Do PyPI
Usando pip:
```bash
pip install tzst
```
Ou usando uv (recomendado):
```bash
uv tool install tzst
```
### 🔧 Do Código Fonte
```bash
@@ -89,8 +99,6 @@ pip install -e .[dev]
### 💻 Uso da Linha de Comando
> **Nota**: Baixe o [binário independente](#dos-releases-do-github) para melhor desempenho e sem dependência do Python. Alternativamente, use `uvx tzst` para executar sem instalação. Veja a [documentação do uv](https://docs.astral.sh/uv/) para detalhes.
```bash
# 📁 Criar um arquivo
tzst a archive.tzst file1.txt file2.txt directory/
@@ -512,6 +520,6 @@ python -m pytest tests/
## 📄 Licença
Direitos autorais &copy; 2025 [Xi Xu](https://xi-xu.me). Todos os direitos reservados.
Direitos autorais &copy; [Xi Xu](https://xi-xu.me). Todos os direitos reservados.
Licenciado sob a licença [BSD 3-Clause](LICENSE).
+12 -4
View File
@@ -6,7 +6,7 @@
[![CodeQL](https://github.com/xixu-me/tzst/actions/workflows/github-code-scanning/codeql/badge.svg)](https://github.com/xixu-me/tzst/actions/workflows/github-code-scanning/codeql)
[![CI/CD](https://github.com/xixu-me/tzst/actions/workflows/ci.yml/badge.svg)](https://github.com/xixu-me/tzst/actions/workflows/ci.yml)
[![PyPI - Version](https://img.shields.io/pypi/v/tzst)](https://pypi.org/project/tzst/)
[![PyPI - Downloads](https://img.shields.io/pypi/dm/tzst)](https://pypi.org/project/tzst/)
[![PyPI - Downloads](https://img.shields.io/pypi/dm/tzst)](https://pypistats.org/packages/tzst)
[![GitHub License](https://img.shields.io/github/license/xixu-me/tzst)](LICENSE)
[![Sponsor](https://img.shields.io/badge/Sponsor-violet)](https://xi-xu.me/#sponsorships)
[![Documentation](https://img.shields.io/badge/Documentation-blue)](https://tzst.xi-xu.me)
@@ -15,6 +15,8 @@
**tzst** — это библиотека Python нового поколения, разработанная для современного управления архивами, использующая передовое сжатие Zstandard для обеспечения превосходной производительности, безопасности и надёжности. Созданная исключительно для Python 3.12+, это корпоративное решение объединяет атомарные операции, эффективность потоковой передачи и тщательно разработанный API для переосмысления того, как разработчики работают с архивами `.tzst`/`.tar.zst` в производственных средах. 🚀
Опубликована статья с углублённым техническим анализом: **[Deep Dive into tzst: A Modern Python Archiving Library Based on Zstandard](https://blog.xi-xu.me/2025/11/01/deep-dive-into-tzst-en.html)**.
## ✨ Особенности
- **🗜️ Высокое сжатие**: Сжатие Zstandard для отличных коэффициентов сжатия и скорости
@@ -63,10 +65,18 @@
### 📦 Из PyPI
Используя pip:
```bash
pip install tzst
```
Или используя uv (рекомендуется):
```bash
uv tool install tzst
```
### 🔧 Из исходного кода
```bash
@@ -89,8 +99,6 @@ pip install -e .[dev]
### 💻 Использование командной строки
> **Примечание**: Скачайте [автономный бинарный файл](#из-релизов-github) для лучшей производительности и отсутствия зависимости от Python. Альтернативно, используйте `uvx tzst` для запуска без установки. Смотрите [документацию uv](https://docs.astral.sh/uv/) для деталей.
```bash
# 📁 Создать архив
tzst a archive.tzst file1.txt file2.txt directory/
@@ -512,6 +520,6 @@ python -m pytest tests/
## 📄 Лицензия
Авторские права &copy; 2025 [Си Сюй](https://xi-xu.me). Все права защищены.
Авторские права &copy; [Си Сюй](https://xi-xu.me). Все права защищены.
Лицензировано под лицензией [BSD 3-Clause](LICENSE).
+12 -4
View File
@@ -6,7 +6,7 @@
[![CodeQL](https://github.com/xixu-me/tzst/actions/workflows/github-code-scanning/codeql/badge.svg)](https://github.com/xixu-me/tzst/actions/workflows/github-code-scanning/codeql)
[![CI/CD](https://github.com/xixu-me/tzst/actions/workflows/ci.yml/badge.svg)](https://github.com/xixu-me/tzst/actions/workflows/ci.yml)
[![PyPI - Version](https://img.shields.io/pypi/v/tzst)](https://pypi.org/project/tzst/)
[![PyPI - Downloads](https://img.shields.io/pypi/dm/tzst)](https://pypi.org/project/tzst/)
[![PyPI - Downloads](https://img.shields.io/pypi/dm/tzst)](https://pypistats.org/packages/tzst)
[![GitHub License](https://img.shields.io/github/license/xixu-me/tzst)](LICENSE)
[![Sponsor](https://img.shields.io/badge/Sponsor-violet)](https://xi-xu.me/#sponsorships)
[![Documentation](https://img.shields.io/badge/Documentation-blue)](https://tzst.xi-xu.me)
@@ -15,6 +15,8 @@
**tzst** 是一个面向现代归档管理的新一代 Python 库,利用前沿的 Zstandard 压缩技术,提供卓越的性能、安全性和可靠性。专为 Python 3.12+ 打造,这个企业级解决方案结合原子操作、流式处理效率和精心设计的 API,重新定义了开发者在生产环境中处理 `.tzst`/`.tar.zst` 归档文件的方式。🚀
技术深度解析文章已发布:**[《深入解析 tzst:一个基于 Zstandard 的现代 Python 归档库》](https://blog.xi-xu.me/2025/11/01/deep-dive-into-tzst.html)**。
## ✨ 功能特性
- **🗜️ 高效压缩**:采用 Zstandard 压缩算法,实现优异的压缩率和速度
@@ -63,10 +65,18 @@
### 📦 通过 PyPI 安装
使用 pip:
```bash
pip install tzst
```
或使用 uv(推荐):
```bash
uv tool install tzst
```
### 🔧 从源码安装
```bash
@@ -87,8 +97,6 @@ pip install -e .[dev]
### 💻 命令行使用
> **注意**:下载[独立二进制文件](#从-github-releases-安装)可获得最佳性能且无需 Python 环境。也可使用 `uvx tzst` 免安装运行,详见 [uv 文档](https://docs.astral.sh/uv/)。
```bash
# 📁 创建归档
tzst a archive.tzst file1.txt file2.txt directory/
@@ -508,6 +516,6 @@ python -m pytest tests/
## 📄 许可证
版权所有 &copy; 2025 [Xi Xu](https://xi-xu.me)。保留所有权利。
版权所有 &copy; [Xi Xu](https://xi-xu.me)。保留所有权利。
采用 [BSD 3-Clause](LICENSE) 许可证授权。
+313
View File
@@ -0,0 +1,313 @@
# Security Policy
## Overview
The tzst project takes security seriously and is committed to providing a secure archive management library. This document outlines our security policies, supported versions, vulnerability reporting procedures, and security best practices.
## Supported Versions
| Version | Supported |
|---------|-----------|
| 1.x.x | ✅ Yes |
| < 1.0 | ❌ No |
We provide security updates for the latest major version. Users are strongly encouraged to keep their installations up to date.
## Security Features
### Built-in Security by Default
tzst is designed with security as a primary concern and implements multiple layers of protection:
#### 🔒 Secure Extraction Filters
tzst provides three security filter levels for extraction operations:
- **`data` (default)**: Maximum security level
- Blocks dangerous files (device files, named pipes, etc.)
- Prevents absolute path extraction
- Blocks directory traversal attacks (`../` sequences)
- Restricts extraction to the specified directory
- **Recommended for untrusted archives**
- **`tar`**: Standard tar compatibility
- Blocks absolute paths
- Prevents directory traversal
- Allows Unix-specific features (symlinks, permissions)
- **Use for trusted archives requiring tar features**
- **`fully_trusted`**: No security restrictions
- Allows all archive features
- **Only use with completely trusted archives**
- ⚠️ **Warning**: Can be dangerous with untrusted content
#### ⚡ Atomic Operations
All file creation operations use atomic file operations by default:
- Archives are created in temporary files first, then atomically moved
- Automatic cleanup if the process is interrupted
- Prevents corrupted or incomplete archives
- Cross-platform compatibility
- Use `use_temp_file=False` only when necessary (not recommended)
#### 🛡️ Path Traversal Protection
- Validates all file paths before extraction
- Normalizes paths to prevent directory traversal
- Blocks extraction outside target directory
- Handles edge cases across different operating systems
#### 🔍 Input Validation
- Validates compression levels (1-22)
- Validates archive formats
- Validates file paths and names
- Comprehensive error handling with clear messages
## Best Practices for Users
### 1. Always Use Secure Defaults
```python
from tzst import extract_archive
# ✅ Good: Uses secure 'data' filter by default
extract_archive("untrusted.tzst", "output/")
# ✅ Good: Explicitly specify secure filter
extract_archive("untrusted.tzst", "output/", filter="data")
```
### 2. Choose Appropriate Security Filters
```python
# For untrusted archives (recommended)
extract_archive("untrusted.tzst", "output/", filter="data")
# For trusted archives needing tar features
extract_archive("trusted.tzst", "output/", filter="tar")
# Only for completely trusted archives (use with caution)
extract_archive("internal.tzst", "output/", filter="fully_trusted")
```
### 3. Validate Archive Sources
- Only process archives from trusted sources
- Verify archive integrity before extraction
- Use appropriate security filters based on trust level
- Consider implementing additional validation layers
### 4. Use Safe Extraction Practices
```python
import tempfile
from pathlib import Path
from tzst import extract_archive, test_archive
def safe_extract(archive_path, trust_level="untrusted"):
"""Safely extract an archive with appropriate security measures."""
# Test archive integrity first
if not test_archive(archive_path):
raise ValueError("Archive integrity check failed")
# Choose security filter based on trust level
filters = {
"untrusted": "data",
"trusted": "tar",
"internal": "fully_trusted"
}
security_filter = filters.get(trust_level, "data")
# Extract to temporary directory first
with tempfile.TemporaryDirectory() as temp_dir:
extract_archive(
archive_path,
temp_dir,
filter=security_filter
)
# Process extracted files safely
# Move to final destination if validation passes
```
### 5. Error Handling
```python
from tzst import TzstArchiveError, TzstDecompressionError
try:
extract_archive("archive.tzst", "output/")
except TzstDecompressionError:
# Handle corrupted or invalid archives
print("Archive appears to be corrupted")
except TzstArchiveError as e:
# Handle general archive errors
print(f"Archive operation failed: {e}")
except PermissionError:
# Handle permission issues
print("Insufficient permissions")
```
## Security Considerations for Different Use Cases
### Processing Untrusted Archives
When processing archives from untrusted sources (internet downloads, user uploads, etc.):
1. **Always use `data` filter** (default behavior)
2. **Extract to isolated directory** with limited permissions
3. **Validate extracted content** before use
4. **Use resource limits** to prevent DoS attacks
5. **Run in sandboxed environment** when possible
### Enterprise/Internal Use
For trusted internal archives:
1. Use `tar` filter for standard compatibility
2. Implement organizational security policies
3. Use secure transport channels
4. Maintain audit logs of archive operations
5. Regular security assessments
### Development/Testing
Even in development:
1. Use secure defaults
2. Don't disable security features without understanding implications
3. Test with malicious archives (in isolated environments)
4. Validate security assumptions
## Reporting Security Vulnerabilities
We take security vulnerabilities seriously and appreciate responsible disclosure.
### How to Report
**DO NOT** report security vulnerabilities through public GitHub issues.
Instead, please report security vulnerabilities via email to:
📧 **[i@xi-xu.me](mailto:i@xi-xu.me)**
### Information to Include
Please include as much of the following information as possible:
1. **Description** of the vulnerability
2. **Steps to reproduce** the issue
3. **Potential impact** and attack scenarios
4. **Affected versions** (if known)
5. **Suggested fix** (if you have one)
6. **Your contact information** for follow-up
### What to Expect
1. **Acknowledgment**: We'll acknowledge receipt within 48 hours
2. **Initial Assessment**: We'll provide an initial assessment within 5 business days
3. **Communication**: We'll keep you informed throughout the investigation
4. **Resolution**: We'll work to resolve confirmed vulnerabilities promptly
5. **Credit**: We'll credit you in security advisories (unless you prefer anonymity)
### Response Timeline
- **Critical vulnerabilities**: Patch within 7 days
- **High-severity vulnerabilities**: Patch within 14 days
- **Medium/Low-severity vulnerabilities**: Patch within 30 days
## Security Updates and Advisories
### How We Communicate Security Issues
1. **GitHub Security Advisories**: For confirmed vulnerabilities
2. **Release Notes**: Security fixes are prominently mentioned
3. **PyPI**: Updated packages with security fixes
4. **Documentation**: Security best practices updates
### Staying Informed
To stay informed about security updates:
1. **Watch the repository** for release notifications
2. **Subscribe to GitHub Security Advisories**
3. **Follow our release notes** for security mentions
4. **Use dependency scanners** to identify outdated versions
## Development Security Practices
### Code Review Process
- All changes undergo security-focused code review
- Security-sensitive changes require additional review
- Automated security scanning in CI/CD pipeline
- Regular dependency vulnerability scanning
### Testing
- Comprehensive security test suite
- Fuzzing with malformed archives
- Path traversal attack simulations
- Permission and access control testing
### Dependencies
- Minimal dependency footprint
- Regular dependency updates
- Automated vulnerability scanning
- Pinned versions for reproducible builds
## Known Security Considerations
### Archive Bombs
While tzst includes basic protections, be aware of:
- **Zip bombs**: Archives with extreme compression ratios
- **Memory exhaustion**: Very large expanded archives
- **Resource consumption**: Processing time attacks
**Mitigation**: Use streaming mode for large archives and implement resource limits.
### Symbolic Links
Different security filters handle symbolic links differently:
- `data` filter: Generally restricts symbolic links
- `tar` filter: Preserves symbolic links with basic safety checks
- `fully_trusted` filter: Allows all symbolic link operations
**Recommendation**: Use `data` filter for untrusted content.
### File Permissions
Extracted file permissions depend on:
- Source archive permissions
- Extraction filter settings
- Operating system capabilities
- User privileges
**Recommendation**: Review and validate extracted file permissions.
## Contact
For security-related questions or concerns:
- **Security issues**: [i@xi-xu.me](mailto:i@xi-xu.me) (private)
- **General questions**: [GitHub Discussions](https://github.com/xixu-me/tzst/discussions)
- **Documentation**: [Project Documentation](https://tzst.xi-xu.me)
## Acknowledgments
We thank the security research community for their responsible disclosure of vulnerabilities and continuous efforts to improve software security.
---
**Last Updated**: June 2025
**Version**: 1.0
For the most current security information, please check our [GitHub repository](https://github.com/xixu-me/tzst) and [official documentation](https://tzst.xi-xu.me).
+21
View File
@@ -0,0 +1,21 @@
# robots.txt for tzst documentation
User-agent: *
Allow: /
# Sitemap location
Sitemap: https://tzst.xi-xu.me/sitemap.xml
# Disallow build artifacts and internal directories
Disallow: /_sources/
Disallow: /_static/*.js$
Disallow: /_images/
# Allow static assets like CSS and images
Allow: /_static/*.css$
Allow: /_static/*.png$
Allow: /_static/*.jpg$
Allow: /_static/*.ico$
Allow: /_static/*.svg$
# Crawl delay (optional, considerate to search engines)
Crawl-delay: 1
+161 -3
View File
@@ -1,7 +1,11 @@
{% extends "!layout.html" %} {% block extrahead %} {{ super() }}
{% extends "!layout.html" %}
{% block extrahead %}
{{ super() }}
<!-- Additional SEO and social meta tags -->
<meta name="application-name" content="tzst" />
<meta name="generator" content="Sphinx {{ sphinx_version }}" />
<meta name="rating" content="General" />
<meta name="revisit-after" content="7 days" />
<!-- Schema.org markup for search engines -->
<script type="application/ld+json">
@@ -13,21 +17,173 @@
"applicationCategory": "DeveloperApplication",
"operatingSystem": "Cross-platform",
"programmingLanguage": "Python",
"license": "https://opensource.org/licenses/MIT",
"license": "https://opensource.org/licenses/BSD-3-Clause",
"url": "https://tzst.xi-xu.me/",
"downloadUrl": "https://pypi.org/project/tzst/",
"codeRepository": "https://github.com/xixu-me/tzst",
"softwareVersion": "{{ version }}",
"author": {
"@type": "Person",
"name": "Xi Xu"
"name": "Xi Xu",
"url": "https://xi-xu.me"
},
"offers": {
"@type": "Offer",
"price": "0",
"priceCurrency": "USD"
},
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": "5",
"reviewCount": "1"
},
"keywords": "tzst, tar, zstandard, compression, archive, python, extraction, backup"
}
</script>
<!-- Breadcrumb Schema -->
{% if pagename != 'index' %}
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [
{
"@type": "ListItem",
"position": 1,
"name": "Home",
"item": "https://tzst.xi-xu.me/"
},
{
"@type": "ListItem",
"position": 2,
"name": "{{ title|striptags }}",
"item": "https://tzst.xi-xu.me/{{ pagename }}.html"
}
]
}
</script>
{% endif %}
<!-- Article/TechArticle Schema for documentation pages -->
{% if pagename in ['quickstart', 'examples', 'performance', 'development'] %}
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "TechArticle",
"headline": "{{ title|striptags }}",
"description": "{{ metatags|striptags }}",
"author": {
"@type": "Person",
"name": "Xi Xu",
"url": "https://xi-xu.me"
},
"publisher": {
"@type": "Person",
"name": "Xi Xu"
},
"datePublished": "2025-01-01",
"dateModified": "2025-01-12",
"url": "https://tzst.xi-xu.me/{{ pagename }}.html",
"inLanguage": "en-US",
"about": {
"@type": "SoftwareApplication",
"name": "tzst"
}
}
</script>
{% endif %}
<!-- FAQ Schema for pages with common questions -->
{% if pagename == 'quickstart' %}
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "FAQPage",
"mainEntity": [
{
"@type": "Question",
"name": "How do I install tzst?",
"acceptedAnswer": {
"@type": "Answer",
"text": "You can install tzst using pip (pip install tzst), download standalone binaries from GitHub Releases, use uvx for no-installation usage (uvx tzst), or install from source."
}
},
{
"@type": "Question",
"name": "What compression levels does tzst support?",
"acceptedAnswer": {
"@type": "Answer",
"text": "tzst supports compression levels from 1 to 22. Level 1 is fastest with lower compression, level 3 is the default balance, and level 22 provides maximum compression but is slower."
}
},
{
"@type": "Question",
"name": "Is tzst secure for extracting untrusted archives?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Yes, tzst uses the 'data' security filter by default, which protects against path traversal attacks and blocks dangerous files. This makes it safe for extracting untrusted archives."
}
},
{
"@type": "Question",
"name": "When should I use streaming mode?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Use streaming mode for archives larger than 100MB to reduce memory usage. Streaming mode is memory-efficient but has limitations such as no random access or specific file extraction."
}
},
{
"@type": "Question",
"name": "What file extensions does tzst support?",
"acceptedAnswer": {
"@type": "Answer",
"text": "tzst supports both .tzst and .tar.zst file extensions. The library automatically handles extension detection and normalization when creating or opening archives."
}
}
]
}
</script>
{% endif %}
<!-- HowTo Schema for examples page -->
{% if pagename == 'examples' %}
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "HowTo",
"name": "How to use tzst for archive management",
"description": "Comprehensive examples of using tzst for creating, extracting, and managing tar.zst archives",
"image": "https://tzst.xi-xu.me/_static/tzst-logo.png",
"step": [
{
"@type": "HowToStep",
"name": "Create an archive",
"text": "Use create_archive() to create a new tzst archive with your files and directories",
"url": "https://tzst.xi-xu.me/examples.html#basic-operations"
},
{
"@type": "HowToStep",
"name": "Extract an archive",
"text": "Use extract_archive() to safely extract files from a tzst archive with security filters",
"url": "https://tzst.xi-xu.me/examples.html#flexible-extraction"
},
{
"@type": "HowToStep",
"name": "List archive contents",
"text": "Use list_archive() to view the contents of an archive without extracting",
"url": "https://tzst.xi-xu.me/examples.html#basic-operations"
},
{
"@type": "HowToStep",
"name": "Test archive integrity",
"text": "Use test_archive() to verify the integrity of your archive files",
"url": "https://tzst.xi-xu.me/examples.html#basic-operations"
}
]
}
</script>
{% endif %}
<!-- Canonical URL for better SEO -->
{% if pagename != 'index' %}
@@ -39,4 +195,6 @@
<!-- Preconnect to external domains for performance -->
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://cdnjs.cloudflare.com" />
<link rel="dns-prefetch" href="https://pypi.org" />
<link rel="dns-prefetch" href="https://github.com" />
{% endblock %}
+27 -1
View File
@@ -2,6 +2,7 @@
import os
import sys
from datetime import datetime
# Add the source directory to the Python path
sys.path.insert(0, os.path.abspath("../src"))
@@ -11,7 +12,7 @@ from tzst import __version__
# -- Project information -----------------------------------------------------
project = "tzst"
copyright = "2025, Xi Xu"
copyright = f"{datetime.now().year}, Xi Xu"
author = "Xi Xu"
release = __version__
version = __version__
@@ -25,11 +26,19 @@ extensions = [
"sphinx.ext.autosummary",
"sphinx.ext.coverage",
"myst_parser",
"sphinx_sitemap",
]
templates_path = ["_templates"]
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
# Base URL for sitemap generation
html_baseurl = "https://tzst.xi-xu.me/"
# Sitemap configuration
sitemap_url_scheme = "{link}"
sitemap_filename = "sitemap.xml"
# -- Options for HTML output -------------------------------------------------
html_theme = "sphinx_rtd_theme"
html_static_path = ["_static"]
@@ -51,10 +60,16 @@ html_meta = {
"og:type": "website",
"og:url": "https://tzst.xi-xu.me/",
"og:image": "https://tzst.xi-xu.me/_static/tzst-logo.png",
"og:site_name": "tzst Documentation",
"og:locale": "en_US",
"twitter:card": "summary_large_image",
"twitter:title": "tzst Documentation",
"twitter:description": "tzst - A Python library for creating and extracting tar.zst archives with high performance and comprehensive features",
"twitter:image": "https://tzst.xi-xu.me/_static/tzst-logo.png",
"twitter:site": "@xixu_me",
"twitter:creator": "@xixu_me",
"article:author": "Xi Xu",
"article:publisher": "https://xi-xu.me",
}
# Theme options
@@ -123,3 +138,14 @@ myst_enable_extensions = [
"substitution",
"tasklist",
]
# SEO optimization settings
html_copy_source = False # Don't copy source files to _sources (reduces crawl)
html_show_sourcelink = False # Hide "View page source" links
html_show_sphinx = False # Don't show "Created using Sphinx" in footer
# Additional HTML files to include (robots.txt will be copied from _static)
html_extra_path = []
# Language for content autogenerated by Sphinx
language = "en"
+16
View File
@@ -1,3 +1,19 @@
---
myst:
html_meta:
description: "Complete development guide for tzst - Setup, testing, contribution guidelines, and best practices"
keywords: "tzst development, Python development, contributing to tzst, testing guide, documentation"
og:title: "tzst Development Guide"
og:description: "Complete development guide for tzst - Setup, testing, contribution guidelines, and best practices"
twitter:title: "tzst Development Guide"
twitter:description: "Complete development guide for tzst - Setup, testing, contribution guidelines, and best practices"
og:type: "website"
og:image: "https://tzst.xi-xu.me/_static/tzst-square-logo.png"
og:url: "https://tzst.xi-xu.me/development.html"
twitter:card: "summary_large_image"
twitter:image: "https://tzst.xi-xu.me/_static/tzst-square-logo.png"
---
# Development Guide
This guide provides comprehensive information for developers contributing to or working with the tzst library.
+6 -60
View File
@@ -20,7 +20,7 @@ myst:
[![CodeQL](https://github.com/xixu-me/tzst/actions/workflows/github-code-scanning/codeql/badge.svg)](https://github.com/xixu-me/tzst/actions/workflows/github-code-scanning/codeql)
[![CI/CD](https://github.com/xixu-me/tzst/actions/workflows/ci.yml/badge.svg)](https://github.com/xixu-me/tzst/actions/workflows/ci.yml)
[![PyPI - Version](https://img.shields.io/pypi/v/tzst)](https://pypi.org/project/tzst/)
[![PyPI - Downloads](https://img.shields.io/pypi/dm/tzst)](https://pypi.org/project/tzst/)
[![PyPI - Downloads](https://img.shields.io/pypi/dm/tzst)](https://pypistats.org/packages/tzst)
[![GitHub License](https://img.shields.io/github/license/xixu-me/tzst)](https://github.com/xixu-me/tzst/blob/main/LICENSE)
[![Sponsor](https://img.shields.io/badge/Sponsor-violet)](https://xi-xu.me/#sponsorships)
@@ -101,74 +101,20 @@ with TzstArchive("data.tzst", "r") as archive:
## Installation
### From PyPI
For detailed installation instructions, including standalone binaries and source installation, please refer to the {doc}`quickstart` guide.
```bash
# Install from PyPI
pip install tzst
```
### From GitHub Releases
Download platform-specific standalone executables from [GitHub Releases](https://github.com/xixu-me/tzst/releases) - no Python installation required!
#### Supported Platforms
| Platform | Architecture | File |
|----------|-------------|------|
| **Linux** | x86_64 | `tzst-{version}-linux-amd64.zip` |
| **Linux** | ARM64 | `tzst-{version}-linux-arm64.zip` |
| **Windows** | x64 | `tzst-{version}-windows-amd64.zip` |
| **Windows** | ARM64 | `tzst-{version}-windows-arm64.zip` |
| **macOS** | Intel | `tzst-{version}-darwin-amd64.zip` |
| **macOS** | Apple Silicon | `tzst-{version}-darwin-arm64.zip` |
#### Installation Steps
1. **Download** the appropriate archive for your platform from the [latest releases page](https://github.com/xixu-me/tzst/releases/latest)
2. **Extract** the archive to get the `tzst` executable (or `tzst.exe` on Windows)
3. **Move** the executable to a directory in your PATH:
- **Linux/macOS**: `sudo mv tzst /usr/local/bin/`
- **Windows**: Add the directory containing `tzst.exe` to your PATH environment variable
4. **Verify** installation: `tzst --help`
#### Benefits of Binary Installation
- **No Python required** - Standalone executable
- **Faster startup** - No Python interpreter overhead
- **Easy deployment** - Single file distribution
- **Consistent behavior** - Bundled dependencies
### Using uvx (No Installation)
Run tzst directly without installation using [uvx](https://docs.astral.sh/uv/):
```bash
uvx tzst --help
uvx tzst a archive.tzst file1.txt file2.txt directory/
uvx tzst x archive.tzst
```
Perfect for one-time usage, testing, CI/CD pipelines, and isolated environments.
### From Source
```bash
git clone https://github.com/xixu-me/tzst.git
cd tzst
pip install .
# Or using uv (recommended)
uv tool install tzst
```
## Getting Started
For a quick introduction, see the {doc}`quickstart` guide. For comprehensive usage examples, explore the {doc}`examples` section.
### Installation Options
1. **PyPI Installation**: `pip install tzst`
2. **Standalone Binaries**: Download from [GitHub Releases](https://github.com/xixu-me/tzst/releases)
3. **uvx (No Installation)**: Run directly with `uvx tzst`
4. **From Source**: Clone and install from repository
### API Documentation
Complete API documentation is available in the {doc}`api/index` section, covering:
@@ -222,7 +168,7 @@ We welcome contributions! Please read our [Contributing Guide](https://github.co
## License
Copyright © 2025 [Xi Xu](https://xi-xu.me). All rights reserved.
Copyright © [Xi Xu](https://xi-xu.me). All rights reserved.
Licensed under the [BSD 3-Clause](https://github.com/xixu-me/tzst/blob/main/LICENSE) license.
+47 -30
View File
@@ -24,45 +24,52 @@ This guide will get you up and running with tzst in just a few minutes.
Choose your preferred installation method:
### Option 1: PyPI
### From GitHub Releases
Download standalone executables that don't require Python installation:
#### Supported Platforms
| Platform | Architecture | File |
|----------|-------------|------|
| **🐧 Linux** | x86_64 | `tzst-{version}-linux-amd64.zip` |
| **🐧 Linux** | ARM64 | `tzst-{version}-linux-arm64.zip` |
| **🪟 Windows** | x64 | `tzst-{version}-windows-amd64.zip` |
| **🪟 Windows** | ARM64 | `tzst-{version}-windows-arm64.zip` |
| **🍎 macOS** | Intel | `tzst-{version}-darwin-amd64.zip` |
| **🍎 macOS** | Apple Silicon | `tzst-{version}-darwin-arm64.zip` |
#### 🛠️ Installation Steps
1. **📥 Download** the appropriate archive for your platform from the [latest releases page](https://github.com/xixu-me/tzst/releases/latest)
2. **📦 Extract** the archive to get the `tzst` executable (or `tzst.exe` on Windows)
3. **📂 Move** the executable to a directory in your PATH:
- **🐧 Linux/macOS**: `sudo mv tzst /usr/local/bin/`
- **🪟 Windows**: Add the directory containing `tzst.exe` to your PATH environment variable
4. **✅ Verify** installation: `tzst --help`
#### 🎯 Benefits of Binary Installation
- ✅ **No Python required** - Standalone executable
- ✅ **Faster startup** - No Python interpreter overhead
- ✅ **Easy deployment** - Single file distribution
- ✅ **Consistent behavior** - Bundled dependencies
### From PyPI
Using pip:
```bash
pip install tzst
```
### Option 2: Standalone Binary
Download the appropriate executable from [GitHub Releases](https://github.com/xixu-me/tzst/releases):
| Platform | Architecture | Download |
|----------|--------------|----------|
| **Linux** | x86_64 | `tzst-{version}-linux-amd64.zip` |
| **Linux** | ARM64 | `tzst-{version}-linux-arm64.zip` |
| **Windows** | x64 | `tzst-{version}-windows-amd64.zip` |
| **Windows** | ARM64 | `tzst-{version}-windows-arm64.zip` |
| **macOS** | Intel | `tzst-{version}-darwin-amd64.zip` |
| **macOS** | Apple Silicon | `tzst-{version}-darwin-arm64.zip` |
Extract the archive and add the executable to your PATH.
### Option 3: Using uvx (No Installation)
Run tzst directly without installation using [uvx](https://docs.astral.sh/uv/):
Or using uv (recommended):
```bash
uvx tzst --help
uvx tzst a archive.tzst file1.txt file2.txt directory/
uvx tzst x archive.tzst
uv tool install tzst
```
This option is perfect for:
- **One-time usage** - No permanent installation needed
- **Testing** - Try tzst without committing to installation
- **CI/CD pipelines** - Use tzst in automated workflows
- **Isolated environments** - Avoid dependency conflicts
### Option 4: From Source
### From Source
```bash
git clone https://github.com/xixu-me/tzst.git
@@ -70,6 +77,16 @@ cd tzst
pip install .
```
### Development Installation
This project uses modern Python packaging standards:
```bash
git clone https://github.com/xixu-me/tzst.git
cd tzst
pip install -e .[dev]
```
(basic-usage)=
## Basic Usage
+1
View File
@@ -10,6 +10,7 @@ sphinx-autobuild>=2021.3.14
sphinx-copybutton>=0.5.2
sphinxext-opengraph>=0.9.0
sphinx-autodoc-typehints>=1.25.0
sphinx-sitemap>=2.6.0
# Alternative modern theme (optional)
furo>=2024.1.29
+1 -1
View File
@@ -4,7 +4,7 @@ Leveraging cutting-edge Zstandard compression to deliver superior performance,
security, and reliability.
"""
__version__ = "1.2.8"
__version__ = "1.3.2"
from .core import (
TzstArchive,
+341 -79
View File
@@ -1,9 +1,10 @@
"""Command-line interface for tzst."""
import argparse
import json
import sys
from pathlib import Path
from typing import Literal, cast
from typing import Any, Literal, cast
from . import __version__
from .core import (
@@ -92,10 +93,70 @@ def print_banner() -> None:
None
"""
print()
print(f"tzst {__version__} : Copyright (c) 2025 Xi Xu")
print(f"tzst {__version__} : Copyright (c) Xi Xu")
print()
def _wants_json_output(args) -> bool:
"""Return True when the caller requested machine-readable output."""
return bool(getattr(args, "json_output", False))
def _emit_json(payload: dict[str, Any], *, to_stderr: bool = False) -> None:
"""Emit a JSON payload to stdout or stderr."""
stream = sys.stderr if to_stderr else sys.stdout
print(json.dumps(payload, ensure_ascii=True), file=stream)
def _emit_error(
args,
message: str,
*,
error_type: str,
exit_code: int = 1,
details: dict[str, Any] | None = None,
) -> int:
"""Emit an error in text or JSON format and return the exit code."""
if _wants_json_output(args):
payload: dict[str, Any] = {
"ok": False,
"error": {"type": error_type, "message": message},
}
if details:
payload["error"]["details"] = details
_emit_json(payload, to_stderr=True)
else:
print(message, file=sys.stderr)
return exit_code
def _summarize_listing(contents: list[dict[str, Any]]) -> dict[str, int | str]:
"""Build the summary block used by list output."""
total_files = 0
total_dirs = 0
total_size = 0
for item in contents:
if item["is_file"]:
total_files += 1
total_size += item["size"]
elif item["is_dir"]:
total_dirs += 1
return {
"files": total_files,
"directories": total_dirs,
"total_size_bytes": total_size,
"total_size_human": format_size(total_size),
}
def _should_print_banner(argv: list[str] | None) -> bool:
"""Determine whether the human-facing banner should be displayed."""
cli_args = argv if argv is not None else sys.argv[1:]
return "--json" not in cli_args and "--no-banner" not in cli_args
def format_size(size: int) -> str:
"""Format file size in human-readable format.
@@ -220,18 +281,23 @@ def _prepare_archive_creation(args) -> tuple[Path, list[Path], int, bool] | int:
# Validate files
missing_files = _validate_files(files)
if missing_files:
print(
return _emit_error(
args,
f"Error: Files not found - {', '.join(map(str, missing_files))}",
file=sys.stderr,
error_type="files_not_found",
details={"missing_files": [str(path) for path in missing_files]},
)
return 1
compression_level, use_temp_file = _extract_add_params(args)
return archive_path, files, compression_level, use_temp_file
def _execute_archive_creation(
archive_path: Path, files: list[Path], compression_level: int, use_temp_file: bool
args,
archive_path: Path,
files: list[Path],
compression_level: int,
use_temp_file: bool,
) -> int:
"""Execute the archive creation process.
@@ -247,6 +313,7 @@ def _execute_archive_creation(
# Normalize archive path to show the correct final filename
normalized_archive_path = _normalize_archive_path(archive_path)
if not _wants_json_output(args):
print(f"Creating archive: {normalized_archive_path}")
for file_path in files:
print(f" Adding: {file_path}")
@@ -254,11 +321,26 @@ def _execute_archive_creation(
# Use atomic file operations by default for better reliability
# This creates the archive in a temporary file first, then moves it
create_archive(archive_path, files, compression_level, use_temp_file=use_temp_file)
if _wants_json_output(args):
_emit_json(
{
"ok": True,
"command": "add",
"archive": str(archive_path),
"normalized_archive": str(normalized_archive_path),
"added": [str(file_path) for file_path in files],
"compression_level": compression_level,
"atomic": use_temp_file,
}
)
else:
print(f"Archive created successfully - {normalized_archive_path}")
return 0
def _handle_archive_creation_exceptions(func, *args, **kwargs) -> int:
def _handle_archive_creation_exceptions(command_args, func, *args, **kwargs) -> int:
"""Handle exceptions during archive creation.
Args:
@@ -274,19 +356,32 @@ def _handle_archive_creation_exceptions(func, *args, **kwargs) -> int:
except OSError:
return 1 # Error already printed in _validate_files
except ValueError as e:
print(f"Error: Invalid parameter - {e}", file=sys.stderr)
return 1
return _emit_error(
command_args,
f"Error: Invalid parameter - {e}",
error_type="invalid_parameter",
)
except TzstArchiveError as e:
print(f"Error: Archive operation failed - {e}", file=sys.stderr)
return 1
return _emit_error(
command_args,
f"Error: Archive operation failed - {e}",
error_type="archive_operation_failed",
)
except KeyboardInterrupt:
print("\nOperation interrupted by user", file=sys.stderr)
return _emit_error(
command_args,
"Operation interrupted by user",
error_type="interrupted",
exit_code=130,
)
# Clean up any partial files - the atomic operations in create_archive
# handle this
return 130 # Standard exit code for SIGINT
except Exception as e:
print(f"Error: Failed to create archive - {e}", file=sys.stderr)
return 1
return _emit_error(
command_args,
f"Error: Failed to create archive - {e}",
error_type="create_failed",
)
def cmd_add(args) -> int:
@@ -326,10 +421,10 @@ def cmd_add(args) -> int:
archive_path, files, compression_level, use_temp_file = preparation_result
return _execute_archive_creation(
archive_path, files, compression_level, use_temp_file
args, archive_path, files, compression_level, use_temp_file
)
return _handle_archive_creation_exceptions(_create_archive_workflow)
return _handle_archive_creation_exceptions(args, _create_archive_workflow)
def cmd_extract_full(args) -> int:
@@ -364,8 +459,12 @@ def cmd_extract_full(args) -> int:
try:
archive_path = Path(args.archive)
if not archive_path.exists():
print(f"Error: Archive not found - {archive_path}", file=sys.stderr)
return 1
return _emit_error(
args,
f"Error: Archive not found - {archive_path}",
error_type="archive_not_found",
details={"archive": str(archive_path)},
)
output_dir = Path(args.output) if args.output else Path.cwd()
members = args.files if hasattr(args, "files") and args.files else None
@@ -385,11 +484,19 @@ def cmd_extract_full(args) -> int:
# Convert string to ConflictResolution enum
conflict_resolution = ConflictResolution(conflict_resolution_str)
if _wants_json_output(args) and conflict_resolution == ConflictResolution.ASK:
return _emit_error(
args,
"Error: JSON mode does not support interactive conflict prompts",
error_type="interactive_conflict_not_supported",
)
# Set up interactive callback if needed
interactive_callback = None
if conflict_resolution == ConflictResolution.ASK:
interactive_callback = _interactive_conflict_callback
if not _wants_json_output(args):
print(f"Extracting from: {archive_path}")
print(f"Output directory: {output_dir}")
if streaming:
@@ -409,24 +516,56 @@ def cmd_extract_full(args) -> int:
conflict_resolution=conflict_resolution,
interactive_callback=interactive_callback,
)
if _wants_json_output(args):
_emit_json(
{
"ok": True,
"command": "extract",
"archive": str(archive_path),
"output_dir": str(output_dir),
"members": members or [],
"flatten": False,
"streaming": streaming,
"filter": filter_type,
"conflict_resolution": conflict_resolution.value,
}
)
else:
print("Extraction completed successfully")
return 0
except FileNotFoundError as e:
print(f"Error: File not found - {e}", file=sys.stderr)
return 1
return _emit_error(
args,
f"Error: File not found - {e}",
error_type="file_not_found",
)
except TzstDecompressionError as e:
print(f"Error: Archive decompression failed - {e}", file=sys.stderr)
return 1
return _emit_error(
args,
f"Error: Archive decompression failed - {e}",
error_type="decompression_failed",
)
except TzstArchiveError as e:
print(f"Error: Archive operation failed - {e}", file=sys.stderr)
return 1
return _emit_error(
args,
f"Error: Archive operation failed - {e}",
error_type="archive_operation_failed",
)
except KeyboardInterrupt:
print("\nOperation interrupted by user", file=sys.stderr)
return 130
return _emit_error(
args,
"Operation interrupted by user",
error_type="interrupted",
exit_code=130,
)
except Exception as e:
print(f"Error: Failed to extract archive - {e}", file=sys.stderr)
return 1
return _emit_error(
args,
f"Error: Failed to extract archive - {e}",
error_type="extract_failed",
)
def cmd_extract_flat(args) -> int:
@@ -462,8 +601,12 @@ def cmd_extract_flat(args) -> int:
try:
archive_path = Path(args.archive)
if not archive_path.exists():
print(f"Error: Archive not found - {archive_path}", file=sys.stderr)
return 1
return _emit_error(
args,
f"Error: Archive not found - {archive_path}",
error_type="archive_not_found",
details={"archive": str(archive_path)},
)
output_dir = Path(args.output) if args.output else Path.cwd()
members = args.files if hasattr(args, "files") and args.files else None
@@ -483,11 +626,19 @@ def cmd_extract_flat(args) -> int:
# Convert string to ConflictResolution enum
conflict_resolution = ConflictResolution(conflict_resolution_str)
if _wants_json_output(args) and conflict_resolution == ConflictResolution.ASK:
return _emit_error(
args,
"Error: JSON mode does not support interactive conflict prompts",
error_type="interactive_conflict_not_supported",
)
# Set up interactive callback if needed
interactive_callback = None
if conflict_resolution == ConflictResolution.ASK:
interactive_callback = _interactive_conflict_callback
if not _wants_json_output(args):
print(f"Extracting from: {archive_path}")
print(f"Output directory: {output_dir}")
if filter_type != "data":
@@ -505,21 +656,49 @@ def cmd_extract_flat(args) -> int:
conflict_resolution=conflict_resolution,
interactive_callback=interactive_callback,
)
if _wants_json_output(args):
_emit_json(
{
"ok": True,
"command": "extract-flat",
"archive": str(archive_path),
"output_dir": str(output_dir),
"members": members or [],
"flatten": True,
"streaming": streaming,
"filter": filter_type,
"conflict_resolution": conflict_resolution.value,
}
)
else:
print("Extraction completed successfully")
return 0
except FileNotFoundError as e:
print(f"Error: File not found - {e}", file=sys.stderr)
return 1
return _emit_error(
args,
f"Error: File not found - {e}",
error_type="file_not_found",
)
except TzstDecompressionError as e:
print(f"Error: Archive decompression failed - {e}", file=sys.stderr)
return 1
return _emit_error(
args,
f"Error: Archive decompression failed - {e}",
error_type="decompression_failed",
)
except TzstArchiveError as e:
print(f"Error: Archive operation failed - {e}", file=sys.stderr)
return 1
return _emit_error(
args,
f"Error: Archive operation failed - {e}",
error_type="archive_operation_failed",
)
except Exception as e:
print(f"Error: Failed to extract archive - {e}", file=sys.stderr)
return 1
return _emit_error(
args,
f"Error: Failed to extract archive - {e}",
error_type="extract_failed",
)
def _print_verbose_listing(contents: list) -> None:
@@ -543,22 +722,14 @@ def _print_simple_listing(contents: list) -> None:
Args:
contents: List of archive items
"""
total_files = 0
total_dirs = 0
total_size = 0
for item in contents:
if item["is_file"]:
total_files += 1
total_size += item["size"]
elif item["is_dir"]:
total_dirs += 1
print(item["name"])
print()
summary = _summarize_listing(contents)
total_msg = (
f"Total: {total_files} files, {total_dirs} directories, "
f"{format_size(total_size)}"
f"Total: {summary['files']} files, {summary['directories']} directories, "
f"{summary['total_size_human']}"
)
print(total_msg)
@@ -592,12 +763,17 @@ def cmd_list(args) -> int:
try:
archive_path = Path(args.archive)
if not archive_path.exists():
print(f"Error: Archive not found - {archive_path}", file=sys.stderr)
return 1
return _emit_error(
args,
f"Error: Archive not found - {archive_path}",
error_type="archive_not_found",
details={"archive": str(archive_path)},
)
verbose = getattr(args, "verbose", False)
streaming = getattr(args, "streaming", False)
if not _wants_json_output(args):
print(f"Listing contents of: {archive_path}")
if streaming:
print("Using streaming mode (memory efficient)")
@@ -605,7 +781,19 @@ def cmd_list(args) -> int:
contents = list_archive(archive_path, verbose=verbose, streaming=streaming)
if verbose:
if _wants_json_output(args):
_emit_json(
{
"ok": True,
"command": "list",
"archive": str(archive_path),
"verbose": verbose,
"streaming": streaming,
"contents": contents,
"summary": _summarize_listing(contents),
}
)
elif verbose:
_print_verbose_listing(contents)
else:
_print_simple_listing(contents)
@@ -613,20 +801,36 @@ def cmd_list(args) -> int:
return 0
except FileNotFoundError as e:
print(f"Error: File not found - {e}", file=sys.stderr)
return 1
return _emit_error(
args,
f"Error: File not found - {e}",
error_type="file_not_found",
)
except TzstDecompressionError as e:
print(f"Error: Archive decompression failed - {e}", file=sys.stderr)
return 1
return _emit_error(
args,
f"Error: Archive decompression failed - {e}",
error_type="decompression_failed",
)
except TzstArchiveError as e:
print(f"Error: Archive operation failed - {e}", file=sys.stderr)
return 1
return _emit_error(
args,
f"Error: Archive operation failed - {e}",
error_type="archive_operation_failed",
)
except KeyboardInterrupt:
print("\nOperation interrupted by user", file=sys.stderr)
return 130
return _emit_error(
args,
"Operation interrupted by user",
error_type="interrupted",
exit_code=130,
)
except Exception as e:
print(f"Error: Failed to list archive - {e}", file=sys.stderr)
return 1
return _emit_error(
args,
f"Error: Failed to list archive - {e}",
error_type="list_failed",
)
def cmd_test(args) -> int:
@@ -658,37 +862,79 @@ def cmd_test(args) -> int:
try:
archive_path = Path(args.archive)
if not archive_path.exists():
print(f"Error: Archive not found - {archive_path}", file=sys.stderr)
return 1
return _emit_error(
args,
f"Error: Archive not found - {archive_path}",
error_type="archive_not_found",
details={"archive": str(archive_path)},
)
streaming = getattr(args, "streaming", False)
if not _wants_json_output(args):
print(f"Testing archive: {archive_path}")
if streaming:
print("Using streaming mode (memory efficient)")
if test_archive(archive_path, streaming=streaming):
healthy = test_archive(archive_path, streaming=streaming)
if healthy:
if _wants_json_output(args):
_emit_json(
{
"ok": True,
"command": "test",
"archive": str(archive_path),
"streaming": streaming,
"healthy": True,
}
)
else:
print("Archive test passed - no errors detected")
return 0
else:
print("Archive test failed - errors detected", file=sys.stderr)
return 1
return _emit_error(
args,
"Archive test failed - errors detected",
error_type="integrity_check_failed",
details={
"command": "test",
"archive": str(archive_path),
"streaming": streaming,
"healthy": False,
},
)
except FileNotFoundError as e:
print(f"Error: File not found - {e}", file=sys.stderr)
return 1
return _emit_error(
args,
f"Error: File not found - {e}",
error_type="file_not_found",
)
except TzstDecompressionError as e:
print(f"Error: Archive decompression failed - {e}", file=sys.stderr)
return 1
return _emit_error(
args,
f"Error: Archive decompression failed - {e}",
error_type="decompression_failed",
)
except TzstArchiveError as e:
print(f"Error: Archive operation failed - {e}", file=sys.stderr)
return 1
return _emit_error(
args,
f"Error: Archive operation failed - {e}",
error_type="archive_operation_failed",
)
except KeyboardInterrupt:
print("\nOperation interrupted by user", file=sys.stderr)
return 130
return _emit_error(
args,
"Operation interrupted by user",
error_type="interrupted",
exit_code=130,
)
except Exception as e:
print(f"Error: Failed to test archive - {e}", file=sys.stderr)
return 1
return _emit_error(
args,
f"Error: Failed to test archive - {e}",
error_type="test_failed",
)
def cmd_version(args) -> int:
@@ -697,7 +943,11 @@ def cmd_version(args) -> int:
Returns:
int: Exit code (always 0)
"""
# Version is already printed in print_banner(), so just exit
if _wants_json_output(args):
_emit_json({"ok": True, "command": "version", "version": __version__})
elif getattr(args, "no_banner", False):
print(f"tzst {__version__}")
return 0
@@ -763,6 +1013,17 @@ documentation:
parser.add_argument(
"--version", action="store_true", help="show version information and exit"
)
parser.add_argument(
"--json",
dest="json_output",
action="store_true",
help="emit machine-readable JSON output",
)
parser.add_argument(
"--no-banner",
action="store_true",
help="suppress the startup banner",
)
# Add global arguments
subparsers = parser.add_subparsers(
@@ -1151,6 +1412,7 @@ def main(argv: list[str] | None = None) -> int:
See Also:
:func:`create_parser`: Creates the argument parser used by this function
"""
if _should_print_banner(argv):
print_banner()
parser = create_parser()
+66 -1
View File
@@ -5,6 +5,8 @@ and provide a single source of truth for CLI testing.
"""
import argparse
import json
from pathlib import Path
import pytest
@@ -96,7 +98,8 @@ class TestUtilityFunctions:
validate_compression_level("abc")
with pytest.raises(
argparse.ArgumentTypeError, match="Invalid compression level: '1.5'"
argparse.ArgumentTypeError,
match=r"Invalid compression level: '1\.5'\. Must be an integer between 1 and 22\.",
):
validate_compression_level("1.5")
@@ -145,6 +148,15 @@ class TestCLIParser:
assert args.command == "t"
assert args.archive == "test.tzst"
def test_global_machine_readable_flags(self):
"""Test parsing of machine-readable output flags."""
parser = create_parser()
args = parser.parse_args(["--json", "--no-banner", "l", "test.tzst"])
assert args.json_output is True
assert args.no_banner is True
assert args.command == "l"
class TestCLICommands:
"""Test CLI command execution."""
@@ -201,6 +213,59 @@ class TestCLICommands:
assert result == 0
def test_add_command_json_output(self, sample_files, temp_dir, capsys):
"""Test add command JSON output for sidecar integrations."""
archive_path = temp_dir / "json-add.tzst"
file_paths = [str(f) for f in sample_files if f.is_file()]
expected_added = [str(Path(path).resolve()) for path in file_paths]
result = main(["--json", "a", str(archive_path), *file_paths])
assert result == 0
payload = json.loads(capsys.readouterr().out)
assert payload["ok"] is True
assert payload["command"] == "add"
assert payload["normalized_archive"] == str(archive_path)
assert payload["added"] == expected_added
def test_list_command_json_output(self, sample_files, temp_dir, capsys):
"""Test list command JSON output for the desktop app."""
archive_path = temp_dir / "json-list.tzst"
file_paths = [str(f) for f in sample_files if f.is_file()]
create_result = main(["--no-banner", "a", str(archive_path), *file_paths])
assert create_result == 0
capsys.readouterr()
result = main(["--json", "l", str(archive_path)])
assert result == 0
payload = json.loads(capsys.readouterr().out)
assert payload["ok"] is True
assert payload["command"] == "list"
assert payload["summary"]["files"] >= 1
assert isinstance(payload["contents"], list)
def test_missing_archive_json_error(self, temp_dir, capsys):
"""Test JSON-formatted error output."""
fake_archive = temp_dir / "missing.tzst"
result = main(["--json", "l", str(fake_archive)])
assert result == 1
payload = json.loads(capsys.readouterr().err)
assert payload["ok"] is False
assert payload["error"]["type"] == "archive_not_found"
def test_version_json_output(self, capsys):
"""Test JSON version output without the startup banner."""
result = main(["--json", "--version"])
assert result == 0
payload = json.loads(capsys.readouterr().out)
assert payload["ok"] is True
assert payload["command"] == "version"
class TestCLIErrorHandling:
"""Test CLI error handling."""