• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

georgia-tech-db / eva / #754

04 Sep 2023 09:54PM UTC coverage: 74.807% (-5.5%) from 80.336%
#754

push

circle-ci

jiashenC
update case

8727 of 11666 relevant lines covered (74.81%)

0.75 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

83.06
/evadb/utils/generic_utils.py
1
# coding=utf-8
2
# Copyright 2018-2023 EvaDB
3
#
4
# Licensed under the Apache License, Version 2.0 (the "License");
5
# you may not use this file except in compliance with the License.
6
# You may obtain a copy of the License at
7
#
8
#     http://www.apache.org/licenses/LICENSE-2.0
9
#
10
# Unless required by applicable law or agreed to in writing, software
11
# distributed under the License is distributed on an "AS IS" BASIS,
12
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
# See the License for the specific language governing permissions and
14
# limitations under the License.
15
import hashlib
1✔
16
import importlib
1✔
17
import inspect
1✔
18
import os
1✔
19
import pickle
1✔
20
import shutil
1✔
21
import sys
1✔
22
import uuid
1✔
23
from pathlib import Path
1✔
24
from typing import List
1✔
25
from urllib.parse import urlparse
1✔
26

27
from aenum import AutoEnum, unique
1✔
28

29
from evadb.configuration.constants import EvaDB_INSTALLATION_DIR
1✔
30
from evadb.utils.logging_manager import logger
1✔
31

32

33
def validate_kwargs(
1✔
34
    kwargs,
35
    allowed_keys: List[str],
36
    required_keys: List[str],
37
    error_message="Keyword argument not understood:",
38
):
39
    """Checks that all keyword arguments are in the set of allowed keys."""
40
    if required_keys is None:
×
41
        required_keys = allowed_keys
×
42
    for kwarg in kwargs:
×
43
        if kwarg not in allowed_keys:
×
44
            raise TypeError(error_message, kwarg)
45

46
    missing_keys = [key for key in required_keys if key not in kwargs]
×
47
    assert len(missing_keys) == 0, f"Missing required keys, {missing_keys}"
×
48

49

50
def str_to_class(class_path: str):
1✔
51
    """
52
    Convert string representation of a class path to Class
53

54
    Arguments:
55
        class_path (str): absolute path of import
56

57
    Returns:
58
        type: A Class for given path
59
    """
60
    assert class_path is not None, "Class path is not found"
×
61
    module_path, class_name = class_path.rsplit(".", 1)
×
62
    module = importlib.import_module(module_path)
×
63
    return getattr(module, class_name)
×
64

65

66
def load_function_class_from_file(filepath, classname=None):
1✔
67
    """
68
    Load a class from a Python file. If the classname is not specified, the function will check if there is only one class in the file and load that. If there are multiple classes, it will raise an error.
69

70
    Args:
71
        filepath (str): The path to the Python file.
72
        classname (str, optional): The name of the class to load. If not specified, the function will try to load a class with the same name as the file. Defaults to None.
73

74
    Returns:
75
        The class instance.
76

77
    Raises:
78
        RuntimeError: If the class name is not found or there is more than one class in the file.
79
    """
80
    try:
1✔
81
        abs_path = Path(filepath).resolve()
1✔
82
        spec = importlib.util.spec_from_file_location(abs_path.stem, abs_path)
1✔
83
        module = importlib.util.module_from_spec(spec)
1✔
84
        spec.loader.exec_module(module)
1✔
85
    except Exception as e:
86
        err_msg = f"Couldn't load function from {filepath} : {str(e)}. This might be due to a missing Python package, or because the function implementation file does not exist, or it is not a valid Python file."
87
        raise RuntimeError(err_msg)
88

89
    # Try to load the specified class by name
90
    if classname and hasattr(module, classname):
1✔
91
        return getattr(module, classname)
1✔
92

93
    # If class name not specified, check if there is only one class in the file
94
    classes = [
×
95
        obj
96
        for _, obj in inspect.getmembers(module, inspect.isclass)
97
        if obj.__module__ == module.__name__
98
    ]
99
    if len(classes) != 1:
×
100
        raise RuntimeError(
101
            f"{filepath} contains {len(classes)} classes, please specify the correct class to load by naming the function with the same name in the CREATE query."
102
        )
103
    return classes[0]
×
104

105

106
def is_gpu_available() -> bool:
1✔
107
    """
108
    Checks if the system has GPUS available to execute tasks
109
    Returns:
110
        [bool] True if system has GPUs, else False
111
    """
112
    try:
1✔
113
        import torch
1✔
114

115
        return torch.cuda.is_available()
1✔
116
    except ImportError:
117
        return False
118

119

120
def get_gpu_count() -> int:
1✔
121
    """
122
    Check number of GPUs through Torch.
123
    """
124
    try:
1✔
125
        import torch
1✔
126

127
        return torch.cuda.device_count()
1✔
128
    except ImportError:
129
        return 0
130

131

132
def generate_file_path(dataset_location: str, name: str = "") -> Path:
1✔
133
    """Generates a arbitrary file_path(md5 hash) based on the a random salt
134
    and name
135

136
    Arguments:
137
        dataset_location(str): parent directory where a file needs to be created
138
        name (str): Input file_name.
139

140
    Returns:
141
        Path: pathlib.Path object
142

143
    """
144
    dataset_location = Path(dataset_location)
1✔
145
    dataset_location.mkdir(parents=True, exist_ok=True)
1✔
146

147
    salt = uuid.uuid4().hex
1✔
148
    file_name = hashlib.md5(salt.encode() + name.encode()).hexdigest()
1✔
149
    path = dataset_location / file_name
1✔
150
    return path.resolve()
1✔
151

152

153
def get_size(obj, seen=None):
1✔
154
    """Recursively finds size of objects
155
    https://goshippo.com/blog/measure-real-size-any-python-object/
156
    """
157
    size = sys.getsizeof(obj)
1✔
158
    if seen is None:
1✔
159
        seen = set()
1✔
160
    obj_id = id(obj)
1✔
161
    if obj_id in seen:
1✔
162
        return 0
1✔
163
    # Important mark as seen *before* entering recursion to gracefully handle
164
    # self-referential objects
165
    seen.add(obj_id)
1✔
166
    if isinstance(obj, dict):
1✔
167
        size += sum([get_size(v, seen) for v in obj.values()])
1✔
168
        size += sum([get_size(k, seen) for k in obj.keys()])
1✔
169
    elif hasattr(obj, "__dict__"):
1✔
170
        size += get_size(obj.__dict__, seen)
1✔
171
    elif hasattr(obj, "__iter__") and not isinstance(obj, (str, bytes, bytearray)):
1✔
172
        size += sum([get_size(i, seen) for i in obj])
1✔
173
    return size
1✔
174

175

176
def get_str_hash(s: str) -> str:
1✔
177
    return hashlib.md5(s.encode("utf-8")).hexdigest()
×
178

179

180
def get_file_checksum(fname: str) -> str:
1✔
181
    """Compute checksum of the file contents
182

183
    Args:
184
        fname (str): file path
185

186
    Returns:
187
        str: hash string representing the checksum of the file content
188
    """
189
    hash_md5 = hashlib.md5()
1✔
190
    with open(fname, "rb") as f:
1✔
191
        for chunk in iter(lambda: f.read(4096), b""):
1✔
192
            hash_md5.update(chunk)
1✔
193
    return hash_md5.hexdigest()
1✔
194

195

196
def parse_config_yml():
1✔
197
    """
198
    Parses the 'evadb.yml' file and returns the config object.
199
    """
200
    import yaml
1✔
201

202
    f = open(Path(EvaDB_INSTALLATION_DIR) / "evadb.yml", "r+")
1✔
203
    config_obj = yaml.load(f, Loader=yaml.FullLoader)
1✔
204
    return config_obj
1✔
205

206

207
def is_postgres_uri(db_uri):
1✔
208
    """
209
    Determines if the db_uri is that of postgres.
210

211
    Args:
212
        db_uri (str) : db_uri to parse
213
    """
214
    parsed_uri = urlparse(db_uri)
1✔
215
    return parsed_uri.scheme == "postgres" or parsed_uri.scheme == "postgresql"
1✔
216

217

218
class PickleSerializer(object):
1✔
219
    @classmethod
1✔
220
    def serialize(cls, data):
1✔
221
        return pickle.dumps(data, protocol=pickle.HIGHEST_PROTOCOL)
1✔
222

223
    @classmethod
1✔
224
    def deserialize(cls, data):
1✔
225
        return pickle.loads(data)
1✔
226

227

228
@unique
1✔
229
class EvaDBEnum(AutoEnum):
1✔
230
    def __str__(self):
1✔
231
        return self.name
1✔
232

233

234
def remove_directory_contents(dir_path):
1✔
235
    if os.path.exists(dir_path):
1✔
236
        for filename in os.listdir(dir_path):
1✔
237
            file_path = os.path.join(dir_path, filename)
1✔
238
            try:
1✔
239
                if os.path.isfile(file_path) or os.path.islink(file_path):
1✔
240
                    os.unlink(file_path)
1✔
241
                elif os.path.isdir(file_path):
1✔
242
                    shutil.rmtree(file_path)
1✔
243
            except Exception as e:
244
                logger.warning(f"Failed to delete {file_path}. Reason: {str(e)}")
245

246

247
def find_nearest_word(word, word_list):
1✔
248
    from thefuzz import process
1✔
249

250
    nearest_word_and_score = process.extractOne(word, word_list)
1✔
251
    nearest_word = nearest_word_and_score[0]
1✔
252

253
    return nearest_word
1✔
254

255

256
##############################
257
## TRY TO IMPORT PACKAGES
258
##############################
259

260

261
def try_to_import_ray():
1✔
262
    try:
1✔
263
        import ray  # noqa: F401
1✔
264
        from ray.util.queue import Queue  # noqa: F401
×
265
    except ImportError:
266
        raise ValueError(
267
            """Could not import ray python package.
268
                Please install it with `pip install ray`."""
269
        )
270

271

272
def is_ray_available() -> bool:
1✔
273
    try:
1✔
274
        try_to_import_ray()
1✔
275
        return True
×
276
    except ValueError:  # noqa: E722
277
        return False
278

279

280
def is_ray_enabled_and_installed(ray_enabled: bool) -> bool:
1✔
281
    ray_installed = is_ray_available()
1✔
282
    return ray_enabled and ray_installed
1✔
283

284

285
##############################
286
## MODEL TRAIN FRAMEWORK
287
##############################
288

289

290
def try_to_import_ludwig():
1✔
291
    try:
1✔
292
        import ludwig  # noqa: F401
1✔
293
        from ludwig.automl import auto_train  # noqa: F401
×
294
    except ImportError:
295
        raise ValueError(
296
            """Could not import ludwig.
297
                Please install it with `pip install ludwig[full]`."""
298
        )
299

300

301
def is_ludwig_available() -> bool:
1✔
302
    try:
1✔
303
        try_to_import_ludwig()
1✔
304
        return True
×
305
    except ValueError:  # noqa: E722
306
        return False
307

308

309
##############################
310
## VISION
311
##############################
312

313

314
def try_to_import_pillow():
1✔
315
    try:
1✔
316
        import PIL  # noqa: F401
1✔
317
    except ImportError:
318
        raise ValueError(
319
            """Could not import pillow python package.
320
                Please install it with `pip install pillow`."""
321
        )
322

323

324
def try_to_import_torch():
1✔
325
    try:
1✔
326
        import torch  # noqa: F401
1✔
327
    except ImportError:
328
        raise ValueError(
329
            """Could not import torch python package.
330
                Please install them with `pip install torch`."""
331
        )
332

333

334
def try_to_import_torchvision():
1✔
335
    try:
1✔
336
        import torchvision  # noqa: F401
1✔
337
    except ImportError:
338
        raise ValueError(
339
            """Could not import torchvision python package.
340
                Please install them with `pip install torchvision`."""
341
        )
342

343

344
def try_to_import_cv2():
1✔
345
    try:
1✔
346
        import cv2  # noqa: F401
1✔
347
    except ImportError:
348
        raise ValueError(
349
            """Could not import cv2 python package.
350
                Please install it with `pip install opencv-python`."""
351
        )
352

353

354
def try_to_import_timm():
1✔
355
    try:
×
356
        import timm  # noqa: F401
×
357
    except ImportError:
358
        raise ValueError(
359
            """Could not import timm python package.
360
                Please install them with `pip install timm`."""
361
        )
362

363

364
def try_to_import_kornia():
1✔
365
    try:
1✔
366
        import kornia  # noqa: F401
1✔
367
    except ImportError:
368
        raise ValueError(
369
            """Could not import kornia python package.
370
                Please install it with `pip install kornia`."""
371
        )
372

373

374
def try_to_import_decord():
1✔
375
    try:
1✔
376
        import decord  # noqa: F401
1✔
377
    except ImportError:
378
        raise ValueError(
379
            """Could not import decord python package.
380
                Please install it with `pip install eva-decord`."""
381
        )
382

383

384
def try_to_import_ultralytics():
1✔
385
    try:
1✔
386
        import ultralytics  # noqa: F401
1✔
387
    except ImportError:
388
        raise ValueError(
389
            """Could not import ultralytics python package.
390
                Please install it with `pip install ultralytics`."""
391
        )
392

393

394
def try_to_import_norfair():
1✔
395
    try:
1✔
396
        import norfair  # noqa: F401
1✔
397
    except ImportError:
398
        raise ValueError(
399
            """Could not import norfair python package.
400
                Please install it with `pip install norfair`."""
401
        )
402

403

404
##############################
405
## DOCUMENT
406
##############################
407

408

409
def try_to_import_transformers():
1✔
410
    try:
×
411
        import transformers  # noqa: F401
×
412
    except ImportError:
413
        raise ValueError(
414
            """Could not import transformers python package.
415
                Please install it with `pip install transformers`."""
416
        )
417

418

419
def try_to_import_facenet_pytorch():
1✔
420
    try:
1✔
421
        import facenet_pytorch  # noqa: F401
1✔
422
    except ImportError:
423
        raise ValueError(
424
            """Could not import facenet_pytorch python package.
425
                Please install it with `pip install facenet-pytorch`."""
426
        )
427

428

429
def try_to_import_openai():
1✔
430
    try:
×
431
        import openai  # noqa: F401
×
432
    except ImportError:
433
        raise ValueError(
434
            """Could not import openai python package.
435
                Please install them with `pip install openai`."""
436
        )
437

438

439
def try_to_import_langchain():
1✔
440
    try:
×
441
        import langchain  # noqa: F401
×
442
    except ImportError:
443
        raise ValueError(
444
            """Could not import langchain package.
445
                Please install it with `pip install langchain`."""
446
        )
447

448

449
##############################
450
## VECTOR STORES
451
##############################
452

453

454
def try_to_import_faiss():
1✔
455
    try:
1✔
456
        import faiss  # noqa: F401
1✔
457
    except ImportError:
458
        raise ValueError(
459
            """Could not import faiss python package.
460
                Please install it with `pip install faiss-cpu` or `pip install faiss-gpu`."""
461
        )
462

463

464
def try_to_import_qdrant_client():
1✔
465
    try:
1✔
466
        import qdrant_client  # noqa: F401
1✔
467
    except ImportError:
468
        raise ValueError(
469
            """Could not import qdrant_client python package.
470
                Please install it with `pip install qdrant_client`."""
471
        )
472

473

474
def is_qdrant_available() -> bool:
1✔
475
    try:
1✔
476
        try_to_import_qdrant_client()
1✔
477
        return True
×
478
    except ValueError:  # noqa: E722
479
        return False
480

481

482
##############################
483
## UTILS
484
##############################
485

486

487
def try_to_import_moto():
1✔
488
    try:
×
489
        import boto3  # noqa: F401
×
490
    except ImportError:
491
        raise ValueError(
492
            """Could not import boto3 python package.
493
                Please install it with `pip install moto[s3]`."""
494
        )
495

496

497
def try_to_import_fitz():
1✔
498
    try:
×
499
        import fitz  # noqa: F401
×
500
    except ImportError:
501
        raise ValueError(
502
            """Could not import fitz python package.
503
                Please install it with `pip install pymupdfs`."""
504
        )
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc