Skip to content
Draft
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
10 changes: 0 additions & 10 deletions .flake8

This file was deleted.

16 changes: 8 additions & 8 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,42 +18,42 @@ repos:

# Ruff replaces Black, isort, flake8, autoflake, pydocstyle
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.15.0
rev: v0.15.15
hooks:
- id: ruff
args: [--fix]
- id: ruff-format

# Check python types with MyPy
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.19.1
rev: v2.1.0
hooks:
- id: mypy

# Strip all output from jupyter notebook cells
- repo: https://github.com/kynan/nbstripout
rev: 0.9.0
rev: 0.9.1
hooks:
- id: nbstripout

# Run nbqa pre-commit hooks for jupyter notebooks
- repo: https://github.com/nbQA-dev/nbQA
rev: 1.9.1
hooks:
- id: nbqa-isort
args: ["--float-to-top"]
- id: nbqa-black
- id: nbqa-ruff
args: ["--fix"]
- id: nbqa-ruff-format

# Find dead code
- repo: https://github.com/jendrikseipp/vulture
rev: v2.14
rev: v2.16
hooks:
- id: vulture
args: ["--min-confidence", "70"]

# Security linter for Python code
- repo: https://github.com/PyCQA/bandit
rev: 1.9.3
rev: 1.9.4
hooks:
- id: bandit
args: ["--skip=B101,B301,B403,B605,B607"]
2 changes: 1 addition & 1 deletion .python-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.12
3.14
8 changes: 3 additions & 5 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ functions.

## Tech stack

- **Language:** Python 3.12 (strict: `>=3.12,<3.13`)
- **Language:** Python 3.14 (strict: `>=3.14`)
- **Package manager:** `uv` (lock file: `uv.lock`)
- **Build backend:** hatchling
- **Solvers:** Gurobi (primary), Pyomo/GLPK, HiGHS, PuLP, AMPL, CPLEX
Expand Down Expand Up @@ -59,11 +59,9 @@ bandit -r src/ --skip=B101,B301,B403,B605,B607 # Security linting
## Code conventions

- **Formatting:** 88-character line length (ruff/black compatible)
- **Type hints:** Required on all function signatures; use `typing` module types and
`numpy.typing.NDArray`
- **Type hints:** Required on all function signatures; use built-in generics (`list[X]`, `dict[K,V]`, `tuple[...]`) for Python 3.9+ style; `typing.Any`/`typing.Callable` still from `typing`; `numpy.typing.NDArray`
- **Docstrings:** NumPy-style with Parameters/Returns sections
- **Imports:** stdlib, then third-party, then local; sorted by isort (black profile);
no wildcard imports
- **Imports:** stdlib, then third-party, then local; sorted by ruff; no wildcard imports
- **Naming:** `snake_case` for functions/variables, `UPPER_CASE` for constants
- **Security:** Uses `secrets.SystemRandom()` for randomness; DB credentials via
environment variables
Expand Down
2 changes: 1 addition & 1 deletion mypy.ini
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

# Global options
explicit_package_bases = True
python_version = 3.12
python_version = 3.14
warn_unused_configs = True
ignore_missing_imports = True
; disallow_untyped_calls = True
Expand Down
84 changes: 39 additions & 45 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,75 +3,69 @@ name = "crash_code"
version = "1.0.0"
description = "Code for crashing optimization."
authors = [{ name = "Ricardo A. Collado" }]
requires-python = ">=3.12,<3.13"
requires-python = ">=3.14"
readme = "README.md"
dependencies = [
"pandas>=2.2.3,<3",
"numpy>=2.2.3,<3",
"scipy>=1.15.2,<2",
"networkx>=3.4.2,<4",
"matplotlib>=3.10.1,<4",
"pydot>=3.0.4,<4",
"sqlalchemy>=2.0.39,<3",
"pyfiglet>=1.0.2,<2",
"bootstrapped>=0.0.2,<0.0.3",
"jellyfish>=1.1.3,<2",
"statsmodels>=0.14.4,<0.15",
"ace-tools-open>=0.1.0,<0.2",
"pandas>=3.0.3",
"numpy>=2.4.6",
"scipy>=1.17.1",
"networkx>=3.6.1",
"matplotlib>=3.10.9",
"pydot>=4.0.1",
"sqlalchemy>=2.0.50",
"pyfiglet>=1.0.4",
"bootstrapped>=0.0.2",
"jellyfish>=1.2.1",
"statsmodels>=0.14.6",
"ace-tools-open>=0.1.0",
# Git submodules as local dependencies:
# "helper @ file:///${PROJECT_ROOT}/libs/helper",
]

[dependency-groups]
open_opt = [
"pyomo>=6.9.1,<7",
"glpk>=0.4.8,<0.5",
"highspy>=1.9.0,<2",
"pulp>=3.0.2,<4",
"amplpy>=0.14.0,<0.15",
"pyomo>=6.10.0",
"glpk>=0.4.8",
"highspy>=1.14.0",
"pulp>=3.3.2",
"amplpy>=0.16.1",
# Installed manually from source:
# uv pip install /path/to/pygmo.whl
# "pygmo>=2.19.7,<3",
# "pygmo>=2.19.7",
]
closed_opt = [
"gurobipy>=12.0.1,<13",
"cplex>=22.1.2.0,<23",
"gurobipy>=13.0.2",
"cplex>=22.2.0.0",
]
dev = [
"jupyter>=1.0.0,<2",
"notebook>=6.5.4,<7",
"mypy>=1.3.0,<2",
"types-python-dateutil>=2.9.0.20241206,<3",
"scipy-stubs>=1.15.2.1,<2",
"flake8>=6.0.0,<7",
"pre-commit>=3.3.1,<4",
"vulture>=2.13,<3",
"bandit>=1.7.10,<2",
"pydeps>=2.0.1,<3",
"isort>=5.12.0,<6",
"pydocstyle>=6.3.0,<7",
"black<23.3.0",
"nbqa>=1.8.5,<2",
"jupyter-contrib-nbextensions>=0.7.0,<0.8",
"nbstripout>=0.7.1,<0.8",
"jupyter>=1.1.1",
"notebook>=7.5.6",
"mypy>=2.1.0",
"types-python-dateutil>=2.9.0.20260518",
"scipy-stubs>=1.17.1.5",
"ruff>=0.15.15",
"pre-commit>=4.6.0",
"vulture>=2.16",
"bandit>=1.9.4",
"pydeps>=3.0.6",
"nbqa>=1.9.1",
"nbstripout>=0.9.1",
]
package = [
"wheel>=0.43.0,<0.44",
"pip~=24.0",
"wheel>=0.47.0",
"hatchling>=1.29.0",
]
doc = [
"mkdocs>=1.6.0,<2",
"mkdocstrings[python]>=0.25.1,<0.26",
"mkdocs-material>=9.5.23,<10",
"mkdocs>=1.6.1",
"mkdocstrings[python]>=1.0.4",
"mkdocs-material>=9.7.6",
"mkdocs-material-extensions>=1.3.1",
"mkdocs-autorefs>=1.4.4",
"python-markdown-math>=0.9",
]

[tool.uv]
default-groups = [
"dev",
]
default-groups = ["dev"]

[tool.hatch.build.targets.sdist]
include = [
Expand Down
28 changes: 13 additions & 15 deletions src/db_manager/driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@
import json
import os
import pickle
from typing import Any, Callable, Dict, List, Tuple, Type
from typing import Any, Callable

import pandas as pd
from networkx.readwrite import json_graph
from sqlalchemy import Column, ForeignKey, Sequence, create_engine
from sqlalchemy import URL, Column, ForeignKey, Sequence, create_engine
from sqlalchemy.dialects.postgresql import (
ARRAY,
BIGINT,
Expand All @@ -23,12 +23,10 @@
JSONB,
TEXT,
)
from sqlalchemy.engine.url import URL
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship, sessionmaker
from sqlalchemy.orm import declarative_base, relationship, sessionmaker


def initialize_db() -> Tuple[ # pylint: disable=too-many-statements
def initialize_db() -> tuple[ # pylint: disable=too-many-statements
Callable,
Callable,
Callable,
Expand All @@ -54,8 +52,8 @@ def initialize_db() -> Tuple[ # pylint: disable=too-many-statements
- close_db: Function to close the database session.
"""
# Database connection from environment variables
connect_url = URL(
"postgres",
connect_url = URL.create(
"postgresql",
host=os.environ["crash_db_host"],
port=os.environ["crash_db_port"],
username=os.environ["crash_db_user"],
Expand All @@ -64,7 +62,7 @@ def initialize_db() -> Tuple[ # pylint: disable=too-many-statements
)

# db = create_engine(connect_url)
Base: Type = declarative_base() # pylint: disable=invalid-name
Base: type = declarative_base() # pylint: disable=invalid-name

class Meta(Base): # pylint: disable=unused-variable
"""Metadata grouping for crash experiments.
Expand Down Expand Up @@ -189,8 +187,8 @@ class Output(Base):
experiment_id = 0

def push_experiment_db(
seeds: List[int],
attributes: Dict[str, Any],
seeds: list[int],
attributes: dict[str, Any],
run_time: float = 0.0,
) -> int:
"""Serialize and insert a new experiment row.
Expand Down Expand Up @@ -265,8 +263,8 @@ def push_experiment_db(

def push_iteration_db(
cov_matrix: pd.DataFrame,
partition_list: List[Dict[str, Any]],
attributes: Dict[str, Any],
partition_list: list[dict[str, Any]],
attributes: dict[str, Any],
iteration_number: int,
elapsed_iter_time: float,
) -> None:
Expand Down Expand Up @@ -329,12 +327,12 @@ def update_exp_time(new_time: float) -> None:
nonlocal experiment_id
nonlocal session

experiment = session.query(Experiment).get(experiment_id)
experiment = session.get(Experiment, experiment_id)
experiment.exp_time = new_time
session.commit()
return

def push_solution_db(solution: Dict[str, Any]) -> None:
def push_solution_db(solution: dict[str, Any]) -> None:
"""Insert a solution row for the current experiment.

Parameters
Expand Down
15 changes: 7 additions & 8 deletions src/gen_manager/crash.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,15 @@
"""

from collections import deque
from typing import List

from numpy.random import uniform
import numpy as np


def generate_crash_times(
no_of_nodes: int,
low_limit: float,
high_limit: float,
) -> List[float]:
) -> list[float]:
"""Generate activity crash times in percentage.

Parameters
Expand All @@ -28,10 +27,10 @@ def generate_crash_times(

Returns
-------
List[float]
list[float]
List of generated crash times.
"""
crash_time_deque = deque(uniform(low_limit, high_limit, no_of_nodes))
crash_time_deque = deque(np.random.uniform(low_limit, high_limit, no_of_nodes))
crash_time_deque.appendleft(0.0)
crash_time_deque.append(0.0)

Expand All @@ -44,7 +43,7 @@ def generate_crash_cost(
no_of_nodes: int,
low_cost: float,
high_cost: float,
) -> List[float]:
) -> list[float]:
"""Generate activity crash costs.

Parameters
Expand All @@ -58,10 +57,10 @@ def generate_crash_cost(

Returns
-------
List[float]
list[float]
List of generated crash costs.
"""
crash_cost_deque = deque(uniform(low_cost, high_cost, no_of_nodes))
crash_cost_deque = deque(np.random.uniform(low_cost, high_cost, no_of_nodes))
crash_cost_deque.appendleft(0.0)
crash_cost_deque.append(0.0)

Expand Down
8 changes: 4 additions & 4 deletions src/gen_manager/distribution.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@
"""

import secrets
from typing import Any, Dict
from typing import Any

import numpy as np
from scipy.stats import beta


def generate_pert_distributions(geom_prob: Dict[Any, float]) -> Dict[str, Any]:
def generate_pert_distributions(geom_prob: dict[Any, float]) -> dict[str, Any]:
"""Generate beta distributions for activity times.

Parameters
Expand All @@ -24,7 +24,7 @@ def generate_pert_distributions(geom_prob: Dict[Any, float]) -> Dict[str, Any]:

Returns
-------
dict of str to Any
dict[str, Any]
Dictionary with:

- ``"distributions"``: mapping from node id to frozen
Expand Down Expand Up @@ -111,7 +111,7 @@ def generate_pert_distributions(geom_prob: Dict[Any, float]) -> Dict[str, Any]:
}


def generate_geometric(no_of_nodes: int) -> Dict[int, float]:
def generate_geometric(no_of_nodes: int) -> dict[int, float]:
"""Generate probabilities for geometric distributions.

Used to select the projects betas.
Expand Down
Loading