From bbcbc1180d1f869d78067f89e937d21195e5c44b Mon Sep 17 00:00:00 2001 From: Goran Jelic-Cizmek Date: Fri, 29 Aug 2025 17:47:17 +0200 Subject: [PATCH 01/11] Update CI to Ubuntu 24.04 --- .github/workflows/check_cmake_format.yml | 2 +- .github/workflows/check_code_formatting.yml | 2 +- .github/workflows/check_python_flake8.yml | 2 +- .github/workflows/check_python_format.yml | 2 +- .github/workflows/check_python_test.yml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/check_cmake_format.yml b/.github/workflows/check_cmake_format.yml index cd6952e..a874036 100644 --- a/.github/workflows/check_cmake_format.yml +++ b/.github/workflows/check_cmake_format.yml @@ -4,7 +4,7 @@ on: [pull_request, push] jobs: build: name: check-cmake-format - runs-on: ubuntu-20.04 + runs-on: ubuntu-24.04 # Run on external PRs, but not internal PRs as they'll be run by the push if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository diff --git a/.github/workflows/check_code_formatting.yml b/.github/workflows/check_code_formatting.yml index ae4cda6..0b6bc4f 100644 --- a/.github/workflows/check_code_formatting.yml +++ b/.github/workflows/check_code_formatting.yml @@ -4,7 +4,7 @@ on: [pull_request, push] jobs: build: name: check-code-formatting - runs-on: ubuntu-20.04 + runs-on: ubuntu-24.04 # Run on external PRs, but not internal PRs as they'll be run by the push if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository diff --git a/.github/workflows/check_python_flake8.yml b/.github/workflows/check_python_flake8.yml index 9fdcd9d..2273e16 100644 --- a/.github/workflows/check_python_flake8.yml +++ b/.github/workflows/check_python_flake8.yml @@ -4,7 +4,7 @@ on: [pull_request, push] jobs: build: name: check-python-flake8 - runs-on: ubuntu-20.04 + runs-on: ubuntu-24.04 # Run on external PRs, but not internal PRs as they'll be run by the push if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository diff --git a/.github/workflows/check_python_format.yml b/.github/workflows/check_python_format.yml index 40eb00f..185daa1 100644 --- a/.github/workflows/check_python_format.yml +++ b/.github/workflows/check_python_format.yml @@ -4,7 +4,7 @@ on: [pull_request, push] jobs: build: name: check-python-format - runs-on: ubuntu-20.04 + runs-on: ubuntu-24.04 # Run on external PRs, but not internal PRs as they'll be run by the push if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository diff --git a/.github/workflows/check_python_test.yml b/.github/workflows/check_python_test.yml index ce42f39..71944b8 100644 --- a/.github/workflows/check_python_test.yml +++ b/.github/workflows/check_python_test.yml @@ -4,7 +4,7 @@ on: [pull_request, push] jobs: build: name: check-python-test - runs-on: ubuntu-20.04 + runs-on: ubuntu-24.04 # Run on external PRs, but not internal PRs as they'll be run by the push if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository From 724846bae320b3e8ad616d4b77329f9678d793cf Mon Sep 17 00:00:00 2001 From: Goran Jelic-Cizmek Date: Fri, 29 Aug 2025 18:18:25 +0200 Subject: [PATCH 02/11] Remove typing import --- cpp/lib.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cpp/lib.py b/cpp/lib.py index bf3add0..e41a615 100644 --- a/cpp/lib.py +++ b/cpp/lib.py @@ -19,11 +19,9 @@ import subprocess import sys import tempfile -from typing import List import urllib.request import venv - THIS_SCRIPT_DIR = Path(__file__).resolve().parent DEFAULT_RE_EXTRACT_VERSION = "([0-9]+\\.[0-9]+(\\.[0-9]+)?[ab]?)" @@ -300,7 +298,7 @@ def interpreter(self) -> str: """ return self.bin_dir.joinpath("python") - def pip_cmd(self, *args) -> List[str]: + def pip_cmd(self, *args) -> list[str]: """ Execute a pip command From 8e23e3dcd97fc54c968cde917c7b58c9505a03e5 Mon Sep 17 00:00:00 2001 From: Goran Jelic-Cizmek Date: Fri, 29 Aug 2025 18:31:03 +0200 Subject: [PATCH 03/11] Corrected version --- cpp/lib.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/cpp/lib.py b/cpp/lib.py index e41a615..ec912d8 100644 --- a/cpp/lib.py +++ b/cpp/lib.py @@ -8,6 +8,8 @@ import copy from fnmatch import fnmatch import functools +import importlib.metadata +import importlib.util import logging import operator import os @@ -811,9 +813,10 @@ def find_version(self, path: str) -> str: pkg_name = self.name if isinstance(self.config["capabilities"].pip_pkg, str): pkg_name = self.config["capabilities"].pip_pkg - import pkg_resources - return pkg_resources.get_distribution(pkg_name).version + import packaging.requirements + req = packaging.requirements.Requirement(pkg_name) + return importlib.metadata.version(req.name) cmd = [path] + self._config["version_opt"] log_command(cmd) From 30f0adef3aeb19d9586b02172695c338316b74db Mon Sep 17 00:00:00 2001 From: Goran Jelic-Cizmek Date: Fri, 29 Aug 2025 19:00:58 +0200 Subject: [PATCH 04/11] Fix issue with validating version --- cpp/lib.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cpp/lib.py b/cpp/lib.py index ec912d8..40fda5d 100644 --- a/cpp/lib.py +++ b/cpp/lib.py @@ -542,9 +542,9 @@ def requirement(self): name = pip_pkg else: name = self.name - import pkg_resources - return pkg_resources.Requirement.parse(f"{name} {self.user_config['version']}") + import packaging.requirements + return packaging.requirements.Requirement(f"{name} {self.user_config['version']}") @abc.abstractmethod def configure(self): @@ -767,7 +767,7 @@ def find_tool_in_path(self, search_paths=None): if not paths: raise FileNotFoundError(f"Could not find tool {self}") all_paths = [(p, self.find_version(p)) for p in paths] - paths = list(filter(lambda tpl: tpl[1] in self.requirement, all_paths)) + paths = list(filter(lambda tpl: self.requirement.specifier.contains(tpl[1]), all_paths)) paths = list(sorted(paths, key=lambda tup: tup[1])) # sort by version if not paths: raise FileNotFoundError( From 54d88e3a0c4c5f3803bbc817916786b77d07cbf1 Mon Sep 17 00:00:00 2001 From: Goran Jelic-Cizmek Date: Fri, 29 Aug 2025 19:02:43 +0200 Subject: [PATCH 05/11] This one works as well maybe --- cpp/lib.py | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/cpp/lib.py b/cpp/lib.py index 40fda5d..7966cd1 100644 --- a/cpp/lib.py +++ b/cpp/lib.py @@ -36,22 +36,31 @@ def forget_python_pkg(package): Args: package: name of the Python package to exclude """ - import pkg_resources - - try: - dist = pkg_resources.get_distribution(package) - except pkg_resources.DistributionNotFound: - return + dist_location = None + dist = importlib.metadata.distribution(package) + if dist.files: + # Get the parent directory of the first file in the distribution + first_file = next(iter(dist.files)) + dist_location = str(first_file.locate().parent.parent) + else: + # Fallback: try to get location from sys.path and package name + try: + spec = importlib.util.find_spec(package) + if spec and spec.origin: + # Get the parent directory containing the package + dist_location = Path(spec.origin).parent.parent + except AttributeError: + pass PYTHONPATH = os.environ.get("PYTHONPATH") - if PYTHONPATH is not None and dist.location in PYTHONPATH: + if PYTHONPATH is not None and dist_location in PYTHONPATH: logging.debug( "Remove incompatible version of %s in PYTHONPATH: %s", package, - dist.location, + dist_location, ) - os.environ["PYTHONPATH"] = PYTHONPATH.replace(dist.location, "") + os.environ["PYTHONPATH"] = PYTHONPATH.replace(dist_location, "") try: - sys.path.remove(dist.location) + sys.path.remove(dist_location) except ValueError: pass From 00facb034a7316ba7c0153f57a329be4b28de261 Mon Sep 17 00:00:00 2001 From: Goran Jelic-Cizmek Date: Fri, 29 Aug 2025 19:04:38 +0200 Subject: [PATCH 06/11] Not working :( --- cpp/lib.py | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/cpp/lib.py b/cpp/lib.py index 7966cd1..ebcc118 100644 --- a/cpp/lib.py +++ b/cpp/lib.py @@ -402,16 +402,25 @@ def is_requirement_met(self, requirement) -> bool: False otherwise """ try: - import pkg_resources + import packaging.requirements + # Parse the requirement string + req = packaging.requirements.Requirement(str(requirement)) + + # Check if the package is installed + try: + dist = importlib.metadata.distribution(req.name) + except importlib.metadata.PackageNotFoundError: + return False + + # Check if the version satisfies the requirement + if req.specifier and not req.specifier.contains(dist.version): + return False - pkg_resources.require(str(requirement)) return True except ImportError: - self._install_requirement("setuptools", restart=True) - except pkg_resources.ContextualVersionConflict as conflict: - forget_python_pkg(conflict.req.name) - return False - except (pkg_resources.VersionConflict, pkg_resources.DistributionNotFound): + self._install_requirement("packaging", restart=True) + except Exception: + # Handle any parsing or version checking errors return False def ensure_requirement(self, requirement, restart=True): From 7f7e44481d24ce7cca9099a4a985a50bd328bcd7 Mon Sep 17 00:00:00 2001 From: Goran Jelic-Cizmek Date: Fri, 29 Aug 2025 19:10:20 +0200 Subject: [PATCH 07/11] Revert "This one works as well maybe" This reverts commit 54d88e3a0c4c5f3803bbc817916786b77d07cbf1. --- cpp/lib.py | 29 ++++++++++------------------- 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/cpp/lib.py b/cpp/lib.py index ebcc118..66f323c 100644 --- a/cpp/lib.py +++ b/cpp/lib.py @@ -36,31 +36,22 @@ def forget_python_pkg(package): Args: package: name of the Python package to exclude """ - dist_location = None - dist = importlib.metadata.distribution(package) - if dist.files: - # Get the parent directory of the first file in the distribution - first_file = next(iter(dist.files)) - dist_location = str(first_file.locate().parent.parent) - else: - # Fallback: try to get location from sys.path and package name - try: - spec = importlib.util.find_spec(package) - if spec and spec.origin: - # Get the parent directory containing the package - dist_location = Path(spec.origin).parent.parent - except AttributeError: - pass + import pkg_resources + + try: + dist = pkg_resources.get_distribution(package) + except pkg_resources.DistributionNotFound: + return PYTHONPATH = os.environ.get("PYTHONPATH") - if PYTHONPATH is not None and dist_location in PYTHONPATH: + if PYTHONPATH is not None and dist.location in PYTHONPATH: logging.debug( "Remove incompatible version of %s in PYTHONPATH: %s", package, - dist_location, + dist.location, ) - os.environ["PYTHONPATH"] = PYTHONPATH.replace(dist_location, "") + os.environ["PYTHONPATH"] = PYTHONPATH.replace(dist.location, "") try: - sys.path.remove(dist_location) + sys.path.remove(dist.location) except ValueError: pass From 353a5bcadc876e7d1d6b71f846993a5f8b4c2545 Mon Sep 17 00:00:00 2001 From: Goran Jelic-Cizmek Date: Fri, 29 Aug 2025 19:16:11 +0200 Subject: [PATCH 08/11] Updates --- cpp/lib.py | 43 +++++++++++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/cpp/lib.py b/cpp/lib.py index 66f323c..790a77c 100644 --- a/cpp/lib.py +++ b/cpp/lib.py @@ -36,22 +36,39 @@ def forget_python_pkg(package): Args: package: name of the Python package to exclude """ - import pkg_resources - try: - dist = pkg_resources.get_distribution(package) - except pkg_resources.DistributionNotFound: + dist = importlib.metadata.distribution(package) + except importlib.metadata.PackageNotFoundError: + return + + dist_location = None + if dist.files: + # Get the parent directory of the first file in the distribution + first_file = next(iter(dist.files)) + dist_location = str(first_file.locate().parent.parent) + else: + # Fallback: try to get location from sys.path and package name + try: + spec = importlib.util.find_spec(package) + if spec and spec.origin: + # Get the parent directory containing the package + dist_location = str(Path(spec.origin).parent.parent) + except (AttributeError, ImportError): + pass + + if dist_location is None: return + PYTHONPATH = os.environ.get("PYTHONPATH") - if PYTHONPATH is not None and dist.location in PYTHONPATH: + if PYTHONPATH is not None and dist_location in PYTHONPATH: logging.debug( "Remove incompatible version of %s in PYTHONPATH: %s", package, - dist.location, + dist_location, ) - os.environ["PYTHONPATH"] = PYTHONPATH.replace(dist.location, "") + os.environ["PYTHONPATH"] = PYTHONPATH.replace(dist_location, "") try: - sys.path.remove(dist.location) + sys.path.remove(dist_location) except ValueError: pass @@ -553,7 +570,9 @@ def requirement(self): name = self.name import packaging.requirements - return packaging.requirements.Requirement(f"{name} {self.user_config['version']}") + return packaging.requirements.Requirement( + f"{name} {self.user_config['version']}" + ) @abc.abstractmethod def configure(self): @@ -776,7 +795,11 @@ def find_tool_in_path(self, search_paths=None): if not paths: raise FileNotFoundError(f"Could not find tool {self}") all_paths = [(p, self.find_version(p)) for p in paths] - paths = list(filter(lambda tpl: self.requirement.specifier.contains(tpl[1]), all_paths)) + paths = list( + filter( + lambda tpl: self.requirement.specifier.contains(tpl[1]), all_paths + ) + ) paths = list(sorted(paths, key=lambda tup: tup[1])) # sort by version if not paths: raise FileNotFoundError( From e5ddbe27372d86eaed62415a7c3ca3b1ab9daa0b Mon Sep 17 00:00:00 2001 From: Goran Jelic-Cizmek Date: Fri, 29 Aug 2025 19:18:49 +0200 Subject: [PATCH 09/11] Fix formatting --- cpp/lib.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/cpp/lib.py b/cpp/lib.py index 790a77c..5e08422 100644 --- a/cpp/lib.py +++ b/cpp/lib.py @@ -411,6 +411,7 @@ def is_requirement_met(self, requirement) -> bool: """ try: import packaging.requirements + # Parse the requirement string req = packaging.requirements.Requirement(str(requirement)) @@ -570,6 +571,7 @@ def requirement(self): name = self.name import packaging.requirements + return packaging.requirements.Requirement( f"{name} {self.user_config['version']}" ) @@ -796,9 +798,7 @@ def find_tool_in_path(self, search_paths=None): raise FileNotFoundError(f"Could not find tool {self}") all_paths = [(p, self.find_version(p)) for p in paths] paths = list( - filter( - lambda tpl: self.requirement.specifier.contains(tpl[1]), all_paths - ) + filter(lambda tpl: self.requirement.specifier.contains(tpl[1]), all_paths) ) paths = list(sorted(paths, key=lambda tup: tup[1])) # sort by version if not paths: @@ -847,6 +847,7 @@ def find_version(self, path: str) -> str: pkg_name = self.config["capabilities"].pip_pkg import packaging.requirements + req = packaging.requirements.Requirement(pkg_name) return importlib.metadata.version(req.name) From b5ef999fe06302f299ed9b47160adff0136c0349 Mon Sep 17 00:00:00 2001 From: Goran Jelic-Cizmek Date: Fri, 29 Aug 2025 19:41:27 +0200 Subject: [PATCH 10/11] Remove uselesstools --- cpp/lib.py | 1 - 1 file changed, 1 deletion(-) diff --git a/cpp/lib.py b/cpp/lib.py index 5e08422..0bb6a68 100644 --- a/cpp/lib.py +++ b/cpp/lib.py @@ -291,7 +291,6 @@ def __init__(self, path: str): assert isinstance(path, Path) self._path = path os.environ["PIP_DISABLE_PIP_VERSION_CHECK"] = "1" - self.ensure_requirement("setuptools", restart=True) @property def path(self) -> str: From 30c996fffcf933e19ad4dfb0b0b13f2be67a1641 Mon Sep 17 00:00:00 2001 From: Goran Jelic-Cizmek Date: Tue, 21 Oct 2025 16:00:37 +0200 Subject: [PATCH 11/11] Update readme --- README.md | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 08cb3d1..fa3ea8c 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,9 @@ -# BlueBrain HPC Team C++ Development Guidelines +# NEURON Team Development Guidelines + +**IMPORTANT NOTE**: this is a fork of the archived [Blue Brain Project HPC Team coding conventions](https://github.com/BlueBrain/hpc-coding-conventions), adapted for use in NEURON. This document describes both C++ development guidelines adopted by -HPC team, and the tools and processes required to +the NEURON team, and the tools and processes required to ensure they are properly followed over time. ## Documentation @@ -54,7 +56,7 @@ Optionally, it will also look for: You can import this CMake project into your Git repository using a git submodule: ``` -git submodule add https://github.com/BlueBrain/hpc-coding-conventions.git +git submodule add https://github.com/neuronsimulator/coding-conventions.git git submodule update --init --recursive ``` @@ -384,9 +386,13 @@ This project provides helper functions to deal with these dependencies: Should you want to contribute to the naming conventions, please refer to the dedicated [contributing document](./cpp/formatting/CONTRIBUTING.md) first. +## Funding + +The development of this software was supported by funding to the Laboratory of Neural Microcircuitry (LNMC), a research center of the École polytechnique fédérale de Lausanne (EPFL), with funding from European Union's Horizon Europe Grant no. 101147319 (EBRAINS 2.0: A Research Infrastructure to Advance Neuroscience and Brain Health). -## Funding & Acknowledgment +## Past Funding The development of this software was supported by funding to the Blue Brain Project, a research center of the École polytechnique fédérale de Lausanne (EPFL), from the Swiss government's ETH Board of the Swiss Federal Institutes of Technology. -Copyright © 2019-2022 Blue Brain Project/EPFL +Copyright © 2019-2024 Blue Brain Project/EPFL +Copyright © 2025-2026 EPFL