Pycharm: property cannot be set - python

I'm trying to override flask_jsonrpc's formatter method:
from flask_jsonrpc import exceptions
def override_jsonrpc_error_formatter(app):
#property
def json_rpc_format(self):
return ErrorFormatter.format_error(self)
exceptions.Error.json_rpc_format = json_rpc_format
override_jsonrpc_error_formatter function is called in a different file then.
Everything works, but pycharm shows me a warning for the last string, saying: "property json_rpc_format cannot be set". Why is it happening? Do I need to override it in a different way?

So, you import the exceptions from the flask_jsonrpc package.
In the package, you can find these lines:
class Error(Exception):
"""Error class based on the JSON-RPC 2.0 specs
http://groups.google.com/group/json-rpc/web/json-rpc-1-2-proposal
code - number
message - string
data - object
status - number from http://groups.google.com/group/json-rpc/web/json-rpc-over-http JSON-RPC over HTTP Errors section
"""
code = 0
message = None
data = None
status = 200
def __init__(self, message=None, code=None, data=None):
"""Setup the Exception and overwrite the default message
"""
super(Error, self).__init__()
if message is not None:
self.message = message
if code is not None:
self.code = code
if data is not None:
self.data = data
#property
def json_rpc_format(self):
"""Return the Exception data in a format for JSON-RPC
"""
error = {
'name': text_type(self.__class__.__name__),
'code': self.code,
'message': '{0}'.format(text_type(self.message)),
'data': self.data
}
if current_app.config['DEBUG']:
import sys, traceback
error['stack'] = traceback.format_exc()
error['executable'] = sys.executable
return error
So basically, you're trying to overwrite a property of the Error class from the flask_jsonrpc package, which is not allowed, because it's an unsettable property.
If you instead want to overwrite it, I think you should inherit from it using a different class, and either import that directly or connect it back to the module.
E.g.:
class myCustomError(exceptions.Error):
#property
def json_rpc_format(self):
return do_some_custom_logic_here()

You need to read about setters
In you case I would do something like:
class CustomError(Error):
#property
def json_rpc_format(self):
return self._json_rpc_format
#json_rpc_format.setter
def json_rpc_format(self, value):
self._json_rpc_format = value

Related

How to initialize an object coming from another class?

I have a function in a class (TableManager) that get the item and a specific field ('body') in DynamoDB.
class TableManager:
def get_body_dynamo(self, item):
get_body = json.loads(item.get('txt_vlr_parm_requ').get('body')) ##dict
return get_body
I need to initialize this 'body' field in another class (S3Connection), but I'm having trouble calling this function inside init.
class S3Connection:
def __init__(self, file, logs):
self.file = file
self.logs = logs
self.versions = None
I need something like this, to use this body I got from Dynamodb and create functions.
class S3Connection:
def __init__(self, file, logs, body_dynamo: TableManager.get_body_dynamo()):
self.body_dynamo = body_dynamo
self.file = file
self.logs = logs
self.versions = None
This way, of course, is giving error (not recognizing what body_dynamo is).
I'm new in programming and Python, so I appreciate any help.

Unable to raise Exception while mocking a whole python class in unittest

Here is the original class:
class Original(object):
def __ init__(self, path):
self.xml = None
self.path = path
self.convert() # <----- I can't modify anything in my class
def convert(self):
#some code here
self.xml = external_api_call # <------------this generates objects for this property
self.transform()
def transform(self):
#some code
if not self._xml:
raise Exception('None value')
for project in self.xml.projects:
try:
value = getattr(project, "name")
except AttributeError:
raise Exception('AttributeError')
print('Yes it worked')
I want to have 100% coverage therefore, i tried to generate mock objects for external api calls. Unfortunately while using a mock object it never raises any exception.
with mock.patch('something.Original', autospec=True) as mock_object:
mock_object.xml = None
mock_object.transform()
It should generate an exception but it doesn't. I have also tried different approaches e.g side_effect property of mock object.
mock_object._xml.return_value
#patch('something.Original')
def test_case_1(Original):
Original.xml.side_effect = Exception()
Original.transform()

Construct object via __init__ and ignore constructor exception

I have a Python class whose __init__ method raises a custom exception called WrongFileSpecified.
However, when I write a unit test, I want to assign the attributes of the instance object from a test fixture. So normally what I would be doing is reading data off a file and then working with the instance object.
But with the test, I cannot use any test files, so I basically need to hard code the data in the instance object in the setUp method of the unit test. Is there any way to get a instance created without __init__ complaining about the exception?
Sample code:
class A(object):
def __init__(self, folderPath):
#check folder path using os.isdir() otherwise raise exception
#...
self.folderPath = folderPath
#Call load record
self._load_records() #uses self.folderPath and raises exceptions as well
#Note i cannot avoid raising these exceptions, its required
class TestA(unittest.TestCase):
.......
obj = None
def setUp(self):
obj = A('fake folder path')
obj.val1 = "testparam1"
obj.param2 = "testparam2"
def test_1(self):
.....
You can create an empty object, bypassing __init__ by using __new__.
obj = obj_type.__new__(obj_type)
Note that obj_type is the appropriate type object. This is a little hacky but it works. You are reponsible for setting the object's members.
Edit: here is an example.
class Foo():
def __init__(self):
self.x = 1
self.y = 2
def say_hello(self):
print('Hello!')
r = Foo.__new__(Foo)
r.say_hello()
print(r.x)
Console output:
Hello!
Traceback (most recent call last):
File "C:\WinPython-64bit-3.3.5.7\python-
3.3.5.amd64\Scripts\projects\luc_utils\dev\test\
unit_test_serialization.py", line 29, in <module>
print(r.x)
AttributeError: 'Foo' object has no attribute 'x'
Here are two options:
Refactor the file loading out to a class method, which is the Pythonic method of providing an alternate constructor (see below); or
Provide an additional parameter to __init__ to suppress the exceptions when necessary (e.g. def __init__(self, folderPath, suppress=False), or validate=True, whichever makes more sense for your usage).
The latter is a bit awkward, in my opinion, but would mean that you don't have to refactor existing code creating A instances. The former would look like:
class A(object):
def __init__(self, ...):
"""Pass whatever is loaded from the file to __init__."""
...
#classmethod
def from_file(cls, folderPath):
"""Load the data from the file, or raise an exception."""
...
and you would replace e.g. a = A(whatever) with a = A.from_file(whatever).
There is a very useful module called mock, you can check it out later, I feel that in this case it will be too much. Instead, you should consider redesigning your class, like this, for example:
class A(object):
def __init__(self, folderPath):
self.folderPath = folderPath
def _load_records(self)
#check folder path using os.isdir() otherwise raise exception
...
#uses self.folderPath and raises exceptions as well
...
#classmethod
def load_records(cls, folderpath):
obj = cls(folderpath)
obj._load_records()
return obj
# Usage
records = A.load_records('/path/to/records')
Then you can do:
class TestA(unittest.TestCase):
.......
obj = None
def setUp(self):
self.obj = A('fake folder path')
self.obj.val1 = "testparam1"
self.obj.param2 = "testparam2"
def test_1(self):
self.assertRaises(self.obj._load_records, HorribleFailureError)
Also i highly recommend to check out pytest, it has wonderful facilities for test fixtures, including fixtures for files and folders.

Proper naming scope for custom error handlers in Python

I'm trying to write an error handling class for my application. Is it necessary to include the full path to the error handler every time? Below is my code.
appname/appname/model/error.py
class UserError(Exception):
""" User errors
"""
def __init__(self, value):
self.value = value
def __str__(self):
return repr(self.value)
My class function:
from error import UserError
def doSomething(
""" Some function
"""
if (value == 2):
pass
else:
raise UserError('Value is not 2')
That is called from my application as follows:
from error import UserError
try:
print names['first']
except appname.model.error.UserError as e:
print e
When raised:
>> appname.model.error.UserError: 'No file specified'
Do I have to refer to this as "appname.model.error.UserError" all the time? Or is there a way to just refer to this error as UserError or even error.UserError? Where to I adjust the scope of this? Seems like not a good idea in case I change the directory structure (or even name) of my application, no?
You could do this:
from appname.model.error import UserError

How do I get the name of the class containing a logging call in Python?

If I want the function name I can simply include %(funcName)s in the Formatter. But how do I get the name of the class containing the logging call instead?
I've gone through the documentation for logging, but I can't find any mentioning of it.
For a rather easy, pythonic way to get the class name to output with your logger, simply use a logging class.
import logging
# Create a base class
class LoggingHandler:
def __init__(self, *args, **kwargs):
self.log = logging.getLogger(self.__class__.__name__)
# Create test class A that inherits the base class
class testclassa(LoggingHandler):
def testmethod1(self):
# call self.log.<log level> instead of logging.log.<log level>
self.log.error("error from test class A")
# Create test class B that inherits the base class
class testclassb(LoggingHandler):
def testmethod2(self):
# call self.log.<log level> instead of logging.log.<log level>
self.log.error("error from test class B")
testclassa().testmethod1()
testclassb().testmethod2()
By naming the logger as above, the %(name)s will be the name of your class
example output
$ python mymodule.py
[2016-02-03 07:12:25,624] ERROR [testclassa.testmethod1:29] error from test class A
[2016-02-03 07:12:25,624] ERROR [testclassb.testmethod2:36] error from test class B
Alternative(s)
Non-inheritance
import logging
def log(className):
return logging.getLogger(className)
class testclassa:
def testmethod1(self):
log(self.__class__.__name__).error("error from test class A")
class testclassb:
def testmethod2(self):
log(self.__class__.__name__).error("error from test class B")
testclassa().testmethod1()
testclassb().testmethod2()
You should use extra argument:
views.py
import logging
class SampleClass():
def sample_func(self):
logging.getLogger('info_logger').info('some text', extra={'className': self.__class__.__name__})
logger_settings.py
'format': '%(className)s | %(message)s ',
output log:
INFO | SampleClass | "some text"
There is almost certainly a better way of doing this, but until someone points that out, this will work:
import inspect
class testclass:
def testmethod(self):
log()
def log():
stack = inspect.stack()
try:
print "Whole stack is:"
print "\n".join([str(x[4]) for x in stack])
print "-"*20
print "Caller was %s" %(str(stack[2][4]))
finally:
del stack
testclass().testmethod()
The output of this is the following:
Whole stack is:
[' stack = inspect.stack()\n']
[' f()\n']
['testclass().testmethod()\n']
[' exec code in self.locals\n']
[' ret = method(*args, **kwargs)\n']
None
--------------------
Caller was ['testclass().testmethod()\n']
Yet another approach if you also want the module name:
class MyClass(object):
#property
def logger(self):
return logging.getLogger(f"{__name__}.{self.__class__.__name__}")
def what(self, ever):
self.logger.info("%r", ever)
I personally just tend to name my loggers after classes, as it makes it much easier to track down where a particular message came from. So you can have a root logger named "top", and for the module "a" and class "testclass", I name my logger "top.a.testclass".
I don't see the need to otherwise retrieve the classname, since the log message should give you all the information you need.
#ed's response above, it feels very unpythonic to me and it is not something I would be comfortable with using on production code.
This is a function to make an informative log message using the representation class method:
https://docs.python.org/3/library/functions.html#repr
def log_message(thing: object = None, message: str = '') -> str:
""":returns: detailed error message using reflection"""
return '{} {}'.format(repr(thing), message)
This can be implemented to any class using a mix-in:
class UtilMixin(object):
def log(self, message: str = '') -> str:
""":returns: Log message formatting"""
return log_message(thing=self, message=message)
You can than be associated with a class using multiple inheritance:
class MyClass(object, UtilMixin):
def __repr__(self) -> str:
return '<{}>'.format(self)
pass
Usage
logger.warning(self.log('error message goes here'))

Categories

Resources