diff --git a/docs/source/conf.py b/docs/source/conf.py index 9076ba895d..17d70c22dd 100755 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -33,7 +33,8 @@ 'sphinx.ext.mathjax', 'sphinx.ext.napoleon', 'sphinx.ext.intersphinx', - 'sphinx.ext.viewcode'] + 'sphinx.ext.viewcode', + 'sphinx_design', 'sphinx_copybutton'] autoclass_content = 'both' autosummary_generate = True diff --git a/docs/source/download.rst b/docs/source/download.rst index a4b99742d2..07002ec2db 100644 --- a/docs/source/download.rst +++ b/docs/source/download.rst @@ -8,39 +8,72 @@ Download For the easiest installation download and install the Standalone package. +.. tab-set:: + + .. tab-item:: Windows + + For the easiest installation download and install the Standalone package. + + .. button-link:: https://github.com/psychopy/psychopy/releases/download/2024.2.1/StandalonePsychoPy-2024.2.1post4-win64-py310.exe + :color: primary + + PsychoPy |version| modern (py3.10) + + .. button-link:: https://github.com/psychopy/psychopy/releases/download/2024.2.1/StandalonePsychoPy-2024.2.1-win64-py3.8.exe + :color: primary + + PsychoPy |version| compatibility+ (py3.8) + + The *Compatibility+* version is for users who need to run older scripts that are not compatible with the newer versions of Python (PsychoPy has supported Python 3.10 since 2022.2.0). + + .. tab-item:: MacOS + + For the easiest installation download and install the Standalone package. + + .. button-link:: https://github.com/psychopy/psychopy/releases/download/2024.2.1/StandalonePsychoPy-2024.2.1-macOS-py3.10.dmg + :color: primary + + PsychoPy |version| modern (py3.10) + + .. button-link:: https://github.com/psychopy/psychopy/releases/download/2024.2.1/StandalonePsychoPy-2024.2.1-macOS-py3.8.dmg + :color: primary + + PsychoPy |version| compatibility+ (py3.8) + + The *Compatibility+* version is for users who need to run older scripts that are not compatible with the newer versions of Python (PsychoPy has supported Python 3.10 since 2022.2.0). + + The *modern* version uses a more recent version of Python and cannot run experiments that use PsychoPy<2023.2.0 + + .. tab-item:: Linux + + The following will install PsychoPy into + + .. code-block:: bash + + # create a virtual environment and activate it + python3.10 -m venv ~/.psychopy_py310 + source ~/.psychopy_py310/bin/activate + + # fetch and run install script + python -c "$(curl -fsSL https://raw.githubusercontent.com/psychopy/psychopy/dev/installPsychoPy.py)" + .. raw:: html **For all versions** see the `PsychoPy releases on github `_ diff --git a/installPsychoPy.py b/installPsychoPy.py index 004cdcf8cc..a3b4315740 100644 --- a/installPsychoPy.py +++ b/installPsychoPy.py @@ -4,183 +4,120 @@ # Part of the PsychoPy library # Copyright (C) 2002-2018 Jonathan Peirce (C) 2019-2024 Open Science Tools Ltd. # Distributed under the terms of the GNU General Public License (GPL). - -import subprocess -import os -import sys -import requests - -"""This script will install PsychoPy to the current Python environment. - -For Linux installations, the script will fetch the supported linux distros for wxPython -and interactively select the distro and version to download the appropriate .whl file. - -After that the script will install PsychoPy using pip. +""" +Python script to install psychopy including dependencies NB: At present, for windows and MacOS you may as well just use `pip install psychopy` but in the future we may add some additional functionality here, like adding application shortcuts, checking/recommending virtual envs etc. """ -# Author: Florian Osmani -# Author: Jonathan Peirce - -wxLinuxUrl = "https://extras.wxpython.org/wxPython4/extras/linux/gtk3/" - -def installWhlFile(whlUrl): - """Installs a single specified wheel file using pip""" - wheel_path = os.path.basename(whlUrl) - subprocess.run([sys.exectuable, '-m', 'pip', 'install', '-U', '-f', wheel_path, 'wxPython'], check=True) - -def installPsychoPy(): - """Runs pip install psychopy""" - subprocess.run([sys.exectuable, '-m', 'pip', 'install', 'psychopy'], check=True) +# Author: Jonathan Peirce, based on work of Flavio Bastos and Florian Osmani -def getWxUrl(distroNames=None): - """Fetch the supported linux distros for wx and interactively select the - distro and version to download the appropriate .whl file. - - Args: - distroNames (_type_, optional): _description_. Defaults to None. - - Returns: - list: URL of the wheel for the selected distro/version - """ - def extractDistroNames(url): - """Extract the names of the linux distributions from the html content""" - - response = requests.get(url) - response.raise_for_status() - - distro_names = [] - lines = response.text.split('\n') - for line in lines: - if ' 10: - print("Sorry, please use Python 3.8, 3.9, or 3.10 to install Psychopy") - return None - - python_cp = f"cp{version_info.major}{version_info.minor}" - - def selectDistro(distroNames): - print("Please select your Linux distribution:") - for i, distro in enumerate(distroNames): - print(f"{i + 1}. {distro}") - - while True: - choice = input("Enter your choice (number): ") - if choice.isdigit() and 1 <= int(choice) <= len(distroNames): - return distroNames[int(choice) - 1] - else: - print("Invalid choice, please try again.") - - def organizeDistributions(distroNames): - distroDict = {} - for distro in distroNames: - nameParts = distro.split('-') - distroName = '-'.join(nameParts[:-1]) - version = nameParts[-1] if len(nameParts) > 1 else 'default' - - if distroName in distroDict: - distroDict[distroName].append(version) +import os, sys +import pathlib +import subprocess +import platform + +_linux_installer = None # will be apt-get or yum depending on system + +print( + "This `install_psychopy.py` script is EXPERIMENTAL and may not work!" + " PsychoPy users have many different systems and it's hard to maintain them all. " + " Let us know how you get on!\n" +) +if sys.version_info[:2] != (3,10): + print( + "PsychoPy is designed for Python 3.10.x " + f"You are running Python {sys.version_info[0]}.{sys.version_info[1]}.{sys.version_info[2]}. " + "PsychoPy may not work and may not even install!\n" + ) + +print( + "This `install_psychopy.py` script is EXPERIMENTAL and may not work!" + " PsychoPy users have many different systems and it's hard to maintain them all. " + " Let us know how you get on!\n" +) + +def pip_install(*packages): + """Install packages using pip.""" + print('Installing packages:', packages) + subprocess.run([sys.executable, '-m', 'pip', 'install', '--upgrade'] + list(packages)) + +def check_venv(): + """Check if this is a virtual environment. If not, recommend quitting and creating one. + """ + # If this is not a venv then recommend quitting to create one + if not hasattr(sys, 'real_prefix'): + print( + 'You should install PsychoPy in a virtual environment,' + ' to avoid conflicts with other packages, or damaging your system.' + ' To create a virtual environment in the current directory, run:') + print(' python3 -m venv .') + print('Then activate the virtual environment with:') + print(' source bin/activate') + print('Then run this script again.') + response = input('Shall we QUIT now? [y]/n: ') + if response.lower() != 'n': + sys.exit(1) + +def apt_install(*packages): + """Install packages using apt, yum, or similar""" + global _linux_installer + # check if using this system has apt-get or yum + if _linux_installer is None: + for installer in ['apt', 'yum', 'dnf', 'zypper', 'apt-cyg']: + out = subprocess.run(['which', installer], stdout=subprocess.PIPE) + if out.returncode == 0: + _linux_installer = installer + break + if _linux_installer is None: + print('On Linux systems, this script requires either apt-get or yum.') + sys.exit(1) + + def find_package(package): + # check pacakage name according to apt/yum + packages_lookup = { + 'python3-dev': {'apt':'libgtk-3-dev', 'yum':'gtk3-devel'}, + 'libgtk-3-dev': {'apt':'libgtk-3-dev', 'yum':'gtk3-devel'}, + 'libwebkit2gtk-4.0-dev': {'apt':'libwebkit2gtk-4.0-dev', 'yum':'webkit2gtk3-devel'}, + 'libxcb-xinerama0': {'apt':'libxcb-xinerama0', 'yum':'libxcb-xinerama'}, + 'libegl1-mesa-dev': {'apt':'libegl1-mesa-dev', 'yum':'mesa-libEGL-devel'}, + } + if package in packages_lookup: + if _linux_installer in packages_lookup[package]: + return packages_lookup[package][_linux_installer] else: - distroDict[distroName] = [version] - - return distroDict - - def selectVersion(selectedDistro, versions): - while True: - print("Please select the version:") - for i, version in enumerate(versions): - print(f"{i + 1}. {selectedDistro}-{version}") - print("0. Go back") - - choice = input("Enter your choice (number): ") - if choice.isdigit(): - choice = int(choice) - if 1 <= choice <= len(versions): - return versions[choice - 1] - elif choice == 0: - return None - print("Invalid choice, please try again.") - - def fetchWhlFiles(htmlContent, pythonVersions): - all = [] - recommended = [] - lines = htmlContent.split('\n') - for line in lines: - if '