Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion .github/workflows/check_cmake_format.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/check_code_formatting.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/check_python_flake8.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/check_python_format.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/check_python_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
16 changes: 11 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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
```

Expand Down Expand Up @@ -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
81 changes: 57 additions & 24 deletions cpp/lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
import copy
from fnmatch import fnmatch
import functools
import importlib.metadata
import importlib.util
import logging
import operator
import os
Expand All @@ -19,11 +21,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]?)"

Expand All @@ -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

Expand Down Expand Up @@ -274,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:
Expand All @@ -300,7 +316,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

Expand Down Expand Up @@ -393,16 +409,26 @@ 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):
Expand Down Expand Up @@ -542,9 +568,12 @@ 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):
Expand Down Expand Up @@ -767,7 +796,9 @@ 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(
Expand Down Expand Up @@ -813,9 +844,11 @@ 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)
Expand Down