| Name | riffy JSON |
| Version |
0.1.1
JSON |
| download |
| home_page | None |
| Summary | A low-dependency Python library for parsing and managing RIFF format files |
| upload_time | 2025-10-27 04:00:31 |
| maintainer | None |
| docs_url | None |
| author | None |
| requires_python | >=3.8 |
| license | MIT License
Copyright (c) 2025 John McMeen
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. |
| keywords |
audio
chunk
parser
riff
wav
|
| VCS |
 |
| bugtrack_url |
|
| requirements |
No requirements were recorded.
|
| Travis-CI |
No Travis.
|
| coveralls test coverage |
No coveralls.
|
# riffy
A low-dependency Python library for parsing and managing RIFF (Resource Interchange File Format) files.
Riffy provides a pure Python implementation for working with RIFF format files, with initial support for WAV audio files. The library is designed to have **zero external dependencies** while providing robust parsing capabilities for managing RIFF chunks.
## Features
- **Zero Dependencies**: Pure Python implementation with no external dependencies
- **WAV File Support**: Complete WAV file parsing with format validation
- **RIFF Chunk Management**: Access and inspect individual RIFF chunks
- **Audio Metadata Extraction**: Extract sample rate, channels, bit depth, and duration
- **Format Validation**: Automatic validation of file format and integrity
- **Type Safety**: Full type hints for better IDE support and code quality
- **Lightweight**: Minimal footprint, perfect for embedded systems or restricted environments
## Installation
### From PyPI
```bash
pip install riffy
```
### From Source
```bash
# Clone the repository
git clone https://github.com/jmcmeen/riffy.git
cd riffy
# Install in development mode
pip install -e .
# Or build and install
pip install build
python -m build
pip install dist/riffy-*.whl
```
### For Development
```bash
# Install with development dependencies
pip install -e ".[dev]"
```
## Quick Start
### Basic WAV File Parsing
```python
from riffy import WAVParser
# Parse a WAV file
parser = WAVParser("audio.wav")
info = parser.parse()
# Access format information
print(f"Sample Rate: {info['format']['sample_rate']} Hz")
print(f"Channels: {info['format']['channels']}")
print(f"Bit Depth: {info['format']['bits_per_sample']} bits")
print(f"Duration: {info['duration_seconds']:.2f} seconds")
```
### Accessing RIFF Chunks
```python
from riffy import WAVParser
parser = WAVParser("audio.wav")
parser.parse()
# Access all chunks
for chunk_id, chunk in parser.chunks.items():
print(f"Chunk: {chunk_id}, Size: {chunk.size} bytes, Offset: {chunk.offset}")
# Access specific chunk
if 'fmt ' in parser.chunks:
fmt_chunk = parser.chunks['fmt ']
print(f"Format chunk size: {fmt_chunk.size}")
```
### Working with Audio Data
```python
from riffy import WAVParser
parser = WAVParser("audio.wav")
parser.parse()
# Access raw audio data
audio_data = parser.audio_data
print(f"Audio data size: {len(audio_data)} bytes")
# Get sample count
info = parser.get_info()
print(f"Total samples: {info['sample_count']}")
```
### Exporting Chunks to Binary Files
```python
from riffy import WAVParser
parser = WAVParser("audio.wav")
parser.parse()
# Export raw audio data (most common use case)
bytes_written = parser.export_audio_data("raw_audio.bin")
print(f"Exported {bytes_written} bytes of audio data")
# Export specific chunks
parser.export_chunk('fmt ', "format_chunk.bin")
parser.export_chunk('data', "data_chunk.bin")
# List all available chunks before exporting
chunks = parser.list_chunks()
for chunk_id, info in chunks.items():
print(f"Chunk '{chunk_id}': {info['size']} bytes at offset {info['offset']}")
# Export all chunks
for chunk_id in chunks.keys():
filename = f"{chunk_id.strip()}_chunk.bin"
parser.export_chunk(chunk_id, filename)
```
### Getting Detailed File Information
```python
from riffy import WAVParser
import json
parser = WAVParser("audio.wav")
info = parser.parse()
# Pretty print all information
print(json.dumps(info, indent=2))
```
Output example:
```json
{
"file_path": "/path/to/audio.wav",
"file_size": 1234567,
"format": {
"audio_format": 1,
"channels": 2,
"sample_rate": 44100,
"byte_rate": 176400,
"block_align": 4,
"bits_per_sample": 16,
"is_pcm": true
},
"duration_seconds": 3.5,
"audio_data_size": 617400,
"sample_count": 154350,
"chunks": {
"fmt ": 16,
"data": 617400
}
}
```
## API Reference
### WAVParser
The main class for parsing WAV files.
#### Constructor
```python
WAVParser(file_path: Union[str, Path])
```
**Parameters:**
- `file_path`: Path to the WAV file (string or `pathlib.Path`)
#### Methods
##### `parse() -> Dict`
Parse the WAV file and return comprehensive information.
**Returns:** Dictionary containing file information, format details, and chunk data
**Raises:**
- `FileNotFoundError`: If the file doesn't exist
- `InvalidWAVFormatError`: If the file is not a valid WAV file
- `CorruptedFileError`: If the file is corrupted or incomplete
##### `get_info() -> Dict`
Get comprehensive information about the parsed WAV file.
**Returns:** Dictionary with file metadata (must call `parse()` first)
##### `export_chunk(chunk_id: str, output_path: Union[str, Path]) -> int`
Export a specific chunk's data to a binary file.
**Parameters:**
- `chunk_id`: The ID of the chunk to export (e.g., 'fmt ', 'data')
- `output_path`: Path where the chunk data will be written
**Returns:** Number of bytes written
**Raises:**
- `WAVError`: If file hasn't been parsed yet
- `KeyError`: If the specified chunk doesn't exist
##### `export_audio_data(output_path: Union[str, Path]) -> int`
Export raw audio data to a binary file (convenience method).
**Parameters:**
- `output_path`: Path where the audio data will be written
**Returns:** Number of bytes written
**Raises:**
- `WAVError`: If file hasn't been parsed yet or no audio data exists
##### `list_chunks() -> Dict[str, Dict[str, int]]`
List all chunks in the WAV file with their sizes and offsets.
**Returns:** Dictionary mapping chunk IDs to their metadata (size and offset)
**Raises:**
- `WAVError`: If file hasn't been parsed yet
#### Properties
- `format_info`: `WAVFormat` object containing format details
- `chunks`: Dictionary of `WAVChunk` objects keyed by chunk ID
- `audio_data`: Raw audio data as bytes
### WAVFormat
Dataclass containing WAV format information.
**Attributes:**
- `audio_format`: Audio format code (1 = PCM)
- `channels`: Number of audio channels
- `sample_rate`: Sample rate in Hz
- `byte_rate`: Bytes per second
- `block_align`: Block alignment in bytes
- `bits_per_sample`: Bits per sample
**Properties:**
- `is_pcm`: Boolean indicating if format is PCM (uncompressed)
- `duration_seconds`: Audio duration in seconds
### WAVChunk
Dataclass representing a RIFF chunk.
**Attributes:**
- `id`: Chunk identifier (e.g., "fmt ", "data")
- `size`: Chunk size in bytes
- `data`: Raw chunk data
- `offset`: Byte offset in the file
## Exception Hierarchy
```
RiffyError (base exception)
├── WAVError
│ ├── InvalidWAVFormatError
│ ├── CorruptedFileError
│ └── UnsupportedFormatError
└── ChunkError
├── InvalidChunkError
└── MissingChunkError
```
### Exception Handling
```python
from riffy import WAVParser, InvalidWAVFormatError, CorruptedFileError
try:
parser = WAVParser("audio.wav")
info = parser.parse()
except InvalidWAVFormatError as e:
print(f"Invalid WAV format: {e}")
except CorruptedFileError as e:
print(f"File is corrupted: {e}")
except FileNotFoundError:
print("File not found")
```
## Supported Formats
Currently, Riffy supports:
- **WAV Files**: PCM (uncompressed) audio only
- **RIFF Chunks**: Standard chunk parsing for any RIFF file
### Planned Support
- AVI files
- WebP images
- Additional WAV compression formats
- RIFF chunk writing/modification
## Requirements
- Python 3.8 or higher
- No external dependencies!
## Development
### Running Tests
```bash
# Install development dependencies
pip install -e ".[dev]"
# Run tests
pytest
# Run tests with coverage
pytest --cov=riffy --cov-report=html
```
### Code Formatting
```bash
# Format code with black
black src/
# Lint with ruff
ruff check src/
```
## Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
1. Fork the repository
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
4. Push to the branch (`git push origin feature/amazing-feature`)
5. Open a Pull Request
## License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
## Changelog
### Version 0.1.0 (Initial Release)
- Pure Python WAV file parser
- RIFF chunk management
- Zero external dependencies
- Full type hints
- Comprehensive error handling
## References
- RIFF format specification: [Microsoft RIFF Specification](https://learn.microsoft.com/en-us/windows/win32/xaudio2/resource-interchange-file-format--riff-)
- WAV format specification: [WAV Audio File Format](http://soundfile.sapp.org/doc/WaveFormat/)
## Support
For bugs, feature requests, or questions, please [open an issue](https://github.com/jmcmeen/riffy/issues).
Raw data
{
"_id": null,
"home_page": null,
"name": "riffy",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.8",
"maintainer_email": null,
"keywords": "audio, chunk, parser, riff, wav",
"author": null,
"author_email": "John McMeen <johnmcmeen@gmail.com>",
"download_url": "https://files.pythonhosted.org/packages/54/fe/9dac0acc652f58d001cdf5cd597415ba3bc97a0c1173bbcf42ea151edc5d/riffy-0.1.1.tar.gz",
"platform": null,
"description": "# riffy\n\nA low-dependency Python library for parsing and managing RIFF (Resource Interchange File Format) files.\n\nRiffy provides a pure Python implementation for working with RIFF format files, with initial support for WAV audio files. The library is designed to have **zero external dependencies** while providing robust parsing capabilities for managing RIFF chunks.\n\n## Features\n\n- **Zero Dependencies**: Pure Python implementation with no external dependencies\n- **WAV File Support**: Complete WAV file parsing with format validation\n- **RIFF Chunk Management**: Access and inspect individual RIFF chunks\n- **Audio Metadata Extraction**: Extract sample rate, channels, bit depth, and duration\n- **Format Validation**: Automatic validation of file format and integrity\n- **Type Safety**: Full type hints for better IDE support and code quality\n- **Lightweight**: Minimal footprint, perfect for embedded systems or restricted environments\n\n## Installation\n\n### From PyPI\n\n```bash\npip install riffy\n```\n\n### From Source\n\n```bash\n# Clone the repository\ngit clone https://github.com/jmcmeen/riffy.git\ncd riffy\n\n# Install in development mode\npip install -e .\n\n# Or build and install\npip install build\npython -m build\npip install dist/riffy-*.whl\n```\n\n### For Development\n\n```bash\n# Install with development dependencies\npip install -e \".[dev]\"\n```\n\n## Quick Start\n\n### Basic WAV File Parsing\n\n```python\nfrom riffy import WAVParser\n\n# Parse a WAV file\nparser = WAVParser(\"audio.wav\")\ninfo = parser.parse()\n\n# Access format information\nprint(f\"Sample Rate: {info['format']['sample_rate']} Hz\")\nprint(f\"Channels: {info['format']['channels']}\")\nprint(f\"Bit Depth: {info['format']['bits_per_sample']} bits\")\nprint(f\"Duration: {info['duration_seconds']:.2f} seconds\")\n```\n\n### Accessing RIFF Chunks\n\n```python\nfrom riffy import WAVParser\n\nparser = WAVParser(\"audio.wav\")\nparser.parse()\n\n# Access all chunks\nfor chunk_id, chunk in parser.chunks.items():\n print(f\"Chunk: {chunk_id}, Size: {chunk.size} bytes, Offset: {chunk.offset}\")\n\n# Access specific chunk\nif 'fmt ' in parser.chunks:\n fmt_chunk = parser.chunks['fmt ']\n print(f\"Format chunk size: {fmt_chunk.size}\")\n```\n\n### Working with Audio Data\n\n```python\nfrom riffy import WAVParser\n\nparser = WAVParser(\"audio.wav\")\nparser.parse()\n\n# Access raw audio data\naudio_data = parser.audio_data\nprint(f\"Audio data size: {len(audio_data)} bytes\")\n\n# Get sample count\ninfo = parser.get_info()\nprint(f\"Total samples: {info['sample_count']}\")\n```\n\n### Exporting Chunks to Binary Files\n\n```python\nfrom riffy import WAVParser\n\nparser = WAVParser(\"audio.wav\")\nparser.parse()\n\n# Export raw audio data (most common use case)\nbytes_written = parser.export_audio_data(\"raw_audio.bin\")\nprint(f\"Exported {bytes_written} bytes of audio data\")\n\n# Export specific chunks\nparser.export_chunk('fmt ', \"format_chunk.bin\")\nparser.export_chunk('data', \"data_chunk.bin\")\n\n# List all available chunks before exporting\nchunks = parser.list_chunks()\nfor chunk_id, info in chunks.items():\n print(f\"Chunk '{chunk_id}': {info['size']} bytes at offset {info['offset']}\")\n\n# Export all chunks\nfor chunk_id in chunks.keys():\n filename = f\"{chunk_id.strip()}_chunk.bin\"\n parser.export_chunk(chunk_id, filename)\n```\n\n### Getting Detailed File Information\n\n```python\nfrom riffy import WAVParser\nimport json\n\nparser = WAVParser(\"audio.wav\")\ninfo = parser.parse()\n\n# Pretty print all information\nprint(json.dumps(info, indent=2))\n```\n\nOutput example:\n\n```json\n{\n \"file_path\": \"/path/to/audio.wav\",\n \"file_size\": 1234567,\n \"format\": {\n \"audio_format\": 1,\n \"channels\": 2,\n \"sample_rate\": 44100,\n \"byte_rate\": 176400,\n \"block_align\": 4,\n \"bits_per_sample\": 16,\n \"is_pcm\": true\n },\n \"duration_seconds\": 3.5,\n \"audio_data_size\": 617400,\n \"sample_count\": 154350,\n \"chunks\": {\n \"fmt \": 16,\n \"data\": 617400\n }\n}\n```\n\n## API Reference\n\n### WAVParser\n\nThe main class for parsing WAV files.\n\n#### Constructor\n\n```python\nWAVParser(file_path: Union[str, Path])\n```\n\n**Parameters:**\n\n- `file_path`: Path to the WAV file (string or `pathlib.Path`)\n\n#### Methods\n\n##### `parse() -> Dict`\n\nParse the WAV file and return comprehensive information.\n\n**Returns:** Dictionary containing file information, format details, and chunk data\n\n**Raises:**\n\n- `FileNotFoundError`: If the file doesn't exist\n- `InvalidWAVFormatError`: If the file is not a valid WAV file\n- `CorruptedFileError`: If the file is corrupted or incomplete\n\n##### `get_info() -> Dict`\n\nGet comprehensive information about the parsed WAV file.\n\n**Returns:** Dictionary with file metadata (must call `parse()` first)\n\n##### `export_chunk(chunk_id: str, output_path: Union[str, Path]) -> int`\n\nExport a specific chunk's data to a binary file.\n\n**Parameters:**\n\n- `chunk_id`: The ID of the chunk to export (e.g., 'fmt ', 'data')\n- `output_path`: Path where the chunk data will be written\n\n**Returns:** Number of bytes written\n\n**Raises:**\n\n- `WAVError`: If file hasn't been parsed yet\n- `KeyError`: If the specified chunk doesn't exist\n\n##### `export_audio_data(output_path: Union[str, Path]) -> int`\n\nExport raw audio data to a binary file (convenience method).\n\n**Parameters:**\n\n- `output_path`: Path where the audio data will be written\n\n**Returns:** Number of bytes written\n\n**Raises:**\n\n- `WAVError`: If file hasn't been parsed yet or no audio data exists\n\n##### `list_chunks() -> Dict[str, Dict[str, int]]`\n\nList all chunks in the WAV file with their sizes and offsets.\n\n**Returns:** Dictionary mapping chunk IDs to their metadata (size and offset)\n\n**Raises:**\n\n- `WAVError`: If file hasn't been parsed yet\n\n#### Properties\n\n- `format_info`: `WAVFormat` object containing format details\n- `chunks`: Dictionary of `WAVChunk` objects keyed by chunk ID\n- `audio_data`: Raw audio data as bytes\n\n### WAVFormat\n\nDataclass containing WAV format information.\n\n**Attributes:**\n\n- `audio_format`: Audio format code (1 = PCM)\n- `channels`: Number of audio channels\n- `sample_rate`: Sample rate in Hz\n- `byte_rate`: Bytes per second\n- `block_align`: Block alignment in bytes\n- `bits_per_sample`: Bits per sample\n\n**Properties:**\n\n- `is_pcm`: Boolean indicating if format is PCM (uncompressed)\n- `duration_seconds`: Audio duration in seconds\n\n### WAVChunk\n\nDataclass representing a RIFF chunk.\n\n**Attributes:**\n\n- `id`: Chunk identifier (e.g., \"fmt \", \"data\")\n- `size`: Chunk size in bytes\n- `data`: Raw chunk data\n- `offset`: Byte offset in the file\n\n## Exception Hierarchy\n\n```\nRiffyError (base exception)\n\u251c\u2500\u2500 WAVError\n\u2502 \u251c\u2500\u2500 InvalidWAVFormatError\n\u2502 \u251c\u2500\u2500 CorruptedFileError\n\u2502 \u2514\u2500\u2500 UnsupportedFormatError\n\u2514\u2500\u2500 ChunkError\n \u251c\u2500\u2500 InvalidChunkError\n \u2514\u2500\u2500 MissingChunkError\n```\n\n### Exception Handling\n\n```python\nfrom riffy import WAVParser, InvalidWAVFormatError, CorruptedFileError\n\ntry:\n parser = WAVParser(\"audio.wav\")\n info = parser.parse()\nexcept InvalidWAVFormatError as e:\n print(f\"Invalid WAV format: {e}\")\nexcept CorruptedFileError as e:\n print(f\"File is corrupted: {e}\")\nexcept FileNotFoundError:\n print(\"File not found\")\n```\n\n## Supported Formats\n\nCurrently, Riffy supports:\n\n- **WAV Files**: PCM (uncompressed) audio only\n- **RIFF Chunks**: Standard chunk parsing for any RIFF file\n\n### Planned Support\n\n- AVI files\n- WebP images\n- Additional WAV compression formats\n- RIFF chunk writing/modification\n\n## Requirements\n\n- Python 3.8 or higher\n- No external dependencies!\n\n## Development\n\n### Running Tests\n\n```bash\n# Install development dependencies\npip install -e \".[dev]\"\n\n# Run tests\npytest\n\n# Run tests with coverage\npytest --cov=riffy --cov-report=html\n```\n\n### Code Formatting\n\n```bash\n# Format code with black\nblack src/\n\n# Lint with ruff\nruff check src/\n```\n\n## Contributing\n\nContributions are welcome! Please feel free to submit a Pull Request.\n\n1. Fork the repository\n2. Create your feature branch (`git checkout -b feature/amazing-feature`)\n3. Commit your changes (`git commit -m 'Add some amazing feature'`)\n4. Push to the branch (`git push origin feature/amazing-feature`)\n5. Open a Pull Request\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n## Changelog\n\n### Version 0.1.0 (Initial Release)\n\n- Pure Python WAV file parser\n- RIFF chunk management\n- Zero external dependencies\n- Full type hints\n- Comprehensive error handling\n\n## References\n\n- RIFF format specification: [Microsoft RIFF Specification](https://learn.microsoft.com/en-us/windows/win32/xaudio2/resource-interchange-file-format--riff-)\n- WAV format specification: [WAV Audio File Format](http://soundfile.sapp.org/doc/WaveFormat/)\n\n## Support\n\nFor bugs, feature requests, or questions, please [open an issue](https://github.com/jmcmeen/riffy/issues).\n",
"bugtrack_url": null,
"license": "MIT License\n \n Copyright (c) 2025 John McMeen\n \n Permission is hereby granted, free of charge, to any person obtaining a copy\n of this software and associated documentation files (the \"Software\"), to deal\n in the Software without restriction, including without limitation the rights\n to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n copies of the Software, and to permit persons to whom the Software is\n furnished to do so, subject to the following conditions:\n \n The above copyright notice and this permission notice shall be included in all\n copies or substantial portions of the Software.\n \n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n SOFTWARE.",
"summary": "A low-dependency Python library for parsing and managing RIFF format files",
"version": "0.1.1",
"project_urls": {
"Homepage": "https://github.com/jmcmeen/riffy",
"Issues": "https://github.com/jmcmeen/riffy/issues",
"Repository": "https://github.com/jmcmeen/riffy"
},
"split_keywords": [
"audio",
" chunk",
" parser",
" riff",
" wav"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "f864f08d964231cafb2f42b518d20fe0fabceac2f81d4298b0c50acf4198a776",
"md5": "badb74a46532baf796e523ceb2610b7e",
"sha256": "c047335c983c32b08a416e0887f562c31145977cacbbb26b1de50f7c5b66f200"
},
"downloads": -1,
"filename": "riffy-0.1.1-py3-none-any.whl",
"has_sig": false,
"md5_digest": "badb74a46532baf796e523ceb2610b7e",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.8",
"size": 9765,
"upload_time": "2025-10-27T04:00:30",
"upload_time_iso_8601": "2025-10-27T04:00:30.271703Z",
"url": "https://files.pythonhosted.org/packages/f8/64/f08d964231cafb2f42b518d20fe0fabceac2f81d4298b0c50acf4198a776/riffy-0.1.1-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "54fe9dac0acc652f58d001cdf5cd597415ba3bc97a0c1173bbcf42ea151edc5d",
"md5": "0c3fe4767729f683a80d36a7d4919313",
"sha256": "b7e04aefad9b74f7dc30e6c70dae1d3dcc3bf0a7b6ef18cd10b795f3a79b721c"
},
"downloads": -1,
"filename": "riffy-0.1.1.tar.gz",
"has_sig": false,
"md5_digest": "0c3fe4767729f683a80d36a7d4919313",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.8",
"size": 9720,
"upload_time": "2025-10-27T04:00:31",
"upload_time_iso_8601": "2025-10-27T04:00:31.435851Z",
"url": "https://files.pythonhosted.org/packages/54/fe/9dac0acc652f58d001cdf5cd597415ba3bc97a0c1173bbcf42ea151edc5d/riffy-0.1.1.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-10-27 04:00:31",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "jmcmeen",
"github_project": "riffy",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"lcname": "riffy"
}