Skip to content

pytest migration#61

Open
fbrausse wants to merge 12 commits intomasterfrom
regr-pytest
Open

pytest migration#61
fbrausse wants to merge 12 commits intomasterfrom
regr-pytest

Conversation

@fbrausse
Copy link
Collaborator

@fbrausse fbrausse commented Mar 18, 2026

The test script "test_cmdline.py" was generated by a script from the smlp_regr.csv file. The logic for constructing the arguments for the command line tests has been reverse engineered from the original smlp_regr.py script.

For now, this is just the beginning. Comparing the generated files and outputs on stdout/stderr for a test run remains to be done. The commands generated by pytest exactly match those smlp_regr.py produces (modulo -out_dir, which is produced by pytest now and no longer defaults to ./).

The script convert-csv-pytest.py was used to convert the .csv to the new "test_cmdline.py" and cmp.py was used to check that the generated command lines exactly match of those of smlp_regr.py. Those files are not part of this PR.

I intend to finish implementing the check of the result files according to the logic of the current regression script in this PR and will mark it as draft until then. In the long run, I think it would be better to replace the "compare log and output files for changes" approach with a more robust check for the properties actually supposed to be tested - we discussed about this earlier. The approach taken in this PR putting the base functionality into a separate class living in lib.py looks extendible enough to me to support those future checks.

@fbrausse
Copy link
Collaborator Author

PS: I've added two warnings while generating the command line: one about absolute paths being used (e.g., for the -solver_path), and one about non-existing -data and -new_dat files. This is the current warning output:

Details
regr_smlp/code/test_cmdline.py: 17 warnings
  /home/kane/intel/smlp-pip/regr_smlp/code/lib.py:75: UserWarning: path for option -data does not exist: ../data/smlp_toy_num_resp_noknobs.csv
    warnings.warn(f'path for option {o} does not exist: {datapath}')

regr_smlp/code/test_cmdline.py::Test74::test
regr_smlp/code/test_cmdline.py::Test75::test
  /home/kane/intel/smlp-pip/regr_smlp/code/lib.py:75: UserWarning: path for option -new_dat does not exist: ../data/smlp_toy_num_resp_noknobs_pred_labeled.csv
    warnings.warn(f'path for option {o} does not exist: {datapath}')

regr_smlp/code/test_cmdline.py::Test130::test
regr_smlp/code/test_cmdline.py::Test131::test
regr_smlp/code/test_cmdline.py::Test132::test
regr_smlp/code/test_cmdline.py::Test133::test
regr_smlp/code/test_cmdline.py::Test134::test
regr_smlp/code/test_cmdline.py::Test135::test
regr_smlp/code/test_cmdline.py::Test138::test
  /home/kane/intel/smlp-pip/regr_smlp/code/lib.py:75: UserWarning: path for option -data does not exist: ../data/smlp_toy_const_input.csv
    warnings.warn(f'path for option {o} does not exist: {datapath}')

regr_smlp/code/test_cmdline.py::Test136::test
  /home/kane/intel/smlp-pip/regr_smlp/code/lib.py:75: UserWarning: path for option -data does not exist: ../data/smlp_toy_num_resp_mult_compressed.csv.gz.csv
    warnings.warn(f'path for option {o} does not exist: {datapath}')

regr_smlp/code/test_cmdline.py::Test137::test
  /home/kane/intel/smlp-pip/regr_smlp/code/lib.py:75: UserWarning: path for option -data does not exist: ../data/smlp_toy_num_resp_mult_compressed.csv
    warnings.warn(f'path for option {o} does not exist: {datapath}')

regr_smlp/code/test_cmdline.py::Test172::test
  /home/kane/intel/smlp-pip/regr_smlp/code/lib.py:59: UserWarning: Test #172: path given to -solver_path in args is absolute: /nfs/iil/proj/dt/eva/smlp/external/mathsat-5.6.8-linux-x86_64-reentrant/bin/mathsat
    warnings.warn(

regr_smlp/code/test_cmdline.py::Test173::test
  /home/kane/intel/smlp-pip/regr_smlp/code/lib.py:59: UserWarning: Test #173: path given to -solver_path in args is absolute: /nfs/iil/proj/dt/eva/smlp/external/mathsat-5.6.8-linux-x86_64-reentrant/bin/mathsat
    warnings.warn(

regr_smlp/code/test_cmdline.py::Test182::test
  /home/kane/intel/smlp-pip/regr_smlp/code/lib.py:59: UserWarning: Test #182: path given to -solver_path in args is absolute: /nfs/iil/proj/dt/eva/smlp/external/mathsat-5.6.8-linux-x86_64-reentrant/bin/mathsat
    warnings.warn(

regr_smlp/code/test_cmdline.py::Test197::test
  /home/kane/intel/smlp-pip/regr_smlp/code/lib.py:59: UserWarning: Test #197: path given to -solver_path in args is absolute: /nfs/iil/proj/dt/eva/smlp/external/mathsat-5.6.8-linux-x86_64-reentrant/bin/mathsat
    warnings.warn(

regr_smlp/code/test_cmdline.py::Test207::test
regr_smlp/code/test_cmdline.py::Test208::test
  /home/kane/intel/smlp-pip/regr_smlp/code/lib.py:75: UserWarning: path for option -data does not exist: ../data/smlp_toy_frontier_beta.csv
    warnings.warn(f'path for option {o} does not exist: {datapath}')

regr_smlp/code/test_cmdline.py::Test209::test
regr_smlp/code/test_cmdline.py::Test212::test
  /home/kane/intel/smlp-pip/regr_smlp/code/lib.py:75: UserWarning: path for option -data does not exist: ../data/smlp_toy_frontier_null_bounds_int.csv
    warnings.warn(f'path for option {o} does not exist: {datapath}')

regr_smlp/code/test_cmdline.py::Test210::test
regr_smlp/code/test_cmdline.py::Test211::test
regr_smlp/code/test_cmdline.py::Test213::test
regr_smlp/code/test_cmdline.py::Test214::test
  /home/kane/intel/smlp-pip/regr_smlp/code/lib.py:75: UserWarning: path for option -data does not exist: ../data/smlp_toy_frontier_null_bounds_empty.csv
    warnings.warn(f'path for option {o} does not exist: {datapath}')

@fbrausse
Copy link
Collaborator Author

fbrausse commented Mar 19, 2026

With the logic pulled over from smlp_regr.py, I now get the following test result summary when running pytest -n 16:

148 failed, 43 passed, 36 skipped, 43 warnings in 493.39s (0:08:13)

I've not yet checked all the failed tests, however here is a short summary that already accounts for a substantial portion of the 148 failures I saw:

  • checking against master log file failed: the paths differ, the -out_dir is part of the log file and thus fails when comparing ./ against some /tmp path generated by pytest.
  • -model_name appears to be interpreted relative to -out_dir and not relative to the current working directory; however it is expected that this file exists in the path relative to -out_dir, which is very strange. E.g. for Test22:
    $ ../../src/run_smlp.py -model_name ../models/test22_model -out_dir /tmp/pytest-of-kane/pytest-1223/test0 -pref Test22 -mode predict -resp 'PF ,|PF |' -model poly_sklearn -save_model f -use_model t -pred_plots t -resp_plots t -data_scaler none -mrmr_pred 0 -plots f -seed 10 -log_time f -new_dat ../data/smlp_toy_num_metasymbol_mult_reg_pred_labeled.csv
    [...]
      File "/home/kane/intel/smlp-pip/src/smlp_py/smlp_data.py", line 633, in _load_data_scaler
        mm_scaler_feat = pickle.load(open(features_scaler_file, 'rb'))
                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    FileNotFoundError: [Errno 2] No such file or directory: '/tmp/pytest-of-kane/pytest-1223/test0/../models/test22_model_features_scaler.pkl'
    
  • absolute paths in -solver_path: in some tests appears the Intel path for @zurabksmlp to be hardcoded: /nfs/iil/proj/dt/eva/smlp/external/mathsat-5.6.8-linux-x86_64-reentrant/bin/mathsat, e.g. for Test197:
    /bin/bash: line 1: /nfs/iil/proj/dt/eva/smlp/external/mathsat-5.6.8-linux-x86_64-reentrant/bin/mathsat: No such file or directory
    python3.11: ../src/ext-solver.cc:87: smlp::str smlp::ext_solver::get_info(const char*): Assertion `reply' failed.
    Abgebrochen
    
    Fix: regression tests: use relative -solver_path to mathsat #63

@fbrausse fbrausse marked this pull request as ready for review March 19, 2026 09:58
@zurabksmlp
Copy link
Collaborator

Loading saved models requires full path. In current regression the saved model files are at smlp/repo/smlp/regr_smlp/models/ . Here is an example of a genrated command:

../../src/run_smlp.py -model_name "../models/Test5_smlp_toy_num_resp_mult" -out_dir ./ -pref Test15 -mode predict -resp y1 -feat x,p1,p2 -model dt_caret -save_model f -use_model t -mrmr_pred 0 -plots f -pred_plots f -resp_plots f -seed 10 -log_time f -new_dat "../data/smlp_toy_num_resp_mult_pred_labeled.csv"

The path ../models/Test5_smlp_toy_num_resp_mult is created using the value in the smlp_regr.csv file in the first column and corresponding row (row 15 in this case), which looks like this:
15,Test5_smlp_toy_num_resp_mult,smlp_toy_num_resp_mult_pred_labeled,"-mode predict -resp y1 -feat x,p1,p2 -model dt_caret -save_model f -use_model t -mrmr_pred 0 -plots f -pred_plots f -resp_plots f -seed 10 -log_time f ",basic dt_caret prediction test from saved model on new data with numeric labels

commenting just in case this clarifies/helps.

@zurabksmlp
Copy link
Collaborator

Is this PR intended for current smlp repo?

In case the recovered test data is not yet in master, I think it is higher priority -- I mean the test input data that Franz recovered, after I renaming input, output and knob names to use the same convention (x, y, p).

Also, I am waiting for the new repo (with limited license) to be opened.

@fbrausse
Copy link
Collaborator Author

fbrausse commented Mar 19, 2026

Loading saved models requires full path.

Does "full path" mean "absolute path"? I am observing that the -out_dir value is prepended to the -model_name. That means, those options are not independent of one another, and basically only work when -out_dir is set to ./. See the error message I posted for the generated command of Test22, where only the -out_dir is different.

The path ../models/Test5_smlp_toy_num_resp_mult is created using the value in the smlp_regr.csv file in the first column and corresponding row (row 15 in this case), [...]

Indeed, the command line is generated this way. But running SMLP somehow expects -model_name to be relative to -out_dir. Which I consider to be a bug that prevents this PR from progressing.

Is this PR intended for current smlp repo?

Yes, a proper way to test that doesn't take hours and is a bit more flexible while also using standard tools such as pytest is essential for the more invasive changes regarding pySMT, etc. I cannot use the smlp_regr.py reliably here because it randomly hangs with -w 16 and I don't have the time to wait for hours until it (hopefully) finishes with -w 1.

In case the recovered test data is not yet in master, I think it is higher priority -- I mean the test input data that Franz recovered, after I renaming input, output and knob names to use the same convention (x, y, p).

This will be a next step after I can reliably run the tests.

@konstantin-korovin
Copy link
Collaborator

konstantin-korovin commented Mar 19, 2026 via email

@zurabksmlp
Copy link
Collaborator

model_name is used both for saving models and loading models. A saved model consists with many files, and model_name is used to identify these files while loading the model, and to save these files while saving the model.

in SMLP out_dir is used for all files generated by a run. These files include saved model files, that s why the output directory is prefixed to saved model file names to generate a full path. Full path can be absolute or relative, depending of course on whether one supplies absolute or relative path as argument to -out_dir.

@fbrausse
Copy link
Collaborator Author

Is there a way to avoid overwriting those model files?

@zurabksmlp
Copy link
Collaborator

Franz, can you clarify your question:
Is there a way to avoid overwriting those model files?

@fbrausse
Copy link
Collaborator Author

Sure. The problem I'm facing is that there are regression tests that read models and expect to find them in a location determined by -out_dir. Writing models should in my view be done using the -out_dir, but reading should not. With the current set of parameters, as I understand it, this might not be easy to do (think -out_dir /tmp -model_name ../models/something - what does that mean for the path the model is read from?). Alternatively, it might be cleaner if we could separate the read path from the write path. So my question is: can those two paths be separated?

@zurabksmlp
Copy link
Collaborator

Loading/reading models in regression are done from saved models directory -- directory smlp/repo/smlp/regr_smlp/models/, located in parallel to code, data, master (and several other) directories. When SMLP is run and saves models, the saved model is in the output directory. When SMLP runs a saved model, it takes the models from the models directory, so if the same command also writes / saves model there will be no clash. In fact, as far as I remember, SMLP does not permit to have -save_model t and use_model t in one command because it does not make sense.

@zurabksmlp
Copy link
Collaborator

If for some reason a regression test model changes and the model is saved, and is reused in some other test that reads that model, the models must be updated in the models/ directory. smlp_regr.py script supports that -- when a difference between newly saved model at output directory is compared to the saved model in the models directory and mismatch is found, the regression scripts asks what to do with the diff -- accept the diff and update both the models/ and/or master/ directories, or to ignore the diff.

@fbrausse
Copy link
Collaborator Author

I think we're still not talking about the same thing. You describe what happens when running ../../src/run_smlp.py -out_dir ./ -model_name ../models/something ..., yes?

I am modifying only the -out_dir parameter to point not to ./ but to some directory under /tmp outside of the repo's tree.

This is what happens:

$ ../../src/run_smlp.py -model_name ../models/test22_model -out_dir /tmp/pytest-of-kane/pytest-1223/test0 -pref Test22 -mode predict -resp 'PF ,|PF |' -model poly_sklearn -save_model f -use_model t -pred_plots t -resp_plots t -data_scaler none -mrmr_pred 0 -plots f -seed 10 -log_time f -new_dat ../data/smlp_toy_num_metasymbol_mult_reg_pred_labeled.csv
[...]
  File "/home/kane/intel/smlp-pip/src/smlp_py/smlp_data.py", line 633, in _load_data_scaler
    mm_scaler_feat = pickle.load(open(features_scaler_file, 'rb'))
                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
FileNotFoundError: [Errno 2] No such file or directory: '/tmp/pytest-of-kane/pytest-1223/test0/../models/test22_model_features_scaler.pkl'

Note the path in the last line of this error message. It is constructed from putting the -out_dir parameter in front of the -model_name parameter. For reading a model! That is not just counter-intuitive, but also means that the -out_dir option itself becomes a bit useless, because as soon as I change it, I need to use a different -model_name for - again - reading. For reading the given -model_name should be taken as it is, while for writing the current behaviour could stay as it is (though I would argue that writing outside of the specified -out_dir should be disallowed).

@fbrausse
Copy link
Collaborator Author

fbrausse commented Mar 19, 2026

Working around this -model_name reading problem by using absolute paths and fixing some issues (also one in original smlp_regr.py), I now arrive at

41 failed, 150 passed, 36 skipped, 43 warnings in 483.56s (0:08:03)

Edit: Out of the 41 failing, 13 already fail on master for me.

Investigating the remaining failed ones...

@zurabksmlp
Copy link
Collaborator

Hi Franz, when you run:

../../src/run_smlp.py -model_name ../models/test22_model -out_dir /tmp/pytest-of-kane/pytest-1223/test0 -pref Test22 -mode predict -resp 'PF ,|PF |' -model poly_sklearn -save_model f -use_model t -pred_plots t -resp_plots t -data_scaler none -mrmr_pred 0 -plots f -seed 10 -log_time f -new_dat ../data/smlp_toy_num_metasymbol_mult_reg_pred_labeled.csv

does directory /tmp/pytest-of-kane/pytest-1223/test0 exist?
Also, what happens if you use -out_dir /tmp/ ?

@fbrausse
Copy link
Collaborator Author

does directory /tmp/pytest-of-kane/pytest-1223/test0 exist?

Yes, it does exist before I run the command (and still does after).

Also, what happens if you use -out_dir /tmp/ ?

The same error, except the FileNotFoundError's message changes:

FileNotFoundError: [Errno 2] No such file or directory: '/tmp/../models/test22_model_features_scaler.pkl'

@fbrausse
Copy link
Collaborator Author

fbrausse commented Mar 20, 2026

Investigating the remaining failed ones...

Outcome: All 41 that fail with this PR already fail on master for me. Here is a summary:

  • Tests 8, 13, 16, 28, 36, 59, 60, 66, 68, 69, 70, 72, 77: smlp_regr.py already says they fail.
  • Test 104: Exception: Knobs ['p1', 'p2'] are not assigned constant values as part of specification, in "verify" mode: aborting...
  • Test 107: Exception: Beta constraints are not supported in "verify" mode: aborting...
  • Tests 145, 205: Exception: DOE levels grid file ../grids/doe_two_levels_opt.csv does not eist
  • Test 146: Exception: DOE levels grid file ../grids/explore_doe_two_levels.csv does not eist
  • Tests 149, 150, 151, 152, 154, 155, 156, 157, 158, 172, 173, 174, 175, 176, 177, 178, 179, 180: keras private attribute issue, see Compatibility with keras >= 3.11.3 #64
  • Test 160: KeyError: "The path: (0,) in the `loss` argument, can't be found in either the model's output (`y_pred`) or in the labels (`y_true`)."
  • Tests 182, 197: absolute solver path issue, see regression tests: use relative -solver_path to mathsat #63
  • Tests 201, 202: Exception: Spec file ../specs/smlp_toy_num_resp_mult_no_input_beta.spec does not exist

Why the smlp_regr.py script claims those tests from the above list except for the first item would be "Passed" I don't know, yet. The above results come from manually running the commands printed by the tool for the respective test.

Thus, this PR performs no worse than the current master, at least on my installation.

Edit: 104 and 107 are expected to fail, this is handled as intended by pytest now.

@fbrausse fbrausse mentioned this pull request Mar 20, 2026
21 tasks
@zurabksmlp
Copy link
Collaborator

  1. These tests have correct behavior -- these are sanity check tests, should be aborting:
    Test 104: Exception: Knobs ['p1', 'p2'] are not assigned constant values as part of specification, in "verify" mode: aborting...
    Test 107: Exception: Beta constraints are not supported in "verify" mode: aborting...
  2. These tests have a simple fix:
    Tests 149, 150, 151, 152, 154, 155, 156, 157, 158, 172, 173, 174, 175, 176, 177, 178, 179, 180: keras private attribute issue, see Compatibility with keras >= 3.11.3 #64
    This test too is related to Keras versions:
    Test 160: KeyError: "The path: (0,) in the loss argument, can't be found in either the model's output (y_pred) or in the labels (y_true)."
    I have a fix in nlp_text.rebase branch for these tests, I can check that these tests are indeed running without errors in nlp_text.rebased branch. As far as I know @mdmitry1 also has fixes for these issues -- maybe his fixes are implemented a little different.
  3. Are the tests with missing input files among the recovered tests?

@fbrausse
Copy link
Collaborator Author

Thanks, Zurab! I've marked 104 and 107 as expected to fail.

I have a fix in nlp_text.rebase branch for these tests,

Do you remember what changes fixed this keras "(0,) in the loss argument" issue?

Are the tests with missing input files among the recovered tests?

I have not finished recovering all those missing files. It's quite some time ago by now that I worked on that. I plan to return there once I can reliably run the tests.

@zurabksmlp
Copy link
Collaborator

The fixes to keras version compatibility are in src/smlp_py/train_keras.py -- changes are conditional with respect to:
if version.parse(keras.version) <= version.parse("3.0.0"):

It makes sense to grep on "3.0.0" or on keras.version to make sure all relevant changes are in train_keras.py.

@fbrausse
Copy link
Collaborator Author

fbrausse commented Mar 20, 2026

With keras-3.13.2 installed (as before), I now get

39 failed, 150 passed, 36 skipped, 2 xfailed, 43 warnings in 518.45s (0:08:38)

Will try the keras-3 patches from your nlp_text branch next.

Edit: However, they are not in master, yet, so we'll have to see whether it might make sense to extract them from your branch as a separate PR.

@fbrausse
Copy link
Collaborator Author

fbrausse commented Mar 20, 2026

With keras-2.15.0 and tensorflow<2.16:

14 failed, 172 passed, 39 skipped, 2 xfailed, 43 warnings in 465.13s (0:07:45)

(I skipped Tests 154, 155 and 157 manually because they were taking too long).

zurabksmlp and others added 3 commits March 22, 2026 16:53
…gr.py

The test script "test_cmdline.py" was generated by a script from the
smlp_regr.csv file. The logic for constructing the arguments for the command
line tests has been reverse engineered from the original smlp_regr.py script.

For now, this is just the beginning. Comparing the generated files and outputs
on stdout/stderr for a test run remains to be done.
Result with this: 41 failed, 150 passed, 36 skipped, 43 warnings in 483.56s (0:08:03)
Fixing access to non-existing private attribute '_metrics' occuring e.g. when running
regression test #4:

Traceback (most recent call last):
  File "/home/kane/intel/smlp/regr_smlp/code/../../src/run_smlp.py", line 18, in <module>
    main(sys.argv)
  File "/home/kane/intel/smlp/regr_smlp/code/../../src/run_smlp.py", line 15, in main
    smlpInst.smlp_flow()
  File "/home/kane/intel/smlp/src/smlp_py/smlp_flows.py", line 317, in smlp_flow
    model = self.modelInst.build_models(args.model, X, y, X_train, y_train, X_test, y_test, X_new, y_new,
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/kane/intel/smlp/src/smlp_py/smlp_models.py", line 472, in build_models
    model = self.model_train(feat_names_dict, resp_names, algo, X_train, X_test, y_train, y_test,
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/kane/intel/smlp/src/smlp_py/smlp_models.py", line 353, in model_train
    model = self._instKeras.keras_main(resp_names, keras_algo, X_train, X_test, y_train, y_test, hparams_dict, plots,
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/kane/intel/smlp/src/smlp_py/train_keras.py", line 924, in keras_main
    model = self._keras_train_multi_response(resp_names, algo,
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/kane/intel/smlp/src/smlp_py/train_keras.py", line 865, in _keras_train_multi_response
    history = self._nn_train(model, epochs, batch_size, weights_precision, self.model_checkpoint_pattern,
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/kane/intel/smlp/src/smlp_py/train_keras.py", line 475, in _nn_train
    self._log_model_summary(model, epochs, batch_size, sample_weights_dict, callbacks)
  File "/home/kane/intel/smlp/src/smlp_py/train_keras.py", line 380, in _log_model_summary
    compiled_metrics = model.compiled_metrics._metrics  # Access the private _metrics attribute
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'DeprecatedCompiledMetric' object has no attribute '_metrics'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants