Skip to content

Stan 2.33: Move IO munging to external package, refactors #681

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 20 commits into from
Sep 5, 2023
Merged
Show file tree
Hide file tree
Changes from 18 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: 8 additions & 2 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ on:
required: false
default: ''

# only run one copy per PR
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true

jobs:
get-cmdstan-version:
# get the latest cmdstan version to use as part of the cache key
Expand All @@ -27,7 +32,8 @@ jobs:
if [[ "${{ github.event.inputs.cmdstan-version }}" != "" ]]; then
echo "version=${{ github.event.inputs.cmdstan-version }}" >> $GITHUB_OUTPUT
else
python -c 'import requests;print("version="+requests.get("https://api.github.com/repos/stan-dev/cmdstan/releases/latest").json()["tag_name"][1:])' >> $GITHUB_OUTPUT
echo "version=git:develop" >> $GITHUB_OUTPUT
# python -c 'import requests;print("version="+requests.get("https://api.github.com/repos/stan-dev/cmdstan/releases/latest").json()["tag_name"][1:])' >> $GITHUB_OUTPUT
fi
outputs:
version: ${{ steps.check-cmdstan.outputs.version }}
Expand All @@ -39,7 +45,7 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
python-version: ["3.7.1 - 3.7.16", "3.8", "3.9", "3.10", "3.11"]
python-version: ["3.8", "3.9", "3.10", "3.11"]
env:
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
steps:
Expand Down
4 changes: 2 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,15 @@ repos:
- id: isort
# https://github.com/python/black#version-control-integration
- repo: https://github.com/psf/black
rev: 22.10.0
rev: 23.7.0
hooks:
- id: black
- repo: https://github.com/pycqa/flake8
rev: 3.9.2
hooks:
- id: flake8
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v0.982
rev: v1.5.0
hooks:
- id: mypy
# Copied from setup.cfg
Expand Down
20 changes: 16 additions & 4 deletions cmdstanpy/compiler_opts.py
Original file line number Diff line number Diff line change
Expand Up @@ -275,8 +275,12 @@ 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) -> List[str]:
def compose_stanc(self, filename_in_msg: Optional[str]) -> List[str]:
opts = []

if filename_in_msg is not None:
opts.append(f'--filename-in-msg={filename_in_msg}')

if self._stanc_options is not None and len(self._stanc_options) > 0:
for key, val in self._stanc_options.items():
if key == 'include-paths':
Expand All @@ -295,11 +299,19 @@ def compose_stanc(self) -> List[str]:
opts.append(f'--{key}')
return opts

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

Parameters
----------
filename_in_msg : str, optional
filename to be displayed in stanc3 error messages
(if different from actual filename on disk), by default None
"""
opts = [
'STANCFLAGS+=' + flag.replace(" ", "\\ ")
for flag in self.compose_stanc()
for flag in self.compose_stanc(filename_in_msg)
]
if self._cpp_options is not None and len(self._cpp_options) > 0:
for key, val in self._cpp_options.items():
Expand Down
6 changes: 3 additions & 3 deletions cmdstanpy/install_cxx_toolchain.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
Linux: Not implemented
Optional command line arguments:
-v, --version : version, defaults to latest
-d, --dir : install directory, defaults to '~/.cmdstan(py)
-d, --dir : install directory, defaults to '~/.cmdstan
-s (--silent) : install with /VERYSILENT instead of /SILENT for RTools
-m --no-make : don't install mingw32-make (Windows RTools 4.0 only)
--progress : flag, when specified show progress bar for RTools download
Expand All @@ -27,7 +27,7 @@
from cmdstanpy.utils import pushd, validate_dir, wrap_url_progress_hook

EXTENSION = '.exe' if platform.system() == 'Windows' else ''
IS_64BITS = sys.maxsize > 2 ** 32
IS_64BITS = sys.maxsize > 2**32


def usage() -> None:
Expand Down Expand Up @@ -333,7 +333,7 @@ def parse_cmdline_args() -> Dict[str, Any]:
parser = argparse.ArgumentParser()
parser.add_argument('--version', '-v', help="version, defaults to latest")
parser.add_argument(
'--dir', '-d', help="install directory, defaults to '~/.cmdstan(py)"
'--dir', '-d', help="install directory, defaults to '~/.cmdstan"
)
parser.add_argument(
'--silent',
Expand Down
31 changes: 7 additions & 24 deletions cmdstanpy/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
Dict,
Iterable,
List,
Literal,
Mapping,
Optional,
TypeVar,
Expand Down Expand Up @@ -117,8 +118,7 @@ def __init__(
model_name: Optional[str] = None,
stan_file: OptionalPath = None,
exe_file: OptionalPath = None,
# TODO should be Literal['force'] not str
compile: Union[bool, str] = True,
compile: Union[bool, Literal['force']] = True,
stanc_options: Optional[Dict[str, Any]] = None,
cpp_options: Optional[Dict[str, Any]] = None,
user_header: OptionalPath = None,
Expand Down Expand Up @@ -300,7 +300,7 @@ def src_info(self) -> Dict[str, Any]:
cmd = (
[os.path.join(cmdstan_path(), 'bin', 'stanc' + EXTENSION)]
# handle include-paths, allow-undefined etc
+ self._compiler_options.compose_stanc()
+ self._compiler_options.compose_stanc(None)
+ ['--info', str(self.stan_file)]
)
proc = subprocess.run(cmd, capture_output=True, text=True, check=False)
Expand Down Expand Up @@ -343,7 +343,7 @@ def format(
cmd = (
[os.path.join(cmdstan_path(), 'bin', 'stanc' + EXTENSION)]
# handle include-paths, allow-undefined etc
+ self._compiler_options.compose_stanc()
+ self._compiler_options.compose_stanc(None)
+ [str(self.stan_file)]
)

Expand Down Expand Up @@ -528,7 +528,7 @@ def compile(
)
cmd = [make]
if self._compiler_options is not None:
cmd.extend(self._compiler_options.compose())
cmd.extend(self._compiler_options.compose(self._stan_file))
cmd.append(Path(exe_file).as_posix())

sout = io.StringIO()
Expand Down Expand Up @@ -996,10 +996,7 @@ def sample(
fixed_param = self._fixed_param

if chains is None:
if fixed_param:
chains = 1
else:
chains = 4
chains = 4
if chains < 1:
raise ValueError(
'Chains must be a positive integer value, found {}.'.format(
Expand Down Expand Up @@ -1090,8 +1087,7 @@ def sample(
one_process_per_chain = True
info_dict = self.exe_info()
stan_threads = info_dict.get('STAN_THREADS', 'false').lower()
# run multi-chain sampler unless algo is fixed_param or 1 chain
if fixed_param or (chains == 1):
if chains == 1:
force_one_process_per_chain = True

if (
Expand Down Expand Up @@ -1195,19 +1191,6 @@ def sample(
sampler_args.fixed_param = True
runset._args.method_args = sampler_args

# if there was an exe-file only initialization,
# this could happen, so throw a nice error
if (
sampler_args.fixed_param
and not one_process_per_chain
and chains > 1
):
raise RuntimeError(
"Cannot use single-process multichain parallelism"
" with algorithm fixed_param.\nTry setting argument"
" force_one_process_per_chain to True"
)

errors = runset.get_err_msgs()
if not runset._check_retcodes():
msg = (
Expand Down
Loading