diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml
index bcbadad51..91532521f 100644
--- a/.github/workflows/coverage.yml
+++ b/.github/workflows/coverage.yml
@@ -6,7 +6,7 @@ concurrency:
on:
push:
- branches:
+ branches:
- master
- live-debug*
- release/**
@@ -41,7 +41,7 @@ jobs:
python-version: ${{ env.PYTHON_VERSION }}
- uses: actions/checkout@v4
with:
- fetch-depth: 2
+ fetch-depth: 2
- name: Install Python3 dependencies
working-directory: ${{runner.workspace}}/nmodl
run: |
diff --git a/.github/workflows/nmodl-ci.yml b/.github/workflows/nmodl-ci.yml
index 1843739ca..903107f64 100644
--- a/.github/workflows/nmodl-ci.yml
+++ b/.github/workflows/nmodl-ci.yml
@@ -191,7 +191,7 @@ jobs:
path: ${{runner.workspace}}/nmodl/build/Testing/*/Test.xml
# This step will set up an SSH connection on tmate.io for live debugging.
- # To enable it, you have to:
+ # To enable it, you have to:
# * add 'live-debug-tests' to your PR title
# * push something to your PR branch (note that just re-running disregards the title update)
- name: live debug session on failure (manual steps required, check `nmodl-ci.yml`)
diff --git a/.github/workflows/nmodl-doc.yml b/.github/workflows/nmodl-doc.yml
index 28fcd606f..da1c062b3 100644
--- a/.github/workflows/nmodl-doc.yml
+++ b/.github/workflows/nmodl-doc.yml
@@ -6,7 +6,7 @@ concurrency:
on:
push:
- branches:
+ branches:
- master
- release/**
pull_request:
@@ -37,7 +37,7 @@ jobs:
uses: jwlawson/actions-setup-cmake@v2
with:
cmake-version: ${{ env.DESIRED_CMAKE_VERSION }}
-
+
- name: Install apt packages
run: |
sudo apt-get update
@@ -55,11 +55,17 @@ jobs:
with:
fetch-depth: 0
- - name: Install Python3 dependencies
+ - name: Documentation
+ id: documentation
working-directory: ${{runner.workspace}}/nmodl
run: |
- pip3 install -U pip setuptools
- pip3 install --user -r requirements.txt
+ echo "------- Build Documentation -------";
+ bash docs/generate_docs.sh public $(command -v python${PYTHON_VERSION})
+ touch public/docs/.nojekyll
+ echo "" > public/docs/index.html
+ echo "status=done" >> $GITHUB_OUTPUT
+ env:
+ CCACHE_DIR: ${{runner.workspace}}/ccache
# This step will set up an SSH connection on tmate.io for live debugging.
# To trigger it, simply add 'live-debug-docs' to your last pushed commit message.
@@ -67,37 +73,10 @@ jobs:
if: failure() && contains(github.event.head_commit.message, 'live-debug-docs')
uses: mxschmitt/action-tmate@v3
- - name: Restore compiler cache
- uses: actions/cache@v4
- with:
- path: |
- ${{runner.workspace}}/ccache
- key: docs-${{github.ref}}-${{github.sha}}
- restore-keys: |
- docs-${{github.ref}}-
- docs-
-
- - name: Documentation
- id: documentation
- working-directory: ${{runner.workspace}}/nmodl
- run: |
- echo "------- Build Documentation -------";
- ccache -z
- ccache -s
- python3 setup.py build_ext --inplace docs -j 2 -G Ninja \
- -- -DCMAKE_CXX_COMPILER_LAUNCHER=ccache;
- ccache -s
- cd _skbuild/linux-x86_64-3.8/setuptools/sphinx;
- rm -rf doctest doctrees && touch .nojekyll;
- echo "" > index.html;
- echo "status=done" >> $GITHUB_OUTPUT
- env:
- CCACHE_DIR: ${{runner.workspace}}/ccache
-
- name: Deploy 🚀
uses: JamesIves/github-pages-deploy-action@v4
if: steps.documentation.outputs.status == 'done' && startsWith(github.ref, 'refs/heads/master')
with:
branch: gh-pages # The branch the action should deploy to.
- folder: ${{runner.workspace}}/nmodl/_skbuild/linux-x86_64-3.8/setuptools/sphinx # The folder the action should deploy.
+ folder: ${{runner.workspace}}/nmodl/public/docs
clean: false # Automatically remove deleted files from the deploy branch
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4b628c4d3..4754ca822 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -26,6 +26,12 @@ set(NMODL_EXTRA_CXX_FLAGS
""
CACHE STRING "Add extra compile flags for NMODL sources")
separate_arguments(NMODL_EXTRA_CXX_FLAGS)
+option(LINK_AGAINST_PYTHON "Should the Python library be linked or not" ON)
+option(NMODL_BUILD_WHEEL "Flag to signal we are building a wheel" OFF)
+if(NMODL_BUILD_WHEEL)
+ set(LINK_AGAINST_PYTHON OFF)
+ set(NMODL_ENABLE_TESTS OFF)
+endif()
# =============================================================================
# Settings to enable project as submodule
@@ -166,12 +172,6 @@ endif()
message(STATUS "CHECKING FOR PYTHON")
find_package(PythonInterp 3.8 REQUIRED)
cpp_cc_strip_python_shims(EXECUTABLE "${PYTHON_EXECUTABLE}" OUTPUT PYTHON_EXECUTABLE)
-include(cmake/hpc-coding-conventions/cpp/cmake/bbp-find-python-module.cmake)
-cpp_cc_find_python_module(jinja2 2.9.3 REQUIRED)
-cpp_cc_find_python_module(pytest 3.3.0 REQUIRED)
-cpp_cc_find_python_module(sympy 1.3 REQUIRED)
-cpp_cc_find_python_module(textwrap 0.9 REQUIRED)
-cpp_cc_find_python_module(yaml 3.12 REQUIRED)
# =============================================================================
# Compiler specific flags for external submodules
diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst
index e61710636..6f21b8aaa 100644
--- a/CONTRIBUTING.rst
+++ b/CONTRIBUTING.rst
@@ -210,9 +210,8 @@ the Python API:
1. setup a sandbox environment with either *virtualenv*, *pyenv*, or
*pipenv*. For instance with *virtualenv*:
``python -m venv .venv && source .venv/bin/activate``
-2. build the Python package with the command: ``python setup.py build``
-3. install *pytest* Python package: ``pip install pytest``
-4. execute the unit-tests: ``pytest``
+2. build the Python wheel with the command: ``python -m pip wheel . --no-deps``
+3. execute the unit-tests for the wheel: ``bash packaging/test_wheel.bash $(command -v python) WHEEL``, where ``WHEEL`` is the path to the wheel generated in the previous step.
Memory Leaks and clang-tidy
~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/INSTALL.rst b/INSTALL.rst
index 72fff92bd..9c4fc6af4 100644
--- a/INSTALL.rst
+++ b/INSTALL.rst
@@ -45,8 +45,8 @@ of all dependencies we recommend using `homebrew `__:
brew install flex bison cmake python3
-The necessary Python packages can then easily be added using the pip3
-command.
+All of the Python dependencies (build, run, and development) can be installed
+using:
.. code:: sh
@@ -74,7 +74,8 @@ installed along with the system toolchain:
apt-get install flex bison gcc python3 python3-pip
-The Python dependencies are installed using:
+All of the Python dependencies (build, run, and development) can be installed
+using:
.. code:: sh
@@ -124,8 +125,8 @@ to cmake as:
-DBISON_EXECUTABLE=/usr/local/opt/bison/bin/bison \
-DCMAKE_INSTALL_PREFIX=$HOME/nmodl
-Using Python setuptools
-~~~~~~~~~~~~~~~~~~~~~~~
+Using the Python build system
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If you are mainly interested in the NMODL Framework parsing and analysis
tools and wish to use them from Python, we recommend building and
@@ -139,6 +140,19 @@ This should build the NMODL framework and install it into your pip user
``site-packages`` folder such that it becomes available as a Python
module.
+Building a wheel
+~~~~~~~~~~~~~~~~
+
+You can also build a wheel you can test and install in another environment using:
+
+.. code:: sh
+
+ pip3 wheel . --no-deps [-C OPTION1=VALUE1 -C OPTION2=VALUE2...] [--wheel-dir DIRECTORY]
+
+where the various ``OPTION`` values describe the build options (for a list of
+all available options, please consult the `reference `_).
+Notably, due to a bug in CMake, on MacOS one should pass ``-C build-dir=DIRECTORY`` to the above.
+
When building without linking against libpython
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -210,6 +224,16 @@ example in your Python 3 interpeter as follows:
SUFFIX hh
}
+You can also run all of the Python tests for a given wheel using:
+
+.. code:: sh
+
+ bash packaging/test_wheel.bash PYTHON_EXECUTABLE WHEEL
+
+where ``PYTHON_EXECUTABLE`` should be replaced by the path to the Python
+executable, and ``WHEEL`` should be replaced by the path to the wheel you wish
+to test.
+
NMODL is now setup correctly!
Generating Documentation
@@ -219,9 +243,14 @@ In order to build the documentation you must have additionally
``pandoc`` installed. Use your system’s package manager to do this
(e.g. ``sudo apt-get install pandoc``).
-You can build the entire documentation simply by using sphinx from
-``setup.py``:
+You can build the entire documentation simply by using the ``generate_docs.sh``
+script:
.. code:: sh
- python3 setup.py build_ext --inplace docs
+ bash docs/generate_docs.sh DIRECTORY [PYTHON_EXECUTABLE]
+
+where ``DIRECTORY`` is where you want to put the output files. The HTML
+documentation will then be available in ``DIRECTORY/docs``, and the temporary
+build will be stored in ``DIRECTORY/build``. You can also specify the path to
+the Python executable if it is not picked up automatically.
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
index 0f46c8548..663a792dc 100644
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -88,7 +88,7 @@ stages:
sudo apt-get install -y python3.8 python3.8-dev python3.8-venv ninja-build
sudo apt-get remove -y python3-importlib-metadata
python3.8 -m pip install --upgrade pip setuptools
- python3.8 -m pip install --user -r $(Build.Repository.LocalPath)/requirements.txt
+ python3.8 -m pip install --user -r requirements.txt
# we manually get version 3.15.0 to make sure that changes in the cmake
# files do not require unsupported versions of cmake in our package.
wget --quiet --output-document=- "https://github.com/Kitware/CMake/releases/download/$CMAKE_VER/$CMAKE_PKG.tar.gz" | tar xzpf -
@@ -149,7 +149,7 @@ stages:
- script: |
brew install flex bison cmake python@3
python3 -m pip install --upgrade pip setuptools
- python3 -m pip install --user -r $(Build.Repository.LocalPath)/requirements.txt
+ python3 -m pip install --user -r requirements.txt
displayName: 'Install Dependencies'
- script: |
export PATH=/usr/local/opt/flex/bin:/usr/local/opt/bison/bin:$PATH;
@@ -222,10 +222,16 @@ stages:
else
export TAG=""
fi
+ # the following 2 lines are a workaround for PEP 621 not allowing a
+ # dynamic `name` in `pyproject.toml`
+ python3 -m pip install --user tomli tomli-w
+ python3 packaging/change_name.py pyproject.toml "NMODL${TAG}"
+ export SETUPTOOLS_SCM_PRETEND_VERSION="$(git describe --tags | cut -d '-' -f 1,2 | tr - .)"
docker run --rm \
-w /root/nmodl \
-v $PWD:/root/nmodl \
-e NMODL_NIGHTLY_TAG=$TAG \
+ -e SETUPTOOLS_SCM_PRETEND_VERSION=$SETUPTOOLS_SCM_PRETEND_VERSION \
'bluebrain/nmodl:wheel' \
packaging/build_wheels.bash linux $(python.version)
condition: succeeded()
@@ -295,7 +301,11 @@ stages:
else
export NMODL_NIGHTLY_TAG=""
fi
- packaging/build_wheels.bash osx $(python.version)
+ # the following 2 lines are a workaround for PEP 621 not allowing a
+ # dynamic `name` in `pyproject.toml`
+ python3 -m pip install tomli tomli-w
+ python3 packaging/change_name.py pyproject.toml "NMODL${NMODL_NIGHTLY_TAG}"
+ SETUPTOOLS_SCM_PRETEND_VERSION="$(git describe --tags | cut -d '-' -f 1,2 | tr - .)" packaging/build_wheels.bash osx $(python.version)
condition: succeeded()
displayName: 'Build macos Wheel'
- task: PublishBuildArtifacts@1
diff --git a/docs/conf.py b/docs/conf.py
index e2695fb9e..ff9c2afbc 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -12,29 +12,14 @@
#
# All configuration values have a default; values that are commented out
# serve to show the default.
-
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
-
-
-
-import os
-import subprocess
-import sys
import textwrap
-# The project needs to be built before documentation in the usual build folder
-sys.path.insert(0, os.path.abspath('..'))
-
import nmodl # isort:skip
-os.environ['PYTHONPATH'] = ':'.join(sys.path)
-
-# Run doxygen
-subprocess.call('doxygen Doxyfile', shell=True)
-
# -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
@@ -134,11 +119,11 @@
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
-#html_static_path = ["_static"]
+# html_static_path = ["_static"]
-# A list of paths that contain extra files not directly related to the
-# documentation, such as robots.txt or .htaccess. Relative paths are taken
-# as relative to the configuration directory. They are copied to the output
+# A list of paths that contain extra files not directly related to the
+# documentation, such as robots.txt or .htaccess. Relative paths are taken
+# as relative to the configuration directory. They are copied to the output
# directory. They will overwrite any existing file of the same name.
html_extra_path = ["sphinx_doxygen"]
diff --git a/docs/generate_docs.sh b/docs/generate_docs.sh
new file mode 100755
index 000000000..c0a756d32
--- /dev/null
+++ b/docs/generate_docs.sh
@@ -0,0 +1,44 @@
+#!/usr/bin/env bash
+
+# script for generating documentation for NMODL
+
+set -eu
+
+if [ $# -lt 1 ]
+then
+ echo "Usage: $(basename "$0") output_dir [python_exe]"
+ exit 1
+fi
+
+# the dir where we put the temporary build and the docs
+output_dir="$1"
+# path to the Python executable
+python_exe="${2:-"$(command -v python3)"}"
+
+if ! [ -d "${output_dir}" ]
+then
+ mkdir -p "${output_dir}"
+fi
+
+build_dir="build"
+docs_dir="docs"
+
+echo "== Building documentation files in: ${output_dir}/${docs_dir} =="
+echo "== Temporary project build directory is: ${output_dir}/${build_dir} =="
+
+venv_name="${output_dir}/env"
+${python_exe} -m venv "${venv_name}"
+. "${venv_name}/bin/activate"
+python_exe="$(command -v python)"
+${python_exe} -m pip install -U pip
+${python_exe} -m pip install ".[docs]" -C build-dir="${output_dir}/${build_dir}"
+
+# the abs dir where this script is located (so we can call it from wherever)
+script_dir="$(cd "$(dirname "$0")"; pwd -P)"
+
+cd "${script_dir}"
+doxygen Doxyfile
+cd -
+sphinx-build docs/ "${output_dir}/${docs_dir}"
+
+deactivate
diff --git a/packaging/build_requirements.txt b/packaging/build_requirements.txt
deleted file mode 100644
index 9f6f031d0..000000000
--- a/packaging/build_requirements.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-Jinja2>=2.9.3
-PyYAML>=3.13
-pytest
-sympy>=1.3
-find_libpython
-scikit-build
diff --git a/packaging/build_wheels.bash b/packaging/build_wheels.bash
index 961033f3f..5dfb0fc49 100755
--- a/packaging/build_wheels.bash
+++ b/packaging/build_wheels.bash
@@ -12,8 +12,8 @@ set -xe
# - python (>=3.8)
# - C/C++ compiler
-if [ ! -f setup.py ]; then
- echo "Error: setup.py not found. Please launch $0 from the nmodl root dir"
+if ! [ -f pyproject.toml ]; then
+ echo "Error: pyproject.toml not found. Please launch $0 from the nmodl root dir"
exit 1
fi
@@ -47,14 +47,13 @@ build_wheel_linux() {
(( $skip )) && return 0
echo " - Installing build requirements"
- pip install pip auditwheel setuptools
- pip install -r packaging/build_requirements.txt
+ pip install pip auditwheel
echo " - Building..."
- rm -rf dist _skbuild
+ rm -rf dist _build
# Workaround for https://github.com/pypa/manylinux/issues/1309
git config --global --add safe.directory "*"
- python setup.py bdist_wheel
+ python -m pip wheel . --wheel-dir dist/ --no-deps
echo " - Repairing..."
auditwheel repair dist/*.whl
@@ -70,11 +69,13 @@ build_wheel_osx() {
(( $skip )) && return 0
echo " - Installing build requirements"
- pip install --upgrade delocate -r packaging/build_requirements.txt
+ pip install --upgrade delocate
echo " - Building..."
- rm -rf dist _skbuild
- python setup.py bdist_wheel
+ rm -rf dist _build
+ # the custom `build-dir` is a workaround for this issue:
+ # https://gitlab.kitware.com/cmake/cmake/-/issues/20107
+ python -m pip wheel . --wheel-dir dist/ -C build-dir=_build --no-deps
echo " - Repairing..."
delocate-wheel -w wheelhouse -v dist/*.whl # we started clean, there's a single wheel
@@ -82,34 +83,31 @@ build_wheel_osx() {
deactivate
}
-# platform for which wheel to be build
-platform=$1
+# platform for which wheel we are building
+platform="$1"
-# python version for which wheel to be built; 3* (default) means all python 3 versions
-python_wheel_version=3*
-if [ "$2" ]; then
- python_wheel_version=$2
-fi
+# python version for which wheel we are building; 3* (default) means all python 3 versions
+python_wheel_version="${2:-3*}"
# MAIN
-case "$1" in
+case "${platform}" in
linux)
- python_wheel_version=${python_wheel_version//[-._]/}
- for py_bin in /opt/python/cp${python_wheel_version}*/bin/python; do
+ python_wheel_version="${python_wheel_version//[-._]/}"
+ for py_bin in /opt/python/cp${python_wheel_version}-cp${python_wheel_version}/bin/python; do
build_wheel_linux "$py_bin"
done
;;
osx)
- for py_bin in /Library/Frameworks/Python.framework/Versions/${python_wheel_version}*/bin/python3; do
+ for py_bin in /Library/Frameworks/Python.framework/Versions/${python_wheel_version}/bin/python3; do
build_wheel_osx "$py_bin"
done
;;
*)
- echo "Usage: $(basename $0) [version]"
+ echo "Usage: $(basename "$0") [version]"
exit 1
;;
diff --git a/packaging/change_name.py b/packaging/change_name.py
new file mode 100755
index 000000000..478eb30c3
--- /dev/null
+++ b/packaging/change_name.py
@@ -0,0 +1,47 @@
+#!/usr/bin/env python3
+"""
+Barebones utility for changing the name of the package in `pyproject.toml`.
+"""
+import re
+from argparse import ArgumentParser
+from pathlib import Path
+
+import tomli
+import tomli_w
+
+
+def main():
+ parser = ArgumentParser(
+ description="Script for changing the name of a project in a pyproject.toml file",
+ )
+ parser.add_argument("pyproject_file", help="The path to the pyproject.toml file")
+ parser.add_argument("name", help="The new name of the project")
+ args = parser.parse_args()
+
+ if not Path(args.pyproject_file).exists():
+ raise FileNotFoundError(f"File {args.pyproject_file} not found")
+
+ with open(args.pyproject_file, "rb") as f:
+ toml_dict = tomli.load(f)
+
+ # check name is conforms to the naming convention
+ # see:
+ # https://packaging.python.org/en/latest/specifications/name-normalization/
+
+ if not re.match(
+ r"^([A-Z0-9]|[A-Z0-9][A-Z0-9._-]*[A-Z0-9])$",
+ args.name,
+ flags=re.IGNORECASE,
+ ):
+ raise ValueError(
+ f"The package name {args.name} does not conform to the standard Python package naming convention"
+ )
+
+ toml_dict["project"]["name"] = args.name
+
+ with open(args.pyproject_file, "wb") as f:
+ tomli_w.dump(toml_dict, f)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/packaging/test_wheel.bash b/packaging/test_wheel.bash
index 71abad95a..ac99d7bdf 100755
--- a/packaging/test_wheel.bash
+++ b/packaging/test_wheel.bash
@@ -23,16 +23,14 @@ test_wheel () {
# sample mod file for nrnivmodl check
TEST_DIR="$(mktemp -d)"
OUTPUT_DIR="$(mktemp -d)"
- cp "${this_dir}/../nmodl/ext/example/"*.mod "$TEST_DIR/"
+ cp "${this_dir}/../python/nmodl/ext/example/"*.mod "$TEST_DIR/"
cp "${this_dir}/../test/integration/mod/cabpump.mod" "${this_dir}/../test/integration/mod/var_init.inc" "$TEST_DIR/"
- cd "${this_dir}"
for mod in "${TEST_DIR}/"*.mod
do
nmodl -o "${OUTPUT_DIR}" "${mod}" sympy --analytic
$python_exe -c "import nmodl; driver = nmodl.NmodlDriver(); driver.parse_file('${mod}')"
done
$python_exe -m pytest -vvv "${this_dir}/../test/"
- cd -
}
echo "== Testing $python_wheel using $python_exe ($python_ver) =="
@@ -51,7 +49,7 @@ fi
# install nmodl
$python_exe -m pip install -U pip
-$python_exe -m pip install "${python_wheel}" pytest
+$python_exe -m pip install "${python_wheel}[test]"
$python_exe -m pip show nmodl || $python_exe -m pip show nmodl-nightly
# run tests
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 000000000..0d057c2f4
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,58 @@
+[project]
+name = "NMODL"
+authors = [
+ {name = "Blue Brain Project", email = "bbp-ou-hpc@groupes.epfl.ch"},
+]
+description = "NEURON Modeling Language Source-to-Source Compiler Framework"
+license = {file = "LICENSE"}
+readme = {file = "README.rst", content-type = "text/x-rst"}
+dynamic = ["version"]
+dependencies = [
+ "find_libpython",
+ "sympy>=1.3",
+ "importlib-metadata;python_version<'3.9'",
+ "importlib-resources;python_version<'3.9'",
+]
+scripts = {nmodl = "nmodl._binwrapper:main"}
+requires-python = ">=3.8"
+
+optional-dependencies.test = ["pytest>=3.3.0", "pytest-cov", "numpy"]
+optional-dependencies.docs = [
+ "jupyter-client",
+ "jupyter",
+ "myst_parser<2.0.0",
+ "mistune<3",
+ "nbconvert",
+ "nbsphinx>=0.3.2",
+ "sphinxcontrib-applehelp<1.0.3", # After this version it needs a toml file to work, no more setup.py
+ "sphinxcontrib-htmlhelp<=2.0.0", # After this version it needs a toml file to work, no more setup.py
+ "sphinx<6",
+ "sphinx-rtd-theme", # needs sphinx < 7
+ "docutils<0.20", # needed by sphinx
+]
+
+[build-system]
+requires = [
+ "scikit-build-core",
+ "setuptools-scm>=8.0",
+ "Jinja2>=2.9.3",
+ "PyYAML>=3.13",
+]
+build-backend = "scikit_build_core.build"
+
+[tool.scikit-build]
+metadata.version.provider = "scikit_build_core.metadata.setuptools_scm"
+wheel.packages = ["python/nmodl"]
+logging.level = "DEBUG"
+
+[tool.scikit-build.cmake]
+verbose = true
+version = ">=3.15.0"
+
+[tool.scikit-build.cmake.define]
+NMODL_BUILD_WHEEL = "ON"
+
+[tool.setuptools_scm]
+
+[tool.pytest.ini_options]
+testpaths = "test/unit/pybind"
diff --git a/nmodl/__init__.py b/python/nmodl/__init__.py
similarity index 100%
rename from nmodl/__init__.py
rename to python/nmodl/__init__.py
diff --git a/pywheel/shim/_binwrapper.py b/python/nmodl/_binwrapper.py
similarity index 86%
rename from pywheel/shim/_binwrapper.py
rename to python/nmodl/_binwrapper.py
index f85086431..036334ceb 100755
--- a/pywheel/shim/_binwrapper.py
+++ b/python/nmodl/_binwrapper.py
@@ -7,7 +7,6 @@
import stat
import sys
-
if sys.version_info >= (3, 9):
from importlib.metadata import metadata, PackageNotFoundError
from importlib.resources import files
@@ -18,7 +17,7 @@
from find_libpython import find_libpython
-def _config_exe(exe_name):
+def main():
"""Sets the environment to run the real executable (returned)"""
try:
@@ -42,12 +41,7 @@ def _config_exe(exe_name):
str(NMODL_PREFIX.parent) + ":" + os.environ.get("PYTHONPATH", "")
)
- return os.path.join(NMODL_BIN, exe_name)
-
-
-if __name__ == "__main__":
- """Set the pointed file as executable"""
- exe = _config_exe(os.path.basename(sys.argv[0]))
+ exe = NMODL_BIN / os.path.basename(sys.argv[0])
st = os.stat(exe)
os.chmod(exe, st.st_mode | stat.S_IEXEC)
os.execv(exe, sys.argv)
diff --git a/nmodl/ast.py b/python/nmodl/ast.py
similarity index 100%
rename from nmodl/ast.py
rename to python/nmodl/ast.py
diff --git a/nmodl/dsl.py b/python/nmodl/dsl.py
similarity index 100%
rename from nmodl/dsl.py
rename to python/nmodl/dsl.py
diff --git a/nmodl/ext/example/exp2syn.mod b/python/nmodl/ext/example/exp2syn.mod
similarity index 100%
rename from nmodl/ext/example/exp2syn.mod
rename to python/nmodl/ext/example/exp2syn.mod
diff --git a/nmodl/ext/example/expsyn.mod b/python/nmodl/ext/example/expsyn.mod
similarity index 100%
rename from nmodl/ext/example/expsyn.mod
rename to python/nmodl/ext/example/expsyn.mod
diff --git a/nmodl/ext/example/hh.mod b/python/nmodl/ext/example/hh.mod
similarity index 100%
rename from nmodl/ext/example/hh.mod
rename to python/nmodl/ext/example/hh.mod
diff --git a/nmodl/ext/example/passive.mod b/python/nmodl/ext/example/passive.mod
similarity index 100%
rename from nmodl/ext/example/passive.mod
rename to python/nmodl/ext/example/passive.mod
diff --git a/nmodl/ext/viz/css/tree.css b/python/nmodl/ext/viz/css/tree.css
similarity index 100%
rename from nmodl/ext/viz/css/tree.css
rename to python/nmodl/ext/viz/css/tree.css
diff --git a/nmodl/ext/viz/index.html b/python/nmodl/ext/viz/index.html
similarity index 100%
rename from nmodl/ext/viz/index.html
rename to python/nmodl/ext/viz/index.html
diff --git a/nmodl/ext/viz/js/d3.min.js b/python/nmodl/ext/viz/js/d3.min.js
similarity index 100%
rename from nmodl/ext/viz/js/d3.min.js
rename to python/nmodl/ext/viz/js/d3.min.js
diff --git a/nmodl/ext/viz/js/tree.js b/python/nmodl/ext/viz/js/tree.js
similarity index 100%
rename from nmodl/ext/viz/js/tree.js
rename to python/nmodl/ext/viz/js/tree.js
diff --git a/nmodl/ode.py b/python/nmodl/ode.py
similarity index 100%
rename from nmodl/ode.py
rename to python/nmodl/ode.py
diff --git a/nmodl/symtab.py b/python/nmodl/symtab.py
similarity index 100%
rename from nmodl/symtab.py
rename to python/nmodl/symtab.py
diff --git a/nmodl/visitor.py b/python/nmodl/visitor.py
similarity index 100%
rename from nmodl/visitor.py
rename to python/nmodl/visitor.py
diff --git a/pywheel/shim/nmodl b/pywheel/shim/nmodl
deleted file mode 120000
index cf9ff4fba..000000000
--- a/pywheel/shim/nmodl
+++ /dev/null
@@ -1 +0,0 @@
-_binwrapper.py
\ No newline at end of file
diff --git a/requirements.txt b/requirements.txt
index 804efaa69..665e4f40c 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,10 +1,26 @@
+# build time dependencies
+scikit-build-core
+setuptools-scm>=8.0
Jinja2>=2.9.3
PyYAML>=3.13
-pytest
+# runtime dependencies
+find_libpython
+sympy>=1.3
+importlib-metadata;python_version<'3.9'
+importlib-resources;python_version<'3.9'
+# dependencies for test
+pytest>=3.3.0
pytest-cov
-sympy
numpy
-find_libpython
-scikit-build
-importlib_resources;python_version<'3.9'
-importlib_metadata;python_version<'3.9'
\ No newline at end of file
+# dependencies for docs
+jupyter-client
+jupyter
+myst_parser<2.0.0
+mistune<3
+nbconvert
+nbsphinx>=0.3.2
+sphinxcontrib-applehelp<1.0.3
+sphinxcontrib-htmlhelp<=2.0.0
+sphinx<6
+sphinx-rtd-theme
+docutils<0.20
diff --git a/setup.cfg b/setup.cfg
index 9de58dd72..54a600626 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,6 +1,3 @@
-[tool:pytest]
-testpaths = test/unit/pybind
-
[doctest]
builder = doctest
diff --git a/setup.py b/setup.py
deleted file mode 100644
index c55bdc2a7..000000000
--- a/setup.py
+++ /dev/null
@@ -1,135 +0,0 @@
-# Copyright 2023 Blue Brain Project, EPFL.
-# See the top-level LICENSE file for details.
-#
-# SPDX-License-Identifier: Apache-2.0
-
-import inspect
-import os
-import subprocess
-import sys
-
-from setuptools import Command
-from skbuild import setup
-
-"""
-A generic wrapper to access nmodl binaries from a python installation
-Please create a softlink with the binary name to be called.
-"""
-import stat
-from find_libpython import find_libpython
-
-
-# Main source of the version. Dont rename, used by Cmake
-try:
- v = (
- subprocess.run(["git", "describe", "--tags"], stdout=subprocess.PIPE)
- .stdout.strip()
- .decode()
- )
- __version__ = v[: v.rfind("-")].replace("-", ".") if "-" in v else v
- # allow to override version during development/testing
- if "NMODL_WHEEL_VERSION" in os.environ:
- __version__ = os.environ['NMODL_WHEEL_VERSION']
-except Exception as e:
- raise RuntimeError("Could not get version from Git repo") from e
-
-
-class lazy_dict(dict):
- """When the value associated to a key is a function, then returns
- the function call instead of the function.
- """
-
- def __getitem__(self, item):
- value = dict.__getitem__(self, item)
- if inspect.isfunction(value):
- return value()
- return value
-
-
-def get_sphinx_command():
- """Lazy load of Sphinx distutils command class
- """
- # If nbconvert is installed to .eggs on the fly when running setup.py then
- # templates from it will not be found. This is a workaround.
- if 'JUPYTER_PATH' not in os.environ:
- import nbconvert
- os.environ['JUPYTER_PATH'] = os.path.realpath(os.path.join(os.path.dirname(nbconvert.__file__), '..', 'share', 'jupyter'))
- print("Setting JUPYTER_PATH={}".format(os.environ['JUPYTER_PATH']))
-
- from sphinx.setup_command import BuildDoc
-
- return BuildDoc
-
-
-class Docs(Command):
- description = "Generate & optionally upload documentation to docs server"
- user_options = []
- finalize_options = lambda self: None
- initialize_options = lambda self: None
-
- def run(self, *args, **kwargs):
- self.run_command("doctest")
- self.run_command("buildhtml")
-
-
-install_requirements = [
- "PyYAML>=3.13",
- "sympy>=1.3",
- "find_libpython",
- "importlib_resources;python_version<'3.9'",
- "importlib_metadata;python_version<'3.9'",
-]
-
-
-cmake_args = ["-DPYTHON_EXECUTABLE=" + sys.executable]
-if "bdist_wheel" in sys.argv:
- cmake_args.append("-DLINK_AGAINST_PYTHON=FALSE")
- cmake_args.append("-DNMODL_ENABLE_TESTS=FALSE")
-
-# For CI, we want to build separate wheel
-package_name = "NMODL"
-if "NMODL_NIGHTLY_TAG" in os.environ:
- package_name += os.environ["NMODL_NIGHTLY_TAG"]
-
-# Parse long description from README.rst
-with open('README.rst', 'r', encoding='utf-8') as f:
- long_description = f.read()
-
-setup(
- name=package_name,
- version=__version__,
- author="Blue Brain Project",
- author_email="bbp-ou-hpc@groupes.epfl.ch",
- description="NEURON Modeling Language Source-to-Source Compiler Framework",
- long_description=long_description,
- long_description_content_type='text/markdown',
- packages=["nmodl"],
- scripts=["pywheel/shim/nmodl"],
- include_package_data=True,
- cmake_minimum_required_version="3.15.0",
- cmake_args=cmake_args,
- cmdclass=lazy_dict(
- docs=Docs, doctest=get_sphinx_command, buildhtml=get_sphinx_command,
- ),
- zip_safe=False,
- # myst_parser 2.0.0 want sphinx >= 6 but it leads to incompatibily with sphinxcontrib-applehelp and
- # sphinxcontrib-htmlhelp that want PEP-517 support instead of setup.py (name clash with '-' and '.')
- # So we pin low versions of packages
- setup_requires=[
- "jinja2>=2.9.3",
- "jupyter-client",
- "jupyter",
- "myst_parser<2.0.0",
- "mistune<3",
- "nbconvert",
- "nbsphinx>=0.3.2",
- "pytest>=3.7.2",
- "sphinxcontrib-applehelp<1.0.3", # After this version it needs a toml file to work, no more setup.py
- "sphinxcontrib-htmlhelp<=2.0.0", # After this version it needs a toml file to work, no more setup.py
- "sphinx<6",
- "sphinx-rtd-theme", # needs sphinx < 7
- "docutils<0.20", # needed by sphinx
- ]
- + install_requirements,
- install_requires=install_requirements,
-)
diff --git a/src/language/code_generator.cmake b/src/language/code_generator.cmake
index 0c6ccae18..a3dea0767 100644
--- a/src/language/code_generator.cmake
+++ b/src/language/code_generator.cmake
@@ -34,9 +34,9 @@ set(CODE_GENERATOR_JINJA_FILES
set(CODE_GENERATOR_PY_FILES
${PROJECT_SOURCE_DIR}/src/language/argument.py
${PROJECT_SOURCE_DIR}/src/language/code_generator.py
+ ${PROJECT_SOURCE_DIR}/src/language/language_parser.py
${PROJECT_SOURCE_DIR}/src/language/node_info.py
${PROJECT_SOURCE_DIR}/src/language/nodes.py
- ${PROJECT_SOURCE_DIR}/src/language/language_parser.py
${PROJECT_SOURCE_DIR}/src/language/utils.py
)
diff --git a/src/pybind/CMakeLists.txt b/src/pybind/CMakeLists.txt
index 9600515e1..0d7516874 100644
--- a/src/pybind/CMakeLists.txt
+++ b/src/pybind/CMakeLists.txt
@@ -70,14 +70,14 @@ endif()
# =============================================================================
file(
GLOB NMODL_PYTHON_FILES
- RELATIVE "${NMODL_PROJECT_SOURCE_DIR}/nmodl/"
- CONFIGURE_DEPENDS "${NMODL_PROJECT_SOURCE_DIR}/nmodl/*.py")
+ RELATIVE "${NMODL_PROJECT_SOURCE_DIR}/python/nmodl/"
+ CONFIGURE_DEPENDS "${NMODL_PROJECT_SOURCE_DIR}/python/nmodl/*.py")
foreach(file IN LISTS NMODL_PYTHON_FILES)
- cpp_cc_build_time_copy(INPUT ${NMODL_PROJECT_SOURCE_DIR}/nmodl/${file} OUTPUT
+ cpp_cc_build_time_copy(INPUT ${NMODL_PROJECT_SOURCE_DIR}/python/nmodl/${file} OUTPUT
${CMAKE_BINARY_DIR}/lib/nmodl/${file})
endforeach()
-file(COPY ${NMODL_PROJECT_SOURCE_DIR}/nmodl/ext DESTINATION ${CMAKE_BINARY_DIR}/lib/nmodl/)
+file(COPY ${NMODL_PROJECT_SOURCE_DIR}/python/nmodl/ext DESTINATION ${CMAKE_BINARY_DIR}/lib/nmodl/)
# =============================================================================
# Install python binding components