diff --git a/tests/test_engine.py b/tests/test_engine.py index bd528a8d833..0a151940983 100644 --- a/tests/test_engine.py +++ b/tests/test_engine.py @@ -1,5 +1,7 @@ # Ultralytics YOLO 🚀, AGPL-3.0 license +import sys +from unittest import mock from ultralytics import YOLO from ultralytics.cfg import get_cfg from ultralytics.engine.exporter import Exporter @@ -49,8 +51,10 @@ def test_detect(): pred = detect.DetectionPredictor(overrides={"imgsz": [64, 64]}) pred.add_callback("on_predict_start", test_func) assert test_func in pred.callbacks["on_predict_start"], "callback test failed" - result = pred(source=ASSETS, model=f"{MODEL}.pt") - assert len(result), "predictor test failed" + # Confirm there is no issue with sys.argv being empty. + with mock.patch.object(sys, 'argv', []): + result = pred(source=ASSETS, model=f"{MODEL}.pt") + assert len(result), "predictor test failed" overrides["resume"] = trainer.last trainer = detect.DetectionTrainer(overrides=overrides) diff --git a/ultralytics/__init__.py b/ultralytics/__init__.py index 0675f7191ea..9ae987df513 100644 --- a/ultralytics/__init__.py +++ b/ultralytics/__init__.py @@ -1,6 +1,6 @@ # Ultralytics YOLO 🚀, AGPL-3.0 license -__version__ = "8.1.36" +__version__ = "8.1.37" from ultralytics.data.explorer.explorer import Explorer from ultralytics.models import RTDETR, SAM, YOLO, YOLOWorld diff --git a/ultralytics/cfg/__init__.py b/ultralytics/cfg/__init__.py index 4dab8102dc2..dbf3a44736c 100644 --- a/ultralytics/cfg/__init__.py +++ b/ultralytics/cfg/__init__.py @@ -54,8 +54,9 @@ "obb": "metrics/mAP50-95(B)", } +ARGV = sys.argv or ["", ""] # sometimes sys.argv = [] CLI_HELP_MSG = f""" - Arguments received: {str(['yolo'] + sys.argv[1:])}. Ultralytics 'yolo' commands use the following syntax: + Arguments received: {str(['yolo'] + ARGV[1:])}. Ultralytics 'yolo' commands use the following syntax: yolo TASK MODE ARGS @@ -452,7 +453,7 @@ def entrypoint(debug=""): It uses the package's default cfg and initializes it using the passed overrides. Then it calls the CLI function with the composed cfg """ - args = (debug.split(" ") if debug else sys.argv)[1:] + args = (debug.split(" ") if debug else ARGV)[1:] if not args: # no arguments passed LOGGER.info(CLI_HELP_MSG) return diff --git a/ultralytics/engine/model.py b/ultralytics/engine/model.py index ef5c93c01cf..b056c09e4c5 100644 --- a/ultralytics/engine/model.py +++ b/ultralytics/engine/model.py @@ -1,7 +1,6 @@ # Ultralytics YOLO 🚀, AGPL-3.0 license import inspect -import sys from pathlib import Path from typing import Union @@ -11,7 +10,18 @@ from ultralytics.cfg import TASK2DATA, get_cfg, get_save_dir from ultralytics.hub.utils import HUB_WEB_ROOT from ultralytics.nn.tasks import attempt_load_one_weight, guess_model_task, nn, yaml_model_load -from ultralytics.utils import ASSETS, DEFAULT_CFG_DICT, LOGGER, RANK, SETTINGS, callbacks, checks, emojis, yaml_load +from ultralytics.utils import ( + ARGV, + ASSETS, + DEFAULT_CFG_DICT, + LOGGER, + RANK, + SETTINGS, + callbacks, + checks, + emojis, + yaml_load, +) class Model(nn.Module): @@ -421,8 +431,8 @@ def predict( source = ASSETS LOGGER.warning(f"WARNING ⚠️ 'source' is missing. Using 'source={source}'.") - is_cli = (sys.argv[0].endswith("yolo") or sys.argv[0].endswith("ultralytics")) and any( - x in sys.argv for x in ("predict", "track", "mode=predict", "mode=track") + is_cli = (ARGV[0].endswith("yolo") or ARGV[0].endswith("ultralytics")) and any( + x in ARGV for x in ("predict", "track", "mode=predict", "mode=track") ) custom = {"conf": 0.25, "batch": 1, "save": is_cli, "mode": "predict"} # method defaults diff --git a/ultralytics/hub/utils.py b/ultralytics/hub/utils.py index 5c0007624a0..1f3de94c3ce 100644 --- a/ultralytics/hub/utils.py +++ b/ultralytics/hub/utils.py @@ -3,7 +3,6 @@ import os import platform import random -import sys import threading import time from pathlib import Path @@ -11,6 +10,7 @@ import requests from ultralytics.utils import ( + ARGV, ENVIRONMENT, LOGGER, ONLINE, @@ -188,7 +188,7 @@ def __init__(self): self.rate_limit = 60.0 # rate limit (seconds) self.t = 0.0 # rate limit timer (seconds) self.metadata = { - "cli": Path(sys.argv[0]).name == "yolo", + "cli": Path(ARGV[0]).name == "yolo", "install": "git" if is_git_dir() else "pip" if is_pip_package() else "other", "python": ".".join(platform.python_version_tuple()[:2]), # i.e. 3.10 "version": __version__, diff --git a/ultralytics/utils/__init__.py b/ultralytics/utils/__init__.py index befa081f888..fdc2b95b8c9 100644 --- a/ultralytics/utils/__init__.py +++ b/ultralytics/utils/__init__.py @@ -30,6 +30,7 @@ LOCAL_RANK = int(os.getenv("LOCAL_RANK", -1)) # https://pytorch.org/docs/stable/elastic/run.html # Other Constants +ARGV = sys.argv or ["", ""] # sometimes sys.argv = [] FILE = Path(__file__).resolve() ROOT = FILE.parents[1] # YOLO ASSETS = ROOT / "assets" # default images @@ -522,7 +523,7 @@ def is_pytest_running(): Returns: (bool): True if pytest is running, False otherwise. """ - return ("PYTEST_CURRENT_TEST" in os.environ) or ("pytest" in sys.modules) or ("pytest" in Path(sys.argv[0]).stem) + return ("PYTEST_CURRENT_TEST" in os.environ) or ("pytest" in sys.modules) or ("pytest" in Path(ARGV[0]).stem) def is_github_action_running() -> bool: @@ -869,8 +870,8 @@ def before_send(event, hint): return None # do not send event event["tags"] = { - "sys_argv": sys.argv[0], - "sys_argv_name": Path(sys.argv[0]).name, + "sys_argv": ARGV[0], + "sys_argv_name": Path(ARGV[0]).name, "install": "git" if is_git_dir() else "pip" if is_pip_package() else "other", "os": ENVIRONMENT, } @@ -879,7 +880,7 @@ def before_send(event, hint): if ( SETTINGS["sync"] and RANK in (-1, 0) - and Path(sys.argv[0]).name == "yolo" + and Path(ARGV[0]).name == "yolo" and not TESTS_RUNNING and ONLINE and is_pip_package()