Why isn't json.dumps() using my custom classes JSON serialiser? - python

I have a Python3 class defined like so:
class Principal:
def __init__(self, id, name):
self.id = id
self.name = name
def default(self, o):
print("default called")
return {"id":self.id, "princpal":self.name}
...
If I create an instance of this class:
new_principal = Principal("p_1", "Ted") and call json.dumps(new_principal) the expected behaviour of the dumps functions would be to use my classes default() in order to return a dict that can be converted to JSON.
This is not happening however, it does not attempt to call my classes default() and so returns an error that the class is not serializable.
The docs states Implement this method in a subclass such that it returns a serializable object for ``o``, or calls the base implementation (to raise a ``TypeError``). which I believe I have done, yet it does not appear to call the classes defult().
Why does is this happening? If I specify the default using json.dumps(new_principal, Principal(new_principal)) then it parses successfully.
I can't see why my function isn't being called.

Because that's simply not how json.dump works. The passage you've quoted about default is for subclassing the JSON serializer, which you're not doing.
If you're just using json.dump, you'll need to pass a default=... function to it that does the Right Thing, e.g.
class Principal:
def __init__(self, id, name):
self.id = id
self.name = name
def to_json(self):
return {"id": self.id, "princpal": self.name}
def default_dumper(o):
if hasattr(o, "to_json"):
return o.to_json()
raise TypeError(f"Unable to JSONify {o}")
# ...
data = json.dumps(new_principal, default=default_dumper)

Related

Using Python decorators to gather information on available method and store that data in the class or instance

I found a lot of questions regarding decorators and classes, and access to the class instance that is being decorated. As far as I could understand, the decorator generator can not access the object instance because, at that time, no object was yet created.
Nevertheless, it seems that if a decorator uses a class reference (I mean, receives cls), then I am able to access to some class field:
class Foo:
_tags = {}
#classmethod
def _tag(cls, tag_name):
def decorator(func):
def tmp(*args, **kwargs):
return func(*args, **kwargs)
cls._tags[tag_name] = func.__name__
return tmp
return decorator
This works as a charm for subclasses, where I can write:
#Foo._tag("something")
def somethingelse():
pass
But this stores the information in the father class (as expected), as we are talking about class variables.
I wonder if there is a way to have a similar behavior, but guaranteeing that each subclass has its own instance of the _tags property.
I can foresee some workarounds, like parsing the source code, or inspecting the functions, during __init__. But I was looking for a simpler way, if there is such a way.
Edit 1: to make it clearer, I want to decorate methods from the subclass. Thus, this is not a possibility:
Class Bar (Foo):
#Bar._tag("method")
def method(self):
pass
as the processor/compiler did not complete the creation of the class yet. Otherwise, the solution proposed of a two level dictionary with class/method would work good enough for me.
WORKAROUND
My decorator:
#classmethod
def TAG(cls, name):
def decorator(func):
def tmp(*args, **kwargs):
return func(*args, **kwargs)
tmp._has_alias = name
return tmp
return decorator
During __init__, I get this info, and store:
self._tags = {getattr(self, name).has_alias: name for name in dir(self) if callable(getattr(self, name)) and hasattr(getattr(self, name), "_has_alias")}
A quick workaround could be to treat _tags as a dictionary of dictionaries, with the top level key being the name of the subclass, and its associated dictionary containing the callables wrapped by its inherited version of _tag:
from collections import defaultdict
class Foo:
_tags = defaultdict(dict)
#classmethod
def _tag(cls, tag_name):
def decorator(func):
def tmp(*args, **kwargs):
return func(*args, **kwargs)
cls._tags[cls.__name__][tag_name] = func.__name__ #storing tag_name under the name of the subclass
return tmp
return decorator
Now, when creating subclasses and wrapping functions, _tags will store the values under the subclass name by which _tag was called:
class A(Foo):
pass
class B(Foo):
pass
#A._tag('test_a')
def a():
pass
#B._tag('test_b')
def b():
pass
print(dict(Foo._tags))
Output:
{'A': {'test_a': 'a'}, 'B': {'test_b': 'b'}}

Get decorated class from its name in the decorator?

I decorated some methods with #bot_thinking, which stores some information about the decorated method in the functions attribute.
One piece of information is 'class_name', but my program needs the class type as a variable, e.g. RandomBot. I would like to get this class.
Here is some sample code:
class DepthPrunedMinimaxAgent(Agent):
#bot_thinking(associated_name="minimax profondeur")
def select_move(self, game_state: GameState):
Above is the decorated part of the code.
The decorator:
functions = {}
def bot_thinking(associated_name, active=True):
def _(func):
if active:
class_name = func.__qualname__.rsplit('.')[-2]
import sys
# class_name_2=getattr(sys.modules[__name__], class_name)
# module=importlib.import_module('sources.agent')
functions[associated_name] = (associated_name, class_name,
globals()[class_name], func)
else:
functions.pop(associated_name)
return _
bot_thinking isn't a real decorator, it's a decorator factory.
From the func function, I get the class_name, but I can't use the accepted answer by #m.kocikowski, to find the correct class because this class is decorated, so it already imports the annotation module, so importing from the module of the annotation the annotated module would result in a cyclic import, which python does not seem to permit.
Do you see a method to get the class from its name?
ps:
ps:
to be clearer : the annotation part of the code need an import to the annotated classes(to retrieve the class from its name), which also need an importation of the annotation (for the annotation to work).
You can do what you want if you use a descriptor class, rather than a function, as the decorator, at least if you're using Python 3.6 or newer. That's because there's a new method added to the descriptor protocol, __set_name__. It gets called when the descriptor object is saved as a class variable. While most descriptors will use it to record the name they're being saved as, you can use it to get the class you're in.
You do need to make your decorator object wrap the real function (implementing calling and descriptor lookup methods), rather than being able to return the unmodified function you were decorating. Here's my attempt at a quick and dirty implementation. I don't really understand what you're doing with functions, so I may not have put the right data in it, but it should be close enough to get the idea across (owner is the class the method stored in).
functions = {}
def bot_thinking(associated_name, active=True):
class decorator:
def __init__(self, func):
self.func = func
def __set_name__(self, owner, name):
if active:
functions[associated_name] = (associated_name, owner.__name__,
owner, self.func)
else:
functions.pop(associated_name)
def __get__(self, obj, owner):
return self.func.__get__(obj, owner)
def __call__(self, *args, **kwargs):
return self.func(*args, **kwargs)
return decorator
The problem is the class hasn't been defined yet when the bot_thinking() decorator factory (and decorator itself) are executing. The only workaround I can think of would be to patch things up after the class is defined, as illustrated below:
from pprint import pprint, pformat
functions = {}
def bot_thinking(associated_name, active=True):
def _(func):
if active:
class_name = func.__qualname__.split(".")[-2]
functions[associated_name] = (associated_name, class_name, class_name, func)
else:
functions.pop(associated_name, None)
return func # Decorators must return a callable.
return _
class Agent: pass
class GameState: pass
class DepthPrunedMinimaxAgent(Agent):
#bot_thinking(associated_name="minimax profondeur")
def select_move(self, game_state: GameState):
pass
# After class is defined, update data put into functions dictionary.
for associated_name, info in functions.items():
functions[associated_name] = (info[0], info[1], globals()[info[2]], info[3])
pprint(functions)
Output:
{'minimax profondeur': ('minimax profondeur',
'DepthPrunedMinimaxAgent',
<class '__main__.DepthPrunedMinimaxAgent'>,
<function DepthPrunedMinimaxAgent.select_move at 0x00F158A0>)}

Call another method in a class when the given method does not exist?

Say I have a class which contains several functions.
class Person:
def __init__(self): pass
def say(self, speech): pass
def walk(self, destination): pass
def jump(self): pass
When the user instantiates a Person, I'd like them to be able to call any method of the class. If the requested method does not exist (e.g. Person.dance()), a default function should be called instead.
I imagine that this could be done via a theoretical magic method -
class Person:
def __init__(self): pass
def say(self, speech): pass
def walk(self, destination): pass
def jump(self): pass
def sleep(self): print("Zzz")
def __method__(self, func):
if func.__name__ not in ['say','walk','jump']:
return self.sleep
else
return func
billy = Person()
billy.dance()
>> "Zzz"
However, I know of no such magic method.
Is there a way to make non-existent methods within a class redirect to another class?
It's important that the end-user doesn't have to do anything - from their perspective, it should just work.
The standard way to catch an undefined attribute is to use __getattr__:
# But see the end of the answer for an afterthought
def __getattr__(self, attr):
return self.sleep
Python does not differentiate between "regular" attributes and methods; a method call starts with an ordinary attribute lookup, whose result just happens to be callable. That is,
billy.run()
is the same as
f = billy.run
f()
This means that __getattr__ will be invoked for any undefined attribute; there is no way to tell at lookup time whether the result is going to be called or not.
However, if all you want is to define "aliases" for a common method, you can do that with a loop after the class statement.
class Person:
def __init__(self): pass
def say(self, speech): pass
def walk(self, destination): pass
def jump(self): pass
def do_all(self): pass
for alias in ["something", "something_else", "other"]:
setattr(Person, alias, Person.do_all)
You can also make hard-coded assignments in the class statement, but that would be unwieldy if there are, as you mention, hundreds of such cases:
class Person:
def do_all(self): pass
something = do_all
something_else = do_all
(I did not experiment with using exec to automate such assignments in a loop; it might be possible, though not recommended.)
You can also embed the list of aliases in the definition of __getattr__, come to think of it:
def __getattr__(self, attr):
if attr in ["something", "something_else", "other"]:
return self.sleep
else:
raise AttributeError(f"type object 'Person' has no attribute '{attr}'")
Your users might find the API behavior confusing. However, if you're sure you need this pattern, you can try something like
# getattr will get the function attribute by a string name version
# None is returned if no function is found
my_func = getattr(self, 'my_func', None)
# callable ensures `my_func` is actually a function and not a generic attribute
# Add your if-else logic here
if callable(my_func):
my_func(args)
else:
...
You could nest your "default" function inside __getattr__ in order to gain access to the called non-existent method's name and arguments.
class Test:
def __getattr__(self, attr):
def default(*args, **kwargs):
return attr, args, kwargs
return default
test = Test()
print(test.test('test'))
# ('test', ('test',), {})

Subclass Python class with same decorators

I'm using Flask-Classy to write a Flask app using class based views.
My base class is called SlugView. It catches URLs like example.com/124/catchy-article-name:
class SlugView(FlaskView):
#route('/<id>')
#route('/<id>/<slug>')
def get(self, id, slug=None)
raise NotImplementedError
My second class is called ArticleView:
class ArticleView(SlugView):
def get(self, id, slug=None):
return render_template('article.html', article=get_article_by_id(id))
What decorator magic can I use to have the subclassed function inherit the same decorators as the parent class?
Magic? Yes. Decorator magic? No. Do you object to metaclass magic?
class InheritableRoutesMeta(type):
def __new__(cls, cls_name, bases, attributes):
for name, value in attributes.items():
if not callable(value):
continue
for base in bases:
super_method = getattr(base, name)
if super_method and hasattr(super_method, "_rule_cache"):
value._rule_cache = super_method._rule_cache
break
return super(InheritableRoutesMeta, cls).__new__(cls, cls_name,
bases, attributes)
Then you should be able to do something like this:
class ArticleView(SlugView, metaclass=InheritableRoutesMeta):
# Use the keyword argument metaclass for Python 3
# For Python 2, remove the argument and uncomment the below
# __metaclass__ = InheritableRoutesMeta
def get(self, id, slug=None):
return render_template('article.html', article=get_article_by_id(id))
Warning: This is based on an internal property. If Flask-Classy chooses to change how it stores these decorators the above code will break (assuming that it works in the first place). If you really need this, it is worth filing an issue with the creator(s) to either make this property part of the public API or to provide another way of doing what you are doing. They may choose not to do either, but at least then they are aware of the use case.

python convert custom object to json using properties

In Bottle framework or python in general, is there a way to convert a custom object to json using the properties of the object?
I saw few posts which recommend to write to_json(self) kind sort of method on the custom class. Was wondering if there is any automated way of doing the same?
Coming from Java world, was hoping for Jackson type of module with XmlRootElement annotation (or decorator in python terms). But didn't find any so far.
UPDATE I do not want to use __dict__ elements. Instead want to use properties of my custom class to build the json.
You could use a decorator to "mark" the properties that needs to be represented.
You would still need to write a to_json function, but you will only need to define it once in the base class
Here's a simple example:
import json
import inspect
def viewable(fnc):
'''
Decorator, mark a function as viewable and gather some metadata in the process
'''
def call(*pargs, **kwargs):
return fnc(*pargs, **kwargs)
# Mark the function as viewable
call.is_viewable = True
return call
class BaseJsonable(object):
def to_json(self):
result = {}
for name, member in inspect.getmembers(self):
if getattr(member, 'is_viewable', False):
value = member()
result[name] = getattr(value, 'to_json', value.__str__)()
return json.dumps(result)
class Person(BaseJsonable):
#viewable
def name(self):
return self._name
#viewable
def surname(self):
return self._surname
def __init__(self, name, surname):
self._name = name
self._surname = surname
p = Person('hello', 'world')
print p.to_json()
Prints
{"surname": "world", "name": "hello"}

Categories