diff --git a/.github/workflows/autoupdate_python_versions.yml b/.github/workflows/autoupdate_python_versions.yml index 57fdd8c..7ea1345 100644 --- a/.github/workflows/autoupdate_python_versions.yml +++ b/.github/workflows/autoupdate_python_versions.yml @@ -33,8 +33,8 @@ jobs: - name: Run the autoupdate script run: | - python -m pip install --upgrade pip - pip install -r scripts/requirements.txt + python -m pip install --upgrade pip uv + uv pip install -r scripts/requirements.txt python scripts/update_python_versions.py - name: Commit changes (if any) diff --git a/.github/workflows/ci_cd.yml b/.github/workflows/ci_cd.yml index fad0ce5..920a084 100644 --- a/.github/workflows/ci_cd.yml +++ b/.github/workflows/ci_cd.yml @@ -84,11 +84,16 @@ jobs: with: python-version: ${{ env.MAIN_PYTHON_VERSION }} + - name: Upgrade pip & uv + run: | + pip install -U pip uv + - name: Install Dependencies - run: pip install -e .[freeze] + run: | + uv sync --extra freeze - name: Freeze application - run: pyinstaller frozen.spec + run: uv run pyinstaller frozen.spec - name: Install NSIS run: choco install nsis -y @@ -192,13 +197,18 @@ jobs: mv python-${{ env.PRECOMPILE_PYTHON_VERSION }}.tar.gz ${RUNNER_WORKSPACE}/python-installer-qt-gui/src/ansys/tools/installer/assets/python-asset/${{ matrix.os }} ls -l ${RUNNER_WORKSPACE}/python-installer-qt-gui/src/ansys/tools/installer/assets/python-asset/${{ matrix.os }} + - name: Upgrade pip & uv + run: | + pip install -U pip uv + - name: Install Dependencies - run: pip install -e .[freeze] + run: | + uv sync --extra freeze - name: Freeze application env: ADD_PYTHON_BINARIES: true - run: pyinstaller frozen.spec + run: uv run pyinstaller frozen.spec - name: Setup and Copy Linux files for packaging run: | @@ -334,19 +344,19 @@ jobs: mv python-${{ env.PRECOMPILE_PYTHON_VERSION }}.tar.gz ${{ env.GITHUB_WORKSPACE }}/src/ansys/tools/installer/assets/python-asset/${{ env.FOLDER_NAME }} ls -l ${{ env.GITHUB_WORKSPACE }}/src/ansys/tools/installer/assets/python-asset/${{ env.FOLDER_NAME }} - - name: Update pip + + - name: Upgrade pip & uv run: | - python3 --version - python3 -m pip install pip -U + pip install -U pip uv - - name: Install pip Dependencies + - name: Install Dependencies run: | - python3 -m pip install --ignore-installed -e .[freeze] + uv sync --extra freeze - name: Freeze application env: ADD_PYTHON_BINARIES: false - run: python3 -m PyInstaller frozen.spec + run: uv run pyinstaller frozen.spec - name: Setup and Copy CentOS/RHEL files for packaging if: contains(matrix.os, 'centos') diff --git a/Makefile b/Makefile index f355241..2f4ed74 100644 --- a/Makefile +++ b/Makefile @@ -1,28 +1,32 @@ # Simple makefile to simplify repetitive build env management tasks under posix -.PHONY: install tests doc build clean fresh-build +.PHONY: setup install tests doc build clean fresh-build -install: +setup: + @echo "Installing uv..." + pip install -U pip uv + +install: setup @echo "Installing..." - pip install -e .[freeze] + uv pip install -e .[freeze] @echo "Installation complete." -tests: +tests: setup @echo "Installing test dependencies..." - pip install -e .[tests] + uv pip install -e .[tests] @echo "Running tests..." - pytest + uv run pytest @echo "Tests complete." -doc: +doc: setup @echo "Installing documentation dependencies..." - pip install -e .[doc] + uv pip install -e .[doc] @echo "Building documentation..." cd doc && make clean && make html && cd .. @echo "Documentation complete." -build: +build: setup @echo "Freezing using pyinstaller" - pyinstaller frozen.spec + uv run pyinstaller frozen.spec clean: @echo "Cleaning up build files..." diff --git a/README.rst b/README.rst index c81aba5..ff8cb24 100644 --- a/README.rst +++ b/README.rst @@ -50,14 +50,15 @@ You can be up and running with four lines of code: git clone https://github.com/ansys/python-installer-qt-gui cd python-installer-qt-gui - pip install pip -U - pip install -e . + pip install pip uv -U + uv venv + uv pip install -e . Now you can run it with: .. code:: bash - ansys_python_installer + uv run ansys_python_installer **Details** @@ -79,7 +80,7 @@ guide`_. You will need to follow these steps: .. code:: bash # Create a virtual environment - python -m venv .venv + python -m uv venv .venv # Activate it in a POSIX system source .venv/bin/activate @@ -94,19 +95,19 @@ guide`_. You will need to follow these steps: .. code:: bash - python -m pip install -U pip + python -m pip install -U pip uv #. Install the project in editable mode: .. code:: bash - python -m pip install -e .[tests,doc] + python -m uv pip install -e .[tests,doc] #. Finally, verify your development installation by running: .. code:: bash - pytest tests -v + uv run pytest tests -v Style and testing @@ -115,8 +116,8 @@ This project uses `pre-commit `_. Install with: .. code:: - pip install pre-commit - pre-commit install + uv pip install pre-commit + uv run pre-commit install This will now run ``pre-commit`` for each commit to ensure you follow project style guidelines. For example: @@ -140,7 +141,7 @@ If you need to run it again on all files and not just staged files, run: .. code:: - pre-commit run --all-files + uv run pre-commit run --all-files Local build @@ -150,8 +151,8 @@ This application can be deployed as a 'frozen' application using `pyinstaller .. code:: - pip install -e .[freeze] - pyinstaller frozen.spec + uv pip install -e .[freeze] + uv run pyinstaller frozen.spec This will generate application files at ``dist/ansys_python_manager`` and you can run it locally by executing ``Ansys Python Manager.exe``. @@ -164,8 +165,8 @@ For building documentation, you can either run the usual rules provided in the .. code:: bash - pip install -e .[doc] - make -C doc/ html + uv pip install -e .[doc] + uv run make -C doc/ html # subsequently open the documentation with (under Linux): doc/html/index.html diff --git a/make.bat b/make.bat index 3b41952..a967607 100644 --- a/make.bat +++ b/make.bat @@ -11,22 +11,30 @@ if "%1" == "build" goto build if "%1" == "clean" goto clean if "%1" == "fresh-build" goto fresh-build +:setup +Echo ^>^>^> Setting up environment... +pip install -U pip uv +goto :eof + :install +call :setup Echo ^>^>^> Installing... -pip install -e .[freeze] +uv pip install -e .[freeze] Echo ^>^>^> Installation complete. goto end :tests +call :setup Echo ^>^>^> Installing test dependencies... -pip install -e .[tests] +uv pip install -e .[tests] Echo ^>^>^> Running tests... -pytest +uv run pytest goto end :doc +call :setup Echo ^>^>^> Installing documentation dependencies... -pip install -e .[doc] +uv pip install -e .[doc] Echo ^>^>^> Building documentation... chdir /d doc call make.bat clean @@ -36,8 +44,9 @@ Echo ^>^>^> Documentation complete. goto end :build +call :setup Echo ^>^>^> Freezing using pyinstaller -pyinstaller frozen.spec +uv run pyinstaller frozen.spec goto end :clean @@ -47,11 +56,8 @@ rmdir /s /q dist > /NUL 2>&1 goto end :fresh-build -Echo ^>^>^> Cleaning up build files... -rmdir /s /q build > /NUL 2>&1 -rmdir /s /q dist > /NUL 2>&1 -Echo ^>^>^> Freezing using pyinstaller -pyinstaller frozen.spec +call :clean +call :build goto end :end diff --git a/pyproject.toml b/pyproject.toml index cea878a..69b6b21 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ build-backend = "flit_core.buildapi" name = "ansys-tools-installer" description = "Python QT app or CLI for installing Python and PyAnsys." readme = "README.rst" -requires-python = ">=3.9,<4" +requires-python = ">=3.10,<4" license = { file = "LICENSE" } authors = [{ name = "Ansys, Inc.", email = "pyansys.core@ansys.com" }] maintainers = [{ name = "Ansys, Inc.", email = "pyansys.core@ansys.com" }] diff --git a/src/ansys/tools/installer/installed_table.py b/src/ansys/tools/installer/installed_table.py index c4a994c..3fbdb4d 100644 --- a/src/ansys/tools/installer/installed_table.py +++ b/src/ansys/tools/installer/installed_table.py @@ -357,16 +357,16 @@ def eventFilter(self, source, event): def launch_spyder(self): """Launch spyder IDE.""" # handle errors - error_msg = "(pip install spyder && spyder && exit 0) || echo Failed to launch. Try reinstalling spyder with pip install spyder --force-reinstall" + error_msg = "(uv pip install spyder && spyder && exit 0) || echo Failed to launch. Try reinstalling spyder with pip install spyder --force-reinstall" self._update_pck_mnger() self.launch_cmd( - f'pip list | {"grep" if is_linux_os() else "findstr"} "spyder" && spyder && exit 0 || {error_msg}' + f'uv pip list | {"grep" if is_linux_os() else "findstr"} "spyder" && spyder && exit 0 || {error_msg}' ) def launch_jupyterlab(self): """Launch Jupyterlab.""" # handle errors - error_msg = "pip install jupyterlab && python -m jupyter lab || echo Failed to launch. Try reinstalling jupyterlab with pip install jupyterlab --force-reinstall" + error_msg = "uv pip install jupyterlab && python -m jupyter lab || echo Failed to launch. Try reinstalling jupyterlab with pip install jupyterlab --force-reinstall" self._update_pck_mnger() self.launch_cmd(f"python -m jupyter lab || {error_msg}") @@ -377,13 +377,13 @@ def launch_vscode(self): def launch_jupyter_notebook(self): """Launch Jupyter Notebook.""" # handle errors - error_msg = "pip install jupyter && python -m jupyter notebook || echo Failed to launch. Try reinstalling jupyter with pip install jupyter --force-reinstall" + error_msg = "uv pip install jupyter && python -m jupyter notebook || echo Failed to launch. Try reinstalling jupyter with pip install jupyter --force-reinstall" self._update_pck_mnger() self.launch_cmd(f"python -m jupyter notebook || {error_msg}") def install_defaults(self): """Install Python default packages.""" - cmd = "pip install numpy pandas scipy scikit-learn matplotlib pyvista[all] && timeout 3 && exit || echo Failed to install default Python packages. Try reinstalling it with pip install numpy pandas scipy scikit-learn matplotlib pyvista[all] --force-reinstall" + cmd = "uv pip install numpy pandas scipy scikit-learn matplotlib pyvista[all] && timeout 3 && exit || echo Failed to install default Python packages. Try reinstalling it with pip install numpy pandas scipy scikit-learn matplotlib pyvista[all] --force-reinstall" self._update_pck_mnger() self.launch_cmd(cmd) @@ -396,7 +396,7 @@ def install_pyansys_packages(self): if chosen_ver else f"{PYANSYS_LIBS[chosen_pkg]}" ) - cmd = f"pip install {pck_ver} && timeout 3 && exit || echo Failed to install this PyAnsys Library. Try reinstalling it with pip install {pck_ver} --force-reinstall" + cmd = f"uv pip install {pck_ver} && timeout 3 && exit || echo Failed to install this PyAnsys Library. Try reinstalling it with uv pip install {pck_ver} --force-reinstall" self._update_pck_mnger() self.launch_cmd(cmd, always_use_pip=True) @@ -417,7 +417,7 @@ def update_package_combo(self, index): def list_packages(self): """List installed Python packages.""" - self.launch_cmd("pip list") + self.launch_cmd("uv pip list") def _update_pck_mnger(self): """Update package manager if needed. @@ -428,7 +428,7 @@ def _update_pck_mnger(self): """ if self.is_chk_box_active(): if "Python" in self.table.active_version: - cmd = "python -m pip install -U pip && exit" + cmd = "python -m pip install -U pip uv && exit" else: # Otherwise, conda cmd = "conda update conda --yes && exit" self.launch_cmd(cmd, minimized_window=True) @@ -581,6 +581,8 @@ def launch_cmd( new_path = f"{py_path};{scripts_path};{myenv}" if extra: + extra = extra.replace("uv pip install", "uv pip install --system") + extra = extra.replace("uv pip list", "uv pip list --system") cmd = f"&& {extra}" else: cmd = f"&& echo Python set to {py_path}" @@ -588,6 +590,12 @@ def launch_cmd( if is_linux_os(): run_linux_command(py_path, extra) else: + # Update the package managers + subprocess.call( + f'start /w /min cmd /K "set PATH={new_path} && python -m pip install --upgrade pip uv && exit"', + shell=True, + ) + subprocess.call( f'start {min_win} cmd /K "set PATH={new_path} && cd %userprofile% {cmd}"', shell=True, @@ -610,7 +618,7 @@ def launch_cmd( if extra: # Replace the pip install command for conda if not always_use_pip: - extra = extra.replace("pip", "conda") + extra = extra.replace("uv pip", "conda") extra = extra.replace("conda install", "conda install --yes") cmd = f"&& {extra}" else: @@ -627,7 +635,7 @@ def launch_cmd( if extra: # Replace the pip install command for conda if not always_use_pip: - extra = extra.replace("pip", "conda") + extra = extra.replace("uv pip", "conda") extra = extra.replace("conda install", "conda install --yes") cmd = f"&& {extra}" else: diff --git a/src/ansys/tools/installer/linux_functions.py b/src/ansys/tools/installer/linux_functions.py index 63cc695..67217d8 100644 --- a/src/ansys/tools/installer/linux_functions.py +++ b/src/ansys/tools/installer/linux_functions.py @@ -133,7 +133,7 @@ def install_python_linux(filename): file = file.replace(".tar.xz", "") file = file.lower() execute_linux_command( - f"cd {untar_dirname};mkdir -p {ansys_linux_path}/{file};make clean;./configure --prefix={ansys_linux_path}/{file};make;make install" + f"cd {untar_dirname};mkdir -p {ansys_linux_path}/{file};make clean;./configure --prefix={ansys_linux_path}/{file};make;make install;cp {ansys_linux_path}/{file}/bin/python3 {ansys_linux_path}/{file}/bin/python" ) os.chdir(cwd) return 0 @@ -203,7 +203,8 @@ def create_venv_linux(venv_dir, py_path): ... ) """ - execute_linux_command(f"{py_path} -m venv {venv_dir}") + execute_linux_command(f"{py_path} -m pip install -U pip uv") + execute_linux_command(f"{py_path} -m uv venv {venv_dir}") def create_venv_linux_conda(venv_dir, py_path): @@ -246,9 +247,13 @@ def run_linux_command(pypath, extra, venv=False): Examples -------- - >>> run_linux_command("/home/sha/.local/ansys/python-3.8.10/bin/python3", "pip list") + >>> run_linux_command("/home/sha/.local/ansys/python-3.8.10/bin/python3", "uv pip list") """ + + # Update package manager before executing commands + execute_linux_command(f"{pypath} -m pip install -U pip uv") + prefix = f"{pypath}" extra = extra.replace("timeout", "sleep") python_name = prefix.split("/")[-1] @@ -263,7 +268,7 @@ def run_linux_command(pypath, extra, venv=False): prefix = f". {pypath}/bin/activate; " else: prefix = "/".join(prefix.split("/")[:-1]) + "/" - extra = extra.replace("pip", f"pip{major_version}") + # extra = extra.replace("pip", f"pip{major_version}") execute_linux_command(f"cd ~ ; {prefix}{extra}", wait=False) @@ -273,13 +278,13 @@ def run_linux_command_conda(pypath, extra, venv=False): Examples -------- - >>> run_linux_command_conda("/home/sha/.local/ansys/python-3.8.10/bin/python3", "pip list") + >>> run_linux_command_conda("/home/sha/.local/ansys/python-3.8.10/bin/python3", "uv pip list") """ venvParam = "" extra = extra.replace("timeout", "sleep") extra = extra.replace("conda install --yes", "mamba install --yes") - # extra = extra.replace("conda update conda --yes", "python -m pip install -U pip") + # extra = extra.replace("conda update conda --yes", "python -m pip install -U pip uv") extra = extra.replace( "conda update conda --yes", "mamba update -n base mamba --yes" ) @@ -302,7 +307,7 @@ def run_linux_command_conda(pypath, extra, venv=False): break venvParam = f"; . {miniforge_path}; . {miniforge_path.replace('conda.sh', 'mamba.sh')} ;mamba activate {pypath}" else: - extra = extra.replace(" pip", f" {pypath}/bin/pip") + extra = extra.replace("uv pip", f" {pypath}/bin/pip") execute_linux_command(f"cd ~ {venvParam} ; {conda_path}{extra} ", wait=False) diff --git a/src/ansys/tools/installer/windows_functions.py b/src/ansys/tools/installer/windows_functions.py index 9ff8abf..4f8a3e7 100644 --- a/src/ansys/tools/installer/windows_functions.py +++ b/src/ansys/tools/installer/windows_functions.py @@ -48,8 +48,17 @@ def create_venv_windows(venv_dir: str, py_path: str): user_profile = os.path.expanduser("~") scripts_path = os.path.join(py_path, "Scripts") new_path = f"{py_path};{scripts_path};%PATH%" + + # Update the package managers + subprocess.call( + f'start /w /min cmd /K "set PATH={new_path} && python -m pip install --upgrade pip uv && exit"', + shell=True, + cwd=user_profile, + ) + + # Create venv using uv subprocess.call( - f'start /w /min cmd /K "set PATH={new_path} && python -m venv {venv_dir} && exit"', + f'start /w /min cmd /K "set PATH={new_path} && python -m uv venv {venv_dir} && exit"', shell=True, cwd=user_profile, )