Python callback fails with access violation - python

I can call functions in my dll from python.
When I call a dll function that does a callback to my python code it fails.
It there some sort of mutex blocking my callback?
from ctypes import *
import _ctypes
#CFUNCTYPE(None)
def Test():
print ("Test here")
return
def SetUpDll():
print ("Setting read / write callback functions...")
windll.ClaRUN.AttachThreadToClarion(1)
MyDll = CDLL('IC2_CommsServer.dll')
SetTestFunc = getattr(MyDll, "SETTESTFUNC#Fl")
SetTestFunc (Test)
CallTestFunc = getattr(MyDll, "CALLTESTFUNC#F")
CallTestFunc()
_ctypes.FreeLibrary(MyDll._handle)
_ctypes.FreeLibrary(windll.ClaRUN._handle)
print ("Done.")
SetUpDll()
C:\Users\Derek\anaconda3_32\python.exe Z:/ps_IC2_dll/ps_IC2_dll.py
Setting read / write callback functions...
Traceback (most recent call last):
File "Z:/ps_IC2_dll/ps_IC2_dll.py", line 48, in <module>
SetUpDll()
File "Z:/ps_IC2_dll/ps_IC2_dll.py", line 40, in SetUpDll
CallTestFunc()
OSError: exception: access violation writing 0x009EF77C
Process finished with exit code 1

First, on Windows, the ctypes uses win32 structured exception handling to prevent crashes from general protection faults when functions are called with invalid argument values.
You have a bad call for this line of code:
CallTestFunc = getattr(MyDll, "CALLTESTFUNC#F")
Try to review your code, then see if the problem is from ps_IC2_dll.py build area.

Thanks to CristiFati who provided half of the answer.
This code now works, note that the clarion dll functions are now prototyped as ,C
A nice side effect is that the function names loose the "#F" suffix and so the code is simpler.
from ctypes import *
import _ctypes
#CFUNCTYPE(None)
def Test():
print ("Test here")
return
def SetUpDll():
print ("Setting read / write callback functions... Ptr=", sizeof(c_void_p), "bytes")
assert sizeof(c_void_p) == 4
ClaRTL = CDLL('./ClaRUN.dll')
MyDll = CDLL('./IC2_CommsServer.dll')
ClaRTL.AttachThreadToClarion.restype = None
ClaRTL.AttachThreadToClarion.argtypes = [c_int32]
ClaRTL.AttachThreadToClarion(1)
MyDll.SETTESTFUNC.restype = None
MyDll.SETTESTFUNC.argtypes = [CFUNCTYPE(None)]
MyDll.SETTESTFUNC (Test)
MyDll.CALLTESTFUNC.restype = None
MyDll.CALLTESTFUNC ()
_ctypes.FreeLibrary(MyDll._handle)
_ctypes.FreeLibrary(ClaRTL._handle)
print ("Done.")
SetUpDll()
Output is now:
C:\Users\Derek\AppData\Local\Programs\Python\Python38-32\python.exe Z:/ps_IC2_dll/ps_IC2_dll.py
Setting read / write callback functions... Ptr= 4 bytes
Test here
Done.
Process finished with exit code 0

Related

Not allowing the developer to use the print method

I have developed a python framework that is being used by others. In order to print any data to the output, the developer should use a Log class (Log.print(...)) and should not use the print() method directly. Is there any ways to force this rule throughout the code? For example, by throwing an error when a developer uses the print method directly like this:
Error: print method cannot be called directly. Please use Log.print().
Suppressing print (as discussed here) is not a good idea as the developer might get confused.
Actullay, below two line code are the same:
sys.stdout.write('hello'+'\n')
print('hello')
so, you can redirect sys.stdout to a class which raise a exception at calling print.
import sys
class BlockPrint():
call_print_exception = Exception('Error: print method cannot be called directly. Please use Log.print().')
def write(self, str):
raise self.call_print_exception
bp = BlockPrint()
sys.stdout=bp
print('aaa')
Output:
Traceback (most recent call last):
File "p.py", line 12, in <module>
print('aaa')
File "p.py", line 7, in write
raise self.call_print_exception
Exception: Error: print method cannot be called directly. Please use Log.print().

Using Python COM objects from Excel VBA

I am trying to create python classes to be used in Excel, taking references from Python: Programming on Win32.
Currently:
Python script (win32comLibrary.py)
class PythonUtilities:
_public_methods_ = [ "SplitString" ]
_reg_progid_ = "PythonDemos.Utilities"
_reg_clsid_ = "{AF272547-D5BC-4452-852E-3F8746672097}"
def SplitString(self, val, item = None):
import string
if item!=None: item = str(item)
return string.split(str(val), item)
if __name__== "__main__":
print("Registering COM server...")
import win32com.server.register
win32com.server.register.UseCommandLine(PythonUtilities)
Excel VBA
Sub test()
Set PythonUtils = CreateObject("PythonDemos.Utilities")
response = PythonUtils.SplitString("Hello From VB", " ")
For Each Item In response
MsgBox Item
Next Item
End Sub
Questions:
(a) at the reponse = ... line, there is a runtime error '-2147467259 (80004005)': Unexpected Python Error: Traceback (most recent call last): File .....
(b) when i typed python win32comLibrary.py --unregister in cmd, it returned Registering COM server...Traceback (most recent call last): File "win32comLibrary.py", line 19, in (module) import win32com.server.register ImportError: No module named win32com.server.register
I am currently using anaconda (spyder) and have installed pywin32. Invoking win32com.client methods from Python don't seem to throw any error.
Any assistance would be appreciated.
I have managed to solve the issue - just to close this off. Not sure if its the difference between older versions of python and 3.x but string.split(str(val), item) doesn't seem to work anymore. Instead, I have changed the return statement to return val.split(item). Oversight on my part - apologies.

How to limit python traceback to specific files

I write a lot of Python code that uses external libraries. Frequently I will write a bug, and when I run the code I get a big long traceback in the Python console. 99.999999% of the time it's due to a coding error in my code, not because of a bug in the package. But the traceback goes all the way to the line of error in the package code, and either it takes a lot of scrolling through the traceback to find the code I wrote, or the traceback is so deep into the package that my own code doesn't even appear in the traceback.
Is there a way to "black-box" the package code, or somehow only show traceback lines from my code? I'd like the ability to specify to the system which directories or files I want to see traceback from.
In order to print your own stacktrace, you would need to handle all unhandled exceptions yourself; this is how the sys.excepthook becomes handy.
The signature for this function is sys.excepthook(type, value, traceback) and its job is:
This function prints out a given traceback and exception to sys.stderr.
So as long as you can play with the traceback and only extract the portion you care about you should be fine. Testing frameworks do that very frequently; they have custom assert functions which usually does not appear in the traceback, in other words they skip the frames that belong to the test framework. Also, in those cases, the tests usually are started by the test framework as well.
You end up with a traceback that looks like this:
[ custom assert code ] + ... [ code under test ] ... + [ test runner code ]
How to identify your code.
You can add a global to your code:
__mycode = True
Then to identify the frames:
def is_mycode(tb):
globals = tb.tb_frame.f_globals
return globals.has_key('__mycode')
How to extract your frames.
skip the frames that don't matter to you (e.g. custom assert code)
identify how many frames are part of your code -> length
extract length frames
def mycode_traceback_levels(tb):
length = 0
while tb and is_mycode(tb):
tb = tb.tb_next
length += 1
return length
Example handler.
def handle_exception(type, value, tb):
# 1. skip custom assert code, e.g.
# while tb and is_custom_assert_code(tb):
# tb = tb.tb_next
# 2. only display your code
length = mycode_traceback_levels(tb)
print ''.join(traceback.format_exception(type, value, tb, length))
install the handler:
sys.excepthook = handle_exception
What next?
You could adjust length to add one or more levels if you still want some info about where the failure is outside of your own code.
see also https://gist.github.com/dnozay/b599a96dc2d8c69b84c6
As others suggested, you could use sys.excepthook:
This function prints out a given traceback and exception to sys.stderr.
When an exception is raised and uncaught, the interpreter calls sys.excepthook with three arguments, the exception class, exception instance, and a traceback object. In an interactive session this happens just before control is returned to the prompt; in a Python program this happens just before the program exits. The handling of such top-level exceptions can be customized by assigning another three-argument function to sys.excepthook.
(emphasis mine)
It's possible to filter a traceback extracted by extract_tb (or similar functions from the traceback module) based on specified directories.
Two functions that can help:
from os.path import join, abspath
from traceback import extract_tb, format_list, format_exception_only
def spotlight(*show):
''' Return a function to be set as new sys.excepthook.
It will SHOW traceback entries for files from these directories. '''
show = tuple(join(abspath(p), '') for p in show)
def _check_file(name):
return name and name.startswith(show)
def _print(type, value, tb):
show = (fs for fs in extract_tb(tb) if _check_file(fs.filename))
fmt = format_list(show) + format_exception_only(type, value)
print(''.join(fmt), end='', file=sys.stderr)
return _print
def shadow(*hide):
''' Return a function to be set as new sys.excepthook.
It will HIDE traceback entries for files from these directories. '''
hide = tuple(join(abspath(p), '') for p in hide)
def _check_file(name):
return name and not name.startswith(hide)
def _print(type, value, tb):
show = (fs for fs in extract_tb(tb) if _check_file(fs.filename))
fmt = format_list(show) + format_exception_only(type, value)
print(''.join(fmt), end='', file=sys.stderr)
return _print
They both use the traceback.extract_tb. It returns "a list of “pre-processed” stack trace entries extracted from the traceback object"; all of them are instances of traceback.FrameSummary (a named tuple). Each traceback.FrameSummary object has a filename field which stores the absolute path of the corresponding file. We check if it starts with any of the directory paths provided as separate function arguments to determine if we'll need to exclude the entry (or keep it).
Here's an Example:
The enum module from the standard library doesn't allow reusing keys,
import enum
enum.Enum('Faulty', 'a a', module=__name__)
yields
Traceback (most recent call last):
File "/home/vaultah/so/shadows/main.py", line 23, in <module>
enum.Enum('Faulty', 'a a', module=__name__)
File "/home/vaultah/cpython/Lib/enum.py", line 243, in __call__
return cls._create_(value, names, module=module, qualname=qualname, type=type, start=start)
File "/home/vaultah/cpython/Lib/enum.py", line 342, in _create_
classdict[member_name] = member_value
File "/home/vaultah/cpython/Lib/enum.py", line 72, in __setitem__
raise TypeError('Attempted to reuse key: %r' % key)
TypeError: Attempted to reuse key: 'a'
We can restrict stack trace entries to our code (in /home/vaultah/so/shadows/main.py).
import sys, enum
sys.excepthook = spotlight('/home/vaultah/so/shadows')
enum.Enum('Faulty', 'a a', module=__name__)
and
import sys, enum
sys.excepthook = shadow('/home/vaultah/cpython/Lib')
enum.Enum('Faulty', 'a a', module=__name__)
give the same result:
File "/home/vaultah/so/shadows/main.py", line 22, in <module>
enum.Enum('Faulty', 'a a', module=__name__)
TypeError: Attempted to reuse key: 'a'
There's a way to exclude all site directories (where 3rd party packages are installed - see site.getsitepackages)
import sys, site, jinja2
sys.excepthook = shadow(*site.getsitepackages())
jinja2.Template('{%}')
# jinja2.exceptions.TemplateSyntaxError: unexpected '}'
# Generates ~30 lines, but will only display 4
Note: Don't forget to restore sys.excepthook from sys.__excepthook__. Unfortunately, you won't be able to "patch-restore" it using a context manager.
the traceback.extract_tb(tb) would return a tuple of error frames in the format(file, line_no, type, error_statement) , you can play with that to format the traceback. Also refer https://pymotw.com/2/sys/exceptions.html
import sys
import traceback
def handle_exception(ex_type, ex_info, tb):
print ex_type, ex_info, traceback.extract_tb(tb)
sys.excepthook = handle_exception

Python handling the name error exception

I wrote a small code and tried to handle the name error exception.
I want to print a custom message even if there is an exception, but it is showing the complete the trace back.
#!/usr/bin/python -tt
import logging
def equaldigits(a, b):
logging.basicConfig(filename='run.log',level=logging.INFO)
try:
c = a - b
logging.info('%s is the difference between both the digits', str(c))
print c
return c
except NameError as e:
c = 'Unable to successfully complete execution'
logging.info(c)
print c
#return c
def main():
print '\n1st call'
equaldigits(10, 10)
print '\n2nd call'
equaldigits(1, 0)
print '\nException call'
equaldigits(a, 0)
# Standard boilerplate to call the main() function.
if __name__ == '__main__':
main()
This is the console output
1st call
0
2nd call
1
Exception call
Traceback (most recent call last):
File "./sut.py", line 28, in <module>
main()
File "./sut.py", line 24, in main
equaldigits(a, 0)
NameError: global name 'a' is not defined
In your attempt to catch an exception, you wrote equaldigits(a, 0). The interpreter sees the a and thinks it is a variable that isn't there, thus throwing the uncaught exception. In order to test your try/catch, you need to pass the letter a, like so
equaldigits('a', 0)
^ ^ note the quotes
The problem isn't happening within your equaldigits function where you have your logging information.
Its happening in your main function when the interpreter tries to pass the value of a to equaldigits. The variable a doesn't exist within the local scope of main, thus Python tries to find a global variable named a. Since it doesn't see one, it throws a NameError.
Your error is caused by the fact that a is not defined when you call equaldigits, the execution doesn't get to the try/except clause inside the function.
when you change
a - b
to
a - d
inside the function you'll see that your try/except works fine

Coloring exceptions from Python on a terminal

Is there an easy way to get the message of the exception to be colored on the command line? For example
def g(): f()
def f(): 1/0
g()
Gives the error
Traceback (most recent call last):
File "test.py", line 3, in <module>
g()
File "test.py", line 1, in g
def g(): f()
File "test.py", line 2, in f
def f(): 1/0
ZeroDivisionError: integer division or modulo by zero
I would like "integer division or modulo by zero" to be colored or highlighted on the terminal so that I can quickly pick it out of a long traceback (Linux only). Ideally, I wouldn't want to write a custom class for each Exception, but somehow catch and format all kinds.
EDIT: The question linked in the comments gives examples on how to solve the problem with external software, but I'm interested in an internal Python solution.
You can assign a custom function to the sys.excepthook handler. The function is called whenever there is a unhandled exception (so one that exits the interpreter).
def set_highlighted_excepthook():
import sys, traceback
from pygments import highlight
from pygments.lexers import get_lexer_by_name
from pygments.formatters import TerminalFormatter
lexer = get_lexer_by_name("pytb" if sys.version_info.major < 3 else "py3tb")
formatter = TerminalFormatter()
def myexcepthook(type, value, tb):
tbtext = ''.join(traceback.format_exception(type, value, tb))
sys.stderr.write(highlight(tbtext, lexer, formatter))
sys.excepthook = myexcepthook
set_highlighted_excepthook()
This version uses the pygments library to convert the traceback text into one formatted with ANSI coloring, before writing it to stderr.
Someone turned this into a project that detects terminal support and lets you set the pygments style, see colored-traceback.py.
Found another way to do this using the IPython module which is likely a dependency that everyone already has installed:
from IPython.core.ultratb import ColorTB
c = ColorTB()
exc = sys.exc_info()
print(''.join(c.structured_traceback(*exc)))
This takes the solution #freakish shared and makes the colorization part of the exception instead of requiring the user to add color to each exception message. Obviously, it only works for custom exceptions, so it may not be exactly what OP was looking for.
from colorama import Fore, init
init()
class Error (Exception):
def __init__ (self, message):
super().__init__(Fore.RED + message)
class BadConfigFile (Error):
pass
raise BadConfigFile("some error message")
This will print the traceback with "some error message" in red. Having 'Error' as a base class means you can create other exceptions that will all inherit the colorization of the message.
Have a look at colorama ( or any other coloring ) module. Then you can wrap you're entire app with:
import traceback
from colorama import Fore, init
init( )
try:
// your app
except Exception:
print Fore.RED + traceback.format_exc( ) + Fore.RESET
// possibly raise again or log to db

Categories

Resources