Skip to content
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

Translate warnings to Python #1201

Merged
merged 8 commits into from
Mar 4, 2022
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 License.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Copyright (c) 2009 Sandia Corporation. Under the terms of
Contract AC04-94AL85000 with Sandia Corporation, the U.S. Government
retains certain rights in this software.

Copyright (c) 2011-2021, Cantera Developers.
Copyright (c) 2011-2022, Cantera Developers.
All rights reserved.

Redistribution and use in source and binary forms, with or without
Expand Down
2 changes: 1 addition & 1 deletion doc/sphinx/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ def escape_splats(app, what, name, obj, options, lines):

# General information about the project.
project = 'Cantera'
copyright = '2001-2021, Cantera Developers'
copyright = "2001-2022, Cantera Developers"

# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
Expand Down
49 changes: 41 additions & 8 deletions include/cantera/base/global.h
Original file line number Diff line number Diff line change
Expand Up @@ -192,18 +192,51 @@ void writelogendl();
void writeline(char repeat, size_t count,
bool endl_after=true, bool endl_before=false);

//! @copydoc Application::warn_deprecated
void warn_deprecated(const std::string& method, const std::string& extra="");
//! helper function passing deprecation warning to global handler
void _warn_deprecated(const std::string& method, const std::string& extra="");

//! Print a deprecation warning raised from *method*. @see Application::warn_deprecated
/*!
* @param method method name
* @param msg Python-style format string with the following arguments
* @param args arguments for the format string
*/
template <typename... Args>
void warn_deprecated(const std::string& method, const std::string& msg,
const Args&... args) {
if (sizeof...(args) == 0) {
_warn_deprecated(method, msg);
} else {
_warn_deprecated(method, fmt::format(msg, args...));
}
}

//! @copydoc Application::suppress_deprecation_warnings
void suppress_deprecation_warnings();

//! helper function passing user warning to global handler
void _warn_user(const std::string& method, const std::string& extra);
//! helper function passing generic warning to global handler
void _warn(const std::string& warning,
const std::string& method, const std::string& extra);

//! Print a generic warning raised from *method*. @see Application::warn
/*!
* @param warning type of warning; @see Logger::warn
* @param method method name
* @param msg Python-style format string with the following arguments
* @param args arguments for the format string
*/
template <typename... Args>
void warn(const std::string& warning, const std::string& method,
const std::string& msg, const Args&... args) {
if (sizeof...(args) == 0) {
_warn(warning, method, msg);
} else {
_warn(warning, method, fmt::format(msg, args...));
}
}

//! Print a user warning raised from *method* as `CanteraWarning`.
/*!
* Print a user warning raised from *method*.
*
* @param method method name
* @param msg Python-style format string with the following arguments
* @param args arguments for the format string
Expand All @@ -212,9 +245,9 @@ template <typename... Args>
void warn_user(const std::string& method, const std::string& msg,
const Args&... args) {
if (sizeof...(args) == 0) {
_warn_user(method, msg);
_warn("Cantera", method, msg);
} else {
_warn_user(method, fmt::format(msg, args...));
_warn("Cantera", method, fmt::format(msg, args...));
}
}

Expand Down
10 changes: 10 additions & 0 deletions include/cantera/base/logger.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,16 @@ class Logger
std::cout << std::endl;
}

//! Write a warning message.
/*!
* The default behavior is to write to the logging output.
* @param warning String specifying type of warning; @see Logger::warn
* @param msg String message to be written to cout
*/
virtual void warn(const std::string& warning, const std::string& msg) {
std::clog << warning << "Warning: " << msg << std::endl;
}

//! Write an error message and quit.
/*!
* The default behavior is to write to the standard error stream, and then
Expand Down
29 changes: 27 additions & 2 deletions include/cantera/cython/wrappers.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,23 @@

#include "Python.h"

// Warning types supported by the Python C-API.
// See https://docs.python.org/3/c-api/exceptions.html#issuing-warnings
std::map<std::string, PyObject*> mapped_PyWarnings = {
{"", PyExc_Warning},
{"Bytes", PyExc_BytesWarning},
{"Cantera", PyExc_UserWarning}, // pre-existing warning
{"Deprecation", PyExc_DeprecationWarning},
{"Future", PyExc_FutureWarning},
{"Import", PyExc_ImportWarning},
{"PendingDeprecation", PyExc_PendingDeprecationWarning},
{"Resource", PyExc_ResourceWarning},
{"Runtime", PyExc_RuntimeWarning},
{"Syntax", PyExc_SyntaxWarning},
{"Unicode", PyExc_UnicodeWarning},
{"User", PyExc_UserWarning}
};

// Wrappers for preprocessor defines
std::string get_cantera_version()
{
Expand Down Expand Up @@ -37,9 +54,17 @@ class PythonLogger : public Cantera::Logger
std::cout.flush();
}

virtual void warn(const std::string& warning, const std::string& msg) {
if (mapped_PyWarnings.find(warning) != mapped_PyWarnings.end()) {
PyErr_WarnEx(mapped_PyWarnings[warning], msg.c_str(), 1);
} else {
// issue generic warning
PyErr_WarnEx(PyExc_Warning, msg.c_str(), 1);
}
}

virtual void error(const std::string& msg) {
std::string err = "raise Exception('''"+msg+"''')";
PyRun_SimpleString(err.c_str());
PyErr_SetString(PyExc_RuntimeError, msg.c_str());
}
};

Expand Down
3 changes: 0 additions & 3 deletions interfaces/cython/cantera/_cantera.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -173,9 +173,6 @@ cdef extern from "cantera/base/global.h" namespace "Cantera":
cdef XML_Node* CxxGetXmlFile "Cantera::get_XML_File" (string) except +translate_exception
cdef XML_Node* CxxGetXmlFromString "Cantera::get_XML_from_string" (string) except +translate_exception
cdef void Cxx_make_deprecation_warnings_fatal "Cantera::make_deprecation_warnings_fatal" ()
cdef void Cxx_make_warnings_fatal "Cantera::make_warnings_fatal" ()
cdef void Cxx_suppress_warnings "Cantera::suppress_warnings" ()
cdef cbool Cxx_warnings_suppressed "Cantera::warnings_suppressed" ()
cdef void Cxx_suppress_deprecation_warnings "Cantera::suppress_deprecation_warnings" ()
cdef void Cxx_suppress_thermo_warnings "Cantera::suppress_thermo_warnings" (cbool)
cdef void Cxx_use_legacy_rate_constants "Cantera::use_legacy_rate_constants" (cbool)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from timeit import default_timer
import numpy as np
from math import exp
import warnings

import cantera as ct

Expand All @@ -29,9 +30,12 @@
gas1 = ct.Solution(thermo='ideal-gas', kinetics='gas',
species=species, reactions=custom_reactions)

# old framework - use xml input
# old framework - use xml input (to be removed after Cantera 2.6)

gas2 = ct.Solution(mech.replace('.yaml', '.xml'))
with warnings.catch_warnings():
# suppress warning: XML input is deprecated
warnings.simplefilter("ignore")
gas2 = ct.Solution(mech.replace(".yaml", ".xml"))

# construct test case - simulate ignition

Expand Down
12 changes: 5 additions & 7 deletions interfaces/cython/cantera/test/test_convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
from pathlib import Path
import logging
import io
import pytest

from . import utilities
from .utilities import allow_deprecated
import cantera as ct
from cantera import ck2cti, ck2yaml, cti2yaml, ctml2yaml

Expand Down Expand Up @@ -534,8 +536,10 @@ def test_error_for_big_element_number(self):
with self.assertRaisesRegex(self.InputError, 'Element amounts can have no more than 3 digits.'):
self.convert('big_element_num_err.inp')


@pytest.mark.usefixtures("allow_deprecated")
class CtmlConverterTest(utilities.CanteraTest):
@utilities.allow_deprecated

def test_sofc(self):
gas_a, anode_bulk, oxide_a = ct.import_phases(
'sofc.cti',
Expand All @@ -546,14 +550,12 @@ def test_sofc(self):
self.assertNear(oxide_a.density_mole, 17.6)

@utilities.slow_test
@utilities.allow_deprecated
def test_diamond(self):
gas, solid = ct.import_phases('diamond.cti', ['gas','diamond'])
face = ct.Interface('diamond.cti', 'diamond_100', [gas, solid])

self.assertNear(face.site_density, 3e-8)

@utilities.allow_deprecated
def test_invalid(self):
try:
gas = ct.Solution('invalid.cti')
Expand All @@ -562,13 +564,11 @@ def test_invalid(self):

self.assertIn('already contains', err.args[0])

@utilities.allow_deprecated
def test_noninteger_atomicity(self):
gas = ct.Solution('noninteger-atomicity.cti')
self.assertNear(gas.molecular_weights[gas.species_index('CnHm')],
10.65*gas.atomic_weight('C') + 21.8*gas.atomic_weight('H'))

@utilities.allow_deprecated
def test_reaction_orders(self):
gas = ct.Solution('reaction-orders.cti')
self.assertEqual(gas.n_reactions, 1)
Expand All @@ -578,7 +578,6 @@ def test_reaction_orders(self):
self.assertTrue(R.allow_negative_orders)
self.assertNear(R.orders.get('H2'), -0.25)

@utilities.allow_deprecated
def test_long_source_input(self):
"""
Here we are testing if passing a very long string will result in a
Expand All @@ -593,7 +592,6 @@ def test_long_source_input(self):

self.assertEqual(gas.n_reactions, gas2.n_reactions)

@utilities.allow_deprecated
def test_short_source_input(self):
"""
Here we are testing if passing a short string will result in a Solution
Expand Down
27 changes: 16 additions & 11 deletions interfaces/cython/cantera/test/test_jacobian.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import numpy as np
import pytest

import cantera as ct
from . import utilities
from .utilities import has_temperature_derivative_warnings


class RateExpressionTests:
Expand Down Expand Up @@ -478,17 +480,20 @@ def setUpClass(cls):
# species: [AR, O, H2, H, OH, O2, H2O, H2O2, HO2]
cls.gas.X = [0.1, 3e-4, 5e-5, 6e-6, 3e-3, 0.6, 0.25, 1e-6, 2e-5]
cls.gas.TP = 2000, 5 * ct.one_atm
super().setUpClass()

# suppress user warning (e.g. temperature derivative of Blowers-Masel)
cls.warnings_suppressed = ct.warnings_suppressed()
ct.suppress_warnings()
@pytest.mark.usefixtures("has_temperature_derivative_warnings")
def test_forward_rop_ddT(self):
super().test_forward_rop_ddT()

super().setUpClass()
@pytest.mark.usefixtures("has_temperature_derivative_warnings")
def test_reverse_rop_ddT(self):
super().test_reverse_rop_ddT()

@pytest.mark.usefixtures("has_temperature_derivative_warnings")
def test_net_rop_ddT(self):
super().test_net_rop_ddT()

@classmethod
def tearDownClass(cls):
if not cls.warnings_suppressed:
ct.make_warnings_fatal()

class TestPlog(FromScratchCases, utilities.CanteraTest):
# Plog reaction
Expand All @@ -510,15 +515,15 @@ class TestBlowersMasel(FromScratchCases, utilities.CanteraTest):
equation = "H2 + O <=> H + OH"
rate_type = "Blowers-Masel"

@utilities.unittest.skip("change of reaction enthalpy is not considered")
@pytest.mark.xfail(reason="Change of reaction enthalpy is not considered")
def test_forward_rop_ddT(self):
super().test_forward_rop_ddT()

@utilities.unittest.skip("change of reaction enthalpy is not considered")
@pytest.mark.xfail(reason="Change of reaction enthalpy is not considered")
def test_reverse_rop_ddT(self):
super().test_reverse_rop_ddT()

@utilities.unittest.skip("change of reaction enthalpy is not considered")
@pytest.mark.xfail(reason="Change of reaction enthalpy is not considered")
def test_net_rop_ddT(self):
super().test_net_rop_ddT()

Expand Down
27 changes: 13 additions & 14 deletions interfaces/cython/cantera/test/test_kinetics.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@
import re
import itertools
import pkg_resources
import pytest

import cantera as ct
from . import utilities
from .utilities import allow_deprecated

# avoid explicit dependence of cantera on scipy
try:
Expand Down Expand Up @@ -476,14 +478,11 @@ def test_sticking_coeff_err(self):
"at T = 5000.0",
"at T = 10000.0",
"Sticking coefficient is greater than 1 for reaction",
"CanteraError thrown by InterfaceReaction::validate:",
"InterfaceReaction::validate:",
)
if not ct.debug_mode_enabled():
err_msg += ("CanteraError thrown by BlowersMaselInterfaceReaction::validate:",)

ct.make_warnings_fatal()
for err in err_msg:
with self.assertRaisesRegex(ct.CanteraError, err):
with pytest.warns(UserWarning, match=err):
gas = ct.Solution('sticking_coeff_check.yaml')
surface = ct.Interface('sticking_coeff_check.yaml', 'Pt_surf', [gas])

Expand Down Expand Up @@ -950,14 +949,14 @@ def test_nonreacting_species(self):

class TestReaction(utilities.CanteraTest):
@classmethod
def setUpClass(self):
def setUpClass(cls):
utilities.CanteraTest.setUpClass()
self.gas = ct.Solution('h2o2.yaml', transport_model=None)
self.gas.X = 'H2:0.1, H2O:0.2, O2:0.7, O:1e-4, OH:1e-5, H:2e-5'
self.gas.TP = 900, 2*ct.one_atm
self.species = ct.Species.list_from_file("h2o2.yaml")
cls.gas = ct.Solution('h2o2.yaml', transport_model=None)
cls.gas.X = 'H2:0.1, H2O:0.2, O2:0.7, O:1e-4, OH:1e-5, H:2e-5'
cls.gas.TP = 900, 2*ct.one_atm
cls.species = ct.Species.list_from_file("h2o2.yaml")

@utilities.allow_deprecated
@pytest.mark.usefixtures("allow_deprecated")
def test_fromCti(self):
r = ct.Reaction.fromCti('''three_body_reaction('2 O + M <=> O2 + M',
[1.200000e+11, -1.0, 0.0], efficiencies='AR:0.83 H2:2.4 H2O:15.4')''')
Expand All @@ -971,7 +970,7 @@ def test_fromCti(self):
self.assertIn('O2', r)
self.assertNotIn('H2O', r)

@utilities.allow_deprecated
@pytest.mark.usefixtures("allow_deprecated")
def test_fromXml(self):
import xml.etree.ElementTree as ET
root = ET.parse(self.cantera_data_path / "h2o2.xml").getroot()
Expand Down Expand Up @@ -1007,15 +1006,15 @@ def test_listFromFile(self):
eq2 = [r.equation for r in self.gas.reactions()]
self.assertEqual(eq1, eq2)

@utilities.allow_deprecated
@pytest.mark.usefixtures("allow_deprecated")
def test_listFromCti(self):
gas = ct.Solution("h2o2.xml", transport_model=None)
R = ct.Reaction.listFromCti((self.cantera_data_path / "h2o2.cti").read_text())
eq1 = [r.equation for r in R]
eq2 = [r.equation for r in gas.reactions()]
self.assertEqual(eq1, eq2)

@utilities.allow_deprecated
@pytest.mark.usefixtures("allow_deprecated")
def test_listFromXml(self):
gas = ct.Solution("h2o2.xml", transport_model=None)
R = ct.Reaction.listFromXml((self.cantera_data_path / "h2o2.xml").read_text())
Expand Down
Loading