diff --git a/libexec/trick/convert_swig b/libexec/trick/convert_swig index ca58cad67..92980ad3c 100755 --- a/libexec/trick/convert_swig +++ b/libexec/trick/convert_swig @@ -337,6 +337,24 @@ sub process_file() { print OUT "\n$new_contents" ; print OUT "$contents\n" ; print OUT $global_template_typedefs ; + + # Add _swig_setattr_nondynamic_instance_variable function for raising AttributeError for improper non-class attribute assingment in input processor. + # _swig_setattr_nondynamic_instance_variable function is added for each class in process_class subroutine. + foreach my $c ( @class_names ) { + if ( ! exists $class_typemap_printed{$c} ) { + my $c_ = $c ; + $c_ =~ s/\:/_/g ; + if ( $c !~ /::/ ) { + print OUT "\n#if SWIG_VERSION > 0x040000\n"; + print OUT "%pythoncode %{\n" ; + print OUT " if '$c' in globals():\n"; + print OUT " $c.__setattr__ = _swig_setattr_nondynamic_instance_variable(object.__setattr__)\n" ; + print OUT "%}\n" ; + print OUT "#endif\n"; + } + } + } + # Add a trick_cast_as macro line for each class parsed in the file. These lines must appear at the bottom of the # file to ensure they are not in a namespace directive and they are after the #define statements they depend on. undef %class_typemap_printed ; @@ -479,6 +497,9 @@ sub process_template($$) { my ( $contents_ref , $new_contents_ref ) = @_ ; my $extracted ; + # Add _swig_setattr_nondynamic_instance_variable function for raising AttributeError for improper class attribute assingment in input processor + # The function call is inserted after the 1st { of the class template so it is placed at the top + $$contents_ref=~s/{\n/{\n\n#if SWIG_VERSION > 0x040000\n\%pythoncode \%{\n __setattr__ = _swig_setattr_nondynamic_instance_variable(object.__setattr__)\n\%}\n#endif\n/m; if ( $$contents_ref =~ s/^(\s*;)//s ) { $$new_contents_ref .= $1 ; } else { @@ -605,6 +626,9 @@ sub process_class($$$$$) { $class_content .= $1 ; } + # Add _swig_setattr_nondynamic_instance_variable function for raising AttributeError for improper class attribute assingment in input processor + $class_content .= "\n#if SWIG_VERSION > 0x040000\n\%pythoncode \%{\n __setattr__ = _swig_setattr_nondynamic_instance_variable(object.__setattr__)\n\%}\n#endif\n" ; + ($extracted, $$contents_ref) = extract_bracketed( "{" . $$contents_ref , "{}") ; # remove the trailing semicolon because we may append text to the class. @@ -709,7 +733,6 @@ sub process_class($$$$$) { push @$class_names_ref , "$curr_namespace$class_name" ; # write the class contents and semicolon to ensure any template declarations below are after the semicolon. - $class_content .= "\n#if SWIG_VERSION > 0x040000\n\%pythoncode \%{\n __setattr__ = _swig_setattr_nondynamic_instance_variable(object.__setattr__)\n\%}\n#endif\n" ; $class_content .= $extracted . ";\n" ; my $c_ = "$curr_namespace$class_name" ; @@ -756,7 +779,7 @@ sub process_typedef_struct($$$$) { my ($typedef_struct_string , $contents_ref, $new_contents_ref , $class_names_ref) = @_ ; my $extracted ; - my ($begin, $tail , $struct_names, @struct_names) ; + my ($tail , $struct_names, @struct_names) ; #print "*** typedef_struct_string = $typedef_struct_string ***\n" ; @@ -765,7 +788,6 @@ sub process_typedef_struct($$$$) { $typedef_struct_string =~ s/((?:typedef\s+)?(struct|union)\s* # the words typedef struct|union ([_A-Za-z]\w*)?\s* # optional name {)//sx ; - $begin = $3 ; ($extracted, $$contents_ref) = extract_bracketed( "{" . $$contents_ref , "{}") ; #print "*** extracted = $extracted ***\n" ; @@ -780,9 +802,6 @@ sub process_typedef_struct($$$$) { $struct_names =~ s/\s//g ; @struct_names = split /,/ , $struct_names ; - if ( $begin ne "" ) { - push @$class_names_ref , $begin ; - } foreach my $s ( @struct_names ) { if ( $s !~ /\*/ ) { push @$class_names_ref , $s ; diff --git a/trick_source/trick_swig/swig_double.i b/trick_source/trick_swig/swig_double.i index 1427c8666..27ef62c09 100644 --- a/trick_source/trick_swig/swig_double.i +++ b/trick_source/trick_swig/swig_double.i @@ -66,3 +66,19 @@ class swig_double { PyObject * __len__() ; } ; +%pythoncode %{ +#if SWIG_VERSION > 0x040000 +def _trick_setattr_nondynamic_instance_variable(set): + def set_instance_attr(self, name, value): + if name == "thisown": + self.this.own(value) + elif name == "this": + set(self, name, value) + else: + msg = f'You cannot add instance attribute \'{name}\' to Trick swig_double' + raise AttributeError(msg) + return set_instance_attr + +swig_double.__setattr__ = _trick_setattr_nondynamic_instance_variable(object.__setattr__) +#endif +%} diff --git a/trick_source/trick_swig/swig_int.i b/trick_source/trick_swig/swig_int.i index d04bc52a2..ad6f0939c 100644 --- a/trick_source/trick_swig/swig_int.i +++ b/trick_source/trick_swig/swig_int.i @@ -89,3 +89,19 @@ class swig_int { PyObject * __bool__() ; } ; +%pythoncode %{ +#if SWIG_VERSION > 0x040000 +def _trick_setattr_nondynamic_instance_variable(set): + def set_instance_attr(self, name, value): + if name == "thisown": + self.this.own(value) + elif name == "this": + set(self, name, value) + else: + msg = f'You cannot add instance attribute \'{name}\' to Trick swig_int' + raise AttributeError(msg) + return set_instance_attr + +swig_int.__setattr__ = _trick_setattr_nondynamic_instance_variable(object.__setattr__) +#endif +%}