Object has no attribute _meta in python Cement App - python-2.7

I am new to python and cement app,
I am just going through the documentation given in cement app and I am facing the following issue
Traceback (most recent call last):
File "/Users/Amith/python/learning/inter.py", line 80, in <module>
app.handler.register(MyHandler)
File "/Users/Amith/python/learning/connectors/lib/python2.7/site-packages/cement/core/handler.py", line 195, in register
if not hasattr(obj._meta, 'label') or not obj._meta.label:
AttributeError: 'MyHandler' object has no attribute '_meta'
I didnt find much help from documentation and verified few other wesites as well.
Please find my code below
from cement.core.foundation import CementApp
from cement.core.interface import Interface, Attribute
from cement.core import interface
from cement.core.handler import CementBaseHandler
def my_validator(klass, obj):
members = [
'_setup',
'do_something',
'my_var',
]
interface.validate(MyInterface, obj, members)
class MyInterface(Interface):
class IMeta:
label = 'myinterface'
validator = my_validator
# Must be provided by the implementation
Meta = Attribute('Handler Meta-data')
my_var = Attribute('A variable of epic proportions.')
def _setup(app_obj):
""" The setup function """
def do_something():
""" This function does something. """
class MyHandler(CementBaseHandler):
class Meta:
interface = MyInterface
label = 'my_handler'
description = 'This handler implements MyInterface'
config_defaults = dict(
foo='bar'
)
my_var = 'This is my var'
def __init__(self):
self.app = None
def _setup(self, app_obj):
self.app = app_obj
def do_something(self):
print "Doing work!"
class MyApp(CementApp):
class Meta:
label = 'myapp'
define_handlers = [MyInterface]
handlers = [MyHandler]
app = CementApp('myapp')
# define interfaces after app is created
app.setup()
print app.config.keys('myapp')
app.config.set('myapp', 'debug', True)
print app.config.keys('myapp')
app.handler.define(MyInterface)
app.handler.register(MyHandler)
app.run()
Any help will be much appriciated

The problem is that MyHandler does not properly sub-class CementBaseHandler. Any methods need to be sub-classed with super()... for example:
class MyHandler(CementBaseHandler):
class Meta:
interface = MyInterface
label = 'my_handler'
description = 'This handler implements MyInterface'
config_defaults = dict(
foo='bar'
)
my_var = 'This is my var'
def __init__(self, *args, **kw):
super(MyHandler, self).__init__(*args, **kw)
# add your code here (if necessary)
def _setup(self, app_obj):
super(MyHandler, self)._setup(app_obj)
# add your code here if necessary
def do_something(self):
print "Doing work!"
Notice the modifications to MyHandler.__init__() and MyHandler._setup() using super()... this fixed the issue for me.
I apologize for the inconvenience in the documentation, and thank you for pointing it out with a proper/working/reproducable example. I've added an issue to the project in Github to have it fixed in the next release.
https://github.com/datafolklabs/cement/issues/423

Related

Override Django (DRF) Serializer object GET

I'm trying to "inject" some raw sql into my DRF nested Serializer:
# SERIALIZERS
class CarSerializer(serializers.ModelSerializer):
class Meta:
model = Car
fields = '__all__'
class DriverSerializer(serializers.ModelSerializer):
car = CarSerializer() # <--- here I don't want to get the Car object but rather inject a raw sql.
class Meta:
model = Driver
fields = '__all__'
The SQL injection is needed to request for a specific version of the data since I'm using MariaDB versioning tables but this is not relevant. How do I override the method that gets the object from CarSerializer? Thank you.
This is untested but I think you want to override the __init__ in DriverSerializer and then load the result of your raw SQL via data, something like this:
class DriverSerializer(serializers.ModelSerializer):
[...]
def __init__(self, *args, **kwargs):
super(DriverSerializer, self).__init__(*args, **kwargs)
name_map = {'column_1': 'obj_attr_1', 'column_2': 'obj_attr_1', 'pk': 'id'}
raw = Car.objects.raw('SELECT ... FROM ...', translations=name_map)
data = {k: getattr(raw[0], k) for k in name_map.keys()}
self.car = CarSerializer(data=data)
You could define method under your model to get related Car
class Car(models.Model):
def current_car(self):
return Car.objects.raw('SELECT ... FROM ...')[0]
Then in serializer you could reuse following method
class DriverSerializer(serializers.ModelSerializer):
car = CarSerializer(source="current_car")
class Meta:
model = Driver
fields = (...)
Thank you everyone for your answers, I managed to make it work although my solution is not as clean as the one suggested from #yvesonline and #iklinak:
I first checked the official DRF documentation on overriding serializers: https://www.django-rest-framework.org/api-guide/serializers/#overriding-serialization-and-deserialization-behavior
In particular I was interested in the overriding of the method: .to_representation(self, instance) that controls the fetching of the object from the database:
from datetime import datetime as dt
from collections import OrderedDict
from rest_framework.relations import PKOnlyObject
from rest_framework.fields import SkipField, empty
def __init__(
self, instance=None, data=empty, asTime=str(dt.now()), **kwargs):
self.asTime = asTime
self.instance = instance
if data is not empty:
self.initial_data = data
self.partial = kwargs.pop('partial', False)
self._context = kwargs.pop('context', {})
kwargs.pop('many', None)
super().__init__(**kwargs)
def to_representation(self, instance):
# substitute instance with my raw query
# WARNING: self.asTime is a custom variable, check the
# __init__ method above!
instance = Car.objects.raw(
'''
select * from db_car
for system_time as of timestamp %s
where id=%s;
''', [self.asTime, instance.id])[0]
ret = OrderedDict()
fields = self._readable_fields
for field in fields:
try:
attribute = field.get_attribute(instance)
except SkipField:
continue
check_for_none = attribute.pk if isinstance(
attribute, PKOnlyObject) else attribute
if check_for_none is None:
ret[field.field_name] = None
else:
ret[field.field_name] = field.to_representation(attribute)
return ret
You can find the original code here: https://github.com/encode/django-rest-framework/blob/19655edbf782aa1fbdd7f8cd56ff9e0b7786ad3c/rest_framework/serializers.py#L335
Then finally in the DriverSerializer class:
class DriverSerializer(serializers.ModelSerializer):
car = CarSerializer(asTime='2021-02-05 14:34:00')
class Meta:
model = Driver
fields = '__all__'

NameError: global name 'MyClass' is not defined in Pepper/Nao

Update: to work around the combination of Choregraphe and Python, I rejected the idea of having #classmethod. Instead I raise AlMemory events in MyCustomClass when I want to make use of MyClass.
I read many posts on NameError but still couldn't find a solution to my problem.
I write a program with Choregraphe using the Python box for Nao.
I got the followings:
class MyClass(GeneratedClass): #GeneratedClass is given
def __init__(self):
GeneratedClass.__init__(self)
#classmethod
def doSomething(cls, a):
print a
class myCustomClass():
def func(self):
MyClass.doSomething(a)
When calling func() from myCustomClass, I got NameError on MyClass.
[ERROR] behavior.box :FMBox::createPythonModule:0 _Behavior__lastUploadedChoregrapheBehaviorbehavior_1275012824__root__test_1: User class evaluation failed with the error:
global name 'MyClass' is not defined
How can I fix that?
As a start your #method and class structure is wrong.
When I ran your code it says this :
class MyClass(GeneratedClass):
#classmethod
def do(self, a):
return a
class myCustomClass():
def func(self):
MyClass.do(a)
Output:
Traceback (most recent call last):
File "test.py", line 236, in <module>
class MyClass(GeneratedClass):
NameError: name 'GeneratedClass' is not defined
Your class structure is completely wrong. If you want to pass a parameter, use __init__ method.
class MyClass:
def __init__(self, GeneratedClass):
self.generated_class = GeneratedClass
def do(self):
doSomething(self.generated_class)
class MyCustomClass:
def func(self):
GeneratedClass = 1
MyClass(GeneratedClass).do()
myCustomClass().func()
If you are using #methodclass you should not pass self, it is cls. Like in this example:
from datetime import date
# random Person
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
#classmethod
def fromBirthYear(cls, name, birthYear):
return cls(name, date.today().year - birthYear)
def display(self):
print(self.name + "'s age is: " + str(self.age))
person = Person('Adam', 19)
person.display()
person1 = Person.fromBirthYear('John', 1985)
person1.display()
In case if you are trying inheritance take this is an example how it should be.
class Mapping:
def __init__(self, iterable):
self.items_list = []
self.__update(iterable)
def update(self, iterable):
for item in iterable:
self.items_list.append(item)
__update = update # private copy of original update() method
class MappingSubclass(Mapping):
def update(self, keys, values):
# provides new signature for update()
# but does not break __init__()
for item in zip(keys, values):
self.items_list.append(item)
Now all in one according to yours:
class GeneratedClass:
def __init__(self):
self.myclass = self
def print(self):
print('hello_people')
class MyClass(GeneratedClass):
def __init__(self,a):
self.a = a
GeneratedClass.__init__(self)
print(a)
#classmethod
def give_param(cls, a):
return cls(a)
class myCustomClass:
def func(self):
MyClass.give_param('aa')
myCustomClass().func()
NOTE: I have used python 3.x.
I think "MyClass" is replaced on the fly by the Choregraphe/PythonBridge interpreter invoked when you press run.
As you can see each choregraphe box classes are named "MyClass", they are so replaced and changed by a generated name like root/class/boxname...
You could try calling and printing the self.getName() in MyClass, to have a clue.
So in your case, you could:
add doSomething directly in myClass
create a not postprocessed, eg:
as:
class MyVeryOneClass:
def __init__(self):
...

Google App Engine: Kind Error

Following is my program
import os
import jinja2
import re
from string import letters
import webapp2
from google.appengine.ext import db
template_dir= os.path.join(os.path.dirname(__file__),'templates')
jinja_env= jinja2.Environment(loader= jinja2.FileSystemLoader(template_dir),autoescape= True)
class Handler(webapp2.RequestHandler):
def write(self,*a,**kw):
self.response.write(*a,**kw)
def render_str(self,template, **params):
t= jinja_env.get_template(template)
return t.render(params)
def render(self,template, **kw):
self.write(self.render_str(template,**kw))
def blog_key(name = "default"):
return db.Key.from_path('blogs',name)
class Post(db.Model):
title= db.StringProperty(required= True)
content= db.TextProperty(required= True)
created= db.DateTimeProperty(auto_now_add= True)
edited= db.DateTimeProperty(auto_now= True)
def render(self):
self._render_text= self.content.replace('\n', '<br>')
return render_str("blogs.html", p= self)
class BlogFront(Handler):
def get(self):
posts= db.GqlQuery("select * from posts order by desc limit 10")
self.render("front.html", posts=posts )
#for a link to the new posts created
class PostPage(Handler):
def get(self, post_id):
key= db.Key.from_path("Post", int(post_id), parent= blog_key())
post=db.get(key)
if not post:
self.error(404)
return
self.render("permalink.html", post=post)
#for new blog entries
class NewPost(Handler):
def get(self):
self.render('newpost.html')
def post(self):
title= self.request.get("title")
content= self.request.get("content")
if title and content:
p= Post(parent= blog_key(), title=title, content=content)
p.put()
self.redirect('/blogs/%s' % str(p.key().id()))
else:
error= "Please write both title and content!!"
self.render("newpost.html",title=title, content=content, error=error)
app = webapp2.WSGIApplication([
('/blog/newpost', NewPost),
('/blogs/?',BlogFront),
('/blogs/([0-9]+)',PostPage), #anything in the bracket will be passed as the parameter
], debug=True)
But when I'm trying to implement this program, I'm getting the following error:
File "C:\Users\tan31102\AppData\Local\Google\Cloud
SDK\google-cloud-sdk\platfo
rm\google_appengine\google\appengine\ext\db__init__.py", line 299, in
class_for
_kind
raise KindError('No implementation for kind \'%s\'' % kind) KindError: No implementation for kind 'posts'
Can someone please help me with this.
Your gql uses post in plural form - "posts"
select * from posts order by desc limit 1
while the db.Model class you have declared uses posts in singular form (Post)
class Post(db.Model):
You need to stick with either form. Also you should consider using ndb.Model instead of db.Model as stated in the docs
You have to import the model definition in the Py file that uses it. This causes the KindError.
from posts import posts
or something similar.
It sounds like you are trying to load a posts entity from a session without importing the posts model first.
To ensure that posts is available when the session middleware runs, you must import the posts model in your script.

How to migrate django custom base64 field. Field does not exist

I have a base64 field that is copied from the django snippet.
https://djangosnippets.org/snippets/1669/
class Base64Field(models.TextField):
"""
https://djangosnippets.org/snippets/1669/
Example use:
class Foo(models.Model):
data = Base64Field()
foo = Foo()
foo.data = 'Hello world!'
print foo.data # will 'Hello world!'
print foo.data_base64 # will print 'SGVsbG8gd29ybGQh\n'
"""
def contribute_to_class(self, cls, name):
if not self.db_column:
self.db_column = name
self.field_name =name+ '_base64'
super(Base64Field, self).contribute_to_class(cls, self.field_name)
setattr(cls, name, property(self.get_data, self.set_data))
def get_data(self, obj):
return base64.decodestring(getattr(obj, self.field_name))
def set_data(self, obj, data):
setattr(obj, self.field_name, base64.encodestring(data))
def deconstruct(self):
ame, path, args, kwargs = super(Base64Field, self).deconstruct()
from pprint import pprint
pprint(vars(self))
return ame, path, args, kwargs
I am facing issues while migrating this field
e.g.
class EmailStatus(models.Model):
attachment = Base64Field(null=True, blank=True, db_column='attachment', name="attachment", verbose_name="attachment")
The error I am getting while migrating is
raise FieldDoesNotExist('%s has no field named %r' % (self.object_name, field_name))
django.core.exceptions.FieldDoesNotExist: EmailStatus has no field named u'attachment'
Now I can see why that is happening. But cant figure out a way around it. I think I might need to change something in the deconstruct field. I have tried multiple things for this but all of them broke.
e.g. removing the _base64. It does not work while saving and retrieving data.
I tried changing the name in the migrations file it does not work.
class Migration(migrations.Migration):
initial = True
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(name='EmailStatus',
fields=[('attachment', gradsite.gradnotes.models.Base64Field(blank=True, null=True)),])]
I think the migrations auto-detecter is getting confused because of the change in name in contribute_to_class. I am not sure what can be a work around.
class Base64Field(models.TextField):
def contribute_to_class(self, cls, name, private_only=False):
if not self.db_column:
self.db_column = name
self.field_name = name + '_base64'
super().contribute_to_class(cls,
name)
setattr(cls, self.field_name, property(self.get_data, self.set_data))
def get_data(self, obj):
return base64.b64encode(getattr(obj, self.name).encode('utf-8'))
def set_data(self, obj, data):
setattr(obj, self.field_name, base64.b64decode(data).decode('utf-8'))
This seems to work. There was a mix-up between self.field_name and name in contribute_to_class leading to the wrong value being used (hence makemigrations not picking up the field the second time around/when using migrate).
I have made python3 specific changes, namely the super calls and the use of base64 functions. The set_data method may be wrong (I didn't look into that too much, since you may be using python2 and encoding would differ), but migrations work.
Added bonus: the private_only argument was missing from your contribute_to_class method.
Here's what I'm getting:
from test_app import models
e = models.EmailStatus()
e.attachment = "Hello world!"
e.attachment # Prints 'Hello world!'
e.attachment_base64 # Prints b'SGVsbG8gd29ybGQh'
Useful link for you.
https://code.djangoproject.com/ticket/24563
HELPFUL TIPs:
The failing migration:
​https://github.com/codefisher/djangopress/blob/master/djangopress/forum/migrations/0011_auto_20150426_1821.py
The models:
​https://github.com/codefisher/djangopress/blob/master/djangopress/forum/models.py
It may be helps to others.

Django - passing extra arguments into default callable function

Original Title: cannot get import to work properly
I am trying to generate a function which will create a random alphanumeric number and make it as default value of a model field in django.
So for a single model I did like this:
# utils.py
def generate_random_unique_code_for_model():
from .models import mymodel
while 1:
code = random_code() #my custom function to generate random alphanumeric
try:
mymodel.objects.get(myfield=code)
except mymodel.DoesNotExist:
return code
#models.py
class mymodel(models.Model):
#other fields
myfield = models.CharField(default=generate_random_unique_code_for_model)
This code works fine, but now I have to provide similar function for another model, so to follow the DRY principle I am trying to make the model , fieldnames dynamic. So basically I am trying to accomplish from some_app.models import some_model inside my generate_random_unique_code_for_model function .
def get_model(location, model_name):
try:
module = __import__('.'.join(location), globals(), locals(), [model_name], -1)
model_instance = getattr(module, model_name)
except:
raise ImportError(_('Could not import %(model_name)s from %(location)s') % {'model_name': model_name,
'location': '.'.join(location)})
return model_instance
def generate_random_unique_code_for_model(location, model_name, field_name):
model_object = get_model(location, model_name)
kwargs = {field_name: ''}
while 1:
code = random_code()
kwargs[field_name] = code
try:
model_object.objects.get(**kwargs)
except model_object.DoesNotExist:
return code
#models.py
class mymodel_name(models.Model):
#other fields
myfield_name = models.CharField(default=generate_random_unique_code_for_model(['myapp_name', 'mymodel_name'], 'myfield_name'))
While debuggin, when I do dir(module) while debugging I don't see mymodel_name in the list. Any workarounds please?
The problem was default takes a callable function so whenever an instance of model is instantiated the default function is called. But since I called the function in the second case whenever the server is started and models are loaded it was trying to load model before the model class was created. So the problem comes down to pass a callable function with parameters to default which is not possible as of now. So what I did is this:
def make_random():
return generate_random_unique_code_for_model(['myapp_name', 'mymodel_name'], 'myfield_name')
class mymodel_name(models.Model):
#other fields
myfield_name = models.CharField(default=make_random)