Is there any simple way to pass custom arguments to View instances with aiohttp ?
This works:
import aiohttp.web
import functools
class Parent():
def __init__(self, val):
self.var = val
class BaseView(aiohttp.web.View):
def __init__(self, *args, **kwargs):
self.parent = kwargs.pop("parent")
super().__init__(*args, **kwargs)
class Handler(BaseView):
async def get(self):
return aiohttp.web.Response(text=self.parent.var)
def partial_class(cls, *args, **kwargs):
class NewCls(cls):
__init__ = functools.partialmethod(cls.__init__, *args, **kwargs)
return NewCls
def main():
parent = Parent("blablabla")
app = aiohttp.web.Application()
# New method with args
app.router.add_view_with_args = functools.partial(
lambda this, path, handler, d: this.add_view(path, partial_class(handler, **d)),
app.router,
)
# Tornado-style
app.router.add_view_with_args("/test", Handler, {"parent": parent})
aiohttp.web.run_app(app)
main()
But I feel like this is overcomplicated.
With Tornado, you can pass additionnal data as a dict object when you instanciate your web Application.
Answering my own question:
It turns out that you are allowed to store global-like variables in an Application instance and then access it in the request handler. It is described in the docs: https://docs.aiohttp.org/en/latest/web_advanced.html#application-s-config
Related
I have a little GUI Program that should only get some inputs to use these inputs for a method call.
Therefore I have several tk.Entry objects. Now my method that I want to execute needs a file from my hard disk. I want to scrape it with ElementTree. (I think the file needs to be in the same directory as my .py file? If not please tell me how to use a file from another path). My Idea was to copy that file into the current filepath and then only use a simple call to get access to this file.
But when I want to copy this file it is getting copied after I close the program and that should not happen. It should instantly copy the file so I can work with it.
Is there a way to refresh my files or do you have another idea?
Thank you and here is my code:
from Modules import copy_file
import tkinter as tk
class MainApplication(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
for Frame in (StartPage, SuccessPage):
page_name = Frame.__name__
frame = Frame(parent=container, controller=self)
self.frames[page_name] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame("StartPage")
# method to show frames
def show_frame(self, page_name):
frame = self.frames[page_name] #getting our frame from our frames list
frame.tkraise() #raise it up to the front
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
# Open File Button
self.button_open_file = ttk.Button(self, text = "Open File", command = self.get_file_directory).grid(row=5, column=0, sticky="WE")
def get_file_directory(self):
filename = filedialog.askopenfilename(initialdir = "/",title = "Select file",filetypes = (("all files","*.*"),("jpeg files","*.jpg")))
copy_file(filename)
class SuccessPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
# Open File Button
self.label = tk.Label(self, text = "Lab").grid(row=0 column=0, sticky="WE")
if __name__ == '__main__':
application = MainApplication().mainloop()
----------------------------------------------------------------------------------------------
Modules.py
from shutil import copy
def copy_file(src):
destination_path = os.path.dirname(os.path.realpath(__file__))
copy(src, destination_path)
I realy tried to find answer to my question, but don't know what should I do. I found following question and they didn't help me. question1, question2, docs
I got different values with different functions that I used. Sometimes None value
sometimes TypeError: Object of type 'method' is not JSON serializable
and
AttributeError: 'str' object has no attribute 'status_code' and this
TypeError: 'method' object is not iterable
But i didn't still find solution to solve my problem.
Here is my Page model it has InlinePanel that takes some data from another class:
class ScreencastPage(Page):
content_panels = Page.content_panels + [
InlinePanel(
'groupstage_screencast_relationship', label="Choose Teams",
panels=None, max_num=2),
]
parent_page_types = ['home.HomePage']
def matches(self):
matches = [
n.match for n in self.groupstage_screencast_relationship.all()
]
return matches
def serve(self, request):
if request.is_ajax():
# TODO Convert self.mathes to JSON and return it
else:
return super(ScreencastPage, self).serve(request)
And here is the model that related to my ScreencastPage
#register_snippet
class GroupstageTournamentModel(ClusterableModel):
number = models.PositiveSmallIntegerField(
verbose_name="Match №:")
starts_at = models.DateTimeField()
# Team 1
team_1 = models.ForeignKey(
TeamRooster,
null=True, verbose_name='Erste Team',
on_delete=models.SET_NULL,
related_name="+",
)
team_1_dress = ColorField(blank=True, verbose_name='Dress')
team_1_first_halftime_score = models.PositiveSmallIntegerField(blank=True, default=0, verbose_name='Resultat 1. HZ')
team_1_first_halftime_point = models.PositiveSmallIntegerField(blank=True, default=0, verbose_name='Punkte 1. HZ')
...
UPDATE
Sorry if I ask too noob questions, but I'm new in programming. #gasman these are the ways I used.
1
def serve(self, request):
if request.is_ajax():
lst = []
d = {}
for pn in self.matches:
d['mpn']=pn
lst.append(d)
return json.dumps([dict(mpn=pn) for pn in lst])
returns: TypeError: 'method' object is not iterable
2
Just changed loop from for pn in self.matches: to for pn in self.matches():
def serve(self, request):
if request.is_ajax():
lst = []
d = {}
for pn in self.matches():
d['mpn']=pn
lst.append(d)
return json.dumps([dict(mpn=pn) for pn in lst])
returns: TypeError: Object of type 'GroupstageTournamentModel' is not JSON serializable
3
def serve(self, request):
if request.is_ajax():
if isinstance(self.matches, (list, dict, str, int, float, bool, type(None))):
data = JSONEncoder.default(self.matches())
return data
elif '_python_object' in self.matches():
data = pickle.loads(str(self.matches['_python_object']))
return data
returns: ValueError: The view wagtail.wagtailcore.views.serve didn't return an HttpResponse object. It returned None instead.
4
def serve(self, request):
if request.is_ajax():
data = [
n.match for n in self.groupstage_screencast_relationship.all()
]
return data
returns: AttributeError: 'list' object has no attribute 'status_code'
5
def serve(self, request):
if request.is_ajax():
data = [
n.match for n in self.groupstage_screencast_relationship.all()
]
if isinstance(data, (list, dict, str, int, float, bool, type(None))):
conv_data = json.JSONEncoder.default(data)
return conv_data
returns: TypeError: default() missing 1 required positional argument: 'o'
As I said, I do not know how this conversion works, so I tried to guess.
The important lesson here is to try to solve one problem at once. You're trying to deal with returning a response from serve at the same time as constructing some JSON, and it doesn't look like you're getting anywhere because fixing the first half of the problem just leads you to an error in the second half.
Let's make sure we know how to return something from serve, even if it's just something useless:
def serve(self, request):
if request.is_ajax():
return "hello world!"
else:
return super(ScreencastPage, self).serve(request)
This will fail with something like: 'str' object has no attribute 'get'. This tells us that returning a string is the wrong thing to do: whatever object we return, Wagtail is expecting it to have a get attribute. Looking at the documentation, we can see that it's supposed to be an HttpResponse object:
from django.http import HttpResponse
def serve(self, request):
if request.is_ajax():
return HttpResponse("hello world!")
else:
return super(ScreencastPage, self).serve(request)
This works, so now we know that whatever other stuff we do with JSON in this method, we need to end with return HttpResponse(some_result).
So now let's bring in json.dumps. Again, let's start with some fake data to make sure we're using it right:
import json
from django.http import HttpResponse
def serve(self, request):
if request.is_ajax():
result = ['first match', 'second match']
json_output = json.dumps(result)
return HttpResponse(json_output)
else:
return super(ScreencastPage, self).serve(request)
Hopefully this works too, so let's bring in the real data:
import json
from django.http import HttpResponse
def serve(self, request):
if request.is_ajax():
result = self.matches()
json_output = json.dumps(result)
return HttpResponse(json_output)
else:
return super(ScreencastPage, self).serve(request)
This now fails with something like: TypeError: Object of type 'GroupstageTournamentModel' is not JSON serializable. So now you have to ask: what's changed here? What's different about my real data from the 'fake' data? If you're not sure, add in a debugging line to see what's going on:
import json
from django.http import HttpResponse
def serve(self, request):
if request.is_ajax():
result = self.matches()
print(result) # this output will appear in the terminal / command prompt
json_output = json.dumps(result)
return HttpResponse(json_output)
else:
return super(ScreencastPage, self).serve(request)
The error message hopefully makes it clear: the value you're passing to json.dumps contains GroupstageTournamentModel objects, and JSON doesn't know how to deal with those. You need to convert them into basic values such as dicts, and that means specifying how each individual field is meant to appear in the output:
def serve(self, request):
if request.is_ajax():
result = [
{
'number': match.number,
'team1': match.team_1.name,
# ...
}
for match in self.matches()
]
json_output = json.dumps(result)
return HttpResponse(json_output)
else:
return super(ScreencastPage, self).serve(request)
In summary - when you encounter an error message:
don't just abandon your code and try something else;
look at what the error message is telling you, and especially, what line of code it's coming from;
see if there's a way to reduce it to a simpler case that does succeed, then work your way back up to the real solution.
I have some trouble getting my static class to work. There is something I am missing about the scope of functions within a class. If called the script gives me following error:
NameError: global name 'disableCostumFrames' is not defined #
import maya.cmds as cmds
from functools import partial
class Blast:
def createWindow():
# Todo:
# hanldes the gui for the user
windowID = 'window'
if cmds.window(windowID, exists = True):
cmds.deleteUI('window')
window = cmds.window(windowID, title="Blast", iconName='Blast', widthHeight=(400, 200) )
cmds.frameLayout( label='')
cmds.rowColumnLayout( numberOfColumns=4, columnWidth=[(1, 100),(3, 100)] )
cmds.text( label='Start: ' )
global Blast_startFrame
Blast_startFrame = cmds.textField( enable = False)
cmds.text( label=' End: ' )
global Blast_endFrame
Blast_endFrame = cmds.textField( enable = False)
cmds.setParent('..')
cmds.rowColumnLayout( numberOfColumns=2, columnWidth=[(1, 100), (2, 100)] )
cmds.radioCollection()
#cmds.radioButton( label='Full', select = True, onCommand= partial(disableCostumFrames, Blast_startFrame, Blast_endFrame ) )
#cmds.radioButton( label='Costum', onCommand= partial(enableCostumFrames, Blast_startFrame, Blast_endFrame ) )
cmds.setParent('..')
cmds.rowColumnLayout( numberOfColumns=1, columnWidth=[(1, 400), (2, 100)] )
cmds.button( label='Playblast' ,command= 'createPlayblast')
cmds.setParent('..')
cmds.showWindow( window )
return Blast_startFrame, Blast_endFrame
def main():
createWindow()
def enableCostumFrames(Blast_startFrame, Blast_endFrame, *args):
cmds.textField(Blast_startFrame, edit=True, enable=True)
cmds.textField(Blast_endFrame, edit=True, enable=True)
def disableCostumFrames(Blast_startFrame, Blast_endFrame, *args):
cmds.textField(Blast_startFrame, edit=True, text="", enable=False)
cmds.textField(Blast_endFrame, edit=True, text="", enable=False)
How do I need to define these functions within the class? I am calling the module like that:
import sys
Dir = 'c:/Blast'
if Dir not in sys.path:
sys.path.append(Dir)
try: reload(Blast_v011)
except: import Blast_v011
Blast_v011.Blast()
maybe iam doing something wrong on this side? Appreciated any help.
In this case you need to add a self reference to all of the methods in your class. The usual python class looks like this:
class MyClass(object):
def __init__(self):
self.variable = 123
def some_method(self):
print "my variable = ", self.variable
def some_other_method(self):
if self.variable > 1:
self.some_method()
The self reference in the member functions is how you get at class member variables and other functions -- it's python's way of referring to what other languages call this.
Instance methods can only be called on an instance (it's the instance that gets passed in as self). You can make a method that is called on the class itself -- rather than any particular instance of the class -- using the #classmethod decorator. Classmethods also take an argument, but instead of self it's a reference to the class. You use it the same way to get variables defined at the class level, which are shared by all copies of the class:
class HasShared(object):
shared = 99
#classmethod
def a_class_method(cls):
print cls.shared
(You can mix and match class and instance methods in the same class).
You can also make static methods using the #staticmethod decorator. These don't get a default argument at all:
class NotPythonic(object):
#staticmethod
def needs_no_args():
print "call me as NotPythonic.needs_no_args()"
In Python we tend to avoid this formula, since you can get a static method by just creating a function in a module without making a class to hold them. For the example code you posted, I'd probably just make a conventional class using instance methods, since your functions need the names of the gui widgets to be able to actually ask them questions.
I would like to use django forms to validate fields being Integer Array. What is the best way to achieve this ? I don't want to use a ChoiceField and I am not sure what is the easiest way to achieve this. Any suggestion in that matter ?
For storing the array I would use a django-picklefield or a custom field like this:
from django.db import models
class IntArrayField(models.TextField):
__metaclass__ = models.SubfieldBase
def __init__(self, *args, **kwargs):
super(IntArrayField, self).__init__(*args, **kwargs)
def to_python(self, value):
if not value:
return None
if isinstance(value, list):
return value
return [int(n) for n in value.split('|')]
def get_db_prep_value(self, value):
if not value:
return None
assert(isinstance(value, list) or isinstance(value, tuple))
return '|'.join(str(value))
def value_to_string(self, obj):
value = self._get_val_from_obj(obj)
return self.get_db_prep_value(value)
For validation you can use clean_fieldname():
def clean_fieldname(self):
data = self.cleaned_data['fieldname']
# if <data is not an int array>:
# raise forms.ValidationError("You must enter an int array.")
return data
And it's also good to have some JavaScript code to validate input and make entering an int array easier on your client side.
I just run into some problems with django models.
Example code is better than any word:
class Cart(models.Model):
updated_at = models.DateTimeField(auto_now=True)
created_at = models.DateTimeField(auto_now_add=True)
def __unicode__(self):
return u'date %s;'%(self.created_at)
def __str__(self):
return self.__unicode__()
def _total_items(self):
""" Totale n di oggetti """
a = 0
for i in self.items.all:
a += i.quantity
return a
total_items = property(_total_items)
class Item(models.Model):
cart = models.ForeignKey(Cart)
quantity = models.PositiveIntegerField()
def __unicode__(self):
return u'product %s'%(self.id)
def __str__(self):
return self.__unicode__()
but, when i call the cart property here's what i get in the python console:
>>> a.total_items
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "models.py", line 49, in _total_items
for i in self.item_set.all:
TypeError: 'RelatedManager' object is not callable
Try replacing this line
for i in self.items.all:
with this one
for i in self.items.all():