typed-ffmpeg-compatible 3.5.2__py3-none-any.whl → 3.6__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. typed_ffmpeg/__init__.py +4 -1
  2. typed_ffmpeg/_version.py +2 -2
  3. typed_ffmpeg/base.py +4 -1
  4. typed_ffmpeg/codecs/__init__.py +2 -0
  5. typed_ffmpeg/codecs/decoders.py +1852 -1853
  6. typed_ffmpeg/codecs/encoders.py +2001 -1782
  7. typed_ffmpeg/codecs/schema.py +6 -12
  8. typed_ffmpeg/common/__init__.py +1 -0
  9. typed_ffmpeg/common/cache.py +9 -6
  10. typed_ffmpeg/common/schema.py +11 -0
  11. typed_ffmpeg/common/serialize.py +13 -7
  12. typed_ffmpeg/compile/__init__.py +1 -0
  13. typed_ffmpeg/compile/compile_cli.py +23 -4
  14. typed_ffmpeg/compile/compile_json.py +4 -0
  15. typed_ffmpeg/compile/compile_python.py +15 -0
  16. typed_ffmpeg/compile/context.py +15 -4
  17. typed_ffmpeg/compile/validate.py +4 -3
  18. typed_ffmpeg/dag/factory.py +2 -0
  19. typed_ffmpeg/dag/global_runnable/__init__.py +1 -0
  20. typed_ffmpeg/dag/global_runnable/global_args.py +2 -2
  21. typed_ffmpeg/dag/global_runnable/runnable.py +6 -2
  22. typed_ffmpeg/dag/io/__init__.py +1 -0
  23. typed_ffmpeg/dag/io/_input.py +20 -5
  24. typed_ffmpeg/dag/io/_output.py +24 -9
  25. typed_ffmpeg/dag/io/output_args.py +21 -7
  26. typed_ffmpeg/dag/nodes.py +20 -0
  27. typed_ffmpeg/dag/schema.py +19 -6
  28. typed_ffmpeg/dag/utils.py +2 -2
  29. typed_ffmpeg/exceptions.py +2 -1
  30. typed_ffmpeg/expressions.py +884 -0
  31. typed_ffmpeg/ffprobe/__init__.py +1 -0
  32. typed_ffmpeg/ffprobe/parse.py +7 -1
  33. typed_ffmpeg/ffprobe/probe.py +3 -1
  34. typed_ffmpeg/ffprobe/schema.py +83 -1
  35. typed_ffmpeg/ffprobe/xml2json.py +8 -2
  36. typed_ffmpeg/filters.py +540 -631
  37. typed_ffmpeg/formats/__init__.py +2 -0
  38. typed_ffmpeg/formats/demuxers.py +1869 -1921
  39. typed_ffmpeg/formats/muxers.py +1382 -1107
  40. typed_ffmpeg/formats/schema.py +6 -12
  41. typed_ffmpeg/info.py +8 -0
  42. typed_ffmpeg/options/__init__.py +15 -0
  43. typed_ffmpeg/options/codec.py +711 -0
  44. typed_ffmpeg/options/format.py +196 -0
  45. typed_ffmpeg/options/framesync.py +43 -0
  46. typed_ffmpeg/options/timeline.py +22 -0
  47. typed_ffmpeg/schema.py +15 -0
  48. typed_ffmpeg/sources.py +392 -381
  49. typed_ffmpeg/streams/__init__.py +2 -0
  50. typed_ffmpeg/streams/audio.py +1071 -882
  51. typed_ffmpeg/streams/av.py +9 -3
  52. typed_ffmpeg/streams/subtitle.py +3 -3
  53. typed_ffmpeg/streams/video.py +1873 -1725
  54. typed_ffmpeg/types.py +3 -2
  55. typed_ffmpeg/utils/__init__.py +1 -0
  56. typed_ffmpeg/utils/escaping.py +8 -4
  57. typed_ffmpeg/utils/frozendict.py +31 -1
  58. typed_ffmpeg/utils/lazy_eval/__init__.py +1 -0
  59. typed_ffmpeg/utils/lazy_eval/operator.py +75 -27
  60. typed_ffmpeg/utils/lazy_eval/schema.py +176 -4
  61. typed_ffmpeg/utils/run.py +2 -0
  62. typed_ffmpeg/utils/snapshot.py +1 -0
  63. typed_ffmpeg/utils/typing.py +2 -1
  64. typed_ffmpeg/utils/view.py +2 -1
  65. {typed_ffmpeg_compatible-3.5.2.dist-info → typed_ffmpeg_compatible-3.6.dist-info}/METADATA +1 -1
  66. typed_ffmpeg_compatible-3.6.dist-info/RECORD +73 -0
  67. typed_ffmpeg_compatible-3.5.2.dist-info/RECORD +0 -67
  68. {typed_ffmpeg_compatible-3.5.2.dist-info → typed_ffmpeg_compatible-3.6.dist-info}/WHEEL +0 -0
  69. {typed_ffmpeg_compatible-3.5.2.dist-info → typed_ffmpeg_compatible-3.6.dist-info}/entry_points.txt +0 -0
  70. {typed_ffmpeg_compatible-3.5.2.dist-info → typed_ffmpeg_compatible-3.6.dist-info}/licenses/LICENSE +0 -0
  71. {typed_ffmpeg_compatible-3.5.2.dist-info → typed_ffmpeg_compatible-3.6.dist-info}/top_level.txt +0 -0
@@ -56,6 +56,7 @@ class GlobalRunable(GlobalArgs):
56
56
  merged = output1.merge_outputs(output2)
57
57
  merged.run() # Creates both output files with one FFmpeg command
58
58
  ```
59
+
59
60
  """
60
61
  return self._global_node(*streams).stream()
61
62
 
@@ -75,6 +76,7 @@ class GlobalRunable(GlobalArgs):
75
76
  # Overwrite output file if it already exists
76
77
  ffmpeg.input("input.mp4").output("output.mp4").overwrite_output().run()
77
78
  ```
79
+
78
80
  """
79
81
  return self._global_node(y=True).stream()
80
82
 
@@ -113,6 +115,7 @@ class GlobalRunable(GlobalArgs):
113
115
  args = ffmpeg.input("input.mp4").output("output.mp4").compile()
114
116
  # Result: ['ffmpeg', '-i', 'input.mp4', 'output.mp4']
115
117
  ```
118
+
116
119
  """
117
120
  from ...compile.compile_cli import compile_as_list
118
121
 
@@ -171,6 +174,7 @@ class GlobalRunable(GlobalArgs):
171
174
  cmd_str = ffmpeg.input("input.mp4").output("output.mp4").compile_line()
172
175
  # Result: 'ffmpeg -i input.mp4 output.mp4'
173
176
  ```
177
+
174
178
  """
175
179
  return command_line(
176
180
  self.compile(
@@ -223,8 +227,8 @@ class GlobalRunable(GlobalArgs):
223
227
  # Do something while FFmpeg is running
224
228
  process.wait() # Wait for completion
225
229
  ```
226
- """
227
230
 
231
+ """
228
232
  args = self.compile(
229
233
  cmd,
230
234
  overwrite_output=overwrite_output,
@@ -294,8 +298,8 @@ class GlobalRunable(GlobalArgs):
294
298
  )
295
299
  print(stderr.decode()) # Print FFmpeg's progress information
296
300
  ```
297
- """
298
301
 
302
+ """
299
303
  process = self.run_async(
300
304
  cmd,
301
305
  pipe_stdin=input is not None,
@@ -0,0 +1 @@
1
+ """Input/output utilities for FFmpeg DAG operations."""
@@ -1,11 +1,17 @@
1
1
  # NOTE: this file is auto-generated, do not modify
2
-
2
+ """Input node."""
3
3
 
4
4
  from pathlib import Path
5
5
  from typing import Any
6
6
 
7
7
  from ...codecs.schema import FFMpegDecoderOption
8
8
  from ...formats.schema import FFMpegDemuxerOption
9
+ from ...options.codec import (
10
+ FFMpegAVCodecContextDecoderOption,
11
+ )
12
+ from ...options.format import (
13
+ FFMpegAVFormatContextDecoderOption,
14
+ )
9
15
  from ...streams.av import AVStream
10
16
  from ...types import (
11
17
  Boolean,
@@ -16,7 +22,9 @@ from ...types import (
16
22
  Time,
17
23
  )
18
24
  from ...utils.frozendict import merge
19
- from ..nodes import InputNode
25
+ from ..nodes import (
26
+ InputNode,
27
+ )
20
28
 
21
29
 
22
30
  def input(
@@ -76,10 +84,12 @@ def input(
76
84
  top: Int = None,
77
85
  decoder_options: FFMpegDecoderOption | None = None,
78
86
  demuxer_options: FFMpegDemuxerOption | None = None,
87
+ format_options: FFMpegAVFormatContextDecoderOption | None = None,
88
+ codec_options: FFMpegAVCodecContextDecoderOption | None = None,
79
89
  extra_options: dict[str, Any] | None = None,
80
90
  ) -> AVStream:
81
91
  """
82
- Input file URL (ffmpeg ``-i`` option)
92
+ Input file URL (ffmpeg ``-i`` option).
83
93
 
84
94
  Args:
85
95
  filename: Input file URL
@@ -137,6 +147,8 @@ def input(
137
147
  top: deprecated, use the setfield video filter
138
148
  decoder_options: ffmpeg's decoder options
139
149
  demuxer_options: ffmpeg's demuxer options
150
+ format_options: ffmpeg's AVFormatContext options
151
+ codec_options: ffmpeg's AVCodecContext options
140
152
  extra_options: ffmpeg's input file options
141
153
 
142
154
  Returns:
@@ -147,6 +159,7 @@ def input(
147
159
  >>> input('input.mp4')
148
160
  <AVStream:input.mp4:0>
149
161
  ```
162
+
150
163
  """
151
164
  return InputNode(
152
165
  filename=str(filename),
@@ -205,8 +218,10 @@ def input(
205
218
  "dn": dn,
206
219
  "top": top,
207
220
  },
208
- decoder_options.kwargs if decoder_options else {},
209
- demuxer_options.kwargs if demuxer_options else {},
221
+ decoder_options,
222
+ demuxer_options,
223
+ format_options,
224
+ codec_options,
210
225
  extra_options,
211
226
  ),
212
227
  ).stream()
@@ -1,11 +1,17 @@
1
1
  # NOTE: this file is auto-generated, do not modify
2
-
2
+ """Output node."""
3
3
 
4
4
  from pathlib import Path
5
5
  from typing import Any
6
6
 
7
7
  from ...codecs.schema import FFMpegEncoderOption
8
8
  from ...formats.schema import FFMpegMuxerOption
9
+ from ...options.codec import (
10
+ FFMpegAVCodecContextEncoderOption,
11
+ )
12
+ from ...options.format import (
13
+ FFMpegAVFormatContextEncoderOption,
14
+ )
9
15
  from ...types import (
10
16
  Boolean,
11
17
  Float,
@@ -16,7 +22,11 @@ from ...types import (
16
22
  Time,
17
23
  )
18
24
  from ...utils.frozendict import merge
19
- from ..nodes import FilterableStream, OutputNode, OutputStream
25
+ from ..nodes import (
26
+ FilterableStream,
27
+ OutputNode,
28
+ OutputStream,
29
+ )
20
30
 
21
31
 
22
32
  def output(
@@ -118,10 +128,12 @@ def output(
118
128
  top: Int = None,
119
129
  encoder_options: FFMpegEncoderOption | None = None,
120
130
  muxer_options: FFMpegMuxerOption | None = None,
131
+ format_options: FFMpegAVFormatContextEncoderOption | None = None,
132
+ codec_options: FFMpegAVCodecContextEncoderOption | None = None,
121
133
  extra_options: dict[str, Any] | None = None,
122
134
  ) -> OutputStream:
123
- """
124
- Output file URL
135
+ r"""
136
+ Output file URL.
125
137
 
126
138
  Args:
127
139
  *streams: the streams to output
@@ -142,8 +154,7 @@ def output(
142
154
  program: add program with specified streams
143
155
  stream_group: add stream group with specified streams and group type-specific arguments
144
156
  dframes: set the number of data frames to output
145
- target: specify target file type (\"vcd\", \"svcd\", \"dvd\", \"dv\" or \"dv50\
146
- "with optional prefixes \"pal-\", \"ntsc-\" or \"film-\")
157
+ target: specify target file type (\"vcd\", \"svcd\", \"dvd\", \"dv\" or \"dv50\ "with optional prefixes \"pal-\", \"ntsc-\" or \"film-\")
147
158
  shortest: finish encoding within shortest input
148
159
  shortest_buf_duration: maximum buffering duration (in seconds) for the -shortest option
149
160
  bitexact: bitexact mode
@@ -223,12 +234,14 @@ def output(
223
234
  top: deprecated, use the setfield video filter
224
235
  encoder_options: ffmpeg's encoder options
225
236
  muxer_options: ffmpeg's muxer options
237
+ format_options: ffmpeg's AVFormatContext options
238
+ codec_options: ffmpeg's AVCodecContext options
226
239
  extra_options: the arguments for the output
227
240
 
228
241
  Returns:
229
242
  the output stream
230
- """
231
243
 
244
+ """
232
245
  return OutputNode(
233
246
  inputs=streams,
234
247
  filename=str(filename),
@@ -329,8 +342,10 @@ def output(
329
342
  "dn": dn,
330
343
  "top": top,
331
344
  },
332
- encoder_options.kwargs if encoder_options else {},
333
- muxer_options.kwargs if muxer_options else {},
345
+ encoder_options,
346
+ muxer_options,
347
+ format_options,
348
+ codec_options,
334
349
  extra_options,
335
350
  ),
336
351
  ).stream()
@@ -1,5 +1,5 @@
1
1
  # NOTE: this file is auto-generated, do not modify
2
-
2
+ """Output arguments."""
3
3
 
4
4
  from __future__ import annotations
5
5
 
@@ -9,6 +9,12 @@ from typing import TYPE_CHECKING, Any
9
9
 
10
10
  from ...codecs.schema import FFMpegEncoderOption
11
11
  from ...formats.schema import FFMpegMuxerOption
12
+ from ...options.codec import (
13
+ FFMpegAVCodecContextEncoderOption,
14
+ )
15
+ from ...options.format import (
16
+ FFMpegAVFormatContextEncoderOption,
17
+ )
12
18
  from ...types import (
13
19
  Boolean,
14
20
  Float,
@@ -25,6 +31,8 @@ if TYPE_CHECKING:
25
31
 
26
32
 
27
33
  class OutputArgs(ABC):
34
+ """Output arguments interface."""
35
+
28
36
  @abstractmethod
29
37
  def _output_node(
30
38
  self, *streams: FilterableStream, filename: str | Path, **kwargs: Any
@@ -130,10 +138,12 @@ class OutputArgs(ABC):
130
138
  top: Int = None,
131
139
  encoder_options: FFMpegEncoderOption | None = None,
132
140
  muxer_options: FFMpegMuxerOption | None = None,
141
+ format_options: FFMpegAVFormatContextEncoderOption | None = None,
142
+ codec_options: FFMpegAVCodecContextEncoderOption | None = None,
133
143
  extra_options: dict[str, Any] | None = None,
134
144
  ) -> OutputStream:
135
- """
136
- Output file URL
145
+ r"""
146
+ Output file URL.
137
147
 
138
148
  Args:
139
149
  *streams: the streams to output
@@ -234,13 +244,15 @@ class OutputArgs(ABC):
234
244
  dn: disable data
235
245
  top: deprecated, use the setfield video filter
236
246
  encoder_options: ffmpeg's encoder options
237
- muxer_options: FFMpegMuxerOption | None = None,
247
+ muxer_options: FFMpegMuxerOption
248
+ format_options: FFMpegAVFormatContextEncoderOption
249
+ codec_options: FFMpegAVCodecContextEncoderOption
238
250
  extra_options: the arguments for the output
239
251
 
240
252
  Returns:
241
253
  the output stream
242
- """
243
254
 
255
+ """
244
256
  return self._output_node(
245
257
  *streams,
246
258
  filename=filename,
@@ -341,8 +353,10 @@ class OutputArgs(ABC):
341
353
  "dn": dn,
342
354
  "top": top,
343
355
  },
344
- encoder_options.kwargs if encoder_options else {},
345
- muxer_options.kwargs if muxer_options else {},
356
+ encoder_options,
357
+ muxer_options,
358
+ format_options,
359
+ codec_options,
346
360
  extra_options,
347
361
  ),
348
362
  ).stream()
typed_ffmpeg/dag/nodes.py CHANGED
@@ -1,3 +1,5 @@
1
+ """DAG node definitions for FFmpeg filter graphs."""
2
+
1
3
  from __future__ import annotations
2
4
 
3
5
  import logging
@@ -60,6 +62,7 @@ class FilterNode(Node):
60
62
 
61
63
  Returns:
62
64
  The name of the filter
65
+
63
66
  """
64
67
  return self.name
65
68
 
@@ -81,6 +84,7 @@ class FilterNode(Node):
81
84
 
82
85
  Raises:
83
86
  FFMpegValueError: If the specified index is out of range
87
+
84
88
  """
85
89
  from ..streams.video import VideoStream
86
90
 
@@ -111,6 +115,7 @@ class FilterNode(Node):
111
115
 
112
116
  Raises:
113
117
  FFMpegValueError: If the specified index is out of range
118
+
114
119
  """
115
120
  from ..streams.audio import AudioStream
116
121
 
@@ -136,6 +141,7 @@ class FilterNode(Node):
136
141
  Raises:
137
142
  FFMpegValueError: If the number of inputs doesn't match input_typings
138
143
  FFMpegTypeError: If an input stream doesn't match its expected type
144
+
139
145
  """
140
146
  from ..streams.audio import AudioStream
141
147
  from ..streams.video import VideoStream
@@ -207,6 +213,7 @@ class FilterableStream(Stream, OutputArgs):
207
213
  filename="output.mp4", c="libx264", crf=23
208
214
  )
209
215
  ```
216
+
210
217
  """
211
218
  return OutputNode(
212
219
  inputs=(self, *streams),
@@ -244,6 +251,7 @@ class FilterableStream(Stream, OutputArgs):
244
251
  # Apply a blur filter to a video stream
245
252
  blurred = stream.vfilter(name="boxblur", luma_radius=2)
246
253
  ```
254
+
247
255
  """
248
256
  return self.filter_multi_output(
249
257
  *streams,
@@ -283,6 +291,7 @@ class FilterableStream(Stream, OutputArgs):
283
291
  # Apply a volume filter to an audio stream
284
292
  louder = stream.afilter(name="volume", volume=2.0)
285
293
  ```
294
+
286
295
  """
287
296
  return self.filter_multi_output(
288
297
  *streams,
@@ -327,6 +336,7 @@ class FilterableStream(Stream, OutputArgs):
327
336
  stream1 = split_node.video(0)
328
337
  stream2 = split_node.video(1)
329
338
  ```
339
+
330
340
  """
331
341
  return FilterNode(
332
342
  name=name,
@@ -337,6 +347,7 @@ class FilterableStream(Stream, OutputArgs):
337
347
  )
338
348
 
339
349
  def __post_init__(self) -> None:
350
+ """Validate that filter streams have an index."""
340
351
  if not isinstance(self.node, InputNode):
341
352
  assert self.index is not None, "Filter streams must have an index"
342
353
 
@@ -368,6 +379,7 @@ class InputNode(Node):
368
379
 
369
380
  Returns:
370
381
  The basename of the input file
382
+
371
383
  """
372
384
  return os.path.basename(self.filename)
373
385
 
@@ -390,6 +402,7 @@ class InputNode(Node):
390
402
  # Apply a filter to the video stream
391
403
  scaled = video.scale(width=1280, height=720)
392
404
  ```
405
+
393
406
  """
394
407
  from ..streams.video import VideoStream
395
408
 
@@ -414,6 +427,7 @@ class InputNode(Node):
414
427
  # Apply a filter to the audio stream
415
428
  volume_adjusted = audio.volume(volume=2.0)
416
429
  ```
430
+
417
431
  """
418
432
  from ..streams.audio import AudioStream
419
433
 
@@ -438,6 +452,7 @@ class InputNode(Node):
438
452
  # Output both audio and video to a new file
439
453
  output = av_stream.output("output.mp4")
440
454
  ```
455
+
441
456
  """
442
457
  from ..streams.av import AVStream
443
458
 
@@ -471,6 +486,7 @@ class OutputNode(Node):
471
486
 
472
487
  Returns:
473
488
  The basename of the output file
489
+
474
490
  """
475
491
  return os.path.basename(self.filename)
476
492
 
@@ -492,6 +508,7 @@ class OutputNode(Node):
492
508
  output_stream = output_node.stream()
493
509
  with_global_opts = output_stream.global_args(y=True)
494
510
  ```
511
+
495
512
  """
496
513
  return OutputStream(node=self)
497
514
 
@@ -531,6 +548,7 @@ class OutputStream(Stream, GlobalRunable):
531
548
  # Add global options to an output stream
532
549
  global_node = output_stream._global_node(y=True, loglevel="quiet")
533
550
  ```
551
+
534
552
  """
535
553
  return GlobalNode(inputs=(self, *streams), kwargs=FrozenDict(kwargs))
536
554
 
@@ -567,6 +585,7 @@ class GlobalNode(Node):
567
585
  # Execute the command
568
586
  global_stream.run()
569
587
  ```
588
+
570
589
  """
571
590
  return GlobalStream(node=self)
572
591
 
@@ -607,6 +626,7 @@ class GlobalStream(Stream, GlobalRunable):
607
626
  global_stream = ffmpeg.output("output.mp4").global_args(y=True)
608
627
  enhanced = global_stream._global_node(loglevel="quiet")
609
628
  ```
629
+
610
630
  """
611
631
  inputs = (*self.node.inputs, *streams)
612
632
  kwargs = dict(self.node.kwargs) | kwargs
@@ -1,3 +1,5 @@
1
+ """DAG schema definitions for FFmpeg filter graphs."""
2
+
1
3
  from __future__ import annotations
2
4
 
3
5
  from dataclasses import dataclass, replace
@@ -12,15 +14,11 @@ from .utils import is_dag
12
14
 
13
15
  @dataclass(frozen=True, kw_only=True)
14
16
  class HashableBaseModel(Serializable):
15
- """
16
- A base class for hashable dataclasses.
17
- """
17
+ """A base class for hashable dataclasses."""
18
18
 
19
19
  @cached_property
20
20
  def hex(self) -> str:
21
- """
22
- Get the hexadecimal hash of the object.
23
- """
21
+ """Get the hexadecimal hash of the object."""
24
22
  return hex(abs(hash(self)))[2:]
25
23
 
26
24
 
@@ -31,6 +29,7 @@ class Stream(HashableBaseModel):
31
29
 
32
30
  Note:
33
31
  Each stream in the DAG is a sequence of operations that transforms the data from its input form to its output form. The stream is an essential component of the DAG, as it defines the order and the nature of the operations that are performed on the data.
32
+
34
33
  """
35
34
 
36
35
  node: Node
@@ -66,6 +65,7 @@ class Stream(HashableBaseModel):
66
65
 
67
66
  Returns:
68
67
  The file path of the visualization.
68
+
69
69
  """
70
70
  from ..utils.view import view
71
71
 
@@ -87,6 +87,7 @@ class Node(HashableBaseModel):
87
87
 
88
88
  Note:
89
89
  Each node in the DAG represents a single operation that transforms the data from its input form to its output form. The node is an essential component of the DAG, as it defines the nature of the operations that are performed on the data.
90
+
90
91
  """
91
92
 
92
93
  # Filter_Node_Option_Type
@@ -102,6 +103,13 @@ class Node(HashableBaseModel):
102
103
  """
103
104
 
104
105
  def __post_init__(self) -> None:
106
+ """
107
+ Validate that the graph is a DAG (Directed Acyclic Graph).
108
+
109
+ Raises:
110
+ ValueError: If the graph is not a DAG
111
+
112
+ """
105
113
  # Validate the DAG
106
114
  passed = set()
107
115
  nodes = [self]
@@ -127,6 +135,7 @@ class Node(HashableBaseModel):
127
135
 
128
136
  Returns:
129
137
  The representation of the node.
138
+
130
139
  """
131
140
  return repr(self)
132
141
 
@@ -140,6 +149,7 @@ class Node(HashableBaseModel):
140
149
 
141
150
  Returns:
142
151
  The new graph with the replaced node.
152
+
143
153
  """
144
154
  if self == old_node:
145
155
  return new_node
@@ -165,6 +175,7 @@ class Node(HashableBaseModel):
165
175
 
166
176
  Returns:
167
177
  The maximum depth of the node.
178
+
168
179
  """
169
180
  return max((i.node.max_depth for i in self.inputs), default=0) + 1
170
181
 
@@ -175,6 +186,7 @@ class Node(HashableBaseModel):
175
186
 
176
187
  Returns:
177
188
  The upstream nodes of the node.
189
+
178
190
  """
179
191
  output = {self}
180
192
  for input in self.inputs:
@@ -191,6 +203,7 @@ class Node(HashableBaseModel):
191
203
 
192
204
  Returns:
193
205
  The file path of the visualization.
206
+
194
207
  """
195
208
  from ..utils.view import view
196
209
 
typed_ffmpeg/dag/utils.py CHANGED
@@ -38,9 +38,9 @@ def is_dag(graph: dict[str, set[str]]) -> bool:
38
38
  graph = {"A": {"B"}, "B": {"C"}, "C": {"A"}}
39
39
  assert is_dag(graph) == False
40
40
  ```
41
- """
42
41
 
43
- in_degree = {u: 0 for u in graph} # Initialize in-degree of each node to 0
42
+ """
43
+ in_degree = dict.fromkeys(graph, 0) # Initialize in-degree of each node to 0
44
44
 
45
45
  # Calculate in-degree of each node
46
46
  for u in graph:
@@ -54,6 +54,7 @@ class FFMpegExecuteError(FFMpegError):
54
54
  stderr: The standard error output of the failed command
55
55
  cmd: The command string that was executed
56
56
  retcode: The process return code
57
+
57
58
  """
58
59
 
59
60
  def __init__(self, retcode: int | None, cmd: str, stdout: bytes, stderr: bytes):
@@ -65,8 +66,8 @@ class FFMpegExecuteError(FFMpegError):
65
66
  cmd: The FFmpeg command string that was executed
66
67
  stdout: The captured standard output from the process
67
68
  stderr: The captured standard error from the process
68
- """
69
69
 
70
+ """
70
71
  self.stdout = stdout
71
72
  self.stderr = stderr
72
73
  self.cmd = cmd