88from packaging .requirements import Requirement
99
1010# Replace this import with your logger, or use logging.getLogger(__name__)
11- from boxmot .utils import logger as LOGGER
11+ from boxmot .utils import logger as LOGGER , ROOT
1212
1313REQUIREMENTS_FILE = Path ("requirements.txt" )
1414
@@ -21,8 +21,7 @@ class RequirementsChecker:
2121 - Check/install a list of requirement specifiers (e.g., ["yolox", "onnx>=1.15"])
2222 - Read and install from a requirements.txt
2323 - Install a uv dependency *group* (requires uv)
24- - Install a project *extra* (PEP 621 optional-dependencies) via uv or pip
25- - Falls back to pip if uv is not available
24+ - Install a project *extra* (PEP 621 optional-dependencies) via uv
2625 - Backward-compatible alias: `cmds` == `extra_args`
2726 """
2827
@@ -35,7 +34,6 @@ def __init__(
3534 """
3635 self .group = group
3736 self .requirements_file = requirements_file
38- self ._uv_available = shutil .which ("uv" ) is not None
3937
4038 # ---------- public API ----------
4139
@@ -84,25 +82,27 @@ def sync_extra(
8482 ):
8583 """
8684 Install a project *extra* (PEP 621 optional-dependencies).
87- - From source checkout + uv available: uv pip install ".[extra]"
88- - From source checkout w/o uv: python -m pip install ".[extra]"
89- - From PyPI install: python -m pip install "boxmot[extra]"
85+ - From source checkout + uv available: uv pip install -e ".[extra]"
86+ - From PyPI install: uv pip install "boxmot[extra]"
9087 """
9188 if not extra :
9289 raise ValueError ("Extra name must be provided (e.g. 'openvino', 'export')." )
9390 LOGGER .warning (f"Installing extra '{ extra } '..." )
9491
95- in_source = Path ("pyproject.toml" ).is_file ()
92+ # Check if we are running from a source install (editable)
93+ # ROOT is the package root. If pyproject.toml exists there, it's an editable install.
94+ root_pyproject = ROOT / "pyproject.toml"
95+
9696 cmd : list [str ]
9797
98- if in_source :
99- if self . _uv_available :
100- cmd = [ "uv" , "pip" , "install" , "--no-cache-dir" , f".[ { extra } ]" ]
101- else :
102- cmd = [sys . executable , "-m " , "pip" , "install" , f".[ { extra } ]" ]
98+ if root_pyproject . is_file () :
99+ # Editable install detected or running from source root
100+ # We use ROOT to point to the source directory
101+ target = f" { ROOT } [ { extra } ]"
102+ cmd = ["uv " , "pip" , "install" , "--no-cache-dir" , "-e" , target ]
103103 else :
104104 # Installed from PyPI: install the published dist extra
105- cmd = [sys . executable , "-m " , "pip" , "install" , f"boxmot[{ extra } ]" ]
105+ cmd = ["uv " , "pip" , "install" , f"boxmot[{ extra } ]" ]
106106
107107 if extra_args :
108108 cmd .extend (extra_args )
@@ -120,17 +120,14 @@ def _install_packages(
120120 self , packages : Sequence [str ], extra_args : Optional [Sequence [str ]] = None
121121 ):
122122 """
123- Install an explicit list of requirement specifiers with uv (if present) or pip .
123+ Install an explicit list of requirement specifiers with uv.
124124 """
125125 try :
126126 LOGGER .warning (
127127 f"\n Missing or mismatched packages: { ', ' .join (packages )} \n "
128128 "Attempting installation..."
129129 )
130- if self ._uv_available :
131- cmd = ["uv" , "pip" , "install" , "--no-cache-dir" ]
132- else :
133- cmd = ["pip" , "install" ]
130+ cmd = ["uv" , "pip" , "install" , "--no-cache-dir" ]
134131
135132 if extra_args :
136133 cmd += list (extra_args )
@@ -140,4 +137,4 @@ def _install_packages(
140137 LOGGER .info ("All missing packages were installed successfully." )
141138 except Exception as e :
142139 LOGGER .error (f"Failed to install packages: { e } " )
143- raise RuntimeError (f"Failed to install packages: { e } " )
140+ raise RuntimeError (f"Failed to install packages: { e } " )
0 commit comments