move throwing Python variable errors to PythonImpl class and change API accordingly.

This commit is contained in:
Axel Kohlmeyer
2025-06-06 00:19:33 -04:00
parent a246619ecf
commit e1aa3cf7ec
5 changed files with 44 additions and 97 deletions

View File

@ -451,16 +451,23 @@ int PythonImpl::find(const char *name)
ensure a string is returned only if retrieve() is the caller
--------------------------------------------------------------------- */
int PythonImpl::function_match(const char *name, const char *varname, int numeric)
int PythonImpl::function_match(const char *name, const char *varname, int numeric, Error *error)
{
// NOTE to Richard - any reason not to put error messages here instead of in Variable class ?
// error messages appear 3x in Variable
int ifunc = find(name);
if (ifunc < 0) return -1;
if (pfuncs[ifunc].noutput == 0) return -2;
if (strcmp(pfuncs[ifunc].ovarname, varname) != 0) return -3;
if (numeric && pfuncs[ifunc].otype == STRING) return -4;
if (ifunc < 0)
error->all(FLERR, Error::NOLASTLINE, "Python function {} specified by variable {} not found",
name, varname);
if (pfuncs[ifunc].noutput == 0)
error->all(FLERR, Error::NOLASTLINE,
"Python function {} for variable {} does not return a value", name, varname);
if (strcmp(pfuncs[ifunc].ovarname, varname) != 0)
error->all(FLERR, Error::NOLASTLINE,
"Python function {} and variable {} do not not link to each other", name, varname);
if (numeric && pfuncs[ifunc].otype == STRING)
error->all(FLERR, Error::NOLASTLINE, "Python function {} for variable {} returns a string",
name, varname);
return ifunc;
}
@ -477,18 +484,18 @@ int PythonImpl::function_match(const char *name, const char *varname, int numeri
other classes avoid this issue by setting variable indices in their init() method
--------------------------------------------------------------------- */
int PythonImpl::wrapper_match(const char *name, const char *varname, int narg, int *argvars)
int PythonImpl::wrapper_match(const char *name, const char *varname, int narg, int *argvars,
Error *error)
{
// NOTE to Richard - any reason not to put 2 extra error messages here instead of in Variable class ?
// only this class knows the name of the missing internal var, so can generate better error message
int ifunc = function_match(name, varname, 1);
int ifunc = function_match(name, varname, 1, error);
if (ifunc < 0) return ifunc;
int internal_count = 0;
for (int i = 0; i < pfuncs[ifunc].ninput; i++)
if (pfuncs[ifunc].ivarflag[i] == INTERNALVAR) internal_count++;
if (internal_count != narg) return -5;
if (internal_count != narg)
error->all(FLERR, Error::NOLASTLINE,
"Python function {} does not use {} internal variable args", name, narg);
// set argvars of internal-style variables for use by Variable class
// in Python wrapper functions
@ -496,13 +503,15 @@ int PythonImpl::wrapper_match(const char *name, const char *varname, int narg, i
// so that invoke_function() is as fast as possible for args which are internal-style vars
int j = 0;
for (int i = 0; i < pfuncs[ifunc].ninput; i++)
for (int i = 0; i < pfuncs[ifunc].ninput; i++) {
if (pfuncs[ifunc].ivarflag[i] == INTERNALVAR) {
int ivar = input->variable->find(pfuncs[ifunc].svalue[i]);
if (ivar < 0) return -6;
error->all(FLERR, Error::NOLASTLINE, "Python function {} cannot find internal variable {}",
name, pfuncs[ifunc].svalue[i]);
pfuncs[ifunc].internal_var[i] = ivar;
argvars[j++] = ivar;
}
}
return ifunc;
}

View File

@ -27,8 +27,8 @@ class PythonImpl : protected Pointers, public PythonInterface {
void command(int, char **) override;
void invoke_function(int, char *, double *) override;
int find(const char *) override;
int function_match(const char *, const char *, int) override;
int wrapper_match(const char *, const char *, int, int *) override;
int function_match(const char *, const char *, int, Error *) override;
int wrapper_match(const char *, const char *, int, int *, Error *) override;
char *long_string(int) override;
int execute_string(char *) override;
int execute_file(char *) override;

View File

@ -14,9 +14,8 @@
#include "lmppython.h"
#if defined(LMP_PYTHON)
#include "python_impl.h"
#else
#include "error.h"
#endif
#include "error.h"
using namespace LAMMPS_NS;
@ -43,7 +42,7 @@ void Python::init()
#if defined(LMP_PYTHON)
if (!impl) impl = new PythonImpl(lmp);
#else
error->all(FLERR, "Python support missing! Compile with PYTHON package installed!");
error->all(FLERR, Error::NOLASTLINE, "Python support missing! Compile with PYTHON package installed!");
#endif
}
@ -83,19 +82,19 @@ int Python::find(const char *name)
/* ------------------------------------------------------------------ */
int Python::function_match(const char *name, const char *varname, int numeric)
int Python::function_match(const char *name, const char *varname, int numeric, Error *errptr)
{
init();
return impl->function_match(name, varname, numeric);
return impl->function_match(name, varname, numeric, errptr);
}
/* ------------------------------------------------------------------ */
int Python::wrapper_match(const char *name, const char *varname,
int narg, int *argvars)
int Python::wrapper_match(const char *name, const char *varname, int narg, int *argvars,
Error *errptr)
{
init();
return impl->wrapper_match(name, varname, narg, argvars);
return impl->wrapper_match(name, varname, narg, argvars, errptr);
}
/* ------------------------------------------------------------------ */

View File

@ -24,8 +24,8 @@ class PythonInterface {
virtual void command(int, char **) = 0;
virtual void invoke_function(int, char *, double *) = 0;
virtual int find(const char *) = 0;
virtual int function_match(const char *, const char *, int) = 0;
virtual int wrapper_match(const char *, const char *, int, int *) = 0;
virtual int function_match(const char *, const char *, int, Error *) = 0;
virtual int wrapper_match(const char *, const char *, int, int *, Error *) = 0;
virtual char *long_string(int ifunc) = 0;
virtual int execute_string(char *) = 0;
virtual int execute_file(char *) = 0;
@ -40,8 +40,8 @@ class Python : protected Pointers {
void command(int, char **);
void invoke_function(int, char *, double *);
int find(const char *);
int function_match(const char *, const char *, int);
int wrapper_match(const char *, const char *, int, int *);
int function_match(const char *, const char *, int, Error *);
int wrapper_match(const char *, const char *, int, int *, Error *);
char *long_string(int ifunc);
int execute_string(char *);
int execute_file(char *);

View File

@ -959,31 +959,10 @@ void Variable::python_command(int narg, char **arg)
int Variable::equalstyle(int ivar)
{
if (style[ivar] == EQUAL || style[ivar] == TIMER ||
style[ivar] == INTERNAL) return 1;
if (style[ivar] == PYTHON) {
pyindex[ivar] = python->function_match(data[ivar][0],names[ivar],1);
if (pyindex[ivar] < 0) {
int ierror = pyindex[ivar];
if (ierror == -1) {
error->all(FLERR, "Python function {} specified by variable {} not found",
data[ivar][0], names[ivar]);
} else if (ierror == -2) {
error->all(FLERR, "Python function {} for variable {} does not return a value",
data[ivar][0], names[ivar]);
} else if (ierror == -3) {
error->all(FLERR, "Python function {} and variable {} do not not link to each other",
data[ivar][0], names[ivar]);
} else if (ierror == -4) {
error->all(FLERR, "Python function {} for variable {} returns a string",
data[ivar][0], names[ivar]);
} else {
error->all(FLERR, "Unknown error linking Python function {} to variable {}",
data[ivar][0],names[ivar]);
}
return 0;
} else return 1;
}
if (style[ivar] == EQUAL || style[ivar] == TIMER || style[ivar] == INTERNAL) return 1;
if ((style[ivar] == PYTHON) && (python->function_match(data[ivar][0], names[ivar], 1, error) >= 0))
return 1;
return 0;
}
@ -1103,22 +1082,7 @@ char *Variable::retrieve(const char *name)
str = data[ivar][1] = utils::strdup(result);
} else if (style[ivar] == PYTHON) {
int ifunc = python->function_match(data[ivar][0],name,0);
if (ifunc < 0) {
if (ifunc == -1) {
error->all(FLERR, "Python function {} specified by variable {} not found",
data[ivar][0], name);
} else if (ifunc == -2) {
error->all(FLERR, "Python function {} for variable {} does not return a value",
data[ivar][0], name);
} else if (ifunc == -3) {
error->all(FLERR, "Python function {} and variable {} do not not link to each other",
data[ivar][0], name);
} else {
error->all(FLERR, "Unknown error linking Python function {} to variable {}",
data[ivar][0],name);
}
}
int ifunc = python->function_match(data[ivar][0],name,0,error);
python->invoke_function(ifunc,data[ivar][1],nullptr);
str = data[ivar][1];
@ -4208,32 +4172,7 @@ int Variable::math_function(char *word, char *contents, Tree **tree, Tree **tree
// jvars = returned indices of narg internal variables used by Python function
int *jvars = new int[narg];
pyindex[pyvar] = python->wrapper_match(data[pyvar][0],names[pyvar],narg,jvars);
if (pyindex[pyvar] < 0) {
int ierror = pyindex[pyvar];
if (ierror == -1) {
error->all(FLERR, "Python function {} specified by variable {} not found",
data[ivar][0], names[ivar]);
} else if (ierror == -2) {
error->all(FLERR, "Python function {} for variable {} does not return a value",
data[ivar][0], names[ivar]);
} else if (ierror == -3) {
error->all(FLERR, "Python function {} and variable {} do not not link to each other",
data[ivar][0], names[ivar]);
} else if (ierror == -4) {
error->all(FLERR, "Python function {} for variable {} returns a string",
data[ivar][0], names[ivar]);
} else if (ierror == -5) {
error->all(FLERR, "Python function {} does not use {} internal variable args",
data[ivar][0], narg);
} else if (ierror == -6) {
error->all(FLERR,"Python function {} cannot find an internal variable",
data[ivar][0]);
} else {
error->all(FLERR, "Unknown error linking Python function {} to variable {}",
data[ivar][0],names[ivar]);
}
}
pyindex[pyvar] = python->wrapper_match(data[pyvar][0],names[pyvar],narg,jvars,error);
// if tree: store python variable and arg info in tree for later eval
// else: one-time eval of python-coded function now via python variable