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/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
env:
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
steps:
Expand Down
4 changes: 2 additions & 2 deletions cmdstanpy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,13 @@ def _cleanup_tmpdir() -> None:
from .utils import (
cmdstan_path,
cmdstan_version,
disable_logging,
enable_logging,
install_cmdstan,
set_cmdstan_path,
set_make_env,
show_versions,
write_stan_json,
enable_logging,
disable_logging,
)

__all__ = [
Expand Down
48 changes: 26 additions & 22 deletions cmdstanpy/cmdstan_args.py
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like this file got processed with string normalization turned on before you updated the pyproject.toml -- mind reverting those changes?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Woops, good catch.

As a side note, we're pretty inconsistent throughout the library with string quoting. It'd be a big edit, but is there any desire to just go ahead and normalize everything to either single or double quotes and be consistent going forward?

Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
"""
CmdStan arguments
"""

import os
from enum import Enum, auto
from time import time
from typing import Any, Dict, List, Mapping, Optional, Union
from typing import Any, Mapping, Optional, Union

import numpy as np
from numpy.random import default_rng
Expand Down Expand Up @@ -65,9 +66,9 @@ def __init__(
thin: Optional[int] = None,
max_treedepth: Optional[int] = None,
metric: Union[
str, Dict[str, Any], List[str], List[Dict[str, Any]], None
str, dict[str, Any], list[str], list[dict[str, Any]], None
] = None,
step_size: Union[float, List[float], None] = None,
step_size: Union[float, list[float], None] = None,
adapt_engaged: bool = True,
adapt_delta: Optional[float] = None,
adapt_init_phase: Optional[int] = None,
Expand All @@ -84,7 +85,7 @@ def __init__(
self.max_treedepth = max_treedepth
self.metric = metric
self.metric_type: Optional[str] = None
self.metric_file: Union[str, List[str], None] = None
self.metric_file: Union[str, list[str], None] = None
self.step_size = step_size
self.adapt_engaged = adapt_engaged
self.adapt_delta = adapt_delta
Expand Down Expand Up @@ -161,8 +162,9 @@ def validate(self, chains: Optional[int]) -> None:
):
if self.step_size <= 0:
raise ValueError(
'Argument "step_size" must be > 0, '
'found {}.'.format(self.step_size)
'Argument "step_size" must be > 0, found {}.'.format(
self.step_size
)
)
else:
if len(self.step_size) != chains:
Expand Down Expand Up @@ -217,9 +219,9 @@ def validate(self, chains: Optional[int]) -> None:
)
)
if all(isinstance(elem, dict) for elem in self.metric):
metric_files: List[str] = []
metric_files: list[str] = []
for i, metric in enumerate(self.metric):
metric_dict: Dict[str, Any] = metric # type: ignore
metric_dict: dict[str, Any] = metric # type: ignore
if 'inv_metric' not in metric_dict:
raise ValueError(
'Entry "inv_metric" not found in metric dict '
Expand Down Expand Up @@ -343,7 +345,7 @@ def validate(self, chains: Optional[int]) -> None:
'When fixed_param=True, cannot specify adaptation parameters.'
)

def compose(self, idx: int, cmd: List[str]) -> List[str]:
def compose(self, idx: int, cmd: list[str]) -> list[str]:
"""
Compose CmdStan command for method-specific non-default arguments.
"""
Expand Down Expand Up @@ -467,7 +469,7 @@ def validate(self, _chains: Optional[int] = None) -> None:
positive_float(self.tol_param, 'tol_param')
positive_int(self.history_size, 'history_size')

def compose(self, _idx: int, cmd: List[str]) -> List[str]:
def compose(self, _idx: int, cmd: list[str]) -> list[str]:
"""compose command string for CmdStan for non-default arg values."""
cmd.append('method=optimize')
if self.algorithm:
Expand Down Expand Up @@ -511,7 +513,7 @@ def validate(self, _chains: Optional[int] = None) -> None:
raise ValueError(f'Invalid path for mode file: {self.mode}')
positive_int(self.draws, 'draws')

def compose(self, _idx: int, cmd: List[str]) -> List[str]:
def compose(self, _idx: int, cmd: list[str]) -> list[str]:
"""compose command string for CmdStan for non-default arg values."""
cmd.append('method=laplace')
cmd.append(f'mode={self.mode}')
Expand Down Expand Up @@ -579,7 +581,7 @@ def validate(self, _chains: Optional[int] = None) -> None:
positive_int(self.num_draws, 'num_draws')
positive_int(self.num_elbo_draws, 'num_elbo_draws')

def compose(self, _idx: int, cmd: List[str]) -> List[str]:
def compose(self, _idx: int, cmd: list[str]) -> list[str]:
"""compose command string for CmdStan for non-default arg values."""
cmd.append('method=pathfinder')

Expand Down Expand Up @@ -624,12 +626,13 @@ def compose(self, _idx: int, cmd: List[str]) -> List[str]:
class GenerateQuantitiesArgs:
"""Arguments needed for generate_quantities method."""

def __init__(self, csv_files: List[str]) -> None:
def __init__(self, csv_files: list[str]) -> None:
"""Initialize object."""
self.sample_csv_files = csv_files

def validate(
self, chains: Optional[int] = None # pylint: disable=unused-argument
self,
chains: Optional[int] = None, # pylint: disable=unused-argument
) -> None:
"""
Check arguments correctness and consistency.
Expand All @@ -642,7 +645,7 @@ def validate(
'Invalid path for sample csv file: {}'.format(csv)
)

def compose(self, idx: int, cmd: List[str]) -> List[str]:
def compose(self, idx: int, cmd: list[str]) -> list[str]:
"""
Compose CmdStan command for method-specific non-default arguments.
"""
Expand Down Expand Up @@ -681,7 +684,8 @@ def __init__(
self.output_samples = output_samples

def validate(
self, chains: Optional[int] = None # pylint: disable=unused-argument
self,
chains: Optional[int] = None, # pylint: disable=unused-argument
) -> None:
"""
Check arguments correctness and consistency.
Expand All @@ -705,7 +709,7 @@ def validate(
positive_int(self.output_samples, 'output_samples')

# pylint: disable=unused-argument
def compose(self, idx: int, cmd: List[str]) -> List[str]:
def compose(self, idx: int, cmd: list[str]) -> list[str]:
"""
Compose CmdStan command for method-specific non-default arguments.
"""
Expand Down Expand Up @@ -747,7 +751,7 @@ def __init__(
self,
model_name: str,
model_exe: OptionalPath,
chain_ids: Optional[List[int]],
chain_ids: Optional[list[int]],
method_args: Union[
SamplerArgs,
OptimizeArgs,
Expand All @@ -757,8 +761,8 @@ def __init__(
PathfinderArgs,
],
data: Union[Mapping[str, Any], str, None] = None,
seed: Union[int, List[int], None] = None,
inits: Union[int, float, str, List[str], None] = None,
seed: Union[int, list[int], None] = None,
inits: Union[int, float, str, list[str], None] = None,
output_dir: OptionalPath = None,
sig_figs: Optional[int] = None,
save_latent_dynamics: bool = False,
Expand Down Expand Up @@ -959,11 +963,11 @@ def compose_command(
*,
diagnostic_file: Optional[str] = None,
profile_file: Optional[str] = None,
) -> List[str]:
) -> list[str]:
"""
Compose CmdStan command for non-default arguments.
"""
cmd: List[str] = []
cmd: list[str] = []
if idx is not None and self.chain_ids is not None:
if idx < 0 or idx > len(self.chain_ids) - 1:
raise ValueError(
Expand Down
34 changes: 17 additions & 17 deletions cmdstanpy/compilation.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from copy import copy
from datetime import datetime
from pathlib import Path
from typing import Any, Dict, Iterable, List, Optional, Union
from typing import Any, Iterable, Optional, Union

from cmdstanpy.utils import get_logger
from cmdstanpy.utils.cmdstan import (
Expand Down Expand Up @@ -81,8 +81,8 @@ class CompilerOptions:
def __init__(
self,
*,
stanc_options: Optional[Dict[str, Any]] = None,
cpp_options: Optional[Dict[str, Any]] = None,
stanc_options: Optional[dict[str, Any]] = None,
cpp_options: Optional[dict[str, Any]] = None,
user_header: OptionalPath = None,
) -> None:
"""Initialize object."""
Expand Down Expand Up @@ -116,12 +116,12 @@ def is_empty(self) -> bool:
)

@property
def stanc_options(self) -> Dict[str, Union[bool, int, str, Iterable[str]]]:
def stanc_options(self) -> dict[str, Union[bool, int, str, Iterable[str]]]:
"""Stanc compiler options."""
return self._stanc_options

@property
def cpp_options(self) -> Dict[str, Union[bool, int]]:
def cpp_options(self) -> dict[str, Union[bool, int]]:
"""C++ compiler options."""
return self._cpp_options

Expand Down Expand Up @@ -165,8 +165,8 @@ def validate_stanc_opts(self) -> None:
del self._stanc_options[deprecated]
else:
get_logger().warning(
'compiler option "%s" is deprecated and '
'should not be used',
'compiler option "%s" is deprecated and should '
'not be used',
deprecated,
)
for key, val in self._stanc_options.items():
Expand Down Expand Up @@ -225,8 +225,8 @@ def validate_cpp_opts(self) -> None:
val = self._cpp_options[key]
if not isinstance(val, int) or val < 0:
raise ValueError(
f'{key} must be a non-negative integer value,'
f' found {val}.'
f'{key} must be a non-negative integer '
f'value, found {val}.'
)

def validate_user_header(self) -> None:
Expand Down Expand Up @@ -298,7 +298,7 @@ def add_include_path(self, path: str) -> None:
elif path not in self._stanc_options['include-paths']:
self._stanc_options['include-paths'].append(path)

def compose_stanc(self, filename_in_msg: Optional[str]) -> List[str]:
def compose_stanc(self, filename_in_msg: Optional[str]) -> list[str]:
opts = []

if filename_in_msg is not None:
Expand All @@ -322,7 +322,7 @@ def compose_stanc(self, filename_in_msg: Optional[str]) -> List[str]:
opts.append(f'--{key}')
return opts

def compose(self, filename_in_msg: Optional[str] = None) -> List[str]:
def compose(self, filename_in_msg: Optional[str] = None) -> list[str]:
"""
Format makefile options as list of strings.

Expand All @@ -344,7 +344,7 @@ def compose(self, filename_in_msg: Optional[str] = None) -> List[str]:

def src_info(
stan_file: str, compiler_options: CompilerOptions
) -> Dict[str, Any]:
) -> dict[str, Any]:
"""
Get source info for Stan program file.

Expand All @@ -363,15 +363,15 @@ def src_info(
f"Failed to get source info for Stan model "
f"'{stan_file}'. Console:\n{proc.stderr}"
)
result: Dict[str, Any] = json.loads(proc.stdout)
result: dict[str, Any] = json.loads(proc.stdout)
return result


def compile_stan_file(
src: Union[str, Path],
force: bool = False,
stanc_options: Optional[Dict[str, Any]] = None,
cpp_options: Optional[Dict[str, Any]] = None,
stanc_options: Optional[dict[str, Any]] = None,
cpp_options: Optional[dict[str, Any]] = None,
user_header: OptionalPath = None,
) -> str:
"""
Expand Down Expand Up @@ -480,7 +480,7 @@ def compile_stan_file(
"If the issue persists please open a bug report"
)
raise ValueError(
f"Failed to compile Stan model '{src}'. " f"Console:\n{console}"
f"Failed to compile Stan model '{src}'. Console:\n{console}"
)
return str(exe_target)

Expand All @@ -492,7 +492,7 @@ def format_stan_file(
canonicalize: Union[bool, str, Iterable[str]] = False,
max_line_length: int = 78,
backup: bool = True,
stanc_options: Optional[Dict[str, Any]] = None,
stanc_options: Optional[dict[str, Any]] = None,
) -> None:
"""
Run stanc's auto-formatter on the model code. Either saves directly
Expand Down
25 changes: 12 additions & 13 deletions cmdstanpy/install_cmdstan.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
--cores: int, number of cores to use when building, defaults to 1
-c, --compiler : flag, add C++ compiler to path (Windows only)
"""

import argparse
import json
import os
Expand All @@ -30,7 +31,7 @@
from collections import OrderedDict
from pathlib import Path
from time import sleep
from typing import TYPE_CHECKING, Any, Callable, Dict, Optional, Union
from typing import TYPE_CHECKING, Any, Callable, Optional, Union

from tqdm.auto import tqdm

Expand Down Expand Up @@ -85,7 +86,7 @@ def is_windows() -> bool:
EXTENSION = '.exe' if is_windows() else ''


def get_headers() -> Dict[str, str]:
def get_headers() -> dict[str, str]:
"""Create headers dictionary."""
headers = {}
GITHUB_PAT = os.environ.get("GITHUB_PAT") # pylint:disable=invalid-name
Expand Down Expand Up @@ -287,13 +288,13 @@ def build(verbose: bool = False, progress: bool = True, cores: int = 1) -> None:
raise CmdStanInstallError(f'Command "make build" failed\n{str(e)}')
if not os.path.exists(os.path.join('bin', 'stansummary' + EXTENSION)):
raise CmdStanInstallError(
f'bin/stansummary{EXTENSION} not found'
', please rebuild or report a bug!'
f'bin/stansummary{EXTENSION} not found, please rebuild or '
'report a bug!'
)
if not os.path.exists(os.path.join('bin', 'diagnose' + EXTENSION)):
raise CmdStanInstallError(
f'bin/stansummary{EXTENSION} not found'
', please rebuild or report a bug!'
f'bin/stansummary{EXTENSION} not found, please rebuild or '
'report a bug!'
)

if is_windows():
Expand Down Expand Up @@ -417,8 +418,8 @@ def install_version(
)
if overwrite and os.path.exists('.'):
print(
'Overwrite requested, remove existing build of version '
'{}'.format(cmdstan_version)
'Overwrite requested, remove existing build '
'of version {}'.format(cmdstan_version)
)
clean_all(verbose)
print('Rebuilding version {}'.format(cmdstan_version))
Expand Down Expand Up @@ -496,10 +497,8 @@ def retrieve_version(version: str, progress: bool = True) -> None:
break
except urllib.error.HTTPError as e:
raise CmdStanRetrieveError(
'HTTPError: {}\n'
'Version {} not available from github.com.'.format(
e.code, version
)
'HTTPError: {}\nVersion {} not available from '
'github.com.'.format(e.code, version)
) from e
except urllib.error.URLError as e:
print(
Expand Down Expand Up @@ -645,7 +644,7 @@ def run_install(args: Union[InteractiveSettings, InstallationSettings]) -> None:
compile_example(args.verbose)


def parse_cmdline_args() -> Dict[str, Any]:
def parse_cmdline_args() -> dict[str, Any]:
parser = argparse.ArgumentParser("install_cmdstan")
parser.add_argument(
'--interactive',
Expand Down
Loading
Loading