python convert custom object to json using properties - python

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"}

Related

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

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)

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>)}

Use outer class instance as self in inner class?

I'm writing a wrapper for the GMAIL API. In this wrapper, I am trying to include subattributes in the "main class" so it more closely follows the below:
Previously, I was use methods such as:
class Foo:
def __init__(self, ...):
# add some attributes
def get_method(self, ...):
return some_stuff
This allows me to do foo.get_method(...). To follow the GMAIL API, I try to do:
class Foo:
def __init__(self, ...):
# add some attributes
#property
def method(self):
class _Method:
#staticmethod
def get(self, ...):
return some_stuff
return _Method()
Which allows me to do foo.method.get(...). The above has some problems, it redefines the class every time, and I have to add #staticmethod above every method as part of it. I do realise that I could create the class at the outer class level, and set a hidden variable for each which then .method returns or creates, but this seems like too much workaround.
tldr: Is it possible to make the instance passed to the inner class as self be the instance of the outer class (I do not wish to have to pass the attributes of the outer class to each inner class).
Instead of sharing the self parameter between classes, you are probably better off just passing the things you need to the constructor of the class you instantiate.
class Messages:
def __init__(self, name):
self.name = name
def method(self, other_arg):
return self.name + other_arg
class Test:
name = "hi"
def __init__(self):
self.messages = Messages(name=self.name)
If you need to pass a lot of information to the constructor and it starts becoming unwieldy, you can do something like split the shared code into a third class, and then pass that between the Test and Messages classes as a single object.
In Python there are all sorts of clever things that you can do with metaclasses and magic methods, but in 99% of cases just refactoring things into different classes and functions will get you more readable and maintainable code.
Users should have an instance of messages, which allows method get. The scetch for code is:
class Messages:
...
def get()
...
class Users:
...
messages = Messages(...)
allows
users = Users()
users.messages.get()
The bad thing in this API is plural names, which is a bad sign for class. If done from scratch you would rather have classes User and Message, which make more sense.
If you have a closer look at GET/POST calls in the API you link provided, you would notice the urls are like UserId/settings, another hint to implement User class, not Users.
self in the methods reference the self of the outer class
maybe this is what you want factory-method
Although the example code I'll provide bellow might be similar to the already provided answers, and the link above to another answer might satify you wish, because it is slight different formed I'll still provide my vision on what you asked. The code is self explanatory.
class User:
def __init__(self, pk, name):
self.pk = pk
self.name = name
self._messages = None
def messages(self):
if self.messages is None:
self._messages = Messages(self.pk)
return self._messages
class Messages:
def __init__(self, usr):
self.usr = usr
def get(self):
return self._grab_data()
def _grab_data(self):
# grab the data from DB
if self.usr == 1:
print('All messages of usr 1')
elif self.usr == 2:
print('All messages of usr 2')
elif self.usr == 3:
print('All messages of usr 3')
one = User(1, 'One')
two = User(2, 'Two')
three = User(3, 'Three')
one.messages().get()
two.messages().get()
three.messages().get()
The messages method approach practical would be the same for labels, history etc.
Edit: I'll give one more try to myself trying to understand what you want to achieve, even though you said that
I have tried numerous things with defining the classes outside of the container class [...]
. I don't know if you tried inheritance, since your inner class me, despite it quite don't represent nothing here, but still looks like you want to make use of its functionality somehow. You said as well
self in the methods reference the self of the outer class
This sounds to me like you want inheritance at the end.
Then the way to go would be (a proximity idea by using inheritance):
class me(object):
def __init__(self):
self.__other_arg = None # private and hidden variable
# setter and getter methods
def set_other_arg(self, new_other_arg):
self.__other_arg = new_other_arg
def get_other_arg(self):
return self.__other_arg
class Test(me):
name = 'Class Test'
#property
def message(self):
other_arg = self.get_other_arg()
if other_arg is not None:
return '{} {}'.format(self.name, other_arg)
else:
return self.name
t = Test()
t.set_other_arg('said Hello')
print(t.message)
# output >>> Class Test said Hello
I think this could be a preferable way to go rather than your inner class approach, my opinion, you'll decide. Just one side note, look up for getter and setter in python, it might help you if you want to stick with the inheritance idea given.

Debugger attribute view for python

is there in python something like a decorator for IDE's or debuggers like IDLE or Visual Studio where I can configure which variable should be written in the variable view for a class?
Example code:
idList = []
idList.append("X342")
idList.append(Token("X9999"))
and the variable view in Visual Studio:
http://i.stack.imgur.com/q9Q0I.png
Instead of the "Tokens.Token object at (...)" i want to specify in the Token class what the debugger should write. In this case the str "X9999".
Can someone help me?
The debugger almost certainly uses the repr() of the object. You can define your own:
class Token(object):
def __init__(self, id):
self.id = id
def __repr__(self):
return "<Token %s>" % self.id
If Token is a class from a library, you can subclass it and use the subclass, or if that's not possible, monkey-patch the original class to override its __repr__. The latter looks something like this:
def __repr__(self):
return "<Token %s>" % self.id # or wherever `X9999` is stored
Token.__repr__ = __repr__

Using base class constructor as factory in Python?

I'm using base class constructor as factory and changing class in this constructor/factory to select appropriate class -- is this approach is good python practice or there are more elegant ways?
I've tried to read help about metaclasses but without big success.
Here example of what I'm doing.
class Project(object):
"Base class and factory."
def __init__(self, url):
if is_url_local(url):
self.__class__ = ProjectLocal
else:
self.__class__ = ProjectRemote
self.url = url
class ProjectLocal(Project):
def do_something(self):
# do the stuff locally in the dir pointed by self.url
class ProjectRemote(Project):
def do_something(self):
# do the stuff communicating with remote server pointed by self.url
Having this code I can create the instance of ProjectLocal/ProjectRemote via base class Project:
project = Project('http://example.com')
project.do_something()
I know that alternate way is to using fabric function that will return the class object based on url, then code will looks similar:
def project_factory(url):
if is_url_local(url):
return ProjectLocal(url)
else:
return ProjectRemote(url)
project = project_factory(url)
project.do_something()
Is my first approach just matter of taste or it has some hidden pitfalls?
You shouldn't need metaclasses for this. Take a look at the __new__ method. This will allow you to take control of the creation of the object, rather than just the initialisation, and so return an object of your choosing.
class Project(object):
"Base class and factory."
def __new__(cls, url):
if is_url_local(url):
return super(Project, cls).__new__(ProjectLocal, url)
else:
return super(Project, cls).__new__(ProjectRemote, url)
def __init__(self, url):
self.url = url
I would stick with the factory function approach. It's very standard python and easy to read and understand. You could make it more generic to handle more options in several ways such as by passing in the discriminator function and a map of results to classes.
If the first example works it's more by luck than by design. What if you wanted to have an __init__ defined in your subclass?
The following links may be helpful:
http://www.suttoncourtenay.org.uk/duncan/accu/pythonpatterns.html#factory
http://code.activestate.com/recipes/86900/
In addition, as you are using new style classes, using __new__ as the factory function (and not in a base class, a separate class is better) is what is usually done (as far as I know).
A factory function is generally simpler (as other people have already posted)
In addition, it isn't a good idea to set the __class__ attribute the way you have done.
I hope you find the answer and the links helpful.
All the best.
Yeah, as mentioned by #scooterXL, factory function is the best approach in that case, but I like to note a case for factories as classmethods.
Consider the following class hierarchy:
class Base(object):
def __init__(self, config):
""" Initialize Base object with config as dict."""
self.config = config
#classmethod
def from_file(cls, filename):
config = read_and_parse_file_with_config(filename)
return cls(filename)
class ExtendedBase(Base):
def behaviour(self):
pass # do something specific to ExtendedBase
Now you can create Base objects from config dict and from config file:
>>> Base({"k": "v"})
>>> Base.from_file("/etc/base/base.conf")
But also, you can do the same with ExtendedBase for free:
>>> ExtendedBase({"k": "v"})
>>> ExtendedBase.from_file("/etc/extended/extended.conf")
So, this classmethod factory can be also considered as auxiliary constructor.
I usually have a seperate factory class to do this. This way you don't have to use meta classes or assignments to self.__class__
I also try to avoid to put the knowledge about which classes are available for creation into the factory. Rather, I have all the available classes register themselves withe the factory during module import. The give there class and some information about when to select this class to the factory (this could be a name, a regex or a callable (e.g. a class method of the registering class)).
Works very well for me and also implements such things like encapsulation and information hiding.
I think the second approach using a factory function is a lot cleaner than making the implementation of your base class depend on its subclasses.
Adding to #Brian's answer, the way __new__ works with *args and **kwargs would be as follows:
class Animal:
def __new__(cls, subclass: str, name: str, *args, **kwargs):
if subclass.upper() == 'CAT':
return super(Animal, cls).__new__(Dog)
elif subclass.upper() == 'DOG':
return super(Animal, cls).__new__(Cat)
raise NotImplementedError(f'Unsupported subclass: "{subclass}"')
class Dog(Animal):
def __init__(self, name: str, *args, **kwargs):
self.name = name
print(f'Created Dog "{self.name}"')
class Cat(Animal):
def __init__(self, name: str, *args, num_whiskers: int = 5, **kwargs):
self.name = name
self.num_whiskers = num_whiskers
print(f'Created Cat "{self.name}" with {self.num_whiskers} whiskers')
sir_meowsalot = Animal(subclass='Cat', name='Sir Meowsalot')
shadow = Animal(subclass='Dog', name='Shadow')

Categories