deffcode 0.2.8__py3-none-any.whl → 0.2.9__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.
- deffcode/ffdecoder.py +124 -26
- deffcode/ffhelper.py +2 -0
- deffcode/sourcer.py +1 -1
- deffcode/version.py +1 -1
- {deffcode-0.2.8.dist-info → deffcode-0.2.9.dist-info}/METADATA +14 -13
- deffcode-0.2.9.dist-info/RECORD +11 -0
- {deffcode-0.2.8.dist-info → deffcode-0.2.9.dist-info}/WHEEL +1 -1
- deffcode-0.2.8.dist-info/RECORD +0 -11
- {deffcode-0.2.8.dist-info → deffcode-0.2.9.dist-info}/licenses/LICENSE +0 -0
- {deffcode-0.2.8.dist-info → deffcode-0.2.9.dist-info}/top_level.txt +0 -0
deffcode/ffdecoder.py
CHANGED
|
@@ -26,9 +26,11 @@ import platform
|
|
|
26
26
|
import queue
|
|
27
27
|
import re
|
|
28
28
|
import subprocess as sp
|
|
29
|
+
import sys
|
|
29
30
|
import threading
|
|
30
|
-
from collections import OrderedDict
|
|
31
|
+
from collections import OrderedDict, deque
|
|
31
32
|
from collections.abc import Generator
|
|
33
|
+
from itertools import pairwise
|
|
32
34
|
from types import TracebackType
|
|
33
35
|
from typing import Any, Self
|
|
34
36
|
|
|
@@ -36,6 +38,7 @@ import numpy as np
|
|
|
36
38
|
|
|
37
39
|
# import utils packages
|
|
38
40
|
from .ffhelper import (
|
|
41
|
+
TERMINATE_TIMEOUT_SUBPROCESS,
|
|
39
42
|
get_supported_pixfmts,
|
|
40
43
|
get_supported_vdecoders,
|
|
41
44
|
)
|
|
@@ -207,6 +210,15 @@ class FFdecoder:
|
|
|
207
210
|
self.__ffmpeg_prefixes = []
|
|
208
211
|
sourcer_params["-ffprefixes"] = self.__ffmpeg_prefixes
|
|
209
212
|
|
|
213
|
+
# handles user-defined additional FFmpeg outputs, appended after the rawvideo pipe output (must be a flat list)
|
|
214
|
+
self.__extra_outputs = self.__extra_params.pop("-extra_outputs", [])
|
|
215
|
+
if not isinstance(self.__extra_outputs, list) or any(
|
|
216
|
+
isinstance(x, (list, tuple, dict)) for x in self.__extra_outputs
|
|
217
|
+
):
|
|
218
|
+
logger.warning("Discarding invalid `-extra_outputs` value! It must be a flat list.")
|
|
219
|
+
self.__extra_outputs = []
|
|
220
|
+
self.__extra_outputs = [str(x) for x in self.__extra_outputs]
|
|
221
|
+
|
|
210
222
|
# pass parameter(if specified) to Sourcer API, specifying where to save the downloaded FFmpeg Static
|
|
211
223
|
# assets on Windows(if specified)
|
|
212
224
|
sourcer_params["-ffmpeg_download_path"] = self.__extra_params.pop(
|
|
@@ -229,6 +241,17 @@ class FFdecoder:
|
|
|
229
241
|
# multi-input output streams are selected via `-map`, so probe with it too
|
|
230
242
|
if self.__is_multi and "-map" in self.__extra_params:
|
|
231
243
|
sourcer_params["-map"] = self.__extra_params["-map"]
|
|
244
|
+
# filtergraph labels consumed only by `-extra_outputs` must also be consumed while
|
|
245
|
+
# probing, otherwise FFmpeg aborts with "unconnected output"; map all into the probe sink.
|
|
246
|
+
if self.__extra_outputs and "-filter_complex" in sourcer_params:
|
|
247
|
+
if "-map" in self.__extra_params:
|
|
248
|
+
sourcer_params["-map"] = self.__extra_params["-map"]
|
|
249
|
+
sourcer_params["-clones"] = [
|
|
250
|
+
arg
|
|
251
|
+
for key, val in pairwise(self.__extra_outputs)
|
|
252
|
+
if key == "-map" and val.startswith("[")
|
|
253
|
+
for arg in (key, val)
|
|
254
|
+
]
|
|
232
255
|
|
|
233
256
|
# define dict to store user-defined parameters
|
|
234
257
|
self.__user_metadata = {}
|
|
@@ -280,6 +303,13 @@ class FFdecoder:
|
|
|
280
303
|
"Enabling asynchronous `showinfo` per-frame metadata extraction."
|
|
281
304
|
)
|
|
282
305
|
|
|
306
|
+
# handle capturing FFmpeg stderr tail for diagnosing pipeline failures
|
|
307
|
+
self.__capture_stderr = self.__extra_params.pop("-capture_stderr", False)
|
|
308
|
+
if not isinstance(self.__capture_stderr, bool):
|
|
309
|
+
self.__capture_stderr = False
|
|
310
|
+
self.__stderr_tail: deque[str] = deque(maxlen=50)
|
|
311
|
+
self.__returncode: int | None = None
|
|
312
|
+
|
|
283
313
|
# handle disabling window for ffmpeg subprocess on Windows OS
|
|
284
314
|
# this patch prevents ffmpeg creation window from opening when
|
|
285
315
|
# building exe files
|
|
@@ -783,16 +813,39 @@ class FFdecoder:
|
|
|
783
813
|
while not self.__terminate_stream: # infinite raw frames
|
|
784
814
|
frame = self.__fetchNextFrame()
|
|
785
815
|
if frame is None:
|
|
786
|
-
self.
|
|
816
|
+
self.__handle_stream_end()
|
|
787
817
|
break
|
|
788
818
|
yield self.__attach_metadata(frame)
|
|
789
819
|
else:
|
|
790
820
|
for _ in range(self.__raw_frame_num): # finite raw frames
|
|
791
821
|
frame = self.__fetchNextFrame()
|
|
792
822
|
if frame is None:
|
|
793
|
-
self.
|
|
823
|
+
self.__handle_stream_end()
|
|
794
824
|
break
|
|
795
825
|
yield self.__attach_metadata(frame)
|
|
826
|
+
# generator exhausted, FFmpeg may still be flushing/exiting cleanly
|
|
827
|
+
self.__terminate_stream = True
|
|
828
|
+
|
|
829
|
+
def __handle_stream_end(self) -> None:
|
|
830
|
+
"""
|
|
831
|
+
Internal: marks stream as ended on a short read and, when `-capture_stderr`
|
|
832
|
+
is enabled and FFmpeg exited with a non-zero code, logs the `stderr_tail`.
|
|
833
|
+
"""
|
|
834
|
+
self.__terminate_stream = True
|
|
835
|
+
if not self.__capture_stderr or self.__process is None:
|
|
836
|
+
return
|
|
837
|
+
try:
|
|
838
|
+
retcode = self.__process.wait(timeout=TERMINATE_TIMEOUT_SUBPROCESS)
|
|
839
|
+
except sp.TimeoutExpired:
|
|
840
|
+
return
|
|
841
|
+
if retcode:
|
|
842
|
+
# let the reader thread drain remaining stderr lines first
|
|
843
|
+
self.__stderr_thread and self.__stderr_thread.join(timeout=TERMINATE_TIMEOUT_SUBPROCESS)
|
|
844
|
+
logger.error(
|
|
845
|
+
"FFmpeg exited with code {}. Last stderr lines:\n{}".format(
|
|
846
|
+
retcode, "\n".join(self.__stderr_tail)
|
|
847
|
+
)
|
|
848
|
+
)
|
|
796
849
|
|
|
797
850
|
def __attach_metadata(self, frame: np.ndarray):
|
|
798
851
|
"""
|
|
@@ -830,6 +883,25 @@ class FFdecoder:
|
|
|
830
883
|
"""
|
|
831
884
|
self.terminate()
|
|
832
885
|
|
|
886
|
+
@property
|
|
887
|
+
def returncode(self) -> int | None:
|
|
888
|
+
"""
|
|
889
|
+
A property object that holds FFmpeg process exit code, set by `terminate()`.
|
|
890
|
+
|
|
891
|
+
**Returns:** FFmpeg exit code, or `None` if pipeline has not been terminated yet.
|
|
892
|
+
"""
|
|
893
|
+
return self.__returncode
|
|
894
|
+
|
|
895
|
+
@property
|
|
896
|
+
def stderr_tail(self) -> list[str]:
|
|
897
|
+
"""
|
|
898
|
+
A property object that holds the last 50 lines of FFmpeg's stderr output.
|
|
899
|
+
Only populated when `-capture_stderr` (or `-extract_metadata`) is enabled.
|
|
900
|
+
|
|
901
|
+
**Returns:** List of stderr lines (oldest first).
|
|
902
|
+
"""
|
|
903
|
+
return list(self.__stderr_tail)
|
|
904
|
+
|
|
833
905
|
@property
|
|
834
906
|
def metadata(self) -> str:
|
|
835
907
|
"""
|
|
@@ -908,8 +980,10 @@ class FFdecoder:
|
|
|
908
980
|
else:
|
|
909
981
|
# otherwise discard and log it
|
|
910
982
|
logger.warning(
|
|
911
|
-
"Manually assigned `{}` metadata property value is of invalid type. Discarding!"
|
|
912
|
-
|
|
983
|
+
"Manually assigned `{}` metadata property value is of invalid type. Discarding!".format(
|
|
984
|
+
key
|
|
985
|
+
)
|
|
986
|
+
)
|
|
913
987
|
# delete invalid key
|
|
914
988
|
del value[key]
|
|
915
989
|
# There is no concept of a tuple in the JSON format.
|
|
@@ -974,11 +1048,12 @@ class FFdecoder:
|
|
|
974
1048
|
|
|
975
1049
|
cmd += output_parameters
|
|
976
1050
|
cmd += ["-f", "rawvideo", "-"]
|
|
977
|
-
|
|
978
|
-
#
|
|
979
|
-
#
|
|
1051
|
+
cmd += self.__extra_outputs
|
|
1052
|
+
# When metadata extraction or stderr capture is enabled we must pipe stderr
|
|
1053
|
+
# regardless of verbose mode so the background reader thread can consume
|
|
1054
|
+
# it. Without PIPE the reader would have nothing to read (verbose
|
|
980
1055
|
# inherits parent stderr; silent discards it).
|
|
981
|
-
if self.__extract_metadata:
|
|
1056
|
+
if self.__extract_metadata or self.__capture_stderr:
|
|
982
1057
|
stderr_target = sp.PIPE
|
|
983
1058
|
elif self.__verbose_logs:
|
|
984
1059
|
stderr_target = None
|
|
@@ -1001,18 +1076,20 @@ class FFdecoder:
|
|
|
1001
1076
|
),
|
|
1002
1077
|
)
|
|
1003
1078
|
|
|
1004
|
-
# spin up the stderr reader thread that
|
|
1005
|
-
#
|
|
1006
|
-
if self.__extract_metadata:
|
|
1007
|
-
self.
|
|
1079
|
+
# spin up the stderr reader thread that records stderr tail, and parses
|
|
1080
|
+
# `showinfo` lines into the metadata queue consumed by generateFrame()
|
|
1081
|
+
if self.__extract_metadata or self.__capture_stderr:
|
|
1082
|
+
if self.__extract_metadata:
|
|
1083
|
+
self.__metadata_queue = queue.Queue()
|
|
1008
1084
|
self.__stderr_stop.clear()
|
|
1009
1085
|
self.__stderr_thread = threading.Thread(target=self.__read_stderr, daemon=True)
|
|
1010
1086
|
self.__stderr_thread.start()
|
|
1011
1087
|
|
|
1012
1088
|
def __read_stderr(self) -> None:
|
|
1013
1089
|
"""
|
|
1014
|
-
Internal: background daemon that
|
|
1015
|
-
|
|
1090
|
+
Internal: background daemon that appends FFmpeg stderr lines to `__stderr_tail`
|
|
1091
|
+
(echoing them when verbose), and parses `showinfo` lines into per-frame metadata
|
|
1092
|
+
dicts on `__metadata_queue` when `-extract_metadata` is enabled.
|
|
1016
1093
|
Exits when FFmpeg closes stderr or when `__stderr_stop` is signalled.
|
|
1017
1094
|
"""
|
|
1018
1095
|
assert self.__process is not None and self.__process.stderr is not None
|
|
@@ -1022,6 +1099,11 @@ class FFdecoder:
|
|
|
1022
1099
|
if self.__stderr_stop.is_set():
|
|
1023
1100
|
break
|
|
1024
1101
|
decoded = line.decode("utf-8", errors="ignore")
|
|
1102
|
+
self.__stderr_tail.append(decoded.rstrip())
|
|
1103
|
+
# echo so verbose console output stays unchanged
|
|
1104
|
+
self.__verbose_logs and sys.stderr.write(decoded)
|
|
1105
|
+
if not self.__extract_metadata:
|
|
1106
|
+
continue
|
|
1025
1107
|
match = _SHOWINFO_REGEX.search(decoded)
|
|
1026
1108
|
if not match:
|
|
1027
1109
|
continue
|
|
@@ -1037,35 +1119,51 @@ class FFdecoder:
|
|
|
1037
1119
|
pass
|
|
1038
1120
|
finally:
|
|
1039
1121
|
# sentinel so consumers unblock on EOF
|
|
1040
|
-
self.__metadata_queue.put(None)
|
|
1122
|
+
self.__metadata_queue is not None and self.__metadata_queue.put(None)
|
|
1041
1123
|
|
|
1042
|
-
def terminate(self) -> None:
|
|
1124
|
+
def terminate(self) -> int | None:
|
|
1043
1125
|
"""
|
|
1044
1126
|
Safely terminates all processes.
|
|
1127
|
+
|
|
1128
|
+
**Returns:** FFmpeg process exit code (also available via `returncode`), or `None` if no process was launched.
|
|
1045
1129
|
"""
|
|
1046
1130
|
|
|
1047
1131
|
# signal we are closing
|
|
1048
1132
|
self.__verbose_logs and logger.debug("Terminating FFdecoder Pipeline...")
|
|
1133
|
+
stream_exhausted = self.__terminate_stream
|
|
1049
1134
|
self.__terminate_stream = True
|
|
1050
1135
|
self.__stderr_stop.set()
|
|
1051
1136
|
# check if no process was initiated at first place
|
|
1052
|
-
if self.__process is None
|
|
1137
|
+
if self.__process is None:
|
|
1053
1138
|
logger.info("Pipeline already terminated.")
|
|
1054
|
-
return
|
|
1139
|
+
return self.__returncode
|
|
1055
1140
|
# Attempt to close pipeline.
|
|
1056
1141
|
# close `stdin` output
|
|
1057
1142
|
self.__process.stdin and self.__process.stdin.close()
|
|
1058
1143
|
# close `stdout` output
|
|
1059
1144
|
self.__process.stdout and self.__process.stdout.close()
|
|
1060
|
-
#
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1145
|
+
# let FFmpeg finalize `-extra_outputs` (trailers/moov) on EPIPE, or exit cleanly
|
|
1146
|
+
# after stream end, before forcing termination
|
|
1147
|
+
if self.__extra_outputs or stream_exhausted:
|
|
1148
|
+
try:
|
|
1149
|
+
self.__process.wait(TERMINATE_TIMEOUT_SUBPROCESS)
|
|
1150
|
+
except sp.TimeoutExpired:
|
|
1151
|
+
pass
|
|
1152
|
+
# terminate process if still processing, escalate to kill if unresponsive
|
|
1153
|
+
if self.__process.poll() is None:
|
|
1154
|
+
self.__process.terminate()
|
|
1155
|
+
try:
|
|
1156
|
+
self.__process.wait(TERMINATE_TIMEOUT_SUBPROCESS)
|
|
1157
|
+
except sp.TimeoutExpired:
|
|
1158
|
+
self.__process.kill()
|
|
1159
|
+
self.__process.wait()
|
|
1160
|
+
# join the stderr reader thread (it hits EOF once FFmpeg exits) so it does not outlive
|
|
1161
|
+
# the pipeline, then close `stderr`; closing earlier blocks on the reader's buffer lock
|
|
1067
1162
|
if self.__stderr_thread is not None and self.__stderr_thread.is_alive():
|
|
1068
1163
|
self.__stderr_thread.join(timeout=2.0)
|
|
1069
1164
|
self.__stderr_thread = None
|
|
1165
|
+
self.__process.stderr and self.__process.stderr.close()
|
|
1166
|
+
self.__returncode = self.__process.returncode
|
|
1070
1167
|
self.__process = None
|
|
1071
1168
|
logger.info("Pipeline terminated successfully.")
|
|
1169
|
+
return self.__returncode
|
deffcode/ffhelper.py
CHANGED
|
@@ -677,6 +677,8 @@ def check_sp_output(*args: Any, **kwargs: Any) -> bytes:
|
|
|
677
677
|
# handle additional params
|
|
678
678
|
retrieve_stderr = kwargs.pop("force_retrieve_stderr", False)
|
|
679
679
|
timeout = kwargs.pop("timeout", None)
|
|
680
|
+
# never inherit parent's stdin, avoids blocking on unexpected input reads
|
|
681
|
+
kwargs.setdefault("stdin", sp.DEVNULL)
|
|
680
682
|
|
|
681
683
|
# execute command in subprocess
|
|
682
684
|
process = sp.Popen(
|
deffcode/sourcer.py
CHANGED
|
@@ -321,7 +321,7 @@ class Sourcer:
|
|
|
321
321
|
_params = self.__sourcer_params.copy()
|
|
322
322
|
_params["-ffprefixes"] = _prefixes
|
|
323
323
|
# output routing references all inputs; meaningless per-source
|
|
324
|
-
for _key in ("-vf", "-filter_complex", "-map"):
|
|
324
|
+
for _key in ("-vf", "-filter_complex", "-map", "-clones"):
|
|
325
325
|
_params.pop(_key, None)
|
|
326
326
|
# Resolve to an absolute path: on Unix `self.__ffmpeg` may be
|
|
327
327
|
# the bare command "ffmpeg" found via PATH, which the nested
|
deffcode/version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__: str = "0.2.
|
|
1
|
+
__version__: str = "0.2.9"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: deffcode
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.9
|
|
4
4
|
Summary: A cross-platform High-performance & Flexible Real-time Video Frames Decoder in Python.
|
|
5
5
|
Author-email: Abhishek Thakur <abhi.una12@gmail.com>
|
|
6
6
|
License: Apache License 2.0
|
|
@@ -108,6 +108,7 @@ Here are some key features that stand out:
|
|
|
108
108
|
- Hands down the easiest [**Index based Camera Device Capturing**][decoding-camera-devices-using-indexes], similar to OpenCV.
|
|
109
109
|
- Easy to code **Real-time [Simple][transcoding-live-simple-filtergraphs] & [Complex][transcoding-live-complex-filtergraphs] Filtergraphs**. _(Yes, You read it correctly "Real-time"!)_
|
|
110
110
|
- Native **[Multi-Input Source Configurations][multi-input-source-configurations]** support for decoding complex topologies.
|
|
111
|
+
- Native **[Multi-Outputs Configurations][multi-outputs-configurations]** support for recording/streaming while decoding, in a single FFmpeg pipeline.
|
|
111
112
|
- Lightning fast dedicated **GPU-Accelerated Video [Decoding][hardware-accelerated-video-decoding] & [Transcoding][hardware-accelerated-video-transcoding]**.
|
|
112
113
|
- Enables precise FFmpeg [**Key-frame Seeking**][extracting-key-frames-as-png-image] with pinpoint accuracy.
|
|
113
114
|
- Effortless [**Metadata Extraction**][extracting-video-metadata] from all streams available in the source.
|
|
@@ -237,6 +238,9 @@ Once you have DeFFcode installed, checkout our Well-Documented **[Recipes 🍱][
|
|
|
237
238
|
- [Multi-Input Source Configurations][multi-input-source-configurations]
|
|
238
239
|
- [Decoding multiple inputs as 2x2 video grid _(mosaic)_][decoding-multiple-inputs-as-2x2-video-grid-mosaic]
|
|
239
240
|
- [Decoding crossfade transition between multiple inputs][decoding-crossfade-transition-between-multiple-inputs]
|
|
241
|
+
- [Multi-Outputs Configurations][multi-outputs-configurations]
|
|
242
|
+
- [Recording while decoding][recording-while-decoding]
|
|
243
|
+
- [Encode once, duplicate to file and stream][encode-once-duplicate-to-file-and-stream]
|
|
240
244
|
|
|
241
245
|
</details>
|
|
242
246
|
|
|
@@ -357,24 +361,18 @@ It is something I am doing with my own free time. But so much more needs to be d
|
|
|
357
361
|
|
|
358
362
|
Here is a Bibtex entry you can use to cite this project in a publication:
|
|
359
363
|
|
|
360
|
-
[](https://doi.org/10.5281/zenodo.23446604)
|
|
361
365
|
|
|
362
366
|
```BibTeX
|
|
363
367
|
@software{deffcode,
|
|
364
368
|
author = {Abhishek Thakur},
|
|
365
|
-
title = {abhiTronix/deffcode: v0.2.
|
|
366
|
-
month =
|
|
369
|
+
title = {abhiTronix/deffcode: v0.2.8},
|
|
370
|
+
month = oct,
|
|
367
371
|
year = 2026,
|
|
368
372
|
publisher = {Zenodo},
|
|
369
|
-
version = {v0.2.
|
|
370
|
-
doi = {10.5281/zenodo.
|
|
371
|
-
url = {https://doi.org/10.5281/zenodo.
|
|
372
|
-
swhid = {swh:1:dir:85e8dfd087aed870deb4043c532faaa9b156d1e1
|
|
373
|
-
;origin=https://doi.org/10.5281/zenodo.6976947;vis
|
|
374
|
-
it=swh:1:snp:af1b478890801c02d56b95f563b86761980bf
|
|
375
|
-
82c;anchor=swh:1:rel:85f9af4452f8030317ec2012acc10
|
|
376
|
-
29e8a945e2d;path=abhiTronix-deffcode-5162649
|
|
377
|
-
},
|
|
373
|
+
version = {v0.2.8},
|
|
374
|
+
doi = {10.5281/zenodo.23446604},
|
|
375
|
+
url = {https://doi.org/10.5281/zenodo.23446604},
|
|
378
376
|
}
|
|
379
377
|
```
|
|
380
378
|
|
|
@@ -489,6 +487,9 @@ Advanced Recipes
|
|
|
489
487
|
[multi-input-source-configurations]: https://abhitronix.github.io/deffcode/latest/recipes/advanced/multi_input/#multi-input-source-configurations
|
|
490
488
|
[decoding-multiple-inputs-as-2x2-video-grid-mosaic]: https://abhitronix.github.io/deffcode/latest/recipes/advanced/multi_input/#decoding-multiple-inputs-as-2x2-video-grid-mosaic
|
|
491
489
|
[decoding-crossfade-transition-between-multiple-inputs]: https://abhitronix.github.io/deffcode/latest/recipes/advanced/multi_input/#decoding-crossfade-transition-between-multiple-inputs
|
|
490
|
+
[multi-outputs-configurations]: https://abhitronix.github.io/deffcode/latest/recipes/advanced/multi_output/#multi-outputs-configurations
|
|
491
|
+
[recording-while-decoding]: https://abhitronix.github.io/deffcode/latest/recipes/advanced/multi_output/#recording-while-decoding
|
|
492
|
+
[encode-once-duplicate-to-file-and-stream]: https://abhitronix.github.io/deffcode/latest/recipes/advanced/multi_output/#encode-once-duplicate-to-file-and-stream
|
|
492
493
|
|
|
493
494
|
<!--
|
|
494
495
|
CI Apps URLs
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
deffcode/__init__.py,sha256=BQO_1Yv0E9PZCPtJ8-1z3X0VLP6VgBbdV5RahJU_RIk,286
|
|
2
|
+
deffcode/ffdecoder.py,sha256=4ywrmP076ZGdrZdcIrFP336HXEAyWT2NKmRiJOo7-5Q,55259
|
|
3
|
+
deffcode/ffhelper.py,sha256=Kms1CiVsyB3CgQvLdScGSuL5ml0eRqxm6xrTd-0g6fE,29032
|
|
4
|
+
deffcode/sourcer.py,sha256=xys3OH4AO0RgdaIj-bYc76rP0F3ZZJSocxGuM0OG2N0,43628
|
|
5
|
+
deffcode/utils.py,sha256=bIR1Hu_icLs3Xe7njHR9YE09MYUbvUfhOUMSqSHh730,4729
|
|
6
|
+
deffcode/version.py,sha256=cHThOwcEXKpIPW-ZC1HETHv-MyCCWj4sJISXFDdM8u4,27
|
|
7
|
+
deffcode-0.2.9.dist-info/licenses/LICENSE,sha256=pF-0xwtgiRjzW5P97fyEOCIqe7LV5Sd5cjIC4fBDwVQ,12259
|
|
8
|
+
deffcode-0.2.9.dist-info/METADATA,sha256=WMCK5mRr3eEfDt5wuvh7iG4gOfJlfKNeVttRqf73dIM,35196
|
|
9
|
+
deffcode-0.2.9.dist-info/WHEEL,sha256=mOdXR9C3wMVov7cSY8PY-XCzo3SmmWCHvGQr5csJoao,91
|
|
10
|
+
deffcode-0.2.9.dist-info/top_level.txt,sha256=1C-kyZgIKFviemaQMmhP0VKR3wkzEZcrf1o5oUckvHI,9
|
|
11
|
+
deffcode-0.2.9.dist-info/RECORD,,
|
deffcode-0.2.8.dist-info/RECORD
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
deffcode/__init__.py,sha256=BQO_1Yv0E9PZCPtJ8-1z3X0VLP6VgBbdV5RahJU_RIk,286
|
|
2
|
-
deffcode/ffdecoder.py,sha256=0N1x1GstU7_RpqXe3RF-Uw4ZMGjBsRiDXlcFaycecxA,50640
|
|
3
|
-
deffcode/ffhelper.py,sha256=6DwWsCf22DQH2bXtkBvsh01APc26TFsDfWD5N00snJg,28911
|
|
4
|
-
deffcode/sourcer.py,sha256=k_Sau4vYLc8uGTJ5kX0Jorx0HC006bnA5Eplu_Ney7A,43617
|
|
5
|
-
deffcode/utils.py,sha256=bIR1Hu_icLs3Xe7njHR9YE09MYUbvUfhOUMSqSHh730,4729
|
|
6
|
-
deffcode/version.py,sha256=HUqwShoZiCc_WHZJmLh-SoGXaMatKowDyny2qENFLOU,27
|
|
7
|
-
deffcode-0.2.8.dist-info/licenses/LICENSE,sha256=pF-0xwtgiRjzW5P97fyEOCIqe7LV5Sd5cjIC4fBDwVQ,12259
|
|
8
|
-
deffcode-0.2.8.dist-info/METADATA,sha256=mZcgTQV75a8E4ytkFBgYiD5bpgRTY0jz6BqKd4wjhUw,34772
|
|
9
|
-
deffcode-0.2.8.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
|
|
10
|
-
deffcode-0.2.8.dist-info/top_level.txt,sha256=1C-kyZgIKFviemaQMmhP0VKR3wkzEZcrf1o5oUckvHI,9
|
|
11
|
-
deffcode-0.2.8.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|