Add pyproject.toml

This commit is contained in:
Milan Nikolic 2024-10-17 19:19:31 +02:00
parent aaa49ef421
commit 47ddad0f4c
No known key found for this signature in database
GPG key ID: 9229D0EAA3AA4E75
4 changed files with 98 additions and 61 deletions

1
.gitignore vendored
View file

@ -4,6 +4,7 @@ src/m64py.egg-info/
# Files # Files
dist/*.egg dist/*.egg
dist/*.tar.gz
# Byte-compiled / optimized / DLL files # Byte-compiled / optimized / DLL files
__pycache__/ __pycache__/

View file

@ -46,7 +46,7 @@ PyPi
To install just the Python dependencies: To install just the Python dependencies:
``pip install -r requirements.txt --user`` ``python -m pip install -r requirements.txt --user``
.. note:: .. note::
@ -59,13 +59,13 @@ To install just the Python dependencies:
Install Install
======= =======
First, run ``python setup.py build`` followed by ``python setup.py install`` First, run ``python setup.py build`` followed by ``python -m pip install .``
to install to install
.. code:: .. code::
python setup.py build python setup.py build
python setup.py install --user python -m pip install . --user
.. note:: .. note::

44
pyproject.toml Normal file
View file

@ -0,0 +1,44 @@
[build-system]
requires = ["setuptools"]
build-backend = "setuptools.build_meta"
[project]
name = "m64py"
description = "A frontend for Mupen64Plus"
dynamic = ["version"]
readme = "README.rst"
license = {text = "GNU GPLv3"}
requires-python = ">=3.9"
keywords = ["emulator", "nintendo64"]
authors = [{name = "Milan Nikolic", email = "gen2brain@gmail.com"}]
dependencies = ["PyQt6", "PySDL2"]
classifiers = [
"Development Status :: 4 - Beta",
"Programming Language :: Python :: 3",
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
"Topic :: Games/Entertainment",
"Intended Audience :: End Users/Desktop",
"Operating System :: Microsoft :: Windows",
"Operating System :: MacOS :: MacOS X",
"Operating System :: POSIX :: Linux"
]
[project.urls]
Homepage = "https://m64py.sourceforge.net"
Repository = "https://github.com/mupen64plus/mupen64plus-ui-python"
Issues = "https://github.com/mupen64plus/mupen64plus-ui-python/issues"
Changelog = "https://raw.githubusercontent.com/mupen64plus/mupen64plus-ui-python/refs/heads/master/CHANGELOG"
[tool.setuptools]
script-files = ["bin/m64py"]
package-dir = {"" = "src"}
[tool.setuptools.packages.find]
where = ["src"]
[tool.setuptools.data-files]
"share/icons/hicolor/96x96/apps" = ["xdg/net.sourceforge.m64py.M64Py.png"]
"share/applications" = ["xdg/net.sourceforge.m64py.M64Py.desktop"]
[tool.setuptools.dynamic]
version = {attr = "m64py.core.defs.FRONTEND_VERSION"}

108
setup.py
View file

@ -1,31 +1,27 @@
#!/usr/bin/env python #!/usr/bin/env python
import fnmatch
import glob
import os import os
import shutil import re
import subprocess import io
import sys import sys
import glob
import shutil
import fnmatch
import subprocess
import fileinput import fileinput
import setuptools import setuptools
from setuptools.command.build import build
try:
from setuptools.modified import newer
except ImportError:
from distutils.dep_util import newer
# Add the src folder to the path
sys.path.insert(0, os.path.realpath("src"))
from m64py.core.defs import FRONTEND_VERSION
BASE_DIR = os.path.dirname(os.path.realpath(__file__)) BASE_DIR = os.path.dirname(os.path.realpath(__file__))
FRONTEND_VERSION = re.search(r'FRONTEND_VERSION\s*=\s*[\'"]([^\'"]*)[\'"]',
io.open(os.path.join(BASE_DIR, "src", "m64py", "core", "defs.py")).read()).group(1)
class BuildQt(setuptools.Command): class BuildQt(setuptools.Command):
description = "Build the Qt interface" description = "Build the Qt user interface"
boolean_options = [] boolean_options = []
user_options = [] user_options = []
@ -36,15 +32,18 @@ class BuildQt(setuptools.Command):
def finalize_options(self): def finalize_options(self):
pass pass
def newer(self, source, target):
return not os.path.exists(target) or (os.path.getmtime(source) > os.path.getmtime(target))
def compile_rc(self, qrc_file): def compile_rc(self, qrc_file):
py_file = os.path.splitext(qrc_file)[0] + "_rc.py" py_file = os.path.splitext(qrc_file)[0] + "_rc.py"
if not newer(qrc_file, py_file): if not self.newer(qrc_file, py_file):
return return
rcc_exe = self.find_executable("rcc") rcc_exe = self.find_executable("rcc")
if rcc_exe is None: if rcc_exe is None:
self.warn("Unable to find Qt Resource Compiler (rcc)") self.warn("Unable to find Qt Resource Compiler (rcc)")
sys.exit(1) sys.exit(1)
if subprocess.call(["rcc", "-g", "python", qrc_file, "-o", py_file]) > 0: if subprocess.call([rcc_exe, "-g", "python", qrc_file, "-o", py_file]) > 0:
self.warn("Unable to compile resource file {}".format(qrc_file)) self.warn("Unable to compile resource file {}".format(qrc_file))
if not os.path.exists(py_file): if not os.path.exists(py_file):
sys.exit(1) sys.exit(1)
@ -54,16 +53,21 @@ class BuildQt(setuptools.Command):
sys.stdout.write(line) sys.stdout.write(line)
def compile_ui(self, ui_file): def compile_ui(self, ui_file):
from PyQt6 import uic
py_file = os.path.splitext(ui_file)[0] + "_ui.py" py_file = os.path.splitext(ui_file)[0] + "_ui.py"
if not newer(ui_file, py_file): if not self.newer(ui_file, py_file):
return return
with open(py_file, "w") as a_file: uic_exe = self.find_executable("pyuic6")
uic.compileUi(ui_file, a_file) if uic_exe is None:
self.warn("Unable to find Qt User Interface Compiler (pyuic6)")
sys.exit(1)
if subprocess.call([uic_exe, "-o", py_file, ui_file]) > 0:
self.warn("Unable to compile ui file {}".format(ui_file))
if not os.path.exists(py_file):
sys.exit(1)
def compile_ts(self, ts_file): def compile_ts(self, ts_file):
qm_file = os.path.splitext(ts_file)[0] + ".qm" qm_file = os.path.splitext(ts_file)[0] + ".qm"
if not newer(ts_file, qm_file): if not self.newer(ts_file, qm_file):
return return
lr_exe = self.find_executable("lrelease") lr_exe = self.find_executable("lrelease")
if lr_exe is None: if lr_exe is None:
@ -75,26 +79,11 @@ class BuildQt(setuptools.Command):
sys.exit(1) sys.exit(1)
def find_executable(self, name): def find_executable(self, name):
from PyQt6.QtCore import QLibraryInfo
path = os.getenv("PATH").split(os.pathsep) path = os.getenv("PATH").split(os.pathsep)
bin_path = QLibraryInfo.path(QLibraryInfo.LibraryPath.BinariesPath)
path.insert(0, bin_path)
os.environ["PATH"] = os.pathsep.join(path)
exe = shutil.which(name)
if exe:
return exe
libexec_path = QLibraryInfo.path(QLibraryInfo.LibraryPath.LibraryExecutablesPath)
path.insert(0, libexec_path)
os.environ["PATH"] = os.pathsep.join(path)
exe = shutil.which(name)
if exe:
return exe
path.extend(["/usr/lib64/qt6/bin", "/usr/lib64/qt6/libexec", path.extend(["/usr/lib64/qt6/bin", "/usr/lib64/qt6/libexec",
"/usr/lib/qt6/bin", "/usr/lib/qt6/libexec", "/usr/lib/qt6/bin", "/usr/lib/qt6/libexec",
"/usr/lib/x86_64-linux-gnu/qt6/bin", "/usr/lib/x86_64-linux-gnu/qt6/libexec"]) "/usr/lib/x86_64-linux-gnu/qt6/bin", "/usr/lib/x86_64-linux-gnu/qt6/libexec"])
os.environ["PATH"] = os.pathsep.join(path) os.environ["PATH"] = os.pathsep.join(path)
exe = shutil.which(name) exe = shutil.which(name)
if exe: if exe:
@ -334,8 +323,8 @@ class CleanLocal(setuptools.Command):
description = "Clean the local project directory" description = "Clean the local project directory"
wildcards = ['*.py[co]', '*_ui.py', '*_rc.py', '__pycache__', '*.qm'] wildcards = ['*.py[co]', '*_ui.py', '*_rc.py', '__pycache__', '*.qm', "build", "*.egg-info"]
excludedirs = ['.git', 'build', 'dist'] excludedirs = ['.git', 'dist']
user_options = [] user_options = []
def initialize_options(self): def initialize_options(self):
@ -367,30 +356,33 @@ class CleanLocal(setuptools.Command):
os.remove(a_path) os.remove(a_path)
class BuildCustom(build):
sub_commands = [('build_qt', None)] + build.sub_commands
setuptools.setup( setuptools.setup(
name="m64py", name = "m64py",
version=FRONTEND_VERSION, version = FRONTEND_VERSION,
description="A frontend for Mupen64Plus", description = "A frontend for Mupen64Plus",
long_description="A Qt6 front-end (GUI) for Mupen64Plus, a cross-platform plugin-based Nintendo 64 emulator.", long_description = "A Qt6 front-end (GUI) for Mupen64Plus, a cross-platform plugin-based Nintendo 64 emulator.",
author="Milan Nikolic", author = "Milan Nikolic",
author_email="gen2brain@gmail.com", author_email = "gen2brain@gmail.com",
license="GNU GPLv3", license = "GNU GPLv3",
url="https://m64py.sourceforge.net", url = "https://m64py.sourceforge.net",
package_dir={'': "src"}, package_dir = {"": "src"},
packages=["m64py", "m64py.core", "m64py.frontend", "m64py.ui"], packages = setuptools.find_namespace_packages(where="src"),
scripts=["bin/m64py"], scripts = ["bin/m64py"],
requires=["PyQt6", "PySDL2"], requires = ["PyQt6", "PySDL2"],
platforms=["Linux", "Windows", "Darwin"], cmdclass = {
cmdclass={ 'build': BuildCustom,
'build': BuildQt, 'build_qt': BuildQt,
'build_dmg': BuildDmg, 'build_dmg': BuildDmg,
'build_exe': BuildExe, 'build_exe': BuildExe,
'build_qt': BuildQt,
'build_zip': BuildZip, 'build_zip': BuildZip,
'clean': CleanLocal 'clean': CleanLocal
}, },
data_files=[ data_files = [
("share/pixmaps", ["xdg/m64py.png"]), ("share/icons/hicolor/96x96/apps", ["xdg/net.sourceforge.m64py.M64Py.png"]),
("share/applications", ["xdg/m64py.desktop"]), ("share/applications", ["xdg/net.sourceforge.m64py.M64Py.desktop"]),
] ]
) )