Skip to content

Commit

Permalink
Merge pull request #433 from genn-team/pygenn_exception_handling
Browse files Browse the repository at this point in the history
PyGeNN exception handling
  • Loading branch information
neworderofjamie authored Jul 6, 2021
2 parents 5cb7dff + 5c3b254 commit af73a4b
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 18 deletions.
46 changes: 28 additions & 18 deletions generate_swig_interfaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
from itertools import product
from string import Template # for better text substitutions
from argparse import ArgumentParser # to parse command line args
from textwrap import dedent

# module attributes
NEURONMODELS = 'neuronModels'
Expand Down Expand Up @@ -173,7 +174,21 @@ def addSwigTemplate( self, tSpec, newName ):
def addCppInclude( self, cHeader, comment='' ):
'''Adds a line for usual including C/C++ header file.'''
self.write( '#include {} {}\n'.format( cHeader, comment ) )


def addStandardExceptionHandler(self):
self.write(dedent(
"""
%exception {
try {
$action
}
SWIG_CATCH_STDEXCEPT // catch std::exception
catch (...) {
SWIG_exception(SWIG_UnknownError, "Unknown exception");
}
}
"""))

def addAutoGenWarning( self ):
'''Adds a comment line telling that this file was generated automatically'''
self.write( '// This code was generated by ' + os.path.split(__file__)[1] + '. DO NOT EDIT\n' )
Expand Down Expand Up @@ -301,7 +316,11 @@ def generateSharedLibraryModelInterface( swigPath ):
mg.addCppInclude( '"sharedLibraryModelNumpy.h"' )

mg.addSwigInclude( '<std_string.i>' )
mg.addSwigInclude( '<exception.i>' )
mg.addSwigInclude( '"numpy.i"' )

mg.addStandardExceptionHandler()

with SwigInitScope( mg ):
mg.write( 'import_array();\n')

Expand Down Expand Up @@ -406,7 +425,7 @@ def generateCustomModelDeclImpls(swigPath):
if model == CUSTOMUPDATEMODELS:
mg.addCppInclude( '"customVarReferences.h"' )
mg.addCppInclude( '"customWUVarReferences.h"' )

mg.write(generateCustomClassDeclaration(nSpace, model==INITVARSNIPPET or model==SPARSEINITSNIPPET,
model==WUPDATEMODELS, model==CUSTOMUPDATEMODELS))
with SwigModuleGenerator( 'impl',
Expand All @@ -425,6 +444,9 @@ def generateBackend(swigPath, folder, namespace):
mg.addSwigEnableUnderCaseConvert()
mg.addSwigInclude('<exception.i>')

# Add exception handler
mg.addStandardExceptionHandler()

with SwigAsIsScope(mg):
mg.addCppInclude('<plog/Appenders/ConsoleAppender.h>')
mg.addCppInclude('"optimiser.h"')
Expand Down Expand Up @@ -456,22 +478,6 @@ def generateBackend(swigPath, folder, namespace):
# Import stl containers so as to support std::string
mg.addSwigImport( '"StlContainers.i"' )

# Include SWIG exception handling library
mg.addSwigInclude('<exception.i>')

mg.write('''
%exception create_backend{
try
{
$action
}
SWIG_CATCH_STDEXCEPT
catch (...) {
SWIG_exception(SWIG_UnknownError, "Unknown exception");
}
}
''')

# To prevent having to expose filesystem, simply export a wrapper that converts a string to a filesystem::path and calls createBackend
with SwigInlineScope(mg):
mg.write('CodeGenerator::' + namespace + '::Backend create_backend(const ModelSpecInternal &model, const std::string &outputPath, plog::Severity backendLevel, const CodeGenerator::' + namespace + '::Preferences &preferences)\n'
Expand Down Expand Up @@ -526,6 +532,8 @@ def generateConfigs(gennPath, backends):

pygennSmg.addAutoGenWarning()
pygennSmg.addSwigModuleHeadline()
pygennSmg.addSwigInclude( '<exception.i>' )
pygennSmg.addStandardExceptionHandler()
with SwigAsIsScope( pygennSmg ):
pygennSmg.addCppInclude( '<fstream>' )
pygennSmg.addCppInclude( '<plog/Appenders/ConsoleAppender.h>' )
Expand Down Expand Up @@ -607,6 +615,8 @@ def generateConfigs(gennPath, backends):
pygennSmg.addSwigImport( '"' + mg.name + '.i"' )
mg.addAutoGenWarning()
mg.addSwigModuleHeadline( directors = True )
mg.addSwigInclude( '<exception.i>' )
mg.addStandardExceptionHandler()
with SwigAsIsScope( mg ):
mg.addCppInclude( '"' + headerFilename + '"' )
mg.addCppInclude( '"' + headerFilename.split('.')[0] + 'Custom.h"' )
Expand Down
12 changes: 12 additions & 0 deletions pygenn/genn_wrapper/swig/Models.i
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
%ignore LegacyWrapper;

%include <std_vector.i>
%include <exception.i>

%import "Snippet.i"
%import "InitVarSnippet.i"
Expand All @@ -51,6 +52,17 @@
%template(VarVector) std::vector<Models::Base::Var>;
%template(VarRefVector) std::vector<Models::Base::VarRef>;

// Add standard exception handler
%exception {
try {
$action
}
SWIG_CATCH_STDEXCEPT // catch std::exception
catch (...) {
SWIG_exception(SWIG_UnknownError, "Unknown exception");
}
}

%include "models.h"
%include "varAccess.h"

Expand Down
11 changes: 11 additions & 0 deletions pygenn/genn_wrapper/swig/Snippet.i
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
%}
%include <std_string.i>
%include <std_vector.i>
%include <exception.i>

%feature("flatnested", "1");
%rename("%(undercase)s", %$isfunction, notregexmatch$name="add[a-zA-Z]*Population", notregexmatch$name="addCurrentSource", notregexmatch$name="addCustomUpdate", notregexmatch$name="assignExternalPointer[a-zA-Z]*") "";
Expand All @@ -26,6 +27,16 @@

%feature("director") Snippet::Base; // for inheritance in python

// Add standard exception handler
%exception {
try {
$action
}
SWIG_CATCH_STDEXCEPT // catch std::exception
catch (...) {
SWIG_exception(SWIG_UnknownError, "Unknown exception");
}
}

// flatten nested classes
%rename (EGP) Snippet::Base::EGP;
Expand Down

0 comments on commit af73a4b

Please sign in to comment.