Repository: stan-dev/cmdstanpy
Pull request #79 (2019-07-18 18:13:59)

Minor fixes
#### Submission Checklist

- [x] Run unit tests
- [x] Declare copyright holder and open-source license: see below

#### Summary
Minor fixes like exception type, more logging ad additional args check.

#### Copyright and Licensing

Please list the copyright holder for the work you are submitting (this will be you or your assignee, such as a university or company):

- Salesforce

By submitting this pull request, the copyright holder is agreeing to license the submitted work under the following licenses:
- Code: BSD 3-clause (https://opensource.org/licenses/BSD-3-Clause)




Patch:
diff --git a/README.md b/README.md
index baf19e7..78a806e 100644
--- a/README.md
+++ b/README.md
@@ -31,15 +31,17 @@ The CmdStanPy, CmdStan, and the core Stan C++ code are licensed under new BSD.
 ::
 
     import os
-    from cmdstanpy import cmdstan_path, compile_model, RunSet, sample, summary
+    from cmdstanpy import Model, StanFit, cmdstan_path
 
-    # create model
-    bernoulli_stan = os.path.join(cmdstan_path(), 'examples', 'bernoulli', 'bernoulli.stan')
-    bernoulli_model = compile_model(bernoulli_stan)
+    # specify Stan file, create, compile Model object
+    bernoulli_path = os.path.join(cmdstan_path(), 'examples', 'bernoulli', 'bernoulli.stan')
+    bernoulli_model = Model(stan_file=bernoulli_path)
+    bernoulli_model.compile()
 
-    # setup data and fit the model
+
+    # specify data, fit the model
     bernoulli_data = { "N" : 10, "y" : [0,1,0,0,0,0,0,0,0,1] }
-    bernoulli_fit = sample(bernoulli_model, data=bernoulli_data)
+    bernoulli_fit = bernoulli_model.sample(chains=5, cores=3, data=bernoulli_data)
 
-    # print summary
-    print(summary(bern_fit))
+    # summarize the results (wraps CmdStan `bin/stansummary`):
+    bernoulli_fit.summary()
diff --git a/cmdstanpy/cmdstan_args.py b/cmdstanpy/cmdstan_args.py
index 45f41e4..856bf8b 100644
--- a/cmdstanpy/cmdstan_args.py
+++ b/cmdstanpy/cmdstan_args.py
@@ -248,6 +248,10 @@ class OptimizeArgs(object):
             )
 
         if self.init_alpha is not None:
+            if self.algorithm == "Newton":
+                raise ValueError(
+                    "init_alpha must not be set when algorithm is Newton"
+                )
             if isinstance(self.init_alpha, Real):
                 if self.init_alpha < 0:
                     raise ValueError("init_alpha must be greater than 0")
diff --git a/cmdstanpy/model.py b/cmdstanpy/model.py
index 5978705..60dcc6b 100644
--- a/cmdstanpy/model.py
+++ b/cmdstanpy/model.py
@@ -130,7 +130,7 @@ class Model(object):
             hpp_file = os.path.splitext(stan_file)[0] + '.hpp'
             hpp_file = Path(hpp_file).as_posix()
             if overwrite or not os.path.exists(hpp_file):
-                self._logger.info('stan to c++ ({})'.format(hpp_file))
+                self._logger.info('stan to c++ (%s)', hpp_file)
                 stanc_path = os.path.join(
                     cmdstan_path(), 'bin', 'stanc' + EXTENSION
                 )
@@ -190,7 +190,7 @@ class Model(object):
             else:
                 self._exe_file = exe_file
 
-        self._logger.info('compiled model file: {}'.format(self._exe_file))
+        self._logger.info('compiled model file: %s', self._exe_file)
 
     def optimize(
             self,
@@ -269,7 +269,7 @@ class Model(object):
                 msg = '{} Got returned error code {}'.format(
                     msg, stanfit._retcode(dummy_chain_id)
                 )
-            raise Exception(msg)
+            raise RuntimeError(msg)
         stanfit._validate_csv_files()
         return stanfit
 
@@ -435,10 +435,10 @@ class Model(object):
                 'cores must be a positive integer value, found {}'.format(cores)
             )
         if cores > cores_avail:
-            self._logger.warn(
-                'requested {} cores, only {} available'.format(
-                    cores, cpu_count()
-                )
+            self._logger.warning(
+                'requested %u cores, only %u available',
+                cores,
+                cpu_count()
             )
             cores = cores_avail
 
@@ -482,7 +482,7 @@ class Model(object):
                         msg = '{}, chain {} returned error code {}'.format(
                             msg, i, stanfit._retcode(i)
                         )
-                raise Exception(msg)
+                raise RuntimeError(msg)
             stanfit._validate_csv_files()
         return stanfit
 
@@ -492,14 +492,15 @@ class Model(object):
         Spawn process, capture console output to file, record returncode.
         """
         cmd = stanfit.cmds[idx]
-        self._logger.info('start chain {}.  '.format(idx + 1))
+        self._logger.info('start chain %u', idx + 1)
+        self._logger.debug('sampling: %s', cmd)
         proc = subprocess.Popen(
             cmd.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE
         )
         proc.wait()
         stdout, stderr = proc.communicate()
         transcript_file = stanfit.console_files[idx]
-        self._logger.info('finish chain {}.  '.format(idx + 1))
+        self._logger.info('finish chain %u', idx + 1)
         with open(transcript_file, 'w+') as transcript:
             if stdout:
                 transcript.write(stdout.decode('utf-8'))
diff --git a/cmdstanpy/stanfit.py b/cmdstanpy/stanfit.py
index 1b7c602..0c84363 100644
--- a/cmdstanpy/stanfit.py
+++ b/cmdstanpy/stanfit.py
@@ -401,9 +401,9 @@ class StanFit(object):
                 )
             try:
                 self._logger.debug(
-                    'saving tmpfile: "{}" as: "{}"'.format(
-                        self.csv_files[i], to_path
-                    )
+                    'saving tmpfile: "%s" as: "%s"',
+                    self.csv_files[i],
+                    to_path
                 )
                 shutil.move(self.csv_files[i], to_path)
                 self.csv_files[i] = to_path
diff --git a/cmdstanpy/utils.py b/cmdstanpy/utils.py
index 0199a4f..39e8490 100644
--- a/cmdstanpy/utils.py
+++ b/cmdstanpy/utils.py
@@ -59,7 +59,7 @@ class MaybeDictToFilePath(object):
                         mode='w+', suffix='.json', dir=TMPDIR, delete=False
                 ) as fd:
                     data_file = fd.name
-                    self._logger.debug('input tempfile: {}'.format(fd.name))
+                    self._logger.debug('input tempfile: %s', fd.name)
                     jsondump(data_file, o)
                 self._paths[i] = data_file
                 self._unlink[i] = True
@@ -431,7 +431,7 @@ def do_command(cmd: str, cwd: str = None, logger: logging.Logger = None) -> str:
     Throws exception on non-zero returncode.
     """
     if logger:
-        logger.debug("cmd: {}".format(cmd))
+        logger.debug('cmd: %s', cmd)
     proc = subprocess.Popen(
         cmd, cwd=cwd, stdout=subprocess.PIPE, stderr=subprocess.PIPE
     )


Test patch:
diff --git a/test/test_cmdstan_args.py b/test/test_cmdstan_args.py
index 8560070..f42a11a 100644
--- a/test/test_cmdstan_args.py
+++ b/test/test_cmdstan_args.py
@@ -24,6 +24,8 @@ class OptimizeArgsTest(unittest.TestCase):
         self.assertIn("init_alpha=0.0002", cmd)
         args = OptimizeArgs(init_alpha=-1.0)
         self.assertRaises(ValueError, lambda: args.validate())
+        args = OptimizeArgs(init_alpha=1.0, algorithm="Newton")
+        self.assertRaises(ValueError, lambda: args.validate())
 
     def test_args_algorithm_iter(self):
         args = OptimizeArgs(iter=400)