Skip to content
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

Meson #77

Merged
merged 46 commits into from
Dec 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
9d8ca29
Create pylint.yml
kif Nov 7, 2023
ef55f50
Merge remote-tracking branch 'upstream/main'
kif Nov 27, 2023
2f360ea
migrate to meson-python
kif Nov 27, 2023
8ce34c3
new meson.build file
kif Nov 27, 2023
226b020
include python source
kif Nov 27, 2023
f89d431
move files
kif Nov 27, 2023
8120ebb
update build
kif Nov 27, 2023
3780c37
make the code compile with meson
kif Nov 27, 2023
8d4da22
app folder moved to meson build system
kif Nov 27, 2023
10920fb
test moved to meson
kif Nov 27, 2023
593d953
include subdir
kif Nov 27, 2023
ac41f7b
typo
kif Nov 27, 2023
8c79220
scipy is a build dependency
kif Nov 27, 2023
7e4829e
fix warning in cython3
kif Nov 27, 2023
26a8592
fix warning
kif Nov 27, 2023
52bb4ae
remove old files
kif Nov 27, 2023
f19151a
fix path
kif Nov 28, 2023
656e35e
auxillary functions
kif Nov 28, 2023
f5d0ed6
make tests work
kif Nov 28, 2023
c18bc3d
update version of python supported
kif Nov 28, 2023
846fc03
update tests
kif Nov 29, 2023
1b91bc4
fix test
kif Nov 29, 2023
8c76977
update testing
kif Nov 29, 2023
3d752bf
Include doc
kif Nov 29, 2023
58a888c
update doc
kif Nov 29, 2023
3dc60ae
Update python-package-mac.yml
kif Nov 29, 2023
11e7deb
Update python-package-ubuntu.yml
kif Nov 29, 2023
d200464
Update requirements.txt
kif Nov 29, 2023
3f3bb30
requires for building docs
kif Nov 29, 2023
1595ca8
use xcode 14 on macos
kif Nov 29, 2023
c4950ae
install dev tools
kif Nov 29, 2023
24a248d
sym-link
kif Nov 29, 2023
9115af1
WIP
kif Nov 30, 2023
58b7657
debian packaging
kif Nov 30, 2023
6eeb184
make executable
kif Nov 30, 2023
60f7dcc
compatibility with debian12
kif Nov 30, 2023
0fbc4f7
update path of cython files
kif Nov 30, 2023
d53d599
helper
kif Nov 30, 2023
555d733
debug
kif Nov 30, 2023
fe1dd59
debug
kif Nov 30, 2023
68da5b5
debug
kif Nov 30, 2023
e580f16
make test pass when data are avaolable
kif Nov 30, 2023
7c6fcc5
debug
kif Nov 30, 2023
d0511f4
lasy load module
kif Dec 1, 2023
0f44695
minor polish
kif Dec 1, 2023
6847a0c
Work around against issue https://github.com/pypa/build/issues/705
kif Dec 4, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions .github/workflows/pylint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
name: Pylint

on: [push]

jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.8", "3.9", "3.10"]
steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v3
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install pylint
- name: Analysing the code with pylint
run: |
pylint $(git ls-files '*.py')
7 changes: 4 additions & 3 deletions .github/workflows/python-package-mac.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ jobs:
runs-on: macos-latest
strategy:
matrix:
python-version: ["3.6", "3.7", "3.8", "3.9", "3.10"]
xcode-version: [latest-stable, 11]
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"]
xcode-version: [latest-stable, 14]

steps:
- uses: actions/checkout@v2
Expand All @@ -30,6 +30,7 @@ jobs:
python -m pip install --upgrade pip
pip install flake8
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
if [ -f requirements-dev.txt ]; then pip install -r requirements-dev.txt; fi
- name: Lint with flake8
run: |
# stop the build if there are Python syntax errors or undefined names
Expand All @@ -41,7 +42,7 @@ jobs:
pip install .
- name: Test of run_tests.py
run: |
python setup.py build test
python run_tests.py
- name: Run end to end tests with e2etest.py
run: |
mkdir empty
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/python-package-ubuntu.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.6", "3.7", "3.8", "3.9", "3.10"]
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"]

steps:
- uses: actions/checkout@v2
Expand Down Expand Up @@ -45,7 +45,7 @@ jobs:
pip install .
- name: Test of run_tests.py
run: |
python setup.py build test
python run_tests.py
- name: Run end to end tests with e2etest.py
run: |
mkdir empty
Expand Down
252 changes: 110 additions & 142 deletions bootstrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,73 +10,94 @@
__authors__ = ["Frédéric-Emmanuel Picca", "Jérôme Kieffer"]
__contact__ = "[email protected]"
__license__ = "MIT"
__date__ = "09/07/2020"
__date__ = "03/03/2023"

import sys
import os
import distutils.util
import subprocess
import logging
import collections
from argparse import ArgumentParser

if sys.version_info[:2] < (3, 11):
import tomli
else:
import tomllib as tomli
logging.basicConfig()
logger = logging.getLogger("bootstrap")


def is_debug_python():
"""Returns true if the Python interpreter is in debug mode."""
try:
import sysconfig
except ImportError: # pragma nocover
# Python < 2.7
import distutils.sysconfig as sysconfig
def get_project_name(root_dir):
"""Retrieve project name by running python setup.py --name in root_dir.

if sysconfig.get_config_var("Py_DEBUG"):
return True
:param str root_dir: Directory where to run the command.
:return: The name of the project stored in root_dir
"""
logger.debug("Getting project name in %s", root_dir)
with open("pyproject.toml") as f:
pyproject = tomli.loads(f.read())
return pyproject.get("project", {}).get("name")

return hasattr(sys, "gettotalrefcount")

def build_project(name, root_dir):
"""Build locally the project using meson

def _distutils_dir_name(dname="lib"):
"""
Returns the name of a distutils build directory
:param str name: Name of the project.
:param str root_dir: Root directory of the project
:return: The path to the directory were build was performed
"""
platform = distutils.util.get_platform()
architecture = "%s.%s-%i.%i" % (dname, platform,
sys.version_info[0], sys.version_info[1])
if is_debug_python():
architecture += "-pydebug"
return architecture


def _distutils_scripts_name():
"""Return the name of the distrutils scripts sirectory"""
f = "scripts-{version[0]}.{version[1]}"
return f.format(version=sys.version_info)
extra = []
libdir = "lib"
if sys.platform == "win32":
libdir = "Lib"
# extra = ["--buildtype", "plain"]

build = os.path.join(root_dir, "build")
if not(os.path.isdir(build) and os.path.isdir(os.path.join(build, name))):
p = subprocess.Popen(["meson", "setup", "build"],
shell=False, cwd=root_dir, env=os.environ)
p.wait()
p = subprocess.Popen(["meson", "configure", "--prefix", "/"] + extra,
shell=False, cwd=build, env=os.environ)
p.wait()
p = subprocess.Popen(["meson", "install", "--destdir", "."],
shell=False, cwd=build, env=os.environ)
logger.debug("meson install ended with rc= %s", p.wait())

home = None
if os.environ.get("PYBUILD_NAME") == name:
# we are in the debian packaging way
home = os.environ.get("PYTHONPATH", "").split(os.pathsep)[-1]
if not home:
if os.environ.get("BUILDPYTHONPATH"):
home = os.path.abspath(os.environ.get("BUILDPYTHONPATH", ""))
else:
if sys.platform == "win32":
home = os.path.join(build, libdir, "site-packages")
else:
python_version = f"python{sys.version_info.major}.{sys.version_info.minor}"
home = os.path.join(build, libdir, python_version, "site-packages")
home = os.path.abspath(home)

cnt = 0
while not os.path.isdir(home):
cnt += 1
home = os.path.split(home)[0]
for _ in range(cnt):
n = os.listdir(home)[0]
home = os.path.join(home, n)

def _get_available_scripts(path):
res = []
try:
res = " ".join([s.rstrip('.py') for s in os.listdir(path)])
except OSError:
res = ["no script available, did you ran "
"'python setup.py build' before bootstrapping ?"]
return res
logger.warning("Building %s to %s", name, home)

return home

if sys.version_info[0] >= 3: # Python3

def execfile(fullpath, globals=None, locals=None):
"Python3 implementation for execfile"
with open(fullpath) as f:
try:
data = f.read()
except UnicodeDecodeError:
raise SyntaxError("Not a Python script")
code = compile(data, fullpath, 'exec')
exec(code, globals, locals)
def execfile(fullpath, globals=None, locals=None):
"Python3 implementation for execfile"
with open(fullpath) as f:
try:
data = f.read()
except UnicodeDecodeError:
raise SyntaxError("Not a Python script")
code = compile(data, fullpath, 'exec')
exec(code, globals, locals)


def run_file(filename, argv):
Expand Down Expand Up @@ -117,21 +138,18 @@ def run_file(filename, argv):
run.wait()


def run_entry_point(entry_point, argv):
def run_entry_point(target_name, entry_point, argv):
"""
Execute an entry_point using the current python context
(http://setuptools.readthedocs.io/en/latest/setuptools.html#automatic-script-creation)

:param str entry_point: A string identifying a function from a module
(NAME = PACKAGE.MODULE:FUNCTION [EXTRA])
(NAME = PACKAGE.MODULE:FUNCTION)
:param argv: list of arguments
"""
import importlib
elements = entry_point.split("=")
target_name = elements[0].strip()
elements = elements[1].split(":")
elements = entry_point.split(":")
module_name = elements[0].strip()
# Take care of entry_point optional "extra" requirements declaration
function_name = elements[1].split()[0].strip()
function_name = elements[1].strip()

logger.info("Execute target %s (function %s from module %s) using importlib", target_name, function_name, module_name)
full_args = [target_name]
Expand Down Expand Up @@ -163,74 +181,49 @@ def find_executable(target):
if os.path.isfile(target):
return ("path", os.path.abspath(target))

# search the file from setup.py
import setup
config = setup.get_project_configuration(dry_run=True)
# scripts from project configuration
if "scripts" in config:
for script_name in config["scripts"]:
if os.path.basename(script_name) == target:
return ("path", os.path.abspath(script_name))
# entry-points from project configuration
if "entry_points" in config:
for kind in config["entry_points"]:
for entry_point in config["entry_points"][kind]:
elements = entry_point.split("=")
name = elements[0].strip()
if name == target:
return ("entry_point", entry_point)

# search the file from env PATH
for dirname in os.environ.get("PATH", "").split(os.pathsep):
path = os.path.join(dirname, target)
if os.path.isfile(path):
return ("path", path)
# search the executable in pyproject.toml
with open(os.path.join(PROJECT_DIR, "pyproject.toml")) as f:
pyproject = tomli.loads(f.read())

scripts = {}
scripts.update(pyproject.get("project", {}).get("scripts", {}))
scripts.update(pyproject.get("project", {}).get("gui-scripts", {}))

for script, entry_point in scripts.items():
if script == target:
print(script, entry_point)
return ("entry_point", target, entry_point)
return None, None


def main(argv):
parser = ArgumentParser(prog="bootstrap", usage="./bootstrap.py <script>",
description=__doc__)
parser.add_argument("script", nargs="*")
parser.add_argument("-m", help="run library module as a script (terminates option list)")
PROJECT_DIR = os.path.dirname(os.path.abspath(__file__))
PROJECT_NAME = get_project_name(PROJECT_DIR)
logger.info("Project name: %s", PROJECT_NAME)

Options = collections.namedtuple("Options", ["script", "module"])
if len(argv) == 1:
options = Options(script=None, module=None)
if __name__ == "__main__":
LIBPATH = build_project(PROJECT_NAME, PROJECT_DIR)
if len(sys.argv) < 2:
logger.warning("usage: ./bootstrap.py <script>\n")
script = None
else:
if argv[1] in ["-h", "--help"]:
parser.print_help()
return
if argv[1] == "-m":
if len(argv) < 3:
parser.parse_args(argv[1:])
return
options = Options(script=None, module=argv[2:])
else:
options = Options(script=argv[1:], module=None)

if options.script is not None:
logger.info("Executing %s from source checkout", options.script)
script = options.script[0]
argv = options.script[1:]
kind, target = find_executable(script)
if kind == "path":
run_file(target, argv)
elif kind == "entry_point":
run_entry_point(target, argv)
script = sys.argv[1]

if script:
logger.info("Executing %s from source checkout", script)
else:
logging.info("Running iPython by default")
sys.path.insert(0, LIBPATH)
logger.info("Patched sys.path with %s", LIBPATH)

if script:
argv = sys.argv[2:]
res = find_executable(script)
if res[0] == "path":
run_file(res[1], argv)
elif res[0] == "entry_point":
run_entry_point(res[1], res[2], argv)
else:
logger.error("Script %s not found", options.script)
elif options.module is not None:
logging.info("Running module %s", options.module)
import runpy
module = options.module[0]
try:
old = sys.argv
sys.argv = [None] + options.module[1:]
runpy.run_module(module, run_name="__main__", alter_sys=True)
finally:
sys.argv = old
logger.error("Script %s not found", script)
else:
logging.info("Running IPython by default")
logger.info("Patch the sys.argv: %s", sys.argv)
Expand All @@ -245,28 +238,3 @@ def main(argv):
else:
embed()


if __name__ == "__main__":
home = os.path.dirname(os.path.abspath(__file__))
LIBPATH = os.path.join(home, 'build', _distutils_dir_name('lib'))
cwd = os.getcwd()
os.chdir(home)
build = subprocess.Popen([sys.executable, "setup.py", "build"],
shell=False, cwd=os.path.dirname(os.path.abspath(__file__)))
build_rc = build.wait()
if not os.path.exists(LIBPATH):
logger.warning("`lib` directory does not exist, trying common Python3 lib")
LIBPATH = os.path.join(os.path.split(LIBPATH)[0], "lib")
os.chdir(cwd)

if build_rc == 0:
logger.info("Build process ended.")
else:
logger.error("Build process ended with rc=%s", build_rc)
sys.exit(-1)

sys.path.insert(0, LIBPATH)
logger.info("Patched sys.path with %s", LIBPATH)

main(sys.argv)

Loading
Loading