@@ -207,6 +207,52 @@ def test_model_info(self):
207207 self .assertIn ('theta' , model_info_include ['parameters' ])
208208 self .assertIn ('included_files' , model_info_include )
209209
210+ def test_compile_with_includes (self ):
211+ getmtime = os .path .getmtime
212+ configs = [
213+ ('add_one_model.stan' , ['include-path' ]),
214+ ('bernoulli_include.stan' , []),
215+ ]
216+ for stan_file , include_paths in configs :
217+ stan_file = os .path .join (DATAFILES_PATH , stan_file )
218+ include_paths = [
219+ os .path .join (DATAFILES_PATH , path ) for path in include_paths
220+ ]
221+
222+ # Compile for the first time.
223+ model = CmdStanModel (
224+ stan_file = stan_file ,
225+ compile = False ,
226+ stanc_options = {"include-paths" : include_paths },
227+ )
228+ with LogCapture (level = logging .INFO ) as log :
229+ model .compile ()
230+ log .check_present (
231+ ('cmdstanpy' , 'INFO' , StringComparison ('compiling stan file' ))
232+ )
233+
234+ # Compile for the second time, ensuring cache is used.
235+ with LogCapture (level = logging .DEBUG ) as log :
236+ model .compile ()
237+ log .check_present (
238+ ('cmdstanpy' , 'DEBUG' , StringComparison ('found newer exe file' ))
239+ )
240+
241+ # Compile after modifying included file, ensuring cache is not used.
242+ def _patched_getmtime (filename : str ) -> float :
243+ includes = ['divide_real_by_two.stan' , 'add_one_function.stan' ]
244+ if any (filename .endswith (include ) for include in includes ):
245+ return float ('inf' )
246+ return getmtime (filename )
247+
248+ with LogCapture (level = logging .INFO ) as log , patch (
249+ 'os.path.getmtime' , side_effect = _patched_getmtime
250+ ):
251+ model .compile ()
252+ log .check_present (
253+ ('cmdstanpy' , 'INFO' , StringComparison ('compiling stan file' ))
254+ )
255+
210256 def test_compile_force (self ):
211257 if os .path .exists (BERN_EXE ):
212258 os .remove (BERN_EXE )
0 commit comments