From 641681b2e80ead456726b98d29ebc62e7a65db49 Mon Sep 17 00:00:00 2001 From: Raja Sekhar Rao Dheekonda Date: Wed, 25 Jun 2025 22:20:08 -0700 Subject: [PATCH 1/8] add multimodal extras and remove pydub for Python 3.13 compatibility --- README.md | 15 +++++++++ docs/sdk/data_types.mdx | 3 -- docs/usage/rich-objects.mdx | 11 ------- dreadnode/data_types/audio.py | 48 +++++++-------------------- dreadnode/data_types/video.py | 24 +++++++++++--- examples/log_object/audio.ipynb | 37 ++++----------------- examples/log_object/video.ipynb | 7 ++-- poetry.lock | 58 ++++++++++++++++----------------- pyproject.toml | 12 +++---- 9 files changed, 91 insertions(+), 124 deletions(-) diff --git a/README.md b/README.md index 733ef722..23a01eaf 100644 --- a/README.md +++ b/README.md @@ -89,6 +89,21 @@ If you want to build from source: poetry install ``` +## Installation with Extras + +For advanced media processing capabilities (audio, video, images), install the multimodal extras: + +```bash +# Multimodal support (audio, video, image processing) +pip install -U "dreadnode[multimodal]" + +# Training support (ML model integration) +pip install -U "dreadnode[training]" + +# All optional features +pip install -U "dreadnode[multimodal,training]" +``` + See our **[installation guide](https://docs.dreadnode.io/strikes/install)** for more options. ## Getting Started diff --git a/docs/sdk/data_types.mdx b/docs/sdk/data_types.mdx index 3e76ba19..21cc612e 100644 --- a/docs/sdk/data_types.mdx +++ b/docs/sdk/data_types.mdx @@ -24,7 +24,6 @@ Supports: - Local file paths (str or Path) - Numpy arrays with sample rate - Raw bytes -- Pydub AudioSegment object Initialize an Audio object. @@ -36,7 +35,6 @@ Initialize an Audio object. - A path to a local audio file (str or Path) - A numpy array (requires sample\_rate) - Raw bytes - - A pydub AudioSegment * **`sample_rate`** (`int | None`, default: `None` @@ -70,7 +68,6 @@ def __init__( - A path to a local audio file (str or Path) - A numpy array (requires sample_rate) - Raw bytes - - A pydub AudioSegment sample_rate: Required when using numpy arrays caption: Optional caption for the audio format: Optional format to use (default is wav for numpy arrays) diff --git a/docs/usage/rich-objects.mdx b/docs/usage/rich-objects.mdx index e25e5ca1..899c1a2e 100644 --- a/docs/usage/rich-objects.mdx +++ b/docs/usage/rich-objects.mdx @@ -76,17 +76,6 @@ with dn.run("audio-example-numpy"): dn.log_input("my-audio", dn.Audio(audio_data, sample_rate=sample_rate)) ``` -```python AudioSegment -import dreadnode as dn -from pydub import AudioSegment - -# Load audio with pydub -audio_segment = AudioSegment.from_file("path/to/audio.mp3") - -with dn.run("audio-example-segment"): - dn.log_input("my-audio", dn.Audio(audio_segment)) -``` - ```python Raw Bytes import dreadnode as dn diff --git a/dreadnode/data_types/audio.py b/dreadnode/data_types/audio.py index 2fc94795..c4bd3964 100644 --- a/dreadnode/data_types/audio.py +++ b/dreadnode/data_types/audio.py @@ -3,12 +3,15 @@ from pathlib import Path import numpy as np -import soundfile as sf # type: ignore # noqa: PGH003 -from pydub import AudioSegment # type: ignore # noqa: PGH003 + +try: + import soundfile as sf # type: ignore # noqa: PGH003 +except ImportError: + sf = None from dreadnode.data_types.base_data_type import BaseDataType -AudioDataType: t.TypeAlias = str | Path | np.ndarray[t.Any, t.Any] | bytes | AudioSegment +AudioDataType: t.TypeAlias = str | Path | np.ndarray[t.Any, t.Any] | bytes class Audio(BaseDataType): @@ -19,7 +22,6 @@ class Audio(BaseDataType): - Local file paths (str or Path) - Numpy arrays with sample rate - Raw bytes - - Pydub AudioSegment object """ def __init__( @@ -37,11 +39,15 @@ def __init__( - A path to a local audio file (str or Path) - A numpy array (requires sample_rate) - Raw bytes - - A pydub AudioSegment sample_rate: Required when using numpy arrays caption: Optional caption for the audio format: Optional format to use (default is wav for numpy arrays) """ + if sf is None: + raise ImportError( + "Audio processing requires optional dependencies. " + "Install with: pip install dreadnode[multimodal]" + ) self._data = data self._sample_rate = sample_rate self._caption = caption @@ -69,8 +75,6 @@ def _process_audio_data(self) -> tuple[bytes, str, int | None, float | None]: return self._process_numpy_array() if isinstance(self._data, bytes): return self._process_raw_bytes() - if isinstance(self._data, AudioSegment): - return self._process_pydub_audio_segment() raise TypeError(f"Unsupported audio data type: {type(self._data)}") def _process_file_path(self) -> tuple[bytes, str, int | None, float | None]: @@ -123,29 +127,6 @@ def _process_raw_bytes(self) -> tuple[bytes, str, int | None, float | None]: raise TypeError("Raw bytes are expected for this processing method.") return self._data, format_name, self._sample_rate, None - def _process_pydub_audio_segment(self) -> tuple[bytes, str, int | None, float | None]: - """ - Process pydub AudioSegment to bytes. - Returns: - A tuple of (audio_bytes, format_name, sample_rate, duration) - """ - - if not isinstance(self._data, AudioSegment): - raise TypeError("AudioSegment is expected for this processing method.") - - sample_rate = self._data.frame_rate - - buffer = io.BytesIO() - format_name = self._format or "wav" - self._data.export(buffer, format=format_name) - buffer.seek(0) - audio_bytes = buffer.read() - - # PyDUB provides duration in milliseconds, convert to seconds for consistency - duration = len(self._data) / 1000.0 - - return audio_bytes, format_name, sample_rate, duration - def _generate_metadata( self, format_name: str, sample_rate: int | None, duration: float | None ) -> dict[str, str | int | float | None]: @@ -166,8 +147,6 @@ def _generate_metadata( metadata["source-type"] = "numpy.ndarray" elif isinstance(self._data, bytes): metadata["source-type"] = "bytes" - elif isinstance(self._data, AudioSegment): - metadata["source-type"] = "pydub.AudioSegment" if sample_rate is not None: metadata["sample-rate"] = sample_rate @@ -175,11 +154,6 @@ def _generate_metadata( if duration is not None: metadata["duration"] = duration - # Add pydub-specific metadata if available - if isinstance(self._data, AudioSegment): - metadata["channels"] = self._data.channels - metadata["sample-width"] = self._data.sample_width - if self._caption: metadata["caption"] = self._caption diff --git a/dreadnode/data_types/video.py b/dreadnode/data_types/video.py index 430ec3e1..f3d87a8a 100644 --- a/dreadnode/data_types/video.py +++ b/dreadnode/data_types/video.py @@ -4,13 +4,19 @@ from pathlib import Path import numpy as np -from moviepy.video.io.ImageSequenceClip import ImageSequenceClip # type: ignore # noqa: PGH003 -from moviepy.video.VideoClip import VideoClip # type: ignore # noqa: PGH003 from numpy.typing import NDArray from dreadnode.data_types.base_data_type import BaseDataType -VideoDataType: t.TypeAlias = str | Path | NDArray[t.Any] | bytes | list[NDArray[t.Any]] | VideoClip +try: + from moviepy.video.io.ImageSequenceClip import ImageSequenceClip # type: ignore # noqa: PGH003 + from moviepy.video.VideoClip import VideoClip # type: ignore # noqa: PGH003 +except ImportError: + ImageSequenceClip = None + VideoClip = None + + +VideoDataType: t.TypeAlias = str | Path | NDArray[t.Any] | bytes | list[NDArray[t.Any]] | t.Any class Video(BaseDataType): @@ -70,8 +76,13 @@ def to_serializable(self) -> tuple[bytes, dict[str, t.Any]]: return self._process_bytes() if isinstance(self._data, (np.ndarray, list)): return self._process_numpy_array() - if isinstance(self._data, VideoClip): + if VideoClip is not None and isinstance(self._data, VideoClip): return self._process_moviepy_clip() + if VideoClip is None and hasattr(self._data, "write_videofile"): + raise ImportError( + "MoviePy VideoClip detected but moviepy not installed. " + "Install with: pip install dreadnode[multimodal]" + ) raise TypeError(f"Unsupported video data type: {type(self._data)}") def _process_file_path(self) -> tuple[bytes, dict[str, t.Any]]: @@ -110,6 +121,11 @@ def _process_numpy_array(self) -> tuple[bytes, dict[str, t.Any]]: Returns: A tuple of (video_bytes, metadata_dict) """ + if ImageSequenceClip is None: + raise ImportError( + "Video processing from numpy arrays requires moviepy. " + "Install with: pip install dreadnode[multimodal]" + ) if not self._fps: raise ValueError("fps is required for numpy array video frames") if not isinstance(self._data, (np.ndarray, list)): diff --git a/examples/log_object/audio.ipynb b/examples/log_object/audio.ipynb index ae224919..e24ff10c 100644 --- a/examples/log_object/audio.ipynb +++ b/examples/log_object/audio.ipynb @@ -6,14 +6,16 @@ "source": [ "# Dreadnode Audio Logging\n", "\n", - "This notebook demonstrates how to log audio data using Dreadnode's `Audio` data type. The examples cover various audio formats and sources including file paths, numpy arrays, and pydub AudioSegment objects.\n", + "This notebook demonstrates how to log audio data using Dreadnode's `Audio` data type. The examples cover various audio formats and sources including file paths, and numpy arrays.\n", "\n", "## Features\n", "\n", "- Log audio files directly from disk (WAV, MP3, etc.)\n", "- Convert and log numpy arrays as audio\n", - "- Process and log pydub AudioSegment objects\n", - "- Add captions and metadata to audio logs" + "- Add captions and metadata to audio logs\n", + "\n", + "⚠️ Note: Ensure you have installed the multimodal extras to use the Audio data type:\n", + "`pip install dreadnode[multimodal]`" ] }, { @@ -128,32 +130,6 @@ " dn.log_input(\"stereo_sine\", Audio(stereo, sample_rate=sample_rate, caption=\"Stereo audio (440 Hz left, 880 Hz right)\"))" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 3. Pydub AudioSegment Examples\n", - "\n", - "Pydub is a popular library for audio manipulation in Python. Dreadnode supports logging AudioSegment objects directly, which enables powerful audio processing before logging." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from pydub import AudioSegment\n", - "from pydub.generators import Sine\n", - "\n", - "with dn.run(\"audio_pydub_examples\") as r:\n", - " # Load the file with pydub\n", - " audio_segment = AudioSegment.from_file(audio_file_path)\n", - " \n", - " # Log the original AudioSegment\n", - " dn.log_input(\"pydub_original\", Audio(audio_segment, caption=\"Original audio with pydub\"))\n" - ] - }, { "cell_type": "markdown", "metadata": {}, @@ -181,7 +157,6 @@ "\n", "1. Audio files (e.g., WAV, MP3 files)\n", "2. Numpy arrays with sample rate\n", - "3. Pydub AudioSegment objects\n", "4. Audio with custom metadata and captions\n", "\n", "We also showed more advanced audio processing techniques including:\n", @@ -194,7 +169,7 @@ ], "metadata": { "kernelspec": { - "display_name": ".venv", + "display_name": "dreadnode-py3.12", "language": "python", "name": "python3" }, diff --git a/examples/log_object/video.ipynb b/examples/log_object/video.ipynb index 1c0b88ca..d5ca910d 100644 --- a/examples/log_object/video.ipynb +++ b/examples/log_object/video.ipynb @@ -13,7 +13,10 @@ "- Log videos from file paths (MP4, MOV, etc.)\n", "- Create and log videos from sequences of numpy array frames\n", "- Log MoviePy video clip objects\n", - "- Control video properties like frame rate, dimensions and format" + "- Control video properties like frame rate, dimensions and format\n", + "\n", + "⚠️ Note: Ensure you have installed the multimodal extras to use the Video data type:\n", + "`pip install dreadnode[multimodal]`" ] }, { @@ -217,7 +220,7 @@ ], "metadata": { "kernelspec": { - "display_name": ".venv", + "display_name": "dreadnode-py3.12", "language": "python", "name": "python3" }, diff --git a/poetry.lock b/poetry.lock index 2c974db9..394f8117 100644 --- a/poetry.lock +++ b/poetry.lock @@ -701,9 +701,10 @@ files = [ name = "cffi" version = "1.17.1" description = "Foreign Function Interface for Python calling C code." -optional = false +optional = true python-versions = ">=3.8" groups = ["main"] +markers = "extra == \"multimodal\"" files = [ {file = "cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"}, {file = "cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67"}, @@ -917,7 +918,7 @@ files = [ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] -markers = {main = "platform_system == \"Windows\""} +markers = {main = "(extra == \"training\" or extra == \"multimodal\") and platform_system == \"Windows\""} [[package]] name = "coolname" @@ -978,9 +979,10 @@ vision = ["Pillow (>=9.4.0)"] name = "decorator" version = "5.2.1" description = "Decorators for Humans" -optional = false +optional = true python-versions = ">=3.8" -groups = ["main", "dev"] +groups = ["main"] +markers = "extra == \"multimodal\"" files = [ {file = "decorator-5.2.1-py3-none-any.whl", hash = "sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a"}, {file = "decorator-5.2.1.tar.gz", hash = "sha256:65f266143752f734b0a7cc83c46f4618af75b8c5911b00ccb61d0ac9b6da0360"}, @@ -1485,9 +1487,10 @@ all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2 name = "imageio" version = "2.37.0" description = "Library for reading and writing a wide range of image, video, scientific, and volumetric data formats." -optional = false +optional = true python-versions = ">=3.9" -groups = ["main", "dev"] +groups = ["main"] +markers = "extra == \"multimodal\"" files = [ {file = "imageio-2.37.0-py3-none-any.whl", hash = "sha256:11efa15b87bc7871b61590326b2d635439acc321cf7f8ce996f812543ce10eed"}, {file = "imageio-2.37.0.tar.gz", hash = "sha256:71b57b3669666272c818497aebba2b4c5f20d5b37c81720e5e1a56d59c492996"}, @@ -1519,9 +1522,10 @@ tifffile = ["tifffile"] name = "imageio-ffmpeg" version = "0.6.0" description = "FFMPEG wrapper for Python" -optional = false +optional = true python-versions = ">=3.9" -groups = ["main", "dev"] +groups = ["main"] +markers = "extra == \"multimodal\"" files = [ {file = "imageio_ffmpeg-0.6.0-py3-none-macosx_10_9_intel.macosx_10_9_x86_64.whl", hash = "sha256:9d2baaf867088508d4a3458e61eeb30e945c4ad8016025545f66c4b5aaef0a61"}, {file = "imageio_ffmpeg-0.6.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:b1ae3173414b5fc5f538a726c4e48ea97edc0d2cdc11f103afee655c463fa742"}, @@ -1965,9 +1969,10 @@ files = [ name = "moviepy" version = "2.2.1" description = "Video editing with Python" -optional = false +optional = true python-versions = "*" -groups = ["main", "dev"] +groups = ["main"] +markers = "extra == \"multimodal\"" files = [ {file = "moviepy-2.2.1-py3-none-any.whl", hash = "sha256:6b56803fec2ac54b557404126ac1160e65448e03798fa282bd23e8fab3795060"}, {file = "moviepy-2.2.1.tar.gz", hash = "sha256:c80cb56815ece94e5e3e2d361aa40070eeb30a09d23a24c4e684d03e16deacb1"}, @@ -2551,9 +2556,10 @@ types-pytz = ">=2022.1.1" name = "pillow" version = "10.4.0" description = "Python Imaging Library (Fork)" -optional = false +optional = true python-versions = ">=3.8" -groups = ["main", "dev"] +groups = ["main"] +markers = "extra == \"multimodal\"" files = [ {file = "pillow-10.4.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:4d9667937cfa347525b319ae34375c37b9ee6b525440f3ef48542fcf66f2731e"}, {file = "pillow-10.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:543f3dc61c18dafb755773efc89aae60d06b6596a63914107f75459cf984164d"}, @@ -2713,9 +2719,10 @@ virtualenv = ">=20.10.0" name = "proglog" version = "0.1.12" description = "Log and progress bar manager for console, notebooks, web..." -optional = false +optional = true python-versions = "*" -groups = ["main", "dev"] +groups = ["main"] +markers = "extra == \"multimodal\"" files = [ {file = "proglog-0.1.12-py3-none-any.whl", hash = "sha256:ccaafce51e80a81c65dc907a460c07ccb8ec1f78dc660cfd8f9ec3a22f01b84c"}, {file = "proglog-0.1.12.tar.gz", hash = "sha256:361ee074721c277b89b75c061336cb8c5f287c92b043efa562ccf7866cda931c"}, @@ -2912,9 +2919,10 @@ test = ["cffi", "hypothesis", "pandas", "pytest", "pytz"] name = "pycparser" version = "2.22" description = "C parser in Python" -optional = false +optional = true python-versions = ">=3.8" groups = ["main"] +markers = "extra == \"multimodal\"" files = [ {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"}, {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, @@ -3074,18 +3082,6 @@ pydantic-core = ">=2.15.0" docs = ["Sphinx (>=5.3.0,<6.0.0)", "furo (>=2022.12.7,<2023.0.0)", "sphinx-copybutton (>=0.5.1,<0.6.0)", "sphinx_design (>=0.3.0,<0.4.0)", "toml (>=0.10.2,<0.11.0)"] lxml = ["lxml (>=4.9.0)"] -[[package]] -name = "pydub" -version = "0.25.1" -description = "Manipulate audio with an simple and easy high level interface" -optional = false -python-versions = "*" -groups = ["main", "dev"] -files = [ - {file = "pydub-0.25.1-py2.py3-none-any.whl", hash = "sha256:65617e33033874b59d87db603aa1ed450633288aefead953b30bded59cb599a6"}, - {file = "pydub-0.25.1.tar.gz", hash = "sha256:980a33ce9949cab2a569606b65674d748ecbca4f0796887fd6f46173a7b0d30f"}, -] - [[package]] name = "pygments" version = "2.19.1" @@ -3170,6 +3166,7 @@ files = [ {file = "python_dotenv-1.1.0-py3-none-any.whl", hash = "sha256:d7c01d9e2293916c18baf562d95698754b0dbbb5e74d457c45d4f6561fb9d55d"}, {file = "python_dotenv-1.1.0.tar.gz", hash = "sha256:41f90bc6f5f177fb41f53e87666db362025010eb28f60a01c9143bfa33a2b2d5"}, ] +markers = {main = "extra == \"multimodal\""} [package.extras] cli = ["click (>=5.0)"] @@ -3803,9 +3800,10 @@ files = [ name = "soundfile" version = "0.13.1" description = "An audio library based on libsndfile, CFFI and NumPy" -optional = false +optional = true python-versions = "*" groups = ["main"] +markers = "extra == \"multimodal\"" files = [ {file = "soundfile-0.13.1-py2.py3-none-any.whl", hash = "sha256:a23c717560da2cf4c7b5ae1142514e0fd82d6bbd9dfc93a50423447142f2c445"}, {file = "soundfile-0.13.1-py2.py3-none-macosx_10_9_x86_64.whl", hash = "sha256:82dc664d19831933fe59adad199bf3945ad06d84bc111a5b4c0d3089a5b9ec33"}, @@ -3957,6 +3955,7 @@ files = [ {file = "tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2"}, {file = "tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2"}, ] +markers = {main = "extra == \"training\" or extra == \"multimodal\""} [package.dependencies] colorama = {version = "*", markers = "platform_system == \"Windows\""} @@ -4591,9 +4590,10 @@ test = ["big-O", "importlib-resources ; python_version < \"3.9\"", "jaraco.funct type = ["pytest-mypy"] [extras] +multimodal = ["moviepy", "soundfile"] training = ["transformers"] [metadata] lock-version = "2.1" python-versions = ">=3.10,<3.14" -content-hash = "712ef7d913cf9c4877eb34100161b9327f40ffd68d6d2a51741f507c65c45106" +content-hash = "e771a859cf2c217a2e982e0542bb673c89a75da742fe2c9030be174e91380a75" diff --git a/pyproject.toml b/pyproject.toml index 9fe93954..1d2bc412 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,12 +1,12 @@ [project] name = "dreadnode" -version = "1.0.8" +version = "1.0.9" description = "Dreadnode SDK" requires-python = ">=3.10,<3.14" [tool.poetry] name = "dreadnode" -version = "1.0.7" +version = "1.0.9" description = "Dreadnode SDK" authors = ["Nick Landers "] repository = "https://github.com/dreadnode/sdk" @@ -25,12 +25,12 @@ fsspec = { version = ">=2023.1.0,<=2025.3.0", extras = [ ] } # Pinned for datasets compatibility transformers = { version = "^4.41.0", optional = true } -soundfile = "^0.13.1" -moviepy = "^2.1.2" -pydub = "^0.25.1" +soundfile = { version = "^0.13.1", optional = true } +moviepy = { version = "^2.1.2", optional = true } [tool.poetry.extras] training = ["transformers"] +multimodal = ["soundfile", "moviepy"] [tool.poetry.group.dev.dependencies] mypy = "^1.8.0" @@ -43,8 +43,6 @@ pandas-stubs = "^2.2.3.250308" types-requests = "^2.32.0.20250306" rigging = "^2.3.0" typer = "^0.15.2" -pydub = "^0.25.1" -moviepy = "^2.1.2" datasets = "^3.5.0" pyarrow = "^19.0.1" From 9564736e3d7033ba09ca95aa8d3c436346479730 Mon Sep 17 00:00:00 2001 From: Raja Sekhar Rao Dheekonda Date: Wed, 25 Jun 2025 22:37:19 -0700 Subject: [PATCH 2/8] Fix ruff errors --- dreadnode/data_types/video.py | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/dreadnode/data_types/video.py b/dreadnode/data_types/video.py index f3d87a8a..73fc1a74 100644 --- a/dreadnode/data_types/video.py +++ b/dreadnode/data_types/video.py @@ -130,9 +130,22 @@ def _process_numpy_array(self) -> tuple[bytes, dict[str, t.Any]]: raise ValueError("fps is required for numpy array video frames") if not isinstance(self._data, (np.ndarray, list)): raise TypeError("data must be a numpy array or list of numpy arrays") + + # Type guard for mypy + assert ImageSequenceClip is not None # noqa: S101 + + frames = self._extract_frames_from_data() + if not frames: + raise ValueError("No frames found in input data") + + return self._create_video_from_frames_data(frames) + + def _extract_frames_from_data(self) -> list[NDArray[t.Any]]: + """Extract frames from numpy array or list data.""" frames = [] rgb_dim = 3 rgba_dim = 4 + if isinstance(self._data, np.ndarray): if self._data.ndim == rgb_dim: # Single frame frames = [self._data] @@ -143,23 +156,23 @@ def _process_numpy_array(self) -> tuple[bytes, dict[str, t.Any]]: elif isinstance(self._data, list): frames = self._data - if not frames: - raise ValueError("No frames found in input data") + return frames + def _create_video_from_frames_data( + self, frames: list[NDArray[t.Any]] + ) -> tuple[bytes, dict[str, t.Any]]: + """Create video file from frames.""" frame_height, frame_width = frames[0].shape[:2] - temp_fd, temp_path = tempfile.mkstemp(suffix=f".{self._format}") os.close(temp_fd) try: # Create clip and write to file clip = ImageSequenceClip(frames, fps=self._fps) - clip.write_videofile( temp_path, fps=self._fps, ) - video_bytes = Path(temp_path).read_bytes() metadata = self._generate_metadata(self._format) From 1546a97e073db242f7a199377786380d9cb2f92a Mon Sep 17 00:00:00 2001 From: Raja Sekhar Rao Dheekonda Date: Thu, 26 Jun 2025 12:42:19 -0700 Subject: [PATCH 3/8] Move pillow version to multimodal extras --- README.md | 13 ++- dreadnode/data_types/image.py | 12 ++- examples/log_object/image.ipynb | 7 +- poetry.lock | 174 ++++++++++++++++---------------- pyproject.toml | 3 +- 5 files changed, 114 insertions(+), 95 deletions(-) diff --git a/README.md b/README.md index 23a01eaf..d9193b3a 100644 --- a/README.md +++ b/README.md @@ -87,6 +87,11 @@ pip install -U dreadnode If you want to build from source: ```bash poetry install +# Install with multimodal extras +poetry install --extras multimodal + +# Install with training extras +poetry install --extras training ``` ## Installation with Extras @@ -94,14 +99,14 @@ poetry install For advanced media processing capabilities (audio, video, images), install the multimodal extras: ```bash -# Multimodal support (audio, video, image processing) -pip install -U "dreadnode[multimodal]" +# Multimodal support (audio, video processing) +pip install -U dreadnode[multimodal] # Training support (ML model integration) -pip install -U "dreadnode[training]" +pip install -U dreadnode[training] # All optional features -pip install -U "dreadnode[multimodal,training]" +pip install -U dreadnode[multimodal,training] ``` See our **[installation guide](https://docs.dreadnode.io/strikes/install)** for more options. diff --git a/dreadnode/data_types/image.py b/dreadnode/data_types/image.py index ee886b2e..8f1ad818 100644 --- a/dreadnode/data_types/image.py +++ b/dreadnode/data_types/image.py @@ -4,11 +4,15 @@ from pathlib import Path import numpy as np -from PIL import Image as PILImage from dreadnode.data_types.base_data_type import BaseDataType -ImageDataType = PILImage.Image | np.ndarray[t.Any, t.Any] +try: + from PIL import Image as PILImage +except ImportError: + PILImage = None + +ImageDataType = t.Any | np.ndarray[t.Any, t.Any] ImageDataOrPathType = str | Path | bytes | ImageDataType @@ -44,6 +48,10 @@ def __init__( caption: Optional caption for the image format: Optional format to use when saving (png, jpg, etc.) """ + if PILImage is None: + raise ImportError( + "Image processing requires PIL (Pillow). Install with: pip install dreadnode[multimodal]" + ) self._data = data self._mode = mode self._caption = caption diff --git a/examples/log_object/image.ipynb b/examples/log_object/image.ipynb index 9f693fcf..4a7414f4 100644 --- a/examples/log_object/image.ipynb +++ b/examples/log_object/image.ipynb @@ -14,7 +14,10 @@ "- Convert and log PIL Image objects\n", "- Transform numpy arrays into images\n", "- Handle raw bytes and base64 encoded images\n", - "- Convert between image modes (RGB, RGBA, grayscale)" + "- Convert between image modes (RGB, RGBA, grayscale)\n", + "\n", + "⚠️ Note: Ensure you have installed the multimodal extras to use the Video data type:\n", + "`pip install dreadnode[multimodal]`" ] }, { @@ -265,7 +268,7 @@ ], "metadata": { "kernelspec": { - "display_name": ".venv", + "display_name": "Python 3", "language": "python", "name": "python3" }, diff --git a/poetry.lock b/poetry.lock index 394f8117..645b1c17 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2554,100 +2554,102 @@ types-pytz = ">=2022.1.1" [[package]] name = "pillow" -version = "10.4.0" +version = "11.2.1" description = "Python Imaging Library (Fork)" optional = true -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["main"] markers = "extra == \"multimodal\"" files = [ - {file = "pillow-10.4.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:4d9667937cfa347525b319ae34375c37b9ee6b525440f3ef48542fcf66f2731e"}, - {file = "pillow-10.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:543f3dc61c18dafb755773efc89aae60d06b6596a63914107f75459cf984164d"}, - {file = "pillow-10.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7928ecbf1ece13956b95d9cbcfc77137652b02763ba384d9ab508099a2eca856"}, - {file = "pillow-10.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4d49b85c4348ea0b31ea63bc75a9f3857869174e2bf17e7aba02945cd218e6f"}, - {file = "pillow-10.4.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:6c762a5b0997f5659a5ef2266abc1d8851ad7749ad9a6a5506eb23d314e4f46b"}, - {file = "pillow-10.4.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:a985e028fc183bf12a77a8bbf36318db4238a3ded7fa9df1b9a133f1cb79f8fc"}, - {file = "pillow-10.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:812f7342b0eee081eaec84d91423d1b4650bb9828eb53d8511bcef8ce5aecf1e"}, - {file = "pillow-10.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ac1452d2fbe4978c2eec89fb5a23b8387aba707ac72810d9490118817d9c0b46"}, - {file = "pillow-10.4.0-cp310-cp310-win32.whl", hash = "sha256:bcd5e41a859bf2e84fdc42f4edb7d9aba0a13d29a2abadccafad99de3feff984"}, - {file = "pillow-10.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:ecd85a8d3e79cd7158dec1c9e5808e821feea088e2f69a974db5edf84dc53141"}, - {file = "pillow-10.4.0-cp310-cp310-win_arm64.whl", hash = "sha256:ff337c552345e95702c5fde3158acb0625111017d0e5f24bf3acdb9cc16b90d1"}, - {file = "pillow-10.4.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:0a9ec697746f268507404647e531e92889890a087e03681a3606d9b920fbee3c"}, - {file = "pillow-10.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dfe91cb65544a1321e631e696759491ae04a2ea11d36715eca01ce07284738be"}, - {file = "pillow-10.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5dc6761a6efc781e6a1544206f22c80c3af4c8cf461206d46a1e6006e4429ff3"}, - {file = "pillow-10.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e84b6cc6a4a3d76c153a6b19270b3526a5a8ed6b09501d3af891daa2a9de7d6"}, - {file = "pillow-10.4.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:bbc527b519bd3aa9d7f429d152fea69f9ad37c95f0b02aebddff592688998abe"}, - {file = "pillow-10.4.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:76a911dfe51a36041f2e756b00f96ed84677cdeb75d25c767f296c1c1eda1319"}, - {file = "pillow-10.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:59291fb29317122398786c2d44427bbd1a6d7ff54017075b22be9d21aa59bd8d"}, - {file = "pillow-10.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:416d3a5d0e8cfe4f27f574362435bc9bae57f679a7158e0096ad2beb427b8696"}, - {file = "pillow-10.4.0-cp311-cp311-win32.whl", hash = "sha256:7086cc1d5eebb91ad24ded9f58bec6c688e9f0ed7eb3dbbf1e4800280a896496"}, - {file = "pillow-10.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:cbed61494057c0f83b83eb3a310f0bf774b09513307c434d4366ed64f4128a91"}, - {file = "pillow-10.4.0-cp311-cp311-win_arm64.whl", hash = "sha256:f5f0c3e969c8f12dd2bb7e0b15d5c468b51e5017e01e2e867335c81903046a22"}, - {file = "pillow-10.4.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:673655af3eadf4df6b5457033f086e90299fdd7a47983a13827acf7459c15d94"}, - {file = "pillow-10.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:866b6942a92f56300012f5fbac71f2d610312ee65e22f1aa2609e491284e5597"}, - {file = "pillow-10.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29dbdc4207642ea6aad70fbde1a9338753d33fb23ed6956e706936706f52dd80"}, - {file = "pillow-10.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf2342ac639c4cf38799a44950bbc2dfcb685f052b9e262f446482afaf4bffca"}, - {file = "pillow-10.4.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:f5b92f4d70791b4a67157321c4e8225d60b119c5cc9aee8ecf153aace4aad4ef"}, - {file = "pillow-10.4.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:86dcb5a1eb778d8b25659d5e4341269e8590ad6b4e8b44d9f4b07f8d136c414a"}, - {file = "pillow-10.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:780c072c2e11c9b2c7ca37f9a2ee8ba66f44367ac3e5c7832afcfe5104fd6d1b"}, - {file = "pillow-10.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:37fb69d905be665f68f28a8bba3c6d3223c8efe1edf14cc4cfa06c241f8c81d9"}, - {file = "pillow-10.4.0-cp312-cp312-win32.whl", hash = "sha256:7dfecdbad5c301d7b5bde160150b4db4c659cee2b69589705b6f8a0c509d9f42"}, - {file = "pillow-10.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:1d846aea995ad352d4bdcc847535bd56e0fd88d36829d2c90be880ef1ee4668a"}, - {file = "pillow-10.4.0-cp312-cp312-win_arm64.whl", hash = "sha256:e553cad5179a66ba15bb18b353a19020e73a7921296a7979c4a2b7f6a5cd57f9"}, - {file = "pillow-10.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8bc1a764ed8c957a2e9cacf97c8b2b053b70307cf2996aafd70e91a082e70df3"}, - {file = "pillow-10.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6209bb41dc692ddfee4942517c19ee81b86c864b626dbfca272ec0f7cff5d9fb"}, - {file = "pillow-10.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bee197b30783295d2eb680b311af15a20a8b24024a19c3a26431ff83eb8d1f70"}, - {file = "pillow-10.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ef61f5dd14c300786318482456481463b9d6b91ebe5ef12f405afbba77ed0be"}, - {file = "pillow-10.4.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:297e388da6e248c98bc4a02e018966af0c5f92dfacf5a5ca22fa01cb3179bca0"}, - {file = "pillow-10.4.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:e4db64794ccdf6cb83a59d73405f63adbe2a1887012e308828596100a0b2f6cc"}, - {file = "pillow-10.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bd2880a07482090a3bcb01f4265f1936a903d70bc740bfcb1fd4e8a2ffe5cf5a"}, - {file = "pillow-10.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4b35b21b819ac1dbd1233317adeecd63495f6babf21b7b2512d244ff6c6ce309"}, - {file = "pillow-10.4.0-cp313-cp313-win32.whl", hash = "sha256:551d3fd6e9dc15e4c1eb6fc4ba2b39c0c7933fa113b220057a34f4bb3268a060"}, - {file = "pillow-10.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:030abdbe43ee02e0de642aee345efa443740aa4d828bfe8e2eb11922ea6a21ea"}, - {file = "pillow-10.4.0-cp313-cp313-win_arm64.whl", hash = "sha256:5b001114dd152cfd6b23befeb28d7aee43553e2402c9f159807bf55f33af8a8d"}, - {file = "pillow-10.4.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:8d4d5063501b6dd4024b8ac2f04962d661222d120381272deea52e3fc52d3736"}, - {file = "pillow-10.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7c1ee6f42250df403c5f103cbd2768a28fe1a0ea1f0f03fe151c8741e1469c8b"}, - {file = "pillow-10.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b15e02e9bb4c21e39876698abf233c8c579127986f8207200bc8a8f6bb27acf2"}, - {file = "pillow-10.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a8d4bade9952ea9a77d0c3e49cbd8b2890a399422258a77f357b9cc9be8d680"}, - {file = "pillow-10.4.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:43efea75eb06b95d1631cb784aa40156177bf9dd5b4b03ff38979e048258bc6b"}, - {file = "pillow-10.4.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:950be4d8ba92aca4b2bb0741285a46bfae3ca699ef913ec8416c1b78eadd64cd"}, - {file = "pillow-10.4.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:d7480af14364494365e89d6fddc510a13e5a2c3584cb19ef65415ca57252fb84"}, - {file = "pillow-10.4.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:73664fe514b34c8f02452ffb73b7a92c6774e39a647087f83d67f010eb9a0cf0"}, - {file = "pillow-10.4.0-cp38-cp38-win32.whl", hash = "sha256:e88d5e6ad0d026fba7bdab8c3f225a69f063f116462c49892b0149e21b6c0a0e"}, - {file = "pillow-10.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:5161eef006d335e46895297f642341111945e2c1c899eb406882a6c61a4357ab"}, - {file = "pillow-10.4.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:0ae24a547e8b711ccaaf99c9ae3cd975470e1a30caa80a6aaee9a2f19c05701d"}, - {file = "pillow-10.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:298478fe4f77a4408895605f3482b6cc6222c018b2ce565c2b6b9c354ac3229b"}, - {file = "pillow-10.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:134ace6dc392116566980ee7436477d844520a26a4b1bd4053f6f47d096997fd"}, - {file = "pillow-10.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:930044bb7679ab003b14023138b50181899da3f25de50e9dbee23b61b4de2126"}, - {file = "pillow-10.4.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:c76e5786951e72ed3686e122d14c5d7012f16c8303a674d18cdcd6d89557fc5b"}, - {file = "pillow-10.4.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:b2724fdb354a868ddf9a880cb84d102da914e99119211ef7ecbdc613b8c96b3c"}, - {file = "pillow-10.4.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:dbc6ae66518ab3c5847659e9988c3b60dc94ffb48ef9168656e0019a93dbf8a1"}, - {file = "pillow-10.4.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:06b2f7898047ae93fad74467ec3d28fe84f7831370e3c258afa533f81ef7f3df"}, - {file = "pillow-10.4.0-cp39-cp39-win32.whl", hash = "sha256:7970285ab628a3779aecc35823296a7869f889b8329c16ad5a71e4901a3dc4ef"}, - {file = "pillow-10.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:961a7293b2457b405967af9c77dcaa43cc1a8cd50d23c532e62d48ab6cdd56f5"}, - {file = "pillow-10.4.0-cp39-cp39-win_arm64.whl", hash = "sha256:32cda9e3d601a52baccb2856b8ea1fc213c90b340c542dcef77140dfa3278a9e"}, - {file = "pillow-10.4.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:5b4815f2e65b30f5fbae9dfffa8636d992d49705723fe86a3661806e069352d4"}, - {file = "pillow-10.4.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:8f0aef4ef59694b12cadee839e2ba6afeab89c0f39a3adc02ed51d109117b8da"}, - {file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f4727572e2918acaa9077c919cbbeb73bd2b3ebcfe033b72f858fc9fbef0026"}, - {file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff25afb18123cea58a591ea0244b92eb1e61a1fd497bf6d6384f09bc3262ec3e"}, - {file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:dc3e2db6ba09ffd7d02ae9141cfa0ae23393ee7687248d46a7507b75d610f4f5"}, - {file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:02a2be69f9c9b8c1e97cf2713e789d4e398c751ecfd9967c18d0ce304efbf885"}, - {file = "pillow-10.4.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:0755ffd4a0c6f267cccbae2e9903d95477ca2f77c4fcf3a3a09570001856c8a5"}, - {file = "pillow-10.4.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:a02364621fe369e06200d4a16558e056fe2805d3468350df3aef21e00d26214b"}, - {file = "pillow-10.4.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:1b5dea9831a90e9d0721ec417a80d4cbd7022093ac38a568db2dd78363b00908"}, - {file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9b885f89040bb8c4a1573566bbb2f44f5c505ef6e74cec7ab9068c900047f04b"}, - {file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87dd88ded2e6d74d31e1e0a99a726a6765cda32d00ba72dc37f0651f306daaa8"}, - {file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:2db98790afc70118bd0255c2eeb465e9767ecf1f3c25f9a1abb8ffc8cfd1fe0a"}, - {file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:f7baece4ce06bade126fb84b8af1c33439a76d8a6fd818970215e0560ca28c27"}, - {file = "pillow-10.4.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:cfdd747216947628af7b259d274771d84db2268ca062dd5faf373639d00113a3"}, - {file = "pillow-10.4.0.tar.gz", hash = "sha256:166c1cd4d24309b30d61f79f4a9114b7b2313d7450912277855ff5dfd7cd4a06"}, + {file = "pillow-11.2.1-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:d57a75d53922fc20c165016a20d9c44f73305e67c351bbc60d1adaf662e74047"}, + {file = "pillow-11.2.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:127bf6ac4a5b58b3d32fc8289656f77f80567d65660bc46f72c0d77e6600cc95"}, + {file = "pillow-11.2.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b4ba4be812c7a40280629e55ae0b14a0aafa150dd6451297562e1764808bbe61"}, + {file = "pillow-11.2.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c8bd62331e5032bc396a93609982a9ab6b411c05078a52f5fe3cc59234a3abd1"}, + {file = "pillow-11.2.1-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:562d11134c97a62fe3af29581f083033179f7ff435f78392565a1ad2d1c2c45c"}, + {file = "pillow-11.2.1-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:c97209e85b5be259994eb5b69ff50c5d20cca0f458ef9abd835e262d9d88b39d"}, + {file = "pillow-11.2.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0c3e6d0f59171dfa2e25d7116217543310908dfa2770aa64b8f87605f8cacc97"}, + {file = "pillow-11.2.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cc1c3bc53befb6096b84165956e886b1729634a799e9d6329a0c512ab651e579"}, + {file = "pillow-11.2.1-cp310-cp310-win32.whl", hash = "sha256:312c77b7f07ab2139924d2639860e084ec2a13e72af54d4f08ac843a5fc9c79d"}, + {file = "pillow-11.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:9bc7ae48b8057a611e5fe9f853baa88093b9a76303937449397899385da06fad"}, + {file = "pillow-11.2.1-cp310-cp310-win_arm64.whl", hash = "sha256:2728567e249cdd939f6cc3d1f049595c66e4187f3c34078cbc0a7d21c47482d2"}, + {file = "pillow-11.2.1-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:35ca289f712ccfc699508c4658a1d14652e8033e9b69839edf83cbdd0ba39e70"}, + {file = "pillow-11.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e0409af9f829f87a2dfb7e259f78f317a5351f2045158be321fd135973fff7bf"}, + {file = "pillow-11.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4e5c5edee874dce4f653dbe59db7c73a600119fbea8d31f53423586ee2aafd7"}, + {file = "pillow-11.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b93a07e76d13bff9444f1a029e0af2964e654bfc2e2c2d46bfd080df5ad5f3d8"}, + {file = "pillow-11.2.1-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:e6def7eed9e7fa90fde255afaf08060dc4b343bbe524a8f69bdd2a2f0018f600"}, + {file = "pillow-11.2.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:8f4f3724c068be008c08257207210c138d5f3731af6c155a81c2b09a9eb3a788"}, + {file = "pillow-11.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a0a6709b47019dff32e678bc12c63008311b82b9327613f534e496dacaefb71e"}, + {file = "pillow-11.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f6b0c664ccb879109ee3ca702a9272d877f4fcd21e5eb63c26422fd6e415365e"}, + {file = "pillow-11.2.1-cp311-cp311-win32.whl", hash = "sha256:cc5d875d56e49f112b6def6813c4e3d3036d269c008bf8aef72cd08d20ca6df6"}, + {file = "pillow-11.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:0f5c7eda47bf8e3c8a283762cab94e496ba977a420868cb819159980b6709193"}, + {file = "pillow-11.2.1-cp311-cp311-win_arm64.whl", hash = "sha256:4d375eb838755f2528ac8cbc926c3e31cc49ca4ad0cf79cff48b20e30634a4a7"}, + {file = "pillow-11.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:78afba22027b4accef10dbd5eed84425930ba41b3ea0a86fa8d20baaf19d807f"}, + {file = "pillow-11.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:78092232a4ab376a35d68c4e6d5e00dfd73454bd12b230420025fbe178ee3b0b"}, + {file = "pillow-11.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25a5f306095c6780c52e6bbb6109624b95c5b18e40aab1c3041da3e9e0cd3e2d"}, + {file = "pillow-11.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c7b29dbd4281923a2bfe562acb734cee96bbb129e96e6972d315ed9f232bef4"}, + {file = "pillow-11.2.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:3e645b020f3209a0181a418bffe7b4a93171eef6c4ef6cc20980b30bebf17b7d"}, + {file = "pillow-11.2.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:b2dbea1012ccb784a65349f57bbc93730b96e85b42e9bf7b01ef40443db720b4"}, + {file = "pillow-11.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:da3104c57bbd72948d75f6a9389e6727d2ab6333c3617f0a89d72d4940aa0443"}, + {file = "pillow-11.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:598174aef4589af795f66f9caab87ba4ff860ce08cd5bb447c6fc553ffee603c"}, + {file = "pillow-11.2.1-cp312-cp312-win32.whl", hash = "sha256:1d535df14716e7f8776b9e7fee118576d65572b4aad3ed639be9e4fa88a1cad3"}, + {file = "pillow-11.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:14e33b28bf17c7a38eede290f77db7c664e4eb01f7869e37fa98a5aa95978941"}, + {file = "pillow-11.2.1-cp312-cp312-win_arm64.whl", hash = "sha256:21e1470ac9e5739ff880c211fc3af01e3ae505859392bf65458c224d0bf283eb"}, + {file = "pillow-11.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:fdec757fea0b793056419bca3e9932eb2b0ceec90ef4813ea4c1e072c389eb28"}, + {file = "pillow-11.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b0e130705d568e2f43a17bcbe74d90958e8a16263868a12c3e0d9c8162690830"}, + {file = "pillow-11.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bdb5e09068332578214cadd9c05e3d64d99e0e87591be22a324bdbc18925be0"}, + {file = "pillow-11.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d189ba1bebfbc0c0e529159631ec72bb9e9bc041f01ec6d3233d6d82eb823bc1"}, + {file = "pillow-11.2.1-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:191955c55d8a712fab8934a42bfefbf99dd0b5875078240943f913bb66d46d9f"}, + {file = "pillow-11.2.1-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:ad275964d52e2243430472fc5d2c2334b4fc3ff9c16cb0a19254e25efa03a155"}, + {file = "pillow-11.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:750f96efe0597382660d8b53e90dd1dd44568a8edb51cb7f9d5d918b80d4de14"}, + {file = "pillow-11.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fe15238d3798788d00716637b3d4e7bb6bde18b26e5d08335a96e88564a36b6b"}, + {file = "pillow-11.2.1-cp313-cp313-win32.whl", hash = "sha256:3fe735ced9a607fee4f481423a9c36701a39719252a9bb251679635f99d0f7d2"}, + {file = "pillow-11.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:74ee3d7ecb3f3c05459ba95eed5efa28d6092d751ce9bf20e3e253a4e497e691"}, + {file = "pillow-11.2.1-cp313-cp313-win_arm64.whl", hash = "sha256:5119225c622403afb4b44bad4c1ca6c1f98eed79db8d3bc6e4e160fc6339d66c"}, + {file = "pillow-11.2.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:8ce2e8411c7aaef53e6bb29fe98f28cd4fbd9a1d9be2eeea434331aac0536b22"}, + {file = "pillow-11.2.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:9ee66787e095127116d91dea2143db65c7bb1e232f617aa5957c0d9d2a3f23a7"}, + {file = "pillow-11.2.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9622e3b6c1d8b551b6e6f21873bdcc55762b4b2126633014cea1803368a9aa16"}, + {file = "pillow-11.2.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63b5dff3a68f371ea06025a1a6966c9a1e1ee452fc8020c2cd0ea41b83e9037b"}, + {file = "pillow-11.2.1-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:31df6e2d3d8fc99f993fd253e97fae451a8db2e7207acf97859732273e108406"}, + {file = "pillow-11.2.1-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:062b7a42d672c45a70fa1f8b43d1d38ff76b63421cbbe7f88146b39e8a558d91"}, + {file = "pillow-11.2.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4eb92eca2711ef8be42fd3f67533765d9fd043b8c80db204f16c8ea62ee1a751"}, + {file = "pillow-11.2.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f91ebf30830a48c825590aede79376cb40f110b387c17ee9bd59932c961044f9"}, + {file = "pillow-11.2.1-cp313-cp313t-win32.whl", hash = "sha256:e0b55f27f584ed623221cfe995c912c61606be8513bfa0e07d2c674b4516d9dd"}, + {file = "pillow-11.2.1-cp313-cp313t-win_amd64.whl", hash = "sha256:36d6b82164c39ce5482f649b437382c0fb2395eabc1e2b1702a6deb8ad647d6e"}, + {file = "pillow-11.2.1-cp313-cp313t-win_arm64.whl", hash = "sha256:225c832a13326e34f212d2072982bb1adb210e0cc0b153e688743018c94a2681"}, + {file = "pillow-11.2.1-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:7491cf8a79b8eb867d419648fff2f83cb0b3891c8b36da92cc7f1931d46108c8"}, + {file = "pillow-11.2.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8b02d8f9cb83c52578a0b4beadba92e37d83a4ef11570a8688bbf43f4ca50909"}, + {file = "pillow-11.2.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:014ca0050c85003620526b0ac1ac53f56fc93af128f7546623cc8e31875ab928"}, + {file = "pillow-11.2.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3692b68c87096ac6308296d96354eddd25f98740c9d2ab54e1549d6c8aea9d79"}, + {file = "pillow-11.2.1-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:f781dcb0bc9929adc77bad571b8621ecb1e4cdef86e940fe2e5b5ee24fd33b35"}, + {file = "pillow-11.2.1-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:2b490402c96f907a166615e9a5afacf2519e28295f157ec3a2bb9bd57de638cb"}, + {file = "pillow-11.2.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:dd6b20b93b3ccc9c1b597999209e4bc5cf2853f9ee66e3fc9a400a78733ffc9a"}, + {file = "pillow-11.2.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:4b835d89c08a6c2ee7781b8dd0a30209a8012b5f09c0a665b65b0eb3560b6f36"}, + {file = "pillow-11.2.1-cp39-cp39-win32.whl", hash = "sha256:b10428b3416d4f9c61f94b494681280be7686bda15898a3a9e08eb66a6d92d67"}, + {file = "pillow-11.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:6ebce70c3f486acf7591a3d73431fa504a4e18a9b97ff27f5f47b7368e4b9dd1"}, + {file = "pillow-11.2.1-cp39-cp39-win_arm64.whl", hash = "sha256:c27476257b2fdcd7872d54cfd119b3a9ce4610fb85c8e32b70b42e3680a29a1e"}, + {file = "pillow-11.2.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:9b7b0d4fd2635f54ad82785d56bc0d94f147096493a79985d0ab57aedd563156"}, + {file = "pillow-11.2.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:aa442755e31c64037aa7c1cb186e0b369f8416c567381852c63444dd666fb772"}, + {file = "pillow-11.2.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f0d3348c95b766f54b76116d53d4cb171b52992a1027e7ca50c81b43b9d9e363"}, + {file = "pillow-11.2.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85d27ea4c889342f7e35f6d56e7e1cb345632ad592e8c51b693d7b7556043ce0"}, + {file = "pillow-11.2.1-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:bf2c33d6791c598142f00c9c4c7d47f6476731c31081331664eb26d6ab583e01"}, + {file = "pillow-11.2.1-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e616e7154c37669fc1dfc14584f11e284e05d1c650e1c0f972f281c4ccc53193"}, + {file = "pillow-11.2.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:39ad2e0f424394e3aebc40168845fee52df1394a4673a6ee512d840d14ab3013"}, + {file = "pillow-11.2.1-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:80f1df8dbe9572b4b7abdfa17eb5d78dd620b1d55d9e25f834efdbee872d3aed"}, + {file = "pillow-11.2.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:ea926cfbc3957090becbcbbb65ad177161a2ff2ad578b5a6ec9bb1e1cd78753c"}, + {file = "pillow-11.2.1-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:738db0e0941ca0376804d4de6a782c005245264edaa253ffce24e5a15cbdc7bd"}, + {file = "pillow-11.2.1-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9db98ab6565c69082ec9b0d4e40dd9f6181dab0dd236d26f7a50b8b9bfbd5076"}, + {file = "pillow-11.2.1-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:036e53f4170e270ddb8797d4c590e6dd14d28e15c7da375c18978045f7e6c37b"}, + {file = "pillow-11.2.1-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:14f73f7c291279bd65fda51ee87affd7c1e097709f7fdd0188957a16c264601f"}, + {file = "pillow-11.2.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:208653868d5c9ecc2b327f9b9ef34e0e42a4cdd172c2988fd81d62d2bc9bc044"}, + {file = "pillow-11.2.1.tar.gz", hash = "sha256:a64dd61998416367b7ef979b73d3a85853ba9bec4c2925f74e588879a58716b6"}, ] [package.extras] -docs = ["furo", "olefile", "sphinx (>=7.3)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinxext-opengraph"] +docs = ["furo", "olefile", "sphinx (>=8.2)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinxext-opengraph"] fpx = ["olefile"] mic = ["olefile"] -tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"] +test-arrow = ["pyarrow"] +tests = ["check-manifest", "coverage (>=7.4.2)", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout", "trove-classifiers (>=2024.10.12)"] typing = ["typing-extensions ; python_version < \"3.10\""] xmp = ["defusedxml"] @@ -4590,10 +4592,10 @@ test = ["big-O", "importlib-resources ; python_version < \"3.9\"", "jaraco.funct type = ["pytest-mypy"] [extras] -multimodal = ["moviepy", "soundfile"] +multimodal = ["moviepy", "pillow", "soundfile"] training = ["transformers"] [metadata] lock-version = "2.1" python-versions = ">=3.10,<3.14" -content-hash = "e771a859cf2c217a2e982e0542bb673c89a75da742fe2c9030be174e91380a75" +content-hash = "86f8613045c32364155789822eea402d78c7994c8ed79e00bb1d3525f2545e4d" diff --git a/pyproject.toml b/pyproject.toml index 1d2bc412..ad4323e5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -27,10 +27,11 @@ fsspec = { version = ">=2023.1.0,<=2025.3.0", extras = [ transformers = { version = "^4.41.0", optional = true } soundfile = { version = "^0.13.1", optional = true } moviepy = { version = "^2.1.2", optional = true } +pillow = { version = "^11.2.1", optional = true } [tool.poetry.extras] training = ["transformers"] -multimodal = ["soundfile", "moviepy"] +multimodal = ["pillow", "soundfile", "moviepy"] [tool.poetry.group.dev.dependencies] mypy = "^1.8.0" From 8d4a661b8de74119436505a8d967da93ac7539e2 Mon Sep 17 00:00:00 2001 From: Raja Sekhar Rao Dheekonda Date: Thu, 26 Jun 2025 12:46:58 -0700 Subject: [PATCH 4/8] fix mypy error --- dreadnode/data_types/image.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dreadnode/data_types/image.py b/dreadnode/data_types/image.py index 8f1ad818..e9ba0e4d 100644 --- a/dreadnode/data_types/image.py +++ b/dreadnode/data_types/image.py @@ -8,7 +8,7 @@ from dreadnode.data_types.base_data_type import BaseDataType try: - from PIL import Image as PILImage + from PIL import Image as PILImage # type: ignore # noqa: PGH003 except ImportError: PILImage = None From 9cef3a0ed5b183eded278f2cc0ef4636a1998c61 Mon Sep 17 00:00:00 2001 From: Raja Sekhar Rao Dheekonda Date: Thu, 26 Jun 2025 13:07:29 -0700 Subject: [PATCH 5/8] Fix mypy --- dreadnode/data_types/image.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dreadnode/data_types/image.py b/dreadnode/data_types/image.py index e9ba0e4d..cd0714e1 100644 --- a/dreadnode/data_types/image.py +++ b/dreadnode/data_types/image.py @@ -8,7 +8,7 @@ from dreadnode.data_types.base_data_type import BaseDataType try: - from PIL import Image as PILImage # type: ignore # noqa: PGH003 + from PIL import Image as PILImage # type: ignore[import-not-found] except ImportError: PILImage = None From ce657ccf5f4390b26802077e37adb2f7a45623ec Mon Sep 17 00:00:00 2001 From: Raja Sekhar Rao Dheekonda Date: Thu, 26 Jun 2025 13:12:56 -0700 Subject: [PATCH 6/8] Fix mypy --- dreadnode/data_types/image.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dreadnode/data_types/image.py b/dreadnode/data_types/image.py index cd0714e1..301e7448 100644 --- a/dreadnode/data_types/image.py +++ b/dreadnode/data_types/image.py @@ -8,9 +8,9 @@ from dreadnode.data_types.base_data_type import BaseDataType try: - from PIL import Image as PILImage # type: ignore[import-not-found] + from PIL import Image as PILImage except ImportError: - PILImage = None + PILImage = None # type: ignore[assignment] ImageDataType = t.Any | np.ndarray[t.Any, t.Any] ImageDataOrPathType = str | Path | bytes | ImageDataType From 47e39a9746eec095683187ea1f8ef957dbd2813f Mon Sep 17 00:00:00 2001 From: Raja Sekhar Rao Dheekonda Date: Thu, 26 Jun 2025 13:16:55 -0700 Subject: [PATCH 7/8] Fix documentation in readme --- README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d9193b3a..2a349bb7 100644 --- a/README.md +++ b/README.md @@ -85,16 +85,21 @@ pip install -U dreadnode ``` If you want to build from source: + ```bash + poetry install # Install with multimodal extras poetry install --extras multimodal # Install with training extras poetry install --extras training + +# Install with all extras +poetry install --all-extras ``` -## Installation with Extras +## Installation from PyPI with Optional Features For advanced media processing capabilities (audio, video, images), install the multimodal extras: From ba90a3c73ef221e682d8b3ad45f395c01e45a030 Mon Sep 17 00:00:00 2001 From: Raja Sekhar Rao Dheekonda Date: Thu, 26 Jun 2025 13:20:46 -0700 Subject: [PATCH 8/8] Add all extras --- README.md | 2 +- poetry.lock | 3 ++- pyproject.toml | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2a349bb7..e3653aa1 100644 --- a/README.md +++ b/README.md @@ -111,7 +111,7 @@ pip install -U dreadnode[multimodal] pip install -U dreadnode[training] # All optional features -pip install -U dreadnode[multimodal,training] +pip install -U dreadnode[all] ``` See our **[installation guide](https://docs.dreadnode.io/strikes/install)** for more options. diff --git a/poetry.lock b/poetry.lock index 645b1c17..93b6ec77 100644 --- a/poetry.lock +++ b/poetry.lock @@ -4592,10 +4592,11 @@ test = ["big-O", "importlib-resources ; python_version < \"3.9\"", "jaraco.funct type = ["pytest-mypy"] [extras] +all = [] multimodal = ["moviepy", "pillow", "soundfile"] training = ["transformers"] [metadata] lock-version = "2.1" python-versions = ">=3.10,<3.14" -content-hash = "86f8613045c32364155789822eea402d78c7994c8ed79e00bb1d3525f2545e4d" +content-hash = "21fe5cf29eefa6f77e8bb811529fa19adff4f32d8e64f13432402631c4d3808f" diff --git a/pyproject.toml b/pyproject.toml index ad4323e5..fb35f4c0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -32,6 +32,7 @@ pillow = { version = "^11.2.1", optional = true } [tool.poetry.extras] training = ["transformers"] multimodal = ["pillow", "soundfile", "moviepy"] +all = ["multimodal", "training"] [tool.poetry.group.dev.dependencies] mypy = "^1.8.0"