-
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
add uv backend
#172
Changes from 8 commits
7b66870
bc35f59
ab0e8e1
c276e31
273c11d
f37f9e5
7854098
4bef3e8
de2bc7c
0e44be1
7dc03ba
cbc6efc
b592784
cbacb0c
38f7184
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 |
|---|---|---|
|
|
@@ -55,6 +55,7 @@ dependencies = [ | |
| "superqt", | ||
| "pip", | ||
| "packaging", | ||
| "uv", | ||
| ] | ||
| dynamic = [ | ||
| "version" | ||
|
|
||
| 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', | ||
|
||
| ) | ||
| 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,6 @@ def constraints() -> list[str]: | |
|
|
||
|
|
||
| class NapariInstallerQueue(InstallerQueue): | ||
| PYPI_INSTALLER_TOOL_CLASS = NapariPipInstallerTool | ||
| PYPI_INSTALLER_TOOL_CLASS = NapariUvInstallerTool | ||
| CONDA_INSTALLER_TOOL_CLASS = NapariCondaInstallerTool | ||
| BASE_PACKAGE_NAME = 'napari' | ||
Uh oh!
There was an error while loading. Please reload this page.