From f2ed2075712d389a29c0ad67950e89343a1b99f7 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 26 Sep 2023 02:25:35 +0200 Subject: [PATCH] `ultralytics 8.0.187` deprecate `ultralytics.yolo` usage (#5084) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Francisco Javier Gañán <95186237+javierganan99@users.noreply.github.com> --- docker/Dockerfile | 3 +- ultralytics/__init__.py | 2 +- ultralytics/cfg/__init__.py | 10 +++--- ultralytics/engine/results.py | 22 -------------- ultralytics/utils/checks.py | 47 ++++++++++++++++------------- ultralytics/yolo/__init__.py | 5 --- ultralytics/yolo/cfg/__init__.py | 10 ------ ultralytics/yolo/data/__init__.py | 17 ----------- ultralytics/yolo/engine/__init__.py | 10 ------ ultralytics/yolo/utils/__init__.py | 15 --------- ultralytics/yolo/v8/__init__.py | 10 ------ 11 files changed, 33 insertions(+), 118 deletions(-) delete mode 100644 ultralytics/yolo/__init__.py delete mode 100644 ultralytics/yolo/cfg/__init__.py delete mode 100644 ultralytics/yolo/data/__init__.py delete mode 100644 ultralytics/yolo/engine/__init__.py delete mode 100644 ultralytics/yolo/utils/__init__.py delete mode 100644 ultralytics/yolo/v8/__init__.py diff --git a/docker/Dockerfile b/docker/Dockerfile index f876a4b4c2..4feeb1f1f1 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -23,9 +23,8 @@ RUN apt upgrade --no-install-recommends -y openssl tar WORKDIR /usr/src/ultralytics # Copy contents -COPY . /usr/src/ultralytics # COPY . /usr/src/ultralytics # git permission issues inside container -# RUN git clone https://github.com/ultralytics/ultralytics -b main /usr/src/ultralytics +RUN git clone https://github.com/ultralytics/ultralytics -b main /usr/src/ultralytics ADD https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov8n.pt /usr/src/ultralytics/ # Install pip packages diff --git a/ultralytics/__init__.py b/ultralytics/__init__.py index fbc937c1e5..1312c2d76b 100644 --- a/ultralytics/__init__.py +++ b/ultralytics/__init__.py @@ -1,6 +1,6 @@ # Ultralytics YOLO 🚀, AGPL-3.0 license -__version__ = '8.0.186' +__version__ = '8.0.187' from ultralytics.models import RTDETR, SAM, YOLO from ultralytics.models.fastsam import FastSAM diff --git a/ultralytics/cfg/__init__.py b/ultralytics/cfg/__init__.py index eb252ed11a..83ee35a75c 100644 --- a/ultralytics/cfg/__init__.py +++ b/ultralytics/cfg/__init__.py @@ -1,7 +1,6 @@ # Ultralytics YOLO 🚀, AGPL-3.0 license import contextlib -import re import shutil import sys from pathlib import Path @@ -291,19 +290,20 @@ def handle_yolo_settings(args: List[str]) -> None: def parse_key_value_pair(pair): """Parse one 'key=value' pair and return key and value.""" - re.sub(r' *= *', '=', pair) # remove spaces around equals sign k, v = pair.split('=', 1) # split on first '=' sign + k, v = k.strip(), v.strip() # remove spaces assert v, f"missing '{k}' value" return k, smart_value(v) def smart_value(v): """Convert a string to an underlying type such as int, float, bool, etc.""" - if v.lower() == 'none': + v_lower = v.lower() + if v_lower == 'none': return None - elif v.lower() == 'true': + elif v_lower == 'true': return True - elif v.lower() == 'false': + elif v_lower == 'false': return False else: with contextlib.suppress(Exception): diff --git a/ultralytics/engine/results.py b/ultralytics/engine/results.py index 85c5406b89..a8cae4a663 100644 --- a/ultralytics/engine/results.py +++ b/ultralytics/engine/results.py @@ -430,19 +430,12 @@ class Boxes(BaseTensor): xywh[..., [1, 3]] /= self.orig_shape[0] return xywh - @property - def boxes(self): - """Return the raw bboxes tensor (deprecated).""" - LOGGER.warning("WARNING ⚠️ 'Boxes.boxes' is deprecated. Use 'Boxes.data' instead.") - return self.data - class Masks(BaseTensor): """ A class for storing and manipulating detection masks. Attributes: - segments (list): Deprecated property for segments (normalized). xy (list): A list of segments in pixel coordinates. xyn (list): A list of normalized segments. @@ -459,15 +452,6 @@ class Masks(BaseTensor): masks = masks[None, :] super().__init__(masks, orig_shape) - @property - @lru_cache(maxsize=1) - def segments(self): - """Return segments (normalized). Deprecated; use xyn property instead.""" - LOGGER.warning( - "WARNING ⚠️ 'Masks.segments' is deprecated. Use 'Masks.xyn' for segments (normalized) and 'Masks.xy' for segments (pixels) instead." - ) - return self.xyn - @property @lru_cache(maxsize=1) def xyn(self): @@ -484,12 +468,6 @@ class Masks(BaseTensor): ops.scale_coords(self.data.shape[1:], x, self.orig_shape, normalize=False) for x in ops.masks2segments(self.data)] - @property - def masks(self): - """Return the raw masks tensor. Deprecated; use data attribute instead.""" - LOGGER.warning("WARNING ⚠️ 'Masks.masks' is deprecated. Use 'Masks.data' instead.") - return self.data - class Keypoints(BaseTensor): """ diff --git a/ultralytics/utils/checks.py b/ultralytics/utils/checks.py index 6f96b9ab06..cbb90365c0 100644 --- a/ultralytics/utils/checks.py +++ b/ultralytics/utils/checks.py @@ -11,7 +11,7 @@ import shutil import subprocess import sys import time -from importlib.metadata import PackageNotFoundError, version +from importlib import metadata from pathlib import Path from typing import Optional @@ -26,19 +26,32 @@ from ultralytics.utils import (ASSETS, AUTOINSTALL, LINUX, LOGGER, ONLINE, ROOT, is_jupyter, is_kaggle, is_online, is_pip_package, url2file) -def parse_requirements(file_path=ROOT.parent / 'requirements.txt'): +def parse_requirements(file_path=ROOT.parent / 'requirements.txt', package=''): """ Parse a requirements.txt file, ignoring lines that start with '#' and any text after '#'. Args: file_path (Path): Path to the requirements.txt file. + package (str, optional): Python package to use instead of requirements.txt file, i.e. package='ultralytics'. Returns: (List[Dict[str, str]]): List of parsed requirements as dictionaries with `name` and `specifier` keys. + + Example: + ```python + from ultralytics.utils.checks import parse_requirements + + parse_requirements(package='ultralytics') + ``` """ + if package: + requires = [x for x in metadata.distribution(package).requires if 'extra == ' not in x] + else: + requires = Path(file_path).read_text().splitlines() + requirements = [] - for line in Path(file_path).read_text().splitlines(): + for line in requires: line = line.strip() if line and not line.startswith('#'): line = line.split('#')[0].strip() # ignore inline comments @@ -63,9 +76,8 @@ def parse_version(version='0.0.0') -> tuple: try: return tuple(map(int, re.findall(r'\d+', version)[:3])) # '2.0.1+cpu' -> (2, 0, 1) except Exception as e: - LOGGER.warning(f'WARNING ⚠️ failure for parse_version({version}), reverting to deprecated pkg_resources: {e}') - import pkg_resources - return pkg_resources.parse_version(version).release + LOGGER.warning(f'WARNING ⚠️ failure for parse_version({version}), returning (0, 0, 0): {e}') + return 0, 0, 0 def is_ascii(s) -> bool: @@ -172,8 +184,8 @@ def check_version(current: str = '0.0.0', elif not current[0].isdigit(): # current is package name rather than version string, i.e. current='ultralytics' try: name = current # assigned package name to 'name' arg - current = version(current) # get version string from package name - except PackageNotFoundError: + current = metadata.version(current) # get version string from package name + except metadata.PackageNotFoundError: if hard: raise ModuleNotFoundError(emojis(f'WARNING ⚠️ {current} package is required but not installed')) else: @@ -329,8 +341,8 @@ def check_requirements(requirements=ROOT.parent / 'requirements.txt', exclude=() match = re.match(r'([a-zA-Z0-9-_]+)([<>!=~]+.*)?', r_stripped) name, required = match[1], match[2].strip() if match[2] else '' try: - assert check_version(version(name), required) # exception if requirements not met - except (AssertionError, PackageNotFoundError): + assert check_version(metadata.version(name), required) # exception if requirements not met + except (AssertionError, metadata.PackageNotFoundError): pkgs.append(r) s = ' '.join(f'"{x}"' for x in pkgs) # console string @@ -503,14 +515,8 @@ def collect_system_info(): f"{'CPU':<20}{get_cpu_info()}\n" f"{'CUDA':<20}{torch.version.cuda if torch and torch.cuda.is_available() else None}\n") - if (ROOT.parent / 'requirements.txt').exists(): # git install - requirements = parse_requirements() - else: # pip install - from pkg_resources import get_distribution - requirements = get_distribution('ultralytics').requires() - - for r in requirements: - current = version(r.name) + for r in parse_requirements(package='ultralytics'): + current = metadata.version(r.name) is_met = '✅ ' if check_version(current, str(r.specifier)) else '❌ ' LOGGER.info(f'{r.name:<20}{is_met}{current}{r.specifier}') @@ -559,9 +565,8 @@ def check_amp(model): except ConnectionError: LOGGER.warning(f'{prefix}checks skipped ⚠️, offline and unable to download YOLOv8n. {warning_msg}') except (AttributeError, ModuleNotFoundError): - LOGGER.warning( - f'{prefix}checks skipped ⚠️. Unable to load YOLOv8n due to possible Ultralytics package modifications. {warning_msg}' - ) + LOGGER.warning(f'{prefix}checks skipped ⚠️. ' + f'Unable to load YOLOv8n due to possible Ultralytics package modifications. {warning_msg}') except AssertionError: LOGGER.warning(f'{prefix}checks failed ❌. Anomalies were detected with AMP on your system that may lead to ' f'NaN losses or zero-mAP results, so AMP will be disabled during training.') diff --git a/ultralytics/yolo/__init__.py b/ultralytics/yolo/__init__.py deleted file mode 100644 index d1fa558458..0000000000 --- a/ultralytics/yolo/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -# Ultralytics YOLO 🚀, AGPL-3.0 license - -from . import v8 - -__all__ = 'v8', # tuple or list diff --git a/ultralytics/yolo/cfg/__init__.py b/ultralytics/yolo/cfg/__init__.py deleted file mode 100644 index 5ea5519b6c..0000000000 --- a/ultralytics/yolo/cfg/__init__.py +++ /dev/null @@ -1,10 +0,0 @@ -import importlib -import sys - -from ultralytics.utils import LOGGER - -# Set modules in sys.modules under their old name -sys.modules['ultralytics.yolo.cfg'] = importlib.import_module('ultralytics.cfg') - -LOGGER.warning("WARNING ⚠️ 'ultralytics.yolo.cfg' is deprecated since '8.0.136' and will be removed in '8.1.0'. " - "Please use 'ultralytics.cfg' instead.") diff --git a/ultralytics/yolo/data/__init__.py b/ultralytics/yolo/data/__init__.py deleted file mode 100644 index f68391ef03..0000000000 --- a/ultralytics/yolo/data/__init__.py +++ /dev/null @@ -1,17 +0,0 @@ -import importlib -import sys - -from ultralytics.utils import LOGGER - -# Set modules in sys.modules under their old name -sys.modules['ultralytics.yolo.data'] = importlib.import_module('ultralytics.data') -# This is for updating old cls models, or the way in following warning won't work. -sys.modules['ultralytics.yolo.data.augment'] = importlib.import_module('ultralytics.data.augment') - -DATA_WARNING = """WARNING ⚠️ 'ultralytics.yolo.data' is deprecated since '8.0.136' and will be removed in '8.1.0'. Please use 'ultralytics.data' instead. -Note this warning may be related to loading older models. You can update your model to current structure with: - import torch - ckpt = torch.load("model.pt") # applies to both official and custom models - torch.save(ckpt, "updated-model.pt") -""" -LOGGER.warning(DATA_WARNING) diff --git a/ultralytics/yolo/engine/__init__.py b/ultralytics/yolo/engine/__init__.py deleted file mode 100644 index 794efcd0c3..0000000000 --- a/ultralytics/yolo/engine/__init__.py +++ /dev/null @@ -1,10 +0,0 @@ -import importlib -import sys - -from ultralytics.utils import LOGGER - -# Set modules in sys.modules under their old name -sys.modules['ultralytics.yolo.engine'] = importlib.import_module('ultralytics.engine') - -LOGGER.warning("WARNING ⚠️ 'ultralytics.yolo.engine' is deprecated since '8.0.136' and will be removed in '8.1.0'. " - "Please use 'ultralytics.engine' instead.") diff --git a/ultralytics/yolo/utils/__init__.py b/ultralytics/yolo/utils/__init__.py deleted file mode 100644 index 71557b0a74..0000000000 --- a/ultralytics/yolo/utils/__init__.py +++ /dev/null @@ -1,15 +0,0 @@ -import importlib -import sys - -from ultralytics.utils import LOGGER - -# Set modules in sys.modules under their old name -sys.modules['ultralytics.yolo.utils'] = importlib.import_module('ultralytics.utils') - -UTILS_WARNING = """WARNING ⚠️ 'ultralytics.yolo.utils' is deprecated since '8.0.136' and will be removed in '8.1.0'. Please use 'ultralytics.utils' instead. -Note this warning may be related to loading older models. You can update your model to current structure with: - import torch - ckpt = torch.load("model.pt") # applies to both official and custom models - torch.save(ckpt, "updated-model.pt") -""" -LOGGER.warning(UTILS_WARNING) diff --git a/ultralytics/yolo/v8/__init__.py b/ultralytics/yolo/v8/__init__.py deleted file mode 100644 index 51adf814cd..0000000000 --- a/ultralytics/yolo/v8/__init__.py +++ /dev/null @@ -1,10 +0,0 @@ -import importlib -import sys - -from ultralytics.utils import LOGGER - -# Set modules in sys.modules under their old name -sys.modules['ultralytics.yolo.v8'] = importlib.import_module('ultralytics.models.yolo') - -LOGGER.warning("WARNING ⚠️ 'ultralytics.yolo.v8' is deprecated since '8.0.136' and will be removed in '8.1.0'. " - "Please use 'ultralytics.models.yolo' instead.")