python: class instance can't see self attribute - python

In my project i use module from known bt_manager to decode sbc audio stream. This module is python wrap for C-functions from rtpsbc library.
class SBCCodec:
def __init__(self, config):
import sys
try:
self.codec = ffi.verify(b'#include "rtpsbc.h"',
libraries=[b'rtpsbc'],
ext_package=b'rtpsbc')
except:
print 'Exception:', sys.exc_info()[0]
self.config = ffi.new('sbc_t *')
self.ts = ffi.new('unsigned int *', 0)
self.seq_num = ffi.new('unsigned int *', 0)
self._init_sbc_config(config)
self.codec.sbc_init(self.config, 0)
When i try to create SBCCodec class instance it gives me:
AttributeError: SBCCodec instance has no attribute 'codec'
You can see this attribute in the piece of code i posted above. It works with ffi-methods (ffi.verify, ffi.new). When i input those commands in ipython everything works correct without errors.
What have i missed?

As #Torxed has already mentioned the only way this would happen is if ffi.verify inside your try block throws an exception. If that happens self.codec will not be initialised. If that happens your code does not rethrow the exception and continues as normal after simply printing (which is not clean behaviour). The final statement then tries to call self.codec.config.sbc_init, that is it assumes that self.codec is already intialised, which is incorrect in this particular case and that is why you get the AttibuteError.
If you want to create the instance anyway regardless of the failure for ffi.verify at the start of init define self.codec = None and in your final statement insert a check such as:
if (self.codec != None ):
self.codec.sbc_init(self.config, 0)
Hope that helps.

Related

How to get the current test name in cocotb

I am using cocotb version 1.5.2, and I would like to write an utility function to create reports/plots per test.
MWE: Implementing the get_test_name function so that the following test will print my_wonderful_test.
import cocotb
#cocotb.test()
async def my_wonderful_test(dut):
print(get_test_name(dut));
def get_test_name(dut):
pass # how do I get the current test from here?
You can use "name" attribute :
import cocotb
#cocotb.test()
async def my_wonderful_test(dut):
print(my_wonderful_test.name);
But not sure that exactly you want.
Thank you for the commenters, and thank you #FabienM for trying to give an answer. Thank you for #Tzane for trying to find an answer. You were close.
If you want to know a one liner answer
import cocotb;
def get_test_name():
return cocotb.regression_manager._test.name
but the underline prefix in _test maybe it will break in the future, but for since I was only concerned about version 1.5.2 this is OK for me.
Any way I implemented another method that scans the stack one level at a time and check if the frame is in a cocotb.test decorated function. This is also the method that cocotb uses to _discover_tests
It won't work if the test is in a closure, but I never use that, and I don't know if it is even supported.
import cocotb
import inspect;
import sys
#cocotb.test()
async def test_get_testname(dut):
print('Runnign from test ', get_test_name())
def get_test_name():
try:
return cocotb.regression_manager._test.name
except:
pass
cocotbdir = '/'.join(cocotb.__file__.split('/')[:-1])
frame = sys._getframe();
prev_frame = None
while frame is not None:
try:
# the [documentation](https://docs.python.org/2/library/inspect.html#inspect.getmodule)
# says
# Try to guess which module an object was defined in.
# Implying it may fail, wrapp in a try block and everything is fine
module = inspect.getmodule(frame.f_code)
func_name = inspect.getframeinfo(frame).function
if hasattr(module, func_name):
ff = getattr(module, func_name)
if isinstance(ff, cocotb.test):
return func_name
except:
pass
prev_frame = frame;
frame = frame.f_back;
# return None if fail to determine the test name
I don't know why my questions are so badly received
It was something simple that I preferred to engage more people

Make python don't undo things after an error is raised in try block

I have a python class in which I open files and read out data. If some creteria are not met, I raise an error, but before that I specify the error by giving the object an attribute: self.Error = specification. But since the error raising undos everything in the try block I can't access it. This happens in the __init__ function, so the created object doesn't even exist..
Here's the necessary code:
class MyClass:
def __init__(self):
#do something
if this_or_that:
self.Error = specification
raise MyCostumError
try:
object = MyClass()
except MyCostumError:
print(object.Error)
I get: NameError: name 'object' is not defined
Just for clarification:
I have defined MyCostumError, the variable names are just for better understanding: I use good ones and they are defined and I need the clarification, because an Error can be raised in different lines.
So here's my question:
Is there something like try/except, but when an error is raised it does NOT undo everything. Or am I just stupid and there is a much easier method for a achieving this?
If you are raising an exception in the initializer, you should not rely on the object to be created to get some error information to the caller. This is where you should use the exception to pass that information:
class MyCustomError(Exception):
pass
class MyClass:
def __init__(self):
#do something
if this_or_that:
raise MyCustomError(specification) # put the spec in the exception itself
try:
object = MyClass()
except MyCustomError as e:
print(e) # the spec is in the exception object
You are trying to reference to an object that cannot exist. Let me explain:
If an error occurs when you try to initialise an object, that object will not be initialised. So if you try to acced to it when it is not initialised, you will get an error.
try:
object = MyClass() #initialising object successful, object existing.
except: #initialising failed, object does not exist.
print(object.Error) #nameError, since object was never created.
Try/except doesn't undo anything, just stops doing something if an error occurs.
Error raising doesn't undo anything. Have a look at the docs.
As your output states, the object is not defined, this is because when you raise an error in the __init__, it is seen as the initialosor of your class failing, and this does not return an object.
I think this is what you're looking for:
class MyClass:
def __init__(self):
# do initialisation stuff
def other_method(self):
# do something
if this_or_that:
self.Error = specification
raise MyCustomError(specification)
object = MyClass()
try:
object.other_method()
except MyCustomError as e:
print(e)
print(object.Error)
It's not a beautiful solution but it should work:
errorcode = None
class MyClass:
def __init__(self):
global errorcode
#do something
if this_or_that:
errorcode = specification
raise MyCostumError
try:
object = MyClass()
except MyCostumError:
print(errorcode)
Given your question I think the following should fit your use case well.
class MyClass:
def __init__(self):
# Do something
try:
if this_or_that:
self.Error = specification
raise MyCostumError
except MyCustomError as e:
# Handle your custom error however you like
object = MyClass()
In the above case you should be able to mitigate the risk of instantiation failing due to custom exception/error raising failing by handling this behaviour within MyClass.__init__ itself.
This is also a much cleaner solution in terms of keeping logic relating to instantiation of MyClass objects contained within the __init__ function of the class - i.e. you won't have to worry about wrapping instantiations of this class in try/except blocks each time they are present in your code.

Why is my program returning NameError: name 'self' is not defined as the error

I'm trying to get a program to tell me how many posts I've liked using the InstagramAPI module. It's returning NameError: name 'self' is not defined and I'm not sure why.
This is my code:
from InstagramAPI import InstagramAPI
import time, json, re
import json
import requests
import os
username = ''
password = ''
i = InstagramAPI(username, password)
i.login()
def getTotalLikedMedia(self, scan_rate=1):
next_id = ''
liked_items = []
for x in range(0, scan_rate):
temp = self.getLikedMedia(next_id)
temp = self.LastJson
try:
next_id = temp["next_max_id"]
for item in temp["items"]:
liked_items.append(item)
except KeyError as e:
break
return liked_items
getTotalLikedMedia
self represents the instance of the class. By using the argument bound to the name self we can access the attributes and methods of the class.
You appear to be defining a method without the class it is supposed to be a method of.
class something:
def __init__(self, something):
self.something = something
ins = something()
Without posting entire traceback it is impossible to know what really happened. I guess that the code you posted is not how it really looks like on your computer. It seems like a method definition but here it is just a plain function, where self is just an argument called... well, self. Technically nothing is wrong with that, and calling that method would probably result in raising AttributeError, when the interpreter tries to execute line temp = self.getLikedMedia(next_id), unless you passed as self some object that does have the method getLikedMedia().

why is pylint complaining about missing Exception.message?

I usually declare a base exception for my modules which does nothing, from that one I derive custom errors that could have additional custom data: AFAIK this is the Right Way™ to use exeptions in Python.
I'm also used to build a human readable message from that custom info and pass it along, so I can refer to that message in error handlers. This is an example:
# this code is meant to be compatible with Python-2.7.x
class MycoolmoduleException(Exception):
'''base Mycoolmodule Exception'''
class TooManyFoo(MycoolmoduleException):
'''got too many Foo things'''
def __init__(self, foo_num):
self.foo_num = foo_num
msg = "someone passed me %d Foos" % foo_num
super(TooManyFoo, self).__init__(msg)
# .... somewhere else ....
try:
do_something()
except Exception as exc:
tell_user(exc.message)
# real world example using Click
#click.command()
#click.pass_context
def foo(ctx):
'''do something'''
try:
# ... try really hard to do something useful ...
except MycoolmoduleException as exc:
click.echo(exc.message, err=True)
ctx.exit(-1)
Now, when I run that code through pylint-2.3.1 it complains about my use of MycoolmoduleException.message:
coolmodule.py:458:19: E1101: Instance of 'MycoolmoduleException' has no 'message' member (no-member)
That kind of code always worked for me (both in Python2 and Python3) and hasattr(exc, 'message') in the same code returns True, so why is pylint complaining? And/or: how could that code be improved?
(NB the same happens if I try to catch the built in Exception instead of my own MycoolmoduleException)

Python DispatchWithEvents results in attribute error:

Using dispatch as win32com.client.Dispatch works fine, but produces attribute error: from DispatchWithEvents call win32com.client.WithEvents, problem exists until Temp\gen_py folder is removed
I can remove the Temp\gen_py folder at the very beginning before import win32com.client
path=r"C:\Users\omc\AppData\Local\Temp\gen_py"
rmtree(path, ignore_errors=True)
while os.path.exists(path):
pass
works fine for the 1st iteration in my test, but for the 2nd iteration for the same code produces attribute error:
from shutil import rmtree
path=r"C:\Users\omc\AppData\Local\Temp\gen_py"
rmtree(path, ignore_errors=True)
while os.path.exists(path):
pass
import win32com.client
class CanoeTestModuleEvents(object):
"""Handler for CANoe TestModule events"""
def OnStart(self):
print("< Test Module started >")
bTestModuleRunning = True
def OnStop(self,Reason) :
print("< Test Module stopped >")
bTestModuleRunning = False
if Reason == 0:
print("Test module was executed completely")
else:
if Reason== 1:
print("Test module was stopped by the user")
else:
print("Test module was stopped by measurement stop")
APP = win32com.client.Dispatch("CANoe.Application")
App.load("CANoeApplication.cfg")
# ---------------------------------------------------------------
# TestEnvironment Item(2)
# ---------------------------------------------------------------
TestEnvironment = self.App.Configuration.TestSetup.TestEnvironments.Item(1)
TestModule = self.TestEnvironment.Items.Item(2)
TestModule.TestVariant = TestVariant
App.Measurement.Start()
WaitForMeasurementStart()
win32com.client.WithEvents(TestModule, CanoeTestModuleEvents)
if MeasurementRunning():
TestModule.Start()
WaitForTestModuleStart()
while app.bTestModuleRunning == True:
pythoncom.PumpWaitingMessages()
time.sleep(.1)
App.Measurement.Stop()
# ---------------------------------------------------------------
# TestEnvironment Item(3)
# ---------------------------------------------------------------
TestEnvironment = self.App.Configuration.TestSetup.TestEnvironments.Item(1)
TestModule = self.TestEnvironment.Items.Item(3)
TestModule.TestVariant = TestVariant
App.Measurement.Start()
WaitForMeasurementStart()
win32com.client.WithEvents(TestModule, CanoeTestModuleEvents)
if MeasurementRunning():
TestModule.Start()
WaitForTestModuleStart()
while app.bTestModuleRunning == True:
pythoncom.PumpWaitingMessages()
time.sleep(.1)
App.Measurement.Stop()
AttributeError: object has no attribute
AttributeError: '<win32com.gen_py.CANoe 8.5 Type Library.ITestSetupItem instance at 0x49756368>' object has no attribute 'TestVariant'
The main reason for this attribute error is because your COM-server has shifted from late-binding (dynamic) to early binding (static).
In Late Binding, whenever a method is called, the object is queried for the method and if it succeeds, then the call can be made.
In Early Binding, the information of the object model is determined in advance from type information supplied by the object call. Early binding makes use of MakePy. Also, early binding is case sensitive.
There are two ways to fix this issue:
Use the dynamic module to force your code to work in a late-bound oriented way. Example use:
"win32com.client.dynamic.Dispatch()" instead of "win32com.client.Dispatch()"
Use camelcase sensitive keywords for the early bound oriented way. Example use:
"excel.Visible()" instead of "excel.VISIBLE()" or "excel.visible()"
Also, I think using early binding dependent methods by default create the gen_py folder every time.
Actually the problem here is that for some reason you need to cast the objects
csbTstMod = win32com.client.CastTo(csbTstMod, "ITSTestModule3")
print(csbTstMod.TestVariant)
This will now work.

Categories