supervisely 6.73.444__py3-none-any.whl → 6.73.468__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.
Potentially problematic release.
This version of supervisely might be problematic. Click here for more details.
- supervisely/__init__.py +24 -1
- supervisely/_utils.py +81 -0
- supervisely/annotation/json_geometries_map.py +2 -0
- supervisely/api/dataset_api.py +74 -12
- supervisely/api/entity_annotation/figure_api.py +8 -5
- supervisely/api/image_api.py +4 -0
- supervisely/api/video/video_annotation_api.py +4 -2
- supervisely/api/video/video_api.py +41 -1
- supervisely/app/__init__.py +1 -1
- supervisely/app/content.py +14 -6
- supervisely/app/fastapi/__init__.py +1 -0
- supervisely/app/fastapi/custom_static_files.py +1 -1
- supervisely/app/fastapi/multi_user.py +88 -0
- supervisely/app/fastapi/subapp.py +88 -42
- supervisely/app/fastapi/websocket.py +77 -9
- supervisely/app/singleton.py +21 -0
- supervisely/app/v1/app_service.py +18 -2
- supervisely/app/v1/constants.py +7 -1
- supervisely/app/widgets/card/card.py +20 -0
- supervisely/app/widgets/deploy_model/deploy_model.py +56 -35
- supervisely/app/widgets/dialog/dialog.py +12 -0
- supervisely/app/widgets/dialog/template.html +2 -1
- supervisely/app/widgets/experiment_selector/experiment_selector.py +8 -0
- supervisely/app/widgets/fast_table/fast_table.py +121 -31
- supervisely/app/widgets/fast_table/template.html +1 -1
- supervisely/app/widgets/radio_tabs/radio_tabs.py +18 -2
- supervisely/app/widgets/radio_tabs/template.html +1 -0
- supervisely/app/widgets/select_dataset_tree/select_dataset_tree.py +65 -7
- supervisely/app/widgets/table/table.py +68 -13
- supervisely/app/widgets/tree_select/tree_select.py +2 -0
- supervisely/convert/image/csv/csv_converter.py +24 -15
- supervisely/convert/video/video_converter.py +2 -2
- supervisely/geometry/polyline_3d.py +110 -0
- supervisely/io/env.py +76 -1
- supervisely/nn/inference/cache.py +37 -17
- supervisely/nn/inference/inference.py +667 -114
- supervisely/nn/inference/inference_request.py +15 -8
- supervisely/nn/inference/predict_app/gui/classes_selector.py +81 -12
- supervisely/nn/inference/predict_app/gui/gui.py +676 -488
- supervisely/nn/inference/predict_app/gui/input_selector.py +205 -26
- supervisely/nn/inference/predict_app/gui/model_selector.py +2 -4
- supervisely/nn/inference/predict_app/gui/output_selector.py +46 -6
- supervisely/nn/inference/predict_app/gui/settings_selector.py +756 -59
- supervisely/nn/inference/predict_app/gui/tags_selector.py +1 -1
- supervisely/nn/inference/predict_app/gui/utils.py +236 -119
- supervisely/nn/inference/predict_app/predict_app.py +2 -2
- supervisely/nn/inference/session.py +43 -35
- supervisely/nn/model/model_api.py +9 -0
- supervisely/nn/model/prediction_session.py +8 -7
- supervisely/nn/prediction_dto.py +7 -0
- supervisely/nn/tracker/base_tracker.py +11 -1
- supervisely/nn/tracker/botsort/botsort_config.yaml +0 -1
- supervisely/nn/tracker/botsort_tracker.py +14 -7
- supervisely/nn/tracker/visualize.py +70 -72
- supervisely/nn/training/gui/train_val_splits_selector.py +52 -31
- supervisely/nn/training/train_app.py +10 -5
- supervisely/project/project.py +9 -1
- supervisely/video/sampling.py +39 -20
- supervisely/video/video.py +41 -12
- supervisely/volume/stl_converter.py +2 -0
- supervisely/worker_api/agent_rpc.py +24 -1
- supervisely/worker_api/rpc_servicer.py +31 -7
- {supervisely-6.73.444.dist-info → supervisely-6.73.468.dist-info}/METADATA +14 -11
- {supervisely-6.73.444.dist-info → supervisely-6.73.468.dist-info}/RECORD +68 -66
- {supervisely-6.73.444.dist-info → supervisely-6.73.468.dist-info}/LICENSE +0 -0
- {supervisely-6.73.444.dist-info → supervisely-6.73.468.dist-info}/WHEEL +0 -0
- {supervisely-6.73.444.dist-info → supervisely-6.73.468.dist-info}/entry_points.txt +0 -0
- {supervisely-6.73.444.dist-info → supervisely-6.73.468.dist-info}/top_level.txt +0 -0
supervisely/video/video.py
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
from __future__ import annotations
|
|
5
5
|
|
|
6
6
|
import os
|
|
7
|
-
from typing import Dict, Generator, List, Optional, Tuple
|
|
7
|
+
from typing import Dict, Generator, Iterable, List, Optional, Tuple
|
|
8
8
|
|
|
9
9
|
import cv2
|
|
10
10
|
import numpy as np
|
|
@@ -18,7 +18,7 @@ ALLOWED_VIDEO_EXTENSIONS = [".avi", ".mp4", ".3gp", ".flv", ".webm", ".wmv", ".m
|
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
_SUPPORTED_CONTAINERS = {"mp4", "webm", "ogg", "ogv"}
|
|
21
|
-
_SUPPORTED_CODECS = {"h264", "vp8", "vp9"}
|
|
21
|
+
_SUPPORTED_CODECS = {"h264", "vp8", "vp9", "h265", "hevc", "av1"}
|
|
22
22
|
|
|
23
23
|
|
|
24
24
|
class VideoExtensionError(Exception):
|
|
@@ -537,11 +537,9 @@ class VideoFrameReader:
|
|
|
537
537
|
try:
|
|
538
538
|
import decord
|
|
539
539
|
|
|
540
|
-
self.vr = decord.VideoReader(str(self.video_path))
|
|
540
|
+
self.vr = decord.VideoReader(str(self.video_path), num_threads=1)
|
|
541
541
|
except ImportError:
|
|
542
|
-
default_logger.debug(
|
|
543
|
-
"Decord is not installed. Falling back to OpenCV for video reading."
|
|
544
|
-
)
|
|
542
|
+
default_logger.debug("Decord is not installed. Falling back to OpenCV for video reading.")
|
|
545
543
|
self.cap = cv2.VideoCapture(str(self.video_path))
|
|
546
544
|
|
|
547
545
|
def close(self):
|
|
@@ -562,24 +560,30 @@ class VideoFrameReader:
|
|
|
562
560
|
def __del__(self):
|
|
563
561
|
self.close()
|
|
564
562
|
|
|
565
|
-
def iterate_frames(self, frame_indexes: List[int] = None) -> Generator[np.ndarray, None, None]:
|
|
563
|
+
def iterate_frames(self, frame_indexes: Optional[List[int]] = None) -> Generator[np.ndarray, None, None]:
|
|
566
564
|
self._ensure_initialized()
|
|
567
565
|
if frame_indexes is None:
|
|
568
566
|
frame_indexes = self.frame_indexes
|
|
569
567
|
if self.vr is not None:
|
|
568
|
+
# Decord
|
|
570
569
|
if frame_indexes is None:
|
|
571
570
|
frame_indexes = range(len(self.vr))
|
|
572
|
-
for
|
|
573
|
-
|
|
574
|
-
yield
|
|
571
|
+
for idx in frame_indexes:
|
|
572
|
+
arr = self.vr[idx].asnumpy()
|
|
573
|
+
yield arr
|
|
574
|
+
del arr
|
|
575
575
|
else:
|
|
576
|
+
# OpenCV fallback
|
|
576
577
|
if frame_indexes is None:
|
|
577
578
|
frame_count = int(self.cap.get(cv2.CAP_PROP_FRAME_COUNT))
|
|
578
579
|
frame_indexes = range(frame_count)
|
|
579
580
|
for frame_index in frame_indexes:
|
|
580
|
-
if 1
|
|
581
|
+
if 1 < frame_index - self.prev_idx < 20:
|
|
581
582
|
while self.prev_idx < frame_index - 1:
|
|
582
|
-
self.cap.read()
|
|
583
|
+
ok, _ = self.cap.read()
|
|
584
|
+
if not ok:
|
|
585
|
+
break
|
|
586
|
+
self.prev_idx += 1
|
|
583
587
|
if frame_index != self.prev_idx + 1:
|
|
584
588
|
self.cap.set(cv2.CAP_PROP_POS_FRAMES, frame_index)
|
|
585
589
|
ret, frame = self.cap.read()
|
|
@@ -588,6 +592,17 @@ class VideoFrameReader:
|
|
|
588
592
|
yield cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
|
|
589
593
|
self.prev_idx = frame_index
|
|
590
594
|
|
|
595
|
+
def read_batch(self, frame_indexes: List[int]) -> List[np.ndarray]:
|
|
596
|
+
self._ensure_initialized()
|
|
597
|
+
if self.vr is not None:
|
|
598
|
+
batch_nd = self.vr.get_batch(frame_indexes)
|
|
599
|
+
batch_np = batch_nd.asnumpy()
|
|
600
|
+
frames = [batch_np[i].copy() for i in range(batch_np.shape[0])]
|
|
601
|
+
del batch_np
|
|
602
|
+
return frames
|
|
603
|
+
else:
|
|
604
|
+
return list(self.iterate_frames(frame_indexes))
|
|
605
|
+
|
|
591
606
|
def read_frames(self, frame_indexes: List[int] = None) -> List[np.ndarray]:
|
|
592
607
|
return list(self.iterate_frames(frame_indexes))
|
|
593
608
|
|
|
@@ -625,3 +640,17 @@ class VideoFrameReader:
|
|
|
625
640
|
return self.vr.get_avg_fps()
|
|
626
641
|
else:
|
|
627
642
|
return int(self.cap.get(cv2.CAP_PROP_FPS))
|
|
643
|
+
|
|
644
|
+
|
|
645
|
+
def create_from_frames(frames: Iterable[np.ndarray], output_path: str, fps: int = 30) -> None:
|
|
646
|
+
video_writer = None
|
|
647
|
+
for frame in frames:
|
|
648
|
+
if video_writer is None:
|
|
649
|
+
height, width, _ = frame.shape
|
|
650
|
+
fourcc = cv2.VideoWriter.fourcc(*"mp4v")
|
|
651
|
+
video_writer = cv2.VideoWriter(output_path, fourcc, fps, (width, height))
|
|
652
|
+
if frame.dtype != np.uint8:
|
|
653
|
+
frame = (frame * 255).astype(np.uint8) if frame.max() <= 1.0 else frame.astype(np.uint8)
|
|
654
|
+
|
|
655
|
+
video_writer.write(frame)
|
|
656
|
+
video_writer.release()
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
# coding: utf-8
|
|
2
|
+
# isort: skip_file
|
|
2
3
|
|
|
3
4
|
import cv2
|
|
4
5
|
import numpy as np
|
|
5
6
|
|
|
6
7
|
from .chunking import load_to_memory_chunked_image, load_to_memory_chunked
|
|
7
|
-
|
|
8
|
+
|
|
9
|
+
# from ..worker_proto import worker_api_pb2 as api_proto # Import moved to methods where needed
|
|
8
10
|
|
|
9
11
|
|
|
10
12
|
class SimpleCache:
|
|
@@ -22,6 +24,13 @@ class SimpleCache:
|
|
|
22
24
|
|
|
23
25
|
|
|
24
26
|
def download_image_from_remote(agent_api, image_hash, src_node_token, logger):
|
|
27
|
+
try:
|
|
28
|
+
from ..worker_proto import worker_api_pb2 as api_proto
|
|
29
|
+
except Exception as e:
|
|
30
|
+
from supervisely.app.v1.constants import PROTOBUF_REQUIRED_ERROR
|
|
31
|
+
|
|
32
|
+
raise ImportError(PROTOBUF_REQUIRED_ERROR) from e
|
|
33
|
+
|
|
25
34
|
resp = agent_api.get_stream_with_data(
|
|
26
35
|
'DownloadImages',
|
|
27
36
|
api_proto.ChunkImage,
|
|
@@ -34,6 +43,13 @@ def download_image_from_remote(agent_api, image_hash, src_node_token, logger):
|
|
|
34
43
|
|
|
35
44
|
|
|
36
45
|
def download_data_from_remote(agent_api, req_id, logger):
|
|
46
|
+
try:
|
|
47
|
+
from ..worker_proto import worker_api_pb2 as api_proto
|
|
48
|
+
except Exception as e:
|
|
49
|
+
from supervisely.app.v1.constants import PROTOBUF_REQUIRED_ERROR
|
|
50
|
+
|
|
51
|
+
raise ImportError(PROTOBUF_REQUIRED_ERROR) from e
|
|
52
|
+
|
|
37
53
|
resp = agent_api.get_stream_with_data('GetGeneralEventData', api_proto.Chunk, api_proto.Empty(),
|
|
38
54
|
addit_headers={'x-request-id': req_id})
|
|
39
55
|
b_data = load_to_memory_chunked(resp)
|
|
@@ -47,6 +63,13 @@ def batched(seq, batch_size):
|
|
|
47
63
|
|
|
48
64
|
|
|
49
65
|
def send_from_memory_generator(out_bytes, chunk_size):
|
|
66
|
+
try:
|
|
67
|
+
from ..worker_proto import worker_api_pb2 as api_proto
|
|
68
|
+
except Exception as e:
|
|
69
|
+
from supervisely.app.v1.constants import PROTOBUF_REQUIRED_ERROR
|
|
70
|
+
|
|
71
|
+
raise ImportError(PROTOBUF_REQUIRED_ERROR) from e
|
|
72
|
+
|
|
50
73
|
for bytes_chunk in batched(out_bytes, chunk_size):
|
|
51
74
|
yield api_proto.Chunk(buffer=bytes_chunk, total_size=len(out_bytes))
|
|
52
75
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
# coding: utf-8
|
|
2
|
+
# isort: skip_file
|
|
2
3
|
|
|
3
4
|
import os
|
|
4
5
|
import concurrent.futures
|
|
@@ -11,18 +12,27 @@ import threading
|
|
|
11
12
|
from supervisely.annotation.annotation import Annotation
|
|
12
13
|
from supervisely.function_wrapper import function_wrapper, function_wrapper_nofail
|
|
13
14
|
from supervisely.imaging.image import drop_image_alpha_channel
|
|
14
|
-
from supervisely.nn.legacy.hosted.inference_modes import
|
|
15
|
-
|
|
15
|
+
from supervisely.nn.legacy.hosted.inference_modes import (
|
|
16
|
+
InferenceModeFactory,
|
|
17
|
+
InfModeFullImage,
|
|
18
|
+
MODE,
|
|
19
|
+
NAME,
|
|
20
|
+
get_effective_inference_mode_config,
|
|
21
|
+
)
|
|
16
22
|
from supervisely.project.project_meta import ProjectMeta
|
|
17
23
|
from supervisely.worker_api.agent_api import AgentAPI
|
|
18
|
-
from supervisely.worker_api.agent_rpc import
|
|
19
|
-
|
|
24
|
+
from supervisely.worker_api.agent_rpc import (
|
|
25
|
+
decode_image,
|
|
26
|
+
download_image_from_remote,
|
|
27
|
+
download_data_from_remote,
|
|
28
|
+
send_from_memory_generator,
|
|
29
|
+
)
|
|
20
30
|
from supervisely.worker_api.interfaces import SingleImageInferenceInterface
|
|
21
|
-
|
|
31
|
+
|
|
32
|
+
# from supervisely.worker_proto import worker_api_pb2 as api_proto # Import moved to methods where needed
|
|
22
33
|
from supervisely.task.progress import report_agent_rpc_ready
|
|
23
34
|
from supervisely.api.api import Api
|
|
24
35
|
|
|
25
|
-
|
|
26
36
|
REQUEST_TYPE = 'request_type'
|
|
27
37
|
GET_OUT_META = 'get_out_meta'
|
|
28
38
|
INFERENCE = 'inference'
|
|
@@ -123,6 +133,13 @@ class AgentRPCServicerBase:
|
|
|
123
133
|
self.thread_pool.submit(function_wrapper_nofail, self._send_data, res_msg, req_id) # skip errors
|
|
124
134
|
|
|
125
135
|
def _send_data(self, out_msg, req_id):
|
|
136
|
+
try:
|
|
137
|
+
from supervisely.worker_proto import worker_api_pb2 as api_proto
|
|
138
|
+
except Exception as e:
|
|
139
|
+
from supervisely.app.v1.constants import PROTOBUF_REQUIRED_ERROR
|
|
140
|
+
|
|
141
|
+
raise ImportError(PROTOBUF_REQUIRED_ERROR) from e
|
|
142
|
+
|
|
126
143
|
self.logger.trace('Will send output data.', extra={REQUEST_ID: req_id})
|
|
127
144
|
out_bytes = json.dumps(out_msg).encode('utf-8')
|
|
128
145
|
|
|
@@ -173,6 +190,13 @@ class AgentRPCServicerBase:
|
|
|
173
190
|
self._load_data_if_required(event_obj)
|
|
174
191
|
|
|
175
192
|
def run_inf_loop(self):
|
|
193
|
+
try:
|
|
194
|
+
from supervisely.worker_proto import worker_api_pb2 as api_proto
|
|
195
|
+
except Exception as e:
|
|
196
|
+
from supervisely.app.v1.constants import PROTOBUF_REQUIRED_ERROR
|
|
197
|
+
|
|
198
|
+
raise ImportError(PROTOBUF_REQUIRED_ERROR) from e
|
|
199
|
+
|
|
176
200
|
def seq_inf_wrapped():
|
|
177
201
|
function_wrapper(self._sequential_final_processing) # exit if raised
|
|
178
202
|
|
|
@@ -252,4 +276,4 @@ class InactiveRPCServicer(AgentRPCServicer):
|
|
|
252
276
|
self.logger.info('Created InactiveRPCServicer for internal usage', extra=conn_config)
|
|
253
277
|
|
|
254
278
|
def run_inf_loop(self):
|
|
255
|
-
raise RuntimeError("Method is not accessible")
|
|
279
|
+
raise RuntimeError("Method is not accessible")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: supervisely
|
|
3
|
-
Version: 6.73.
|
|
3
|
+
Version: 6.73.468
|
|
4
4
|
Summary: Supervisely Python SDK.
|
|
5
5
|
Home-page: https://github.com/supervisely/supervisely
|
|
6
6
|
Author: Supervisely
|
|
@@ -21,15 +21,14 @@ Requires-Python: >=3.8
|
|
|
21
21
|
Description-Content-Type: text/markdown
|
|
22
22
|
License-File: LICENSE
|
|
23
23
|
Requires-Dist: cachetools<=5.5.0,>=4.2.3
|
|
24
|
-
Requires-Dist: numpy
|
|
24
|
+
Requires-Dist: numpy<=2.3.3,>=1.19
|
|
25
25
|
Requires-Dist: opencv-python<5.0.0.0,>=4.6.0.66
|
|
26
26
|
Requires-Dist: PTable<1.0.0,>=0.9.2
|
|
27
|
-
Requires-Dist: pillow<=10.
|
|
28
|
-
Requires-Dist: protobuf<=3.20.3,>=3.19.5
|
|
27
|
+
Requires-Dist: pillow<=10.4.0,>=5.4.1
|
|
29
28
|
Requires-Dist: python-json-logger<3.0.0,>=0.1.11
|
|
30
29
|
Requires-Dist: requests<3.0.0,>=2.27.1
|
|
31
30
|
Requires-Dist: requests-toolbelt>=0.9.1
|
|
32
|
-
Requires-Dist: Shapely<=2.
|
|
31
|
+
Requires-Dist: Shapely<=2.1.2,>=1.7.1
|
|
33
32
|
Requires-Dist: bidict<1.0.0,>=0.21.2
|
|
34
33
|
Requires-Dist: varname<1.0.0,>=0.8.1
|
|
35
34
|
Requires-Dist: python-dotenv<=1.0.1,>=0.19.2
|
|
@@ -40,9 +39,9 @@ Requires-Dist: stringcase<2.0.0,>=1.2.0
|
|
|
40
39
|
Requires-Dist: python-magic<1.0.0,>=0.4.25
|
|
41
40
|
Requires-Dist: trimesh<=4.5.0,>=3.11.2
|
|
42
41
|
Requires-Dist: uvicorn[standard]<1.0.0,>=0.18.2
|
|
43
|
-
Requires-Dist:
|
|
44
|
-
Requires-Dist:
|
|
45
|
-
Requires-Dist: fastapi<=0.
|
|
42
|
+
Requires-Dist: starlette<=0.47.3
|
|
43
|
+
Requires-Dist: pydantic<=2.12.3,>=1.7.4
|
|
44
|
+
Requires-Dist: fastapi<=0.119.1,>=0.103.1
|
|
46
45
|
Requires-Dist: websockets<=13.1,>=10.3
|
|
47
46
|
Requires-Dist: jinja2<4.0.0,>=3.0.3
|
|
48
47
|
Requires-Dist: psutil<6.0.0,>=5.9.0
|
|
@@ -50,7 +49,7 @@ Requires-Dist: jsonpatch<2.0,>=1.32
|
|
|
50
49
|
Requires-Dist: MarkupSafe<3.0.0,>=2.1.1
|
|
51
50
|
Requires-Dist: arel<1.0.0,>=0.2.0
|
|
52
51
|
Requires-Dist: tqdm<5.0.0,>=4.62.3
|
|
53
|
-
Requires-Dist: pandas<=2.
|
|
52
|
+
Requires-Dist: pandas<=2.3.3,>=1.1.3
|
|
54
53
|
Requires-Dist: async-asgi-testclient
|
|
55
54
|
Requires-Dist: PyYAML>=5.4.0
|
|
56
55
|
Requires-Dist: distinctipy
|
|
@@ -71,6 +70,9 @@ Requires-Dist: zstd
|
|
|
71
70
|
Requires-Dist: aiofiles
|
|
72
71
|
Requires-Dist: httpx[http2]==0.27.2
|
|
73
72
|
Requires-Dist: debugpy
|
|
73
|
+
Requires-Dist: setuptools<81.0.0
|
|
74
|
+
Provides-Extra: agent
|
|
75
|
+
Requires-Dist: protobuf<=3.20.3,>=3.19.5; extra == "agent"
|
|
74
76
|
Provides-Extra: apps
|
|
75
77
|
Requires-Dist: uvicorn[standard]<1.0.0,>=0.18.2; extra == "apps"
|
|
76
78
|
Requires-Dist: fastapi<1.0.0,>=0.79.0; extra == "apps"
|
|
@@ -81,10 +83,11 @@ Requires-Dist: jsonpatch<2.0,>=1.32; extra == "apps"
|
|
|
81
83
|
Requires-Dist: MarkupSafe<3.0.0,>=2.1.1; extra == "apps"
|
|
82
84
|
Requires-Dist: arel<1.0.0,>=0.2.0; extra == "apps"
|
|
83
85
|
Requires-Dist: tqdm<5.0.0,>=4.62.3; extra == "apps"
|
|
84
|
-
Requires-Dist: pandas
|
|
86
|
+
Requires-Dist: pandas<=2.3.3,>=1.1.3; extra == "apps"
|
|
85
87
|
Provides-Extra: aug
|
|
86
88
|
Requires-Dist: imgaug<1.0.0,>=0.4.0; extra == "aug"
|
|
87
89
|
Requires-Dist: imagecorruptions<2.0.0,>=1.1.2; extra == "aug"
|
|
90
|
+
Requires-Dist: numpy<2.0.0,>=1.19; extra == "aug"
|
|
88
91
|
Provides-Extra: docs
|
|
89
92
|
Requires-Dist: sphinx==4.4.0; extra == "docs"
|
|
90
93
|
Requires-Dist: jinja2==3.0.3; extra == "docs"
|
|
@@ -100,7 +103,7 @@ Requires-Dist: scikit-image<1.0.0,>=0.17.1; extra == "extras"
|
|
|
100
103
|
Requires-Dist: matplotlib<4.0.0,>=3.3.2; extra == "extras"
|
|
101
104
|
Requires-Dist: pascal-voc-writer<1.0.0,>=0.1.4; extra == "extras"
|
|
102
105
|
Requires-Dist: scipy<2.0.0,>=1.8.0; extra == "extras"
|
|
103
|
-
Requires-Dist: pandas
|
|
106
|
+
Requires-Dist: pandas<=2.3.3,>=1.1.3; extra == "extras"
|
|
104
107
|
Requires-Dist: ruamel.yaml==0.17.21; extra == "extras"
|
|
105
108
|
Provides-Extra: model-benchmark
|
|
106
109
|
Requires-Dist: pycocotools; extra == "model-benchmark"
|