-
Notifications
You must be signed in to change notification settings - Fork 10
add uv
backend
#172
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
add uv
backend
#172
Changes from all commits
7b66870
bc35f59
ab0e8e1
c276e31
273c11d
f37f9e5
7854098
4bef3e8
de2bc7c
0e44be1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -65,6 +65,9 @@ dev = [ | |
"PyQt6", | ||
"pre-commit", | ||
] | ||
uv = [ | ||
"uv", | ||
] | ||
|
||
testing = [ | ||
"coverage", | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,6 +19,7 @@ | |
NapariCondaInstallerTool, | ||
NapariInstallerQueue, | ||
NapariPipInstallerTool, | ||
NapariUvInstallerTool, | ||
) | ||
|
||
if TYPE_CHECKING: | ||
|
@@ -60,21 +61,30 @@ def environment(self, env=None): | |
return QProcessEnvironment.systemEnvironment() | ||
|
||
|
||
@pytest.mark.parametrize( | ||
'tool', [NapariPipInstallerTool, NapariUvInstallerTool] | ||
) | ||
def test_pip_installer_tasks( | ||
qtbot, tmp_virtualenv: 'Session', monkeypatch, caplog | ||
qtbot, tool, tmp_virtualenv: 'Session', monkeypatch, caplog | ||
): | ||
caplog.set_level(logging.DEBUG, logger=bqpi.__name__) | ||
installer = NapariInstallerQueue() | ||
monkeypatch.setattr( | ||
NapariPipInstallerTool, | ||
'executable', | ||
lambda *a: tmp_virtualenv.creator.exe, | ||
NapariInstallerQueue, 'PYPI_INSTALLER_TOOL_CLASS', tool | ||
) | ||
installer = NapariInstallerQueue() | ||
monkeypatch.setattr( | ||
NapariPipInstallerTool, | ||
'origins', | ||
('https://pypi.org/simple',), | ||
tool, | ||
'executable' | ||
if tool == NapariPipInstallerTool | ||
else '_python_executable', | ||
lambda *a: tmp_virtualenv.creator.exe, | ||
) | ||
if tool == NapariPipInstallerTool: | ||
monkeypatch.setattr( | ||
NapariPipInstallerTool, | ||
'origins', | ||
('https://pypi.org/simple',), | ||
) | ||
with qtbot.waitSignal(installer.allFinished, timeout=30_000): | ||
installer.install( | ||
tool=InstallerTools.PYPI, | ||
|
@@ -140,13 +150,23 @@ def test_pip_installer_tasks( | |
) | ||
|
||
|
||
def test_pip_installer_invalid_action(tmp_virtualenv: 'Session', monkeypatch): | ||
installer = NapariInstallerQueue() | ||
@pytest.mark.parametrize( | ||
'tool', [NapariPipInstallerTool, NapariUvInstallerTool] | ||
) | ||
def test_pip_installer_invalid_action( | ||
tool, tmp_virtualenv: 'Session', monkeypatch | ||
): | ||
monkeypatch.setattr( | ||
NapariInstallerQueue, 'PYPI_INSTALLER_TOOL_CLASS', tool | ||
) | ||
monkeypatch.setattr( | ||
NapariPipInstallerTool, | ||
'executable', | ||
tool, | ||
'executable' | ||
if tool == NapariPipInstallerTool | ||
else '_python_executable', | ||
lambda *a: tmp_virtualenv.creator.exe, | ||
) | ||
installer = NapariInstallerQueue() | ||
invalid_action = 'Invalid Action' | ||
item = installer._build_queue_item( | ||
tool=InstallerTools.PYPI, | ||
|
@@ -162,11 +182,21 @@ def test_pip_installer_invalid_action(tmp_virtualenv: 'Session', monkeypatch): | |
installer._queue_item(item) | ||
|
||
|
||
def test_installer_failures(qtbot, tmp_virtualenv: 'Session', monkeypatch): | ||
@pytest.mark.parametrize( | ||
'tool', [NapariPipInstallerTool, NapariUvInstallerTool] | ||
) | ||
def test_installer_failures( | ||
tool, qtbot, tmp_virtualenv: 'Session', monkeypatch | ||
): | ||
monkeypatch.setattr( | ||
NapariInstallerQueue, 'PYPI_INSTALLER_TOOL_CLASS', tool | ||
) | ||
installer = NapariInstallerQueue() | ||
monkeypatch.setattr( | ||
NapariPipInstallerTool, | ||
'executable', | ||
tool, | ||
'executable' | ||
if tool == NapariPipInstallerTool | ||
else '_python_executable', | ||
lambda *a: tmp_virtualenv.creator.exe, | ||
) | ||
|
||
|
@@ -206,7 +236,13 @@ def test_installer_failures(qtbot, tmp_virtualenv: 'Session', monkeypatch): | |
) | ||
|
||
|
||
def test_cancel_incorrect_job_id(qtbot, tmp_virtualenv: 'Session'): | ||
@pytest.mark.parametrize( | ||
'tool', [NapariPipInstallerTool, NapariUvInstallerTool] | ||
) | ||
def test_cancel_incorrect_job_id(tool, qtbot, monkeypatch): | ||
monkeypatch.setattr( | ||
NapariInstallerQueue, 'PYPI_INSTALLER_TOOL_CLASS', tool | ||
) | ||
installer = NapariInstallerQueue() | ||
with qtbot.waitSignal(installer.allFinished, timeout=30_000): | ||
job_id = installer.install( | ||
|
@@ -306,11 +342,19 @@ def test_conda_installer(qtbot, caplog, monkeypatch, tmp_conda_env: Path): | |
assert not installer.hasJobs() | ||
|
||
|
||
def test_installer_error(qtbot, tmp_virtualenv: 'Session', monkeypatch): | ||
@pytest.mark.parametrize( | ||
'tool', [NapariPipInstallerTool, NapariUvInstallerTool] | ||
) | ||
def test_installer_error(qtbot, tool, monkeypatch): | ||
monkeypatch.setattr( | ||
NapariInstallerQueue, 'PYPI_INSTALLER_TOOL_CLASS', tool | ||
) | ||
installer = NapariInstallerQueue() | ||
monkeypatch.setattr( | ||
NapariPipInstallerTool, | ||
'executable', | ||
tool, | ||
'executable' | ||
if tool == NapariPipInstallerTool | ||
else '_python_executable', | ||
lambda *a: 'not-a-real-executable', | ||
Comment on lines
+356
to
358
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why we can not unify this? |
||
) | ||
with qtbot.waitSignal(installer.allFinished, timeout=600_000): | ||
|
@@ -358,11 +402,13 @@ def test_constraints_are_in_sync(): | |
def test_executables(): | ||
assert NapariCondaInstallerTool.executable() | ||
assert NapariPipInstallerTool.executable() | ||
assert NapariUvInstallerTool.executable() | ||
|
||
|
||
def test_available(): | ||
assert str(NapariCondaInstallerTool.available()) | ||
assert NapariPipInstallerTool.available() | ||
assert NapariUvInstallerTool.available() | ||
|
||
|
||
def test_unrecognized_tool(): | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -23,6 +23,7 @@ | |
CondaInstallerTool, | ||
InstallerQueue, | ||
PipInstallerTool, | ||
UvInstallerTool, | ||
) | ||
|
||
|
||
|
@@ -62,6 +63,28 @@ def _constraints_file(cls) -> str: | |
return f.name | ||
|
||
|
||
class NapariUvInstallerTool(UvInstallerTool): | ||
@staticmethod | ||
def constraints() -> list[str]: | ||
""" | ||
Version constraints to limit unwanted changes in installation. | ||
""" | ||
return [f'napari=={_napari_version}'] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hm. So the only risk for now is if the environment has Numba installed and the plugin needs a NumPy newer than the installed one. But it is a problem as well for pip. |
||
|
||
@classmethod | ||
@lru_cache(maxsize=0) | ||
def _constraints_file(cls) -> str: | ||
with NamedTemporaryFile( | ||
'w', suffix='-napari-constraints.txt', delete=False | ||
) as f: | ||
f.write('\n'.join(cls.constraints())) | ||
atexit.register(os.unlink, f.name) | ||
return f.name | ||
|
||
def _python_executable(self) -> str: | ||
return str(_get_python_exe()) | ||
|
||
|
||
class NapariCondaInstallerTool(CondaInstallerTool): | ||
@staticmethod | ||
def constraints() -> list[str]: | ||
|
@@ -80,6 +103,10 @@ def constraints() -> list[str]: | |
|
||
|
||
class NapariInstallerQueue(InstallerQueue): | ||
PYPI_INSTALLER_TOOL_CLASS = NapariPipInstallerTool | ||
PYPI_INSTALLER_TOOL_CLASS = ( | ||
NapariUvInstallerTool | ||
if NapariUvInstallerTool.available() | ||
else NapariPipInstallerTool | ||
) | ||
CONDA_INSTALLER_TOOL_CLASS = NapariCondaInstallerTool | ||
BASE_PACKAGE_NAME = 'napari' |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -35,7 +35,7 @@ setenv = | |
|
||
deps = | ||
napari_repo: git+https://github.com/napari/napari.git | ||
extras = testing | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As there is no skip for uv tests I prefer to add uv to testing extras. Using |
||
extras = testing,uv | ||
commands = coverage run --parallel-mode -m pytest -v --color=yes | ||
|
||
# Conditional PIP dependencies based on environment variables | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this
if
is needed? Why we cannot uify this?