I'm very close to finishing up a project that uses push task queues in GAE to send out follow-up emails to users. However, I keep getting a KeyError and don't know why. I been looking for good models to base my project on but haven't found any decent examples that use multiple parameters. The GAE documentation has improved in the last month but still leaves a lot to be desired.
I've checked many pieces of the code using the interactive console in the development server but still I don't know what I am doing wrong. My best guess is that the parameters are not getting passed along to the next part of the script (class pushQueue).
app.yaml:
application: gae-project
version: 1
runtime: python27
api_version: 1
threadsafe: true
handlers:
- url: /cron/sendfu
script: main.app
login: admin
- url: /emailworker
script: main.app
login: admin
- url: /worker
script: main.app
login: admin
- url: /.*
script: main.app
login: required
cron.yaml:
cron:
- description: sends follow-up emails
url: /cron/sendfu
schedule: every day 20:00
queue.yaml:
total_storage_limit: 120M
queue:
- name: emailworker
rate: 1/s
bucket_size: 50
retry_parameters:
task_retry_limit: 5
task_age_limit: 6h
min_backoff_seconds: 10
max_backoff_seconds: 60
main.py:
import webapp2
import datetime
from google.appengine.ext import db
from google.appengine.api import users
from google.appengine.api import taskqueue
import jinja2
import os
jinja_environment = jinja2.Environment(
loader=jinja2.FileSystemLoader(os.path.dirname(__file__)))
class emailJobs(db.Model):
""" Models an a list of email jobs for each user """
triggerid = db.StringProperty() #Trig id
recipientid_po = db.StringProperty() # id
recipientlang = db.StringProperty() #Language
fu_email_sent = db.DateTimeProperty()
fuperiod = db.IntegerProperty() # (0 - 13)
fu1 = db.DateTimeProperty()
fu2 = db.DateTimeProperty()
#classmethod
def update_fusent(cls, key_name, senddate):
""" Class method that updates fu messages sent in the GAE Datastore """
emailsjobs = cls.get_by_key_name(key_name)
if emailsjobs is None:
emailsjobs = cls(key_name=key_name)
emailsjobs.fu_email_sent = senddate
emailsjobs.put()
def timeStampFM(now):
d = now.date()
year = d.year
month = d.month
day = d.day
t = now.time()
hour = t.hour
minute = t.minute + 5
second = t.second
today_datetime = datetime.datetime(year, month, day, hour, minute, second)
return today_datetime
class MainPage(webapp2.RequestHandler):
""" Main admin login page """
def get(self):
if users.get_current_user():
url = users.create_logout_url(self.request.uri)
url_linktext = 'Logout'
urla = '/'
url_admin = ""
if users.is_current_user_admin():
url = users.create_logout_url(self.request.uri)
urla = "_ah/admin/"
url_admin = 'Go to admin pages'
url_linktext = 'Logout'
else:
url = users.create_login_url(self.request.uri)
url_linktext = 'Login'
template_values = {
'url': url,
'url_linktext': url_linktext,
'url_admin': url_admin,
'urla': urla,
}
template = jinja_environment.get_template('index.html')
self.response.out.write(template.render(template_values))
class sendFollowUp(webapp2.RequestHandler):
""" Queries Datastore for fu dates that match today's date, then adds them to a task queue """
def get(self):
now = datetime.datetime.now()
now_dt = now.date() #today's date to compare with fu dates
q = emailJobs.all()
q.filter('fuperiod >', 0)
q.filter('fuperiod <', 99)
for part in q:
guid = str(part.recipientid_po)
lang = str(part.recipientlang)
trigid = str(part.triggerid)
if part.fuperiod == 1:
fu1rawdt = part.fu1
fu1dt = fu1rawdt.date()
if fu1dt == now_dt:
follow_up = '1'
if part.fuperiod == 2:
fu2rawdt = part.fu2
fu2dt = fu2rawdt.date()
if fu2dt == now_dt:
follow_up = '2'
if follow_up != None:
taskqueue.add(queue_name='emailworker', url='/emailworker', params={'guid': guid,
'fu': follow_up,
'lang': lang,
'trigid': trigid,
})
self.redirect('/emailworker')
class pushQueue(webapp2.RequestHandler):
""" Sends fu emails, updates the Datastore with datetime sent """
def store_emails(self, trigid, senddate):
db.run_in_transaction(emailJobs.update_fusent, trigid, senddate)
def get(self):
fu_messages = {'1': 'MS_x01',
'2': 'MS_x02',
}
langs = {'EN': 'English subject',
'ES': 'Spanish subject',
}
fu = str(self.request.get('fu'))
messageid = fu_messages[fu]
lang = str(self.request.get('lang'))
subject = langs[lang]
now = datetime.datetime.now()
senddate = timeStampFM(now)
guid = str(self.request.get('guid'))
trigid = str(self.request.get('trigid'))
data = {}
data['Subject'] = subject
data['MessageID'] = messageid
data['SendDate'] = senddate
data['RecipientID'] = guid
# Here I do something with data = {}
self.store_emails(trigid, senddate)
app = webapp2.WSGIApplication([('/', MainPage),
('/cron/sendfu', sendFollowUp),
('/emailworker', pushQueue)],
debug=True)
When I test the cron job at: localhost:8086/cron/sendfu
It redirects to: localhost:8086/emailworker
and I get the following error message:
Internal Server Error
The server has either erred or is incapable of performing the requested operation.
Traceback (most recent call last):
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2.py", line 1535, in __call__
rv = self.handle_exception(request, response, e)
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2.py", line 1529, in __call__
rv = self.router.dispatch(request, response)
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2.py", line 1278, in default_dispatcher
return route.handler_adapter(request, response)
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2.py", line 1102, in __call__
return handler.dispatch()
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2.py", line 572, in dispatch
return self.handle_exception(e, self.app.debug)
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2.py", line 570, in dispatch
return method(*args, **kwargs)
File "/Users/me/Documents/workspace/gae-project/src/main.py", line 478, in get
messageid = fu_messages[fu]
KeyError: ''
from the logs:
INFO 2013-03-05 03:03:22,337 dev_appserver.py:3104] "GET /cron/sendfu HTTP/1.1" 302 -
ERROR 2013-03-05 03:03:22,348 webapp2.py:1552] ''
Traceback (most recent call last):
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2.py", line 1535, in __call__
rv = self.handle_exception(request, response, e)
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2.py", line 1529, in __call__
rv = self.router.dispatch(request, response)
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2.py", line 1278, in default_dispatcher
return route.handler_adapter(request, response)
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2.py", line 1102, in __call__
return handler.dispatch()
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2.py", line 572, in dispatch
return self.handle_exception(e, self.app.debug)
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2.py", line 570, in dispatch
return method(*args, **kwargs)
File "/Users/me/Documents/workspace/gae-project/src/main.py", line 478, in get
messageid = fu_messages[fu]
KeyError: ''
INFO 2013-03-05 03:03:22,355 dev_appserver.py:3104] "GET /emailworker HTTP/1.1" 500 -
INFO 2013-03-05 03:03:22,509 dev_appserver.py:3104] "GET /favicon.ico HTTP/1.1" 404 -
lines:
469 def get(self):
470 fu_messages = {'1': 'MS_x01',
471 '2': 'MS_x02',
472 }
473 langs = {'EN': 'English subject',
474 'ES': 'Spanish subject',
475 }
476
477 fu = str(self.request.get('fu'))
478 messageid = fu_messages[fu]
When you call
fu = str(self.request.get('fu'))
if there is no 'fu' in the request, self.request.get will return the empty string (''). So when you try
messageid = fu_messages[fu]
it looks up the empty string in
fu_messages = {'1': 'MS_x01',
'2': 'MS_x02',
}
which only has '1' and '2' as keys.
The reason your pushQueue handler is not seeing the params you send via
params = {
'guid': guid,
'fu': follow_up,
'lang': lang,
'trigid': trigid,
}
taskqueue.add(queue_name='emailworker', url='/emailworker',
params=params)
is because you are using a GET handler instead of a POST or PUT handler. As the documentation states:
Params are encoded as application/x-www-form-urlencoded and set to
the payload.
So the payload of the request has your 'fu' param in it, but since it is a GET request, the payload is dropped (this is how HTTP works, not specific to App Engine). If you use POST as your handler, the payload will come through as expected.
I noticed your code is very similar to the documented sample, but simply uses get where the sample uses post.
Related
I'm trying to make a blackjack command for my Discord Bot in python, I'm making small codes and little by little testing and improving, see below:
import discord
from discord.ext import commands
from discord import app_commands
import random, json, datetime
class bj(discord.ui.Button):
def __init__(self, game ,gamesum, player_cards):
super().__init__()
self.value = None
#discord.ui.button (label="Hit", style=discord.ButtonStyle.blurple)
async def confirm(self, button: discord.ui.Button, interaction: discord. Interaction):
self.value = True
self.stop()
value_1=["A", 1,2,3,4,5,6,7,8,9,10,"J","Q","K",]
nype_1=["♦️","♠️","♥️","♣️"]
card_value_3 = random.randint(0, len(value_1) - 1)
nype_card_3 = random.randint(0, len(nype_1) - 1)
card_3 = f"{card_value_3[card_value_3]} {card_value_3[nype_card_3]}"
await match.edit()
match.edit_field(name='Your hand', value=f"{player_cards} {card_value_3}{nype_card_3}")
if type(card_value_3)==str:
if value_card_3=="A":
value_letter_3=11
else:
value_letter_3=10
else:
value_letter_3=value_card_3
class client(discord.Client):
def __init__(self):
super().__init__(intents=discord.Intents.default())
self.synced = False
async def setup_hook(self) -> None:
self.add_view(DropdownView())
async def on_ready(self):
await aclient.change_presence(activity = discord.Streaming(name = "/news", url = "https://www.youtube.com/watch?v=dQw4w9WgXcQ"))
await self.wait_until_ready()
if not self.synced:
await tree.sync()
self.synced = True
print(f"We entered as {self.user}!")
print(f"That has the ID {self.user.id}")
client = client()
tree = app_commands.CommandTree(aclient)
#tree.command(name='blackjack', description='Play a game of blackjack')
async def blackjack(interaction: discord.Interaction, amount:int):
await open_account(interaction.user)
money = await add_money(interaction.user)
if amount>money[0]:
await interaction.response.send_message(f"You don't have all this amount {interaction.user.mention}.")
else:
if quantity<0:
await interaction.response.send_message(f"You must enter a positive value")
else:
value_1=["A",2,3,4,5,6,7,8,9,10,'J','Q',"K"]
nype_1=["♦️","♠️","♥️","♣️"]
value_card_a = random.randint(0, len(value_1) - 1)
nype_card_a = random.randint(0, len(nype_1) - 1)
letter_a = f"{value_1[value_card_a]}{nype_1[nype_letter_a]}"
b_card_value = random.randint(0, len(1_value) - 1)
nype_card_b = random.randint(0, len(nype_1) - 1)
letter_b = f"{value_1[value_card_b]}{nype_1[nype_letter_a]}"
player_cards = f"{card_a} {card_b}"
if type(value_card_a)==str:
if value_card_a=="A":
value_letter_a=11
else:
value_letter_a=10
else:
value_card_a=value_card_a
if type(value_card_b)==str:
if value_card_b=="A":
value_letter_b=11
else:
value_letter_b=10
else:
value_card_b=value_card_b
sum_of_game=value_card_a+value_card_b
await add_money(interaction.user, -1*amount)
if sum_of_game==21:
result='Blackjack'
titulo_resultado=f'You won ~~K~~ {1.5*amount}'
else:
result=sum_of_game
titulo_resultado=f'You invested ~~K~~ {amount} in this blackjack'
departure=discord.Embed(
description=f'{result_title}',
colour=discord.Color.random()
)
match.add_field(name='Your hand', value=f"{player_cards}\n{result}")
if result=='Blackjack':
await add_money(interaction.user, 1.5*amount)
await interaction.response.send_message(embed=game, view=bj(game ,gamesum, player_cards))
async def open_account(user):
users = await bank_data()
if str(user.id) in users:
return False
else:
users[str(user.id)] = {}
users[str(user.id)]['wallet'] = 0
users[str(user.id)]['bank']= 0
with open("money.json", "w") as f:
json.dump(users, f)
return true
async def bank_data():
with open("money.json", "r") as f:
users = json.load(f)
return users
async def add_money(user, change=0, mode = "wallet"):
users = await bank_data()
users[str(user.id)][mode] +=change
with open("money.json", "w") as f:
json.dump(users, f)
money = [users[str(user.id)]["wallet"], users[str(user.id)]["bank"]]
return money
aclient.run(Token)
But in await interaction.response.send_message(embed=match, view=bj(match ,game_sum, player_cards)) is reporting the error
2023-02-06 19:14:31 ERROR discord.app_commands.tree Ignoring exception in command 'blackjack'
Traceback (most recent call last):
File "/home/runner/Kllin/venv/lib/python3.10/site-packages/discord/app_commands/commands.py", line 862, in _do_call
return await self._callback(interaction, **params) # type: ignore
File "main.py", line 1155, in blackjack
await interaction.response.send_message(embed=partida, view=bj(partida ,soma_de_jogo, cartas_jogador))
File "/home/runner/Kllin/venv/lib/python3.10/site-packages/discord/interactions.py", line 754, in send_message
params = interaction_message_response_params(
File "/home/runner/Kllin/venv/lib/python3.10/site-packages/discord/webhook/async_.py", line 577, in interaction_message_response_params
data['components'] = view.to_components()
AttributeError: 'bj' object has no attribute 'to_components'
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/home/runner/Kllin/venv/lib/python3.10/site-packages/discord/app_commands/tree.py", line 1242, in _call
await command._invoke_with_namespace(interaction, namespace)
File "/home/runner/Kllin/venv/lib/python3.10/site-packages/discord/app_commands/commands.py", line 887, in _invoke_with_namespace
return await self._do_call(interaction, transformed_values)
File "/home/runner/Kllin/venv/lib/python3.10/site-packages/discord/app_commands/commands.py", line 880, in _do_call
raise CommandInvokeError(self, e) from e
discord.app_commands.errors.CommandInvokeError: Command 'blackjack' raised an exception: AttributeError: 'bj' object has no attribute 'to_components'
I tried to interpret the error, as I recently started programming, it didn't help much, I asked in ChatGPT, and it also didn't help much (the error didn't even change), so the artificial intelligence itself suggested that I come and ask here, I hope it helps me help(Oh, and sorry for not leaving everything organized and well separated, they said there was a lot of code and little information).
I am attempting my first React + DRF project. Here is my difficulty. When I try to create a user with an existing username I get a 500 internal server error and I can't seem to catch it or do anything with it in React. It otherwise works perfectly well and I can display errors when retrieving user info (such as: "sure does not exist").
The full traceback of the IntegrityError error I get from the backend is:
Traceback (most recent call last):
File "/Users/bernardino/Desktop/boombust/.env/lib/python3.8/site-packages/django/db/backends/utils.py", line 89, in _execute
return self.cursor.execute(sql, params)
psycopg2.errors.UniqueViolation: duplicate key value violates unique constraint "users_customuser_username_key"
DETAIL: Key (username)=(kenshiro) already exists.
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/Users/bernardino/Desktop/boombust/.env/lib/python3.8/site-packages/django/core/handlers/exception.py", line 55, in inner
response = get_response(request)
File "/Users/bernardino/Desktop/boombust/.env/lib/python3.8/site-packages/django/core/handlers/base.py", line 197, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/Users/bernardino/Desktop/boombust/.env/lib/python3.8/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
return view_func(*args, **kwargs)
File "/Users/bernardino/Desktop/boombust/.env/lib/python3.8/site-packages/django/views/generic/base.py", line 84, in view
return self.dispatch(request, *args, **kwargs)
File "/Users/bernardino/Desktop/boombust/.env/lib/python3.8/site-packages/rest_framework/views.py", line 509, in dispatch
response = self.handle_exception(exc)
File "/Users/bernardino/Desktop/boombust/.env/lib/python3.8/site-packages/rest_framework/views.py", line 469, in handle_exception
self.raise_uncaught_exception(exc)
File "/Users/bernardino/Desktop/boombust/.env/lib/python3.8/site-packages/rest_framework/views.py", line 480, in raise_uncaught_exception
raise exc
File "/Users/bernardino/Desktop/boombust/.env/lib/python3.8/site-packages/rest_framework/views.py", line 506, in dispatch
response = handler(request, *args, **kwargs)
File "/Users/bernardino/Desktop/boombust/users/views.py", line 33, in post
user = serializer.save()
File "/Users/bernardino/Desktop/boombust/.env/lib/python3.8/site-packages/rest_framework/serializers.py", line 212, in save
self.instance = self.create(validated_data)
File "/Users/bernardino/Desktop/boombust/users/serializers.py", line 59, in create
instance.save()
File "/Users/bernardino/Desktop/boombust/.env/lib/python3.8/site-packages/django/contrib/auth/base_user.py", line 68, in save
super().save(*args, **kwargs)
File "/Users/bernardino/Desktop/boombust/.env/lib/python3.8/site-packages/django/db/models/base.py", line 806, in save
self.save_base(
File "/Users/bernardino/Desktop/boombust/.env/lib/python3.8/site-packages/django/db/models/base.py", line 857, in save_base
updated = self._save_table(
File "/Users/bernardino/Desktop/boombust/.env/lib/python3.8/site-packages/django/db/models/base.py", line 1000, in _save_table
results = self._do_insert(
File "/Users/bernardino/Desktop/boombust/.env/lib/python3.8/site-packages/django/db/models/base.py", line 1041, in _do_insert
return manager._insert(
File "/Users/bernardino/Desktop/boombust/.env/lib/python3.8/site-packages/django/db/models/manager.py", line 85, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/Users/bernardino/Desktop/boombust/.env/lib/python3.8/site-packages/django/db/models/query.py", line 1434, in _insert
return query.get_compiler(using=using).execute_sql(returning_fields)
File "/Users/bernardino/Desktop/boombust/.env/lib/python3.8/site-packages/django/db/models/sql/compiler.py", line 1621, in execute_sql
cursor.execute(sql, params)
File "/Users/bernardino/Desktop/boombust/.env/lib/python3.8/site-packages/django/db/backends/utils.py", line 103, in execute
return super().execute(sql, params)
File "/Users/bernardino/Desktop/boombust/.env/lib/python3.8/site-packages/django/db/backends/utils.py", line 67, in execute
return self._execute_with_wrappers(
File "/Users/bernardino/Desktop/boombust/.env/lib/python3.8/site-packages/django/db/backends/utils.py", line 80, in _execute_with_wrappers
return executor(sql, params, many, context)
File "/Users/bernardino/Desktop/boombust/.env/lib/python3.8/site-packages/django/db/backends/utils.py", line 89, in _execute
return self.cursor.execute(sql, params)
File "/Users/bernardino/Desktop/boombust/.env/lib/python3.8/site-packages/django/db/utils.py", line 91, in __exit__
raise dj_exc_value.with_traceback(traceback) from exc_value
File "/Users/bernardino/Desktop/boombust/.env/lib/python3.8/site-packages/django/db/backends/utils.py", line 89, in _execute
return self.cursor.execute(sql, params)
django.db.utils.IntegrityError: duplicate key value violates unique constraint "users_customuser_username_key"
DETAIL: Key (username)=(kenshiro) already exists.
The view in views.py is:
class CustomUserCreate(APIView):
permission_classes = (permissions.AllowAny,)
def post(self, request, format='json'):
serializer = CustomUserSerializer(data=request.data)
if serializer.is_valid(raise_exception=True):
try:
user = serializer.save()
if user:
json = serializer.data
return Response(json, status=status.HTTP_201_CREATED)
except IntegrityError:
return Response({"error": "This username is already taken."}, status=status.HTTP_406_NOT_ACCEPTABLE)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
And this is the React logic:
const onSubmit = async (values) => {
const user = {
first_name: values.firstName,
last_name: values.lastName,
username: values.username,
email: values.email,
password: values.password,
};
const response = await fetch(`users/user/create/`, {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
body: JSON.stringify({...user}),
}).catch(err => err);
const text = await response.text();
console.log(response.status);
if (response.status === 201) {
console.log("success", JSON.parse(text));
} else {
console.log("failed", text);
}
};
This is the serializer from serializers.py:
class CustomUserSerializer(serializers.ModelSerializer):
token = serializers.SerializerMethodField()
password = serializers.CharField(write_only=True)
email = serializers.EmailField(
required=True
)
username = serializers.CharField(required=True)
first_name = serializers.CharField(required=True)
last_name = serializers.CharField(required=True)
password = serializers.CharField(
min_length=8, write_only=True, required=True)
class Meta:
model = CustomUser
fields = ('email', 'username', 'password', 'token', 'first_name', 'last_name')
extra_kwargs = {'password': {'write_only': True}}
def get_token(self, user):
refresh = RefreshToken.for_user(user)
return {
'refresh': str(refresh),
'access': str(refresh.access_token),
}
I do have a username = CICharField(unique=True) in the CustomUser class in models.py if it helps.
You need to check before you save the model.
class CustomUserCreate(APIView):
permission_classes = (permissions.AllowAny,)
def post(self, request, format='json'):
serializer = CustomUserSerializer(data=request.data)
if serializer.is_valid(raise_exception=True):
# here you can check if the username already exists or not
username = serializer.validated_data.get('username')
if CustomUser.objects.filter(username = username).count() > 0:
return Response({"error": "This username is already taken."}, status=status.HTTP_406_NOT_ACCEPTABLE)
# if username is new
user = serializer.save()
if user:
json = serializer.data
return Response(json, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
I found a command that sends the latest deleted message. While testing I found that when I delete a message it sends a traceback error to the console. Here's the traceback error and code.
Ignoring exception in on_message_delete
Traceback (most recent call last):
File "/opt/virtualenvs/python3/lib/python3.8/site-packages/discord/client.py", line 343, in _run_event
await coro(*args, **kwargs)
File "/home/runner/Isla/cogs/awp.py", line 21, in on_message_delete
if msg.author.client:
AttributeError: 'Member' object has no attribute 'client'
import discord
from discord.ext import commands
import datetime
import editdistance
import re
invitere = r"(?:https?:\/\/)?discord(?:\.gg|app\.com\/invite)?\/(?:#\/)([a-zA-Z0-9-]*)"
invitere2 = r"(http[s]?:\/\/)*discord((app\.com\/invite)|(\.gg))\/(invite\/)?(#\/)?([A-Za-z0-9\-]+)(\/)?"
class Awp(commands.Cog):
def __init__(self, client):
self.client = client
self.snipes = {}
#client.listen('on_message_delete')
async def on_message_delete(msg):
if msg.author.client:
return
self.snipes[msg.channel.id] = msg
#client.listen('on_message_edit')
async def on_message_edit(before, after):
if before.author.client or after.author.client:
return # DEPARTMENT OF REDUNDANCY DEPARTMENT
if (editdistance.eval(before.content, after.content) >= 10) and (
len(before.content) > len(after.content)):
self.snipes[before.channel.id] = [before, after]
#commands.Cog.listener()
async def on_ready(self):
print('Gifs bot is online.')
def sanitise(self, string):
if len(string) > 1024:
string = string[0:1021] + "..."
string = re.sub(invitere2, '[INVITE REDACTED]', string)
return string
#commands.command()
async def awp(self, ctx):
'"Snipes" someone\'s message that\'s been edited or deleted.'
try:
snipe = self.snipes[ctx.channel.id]
except KeyError:
return await ctx.send('No snipes in this channel!')
if snipe is None:
return await ctx.send('No snipes in this channel!')
# there's gonna be a snipe after this point
emb = discord.Embed()
if type(snipe) == list: # edit snipe
emb.set_author(
name=str(snipe[0].author),
icon_url=snipe[0].author.avatar_url)
emb.colour = snipe[0].author.colour
emb.add_field(
name='Before',
value=self.sanitise(snipe[0].content),
inline=False)
emb.add_field(
name='After',
value=self.sanitise(snipe[1].content),
inline=False)
emb.timestamp = snipe[0].created_at
else: # delete snipe
emb.set_author(
name=str(snipe.author),
icon_url=snipe.author.avatar_url)
emb.description = self.sanitise(snipe.content)
emb.colour = snipe.author.colour
emb.timestamp = snipe.created_at
emb.set_footer(
text=f'Message sniped by {str(ctx.author)}',
icon_url=ctx.author.avatar_url)
await ctx.send(embed=emb)
self.snipes[ctx.channel.id] = None
def setup(client):
client.add_cog(Awp(client))
You simply have to change message.author.client to message.author.bot, regardless of you using client or bot.
References:
discord.Member
I am creating a system consisting angularjs frontend web app and DRF rest interface.
I can use command line 'curl' to upload image file to DRF rest interface, but when I use angularjs http post, I got the error message: 'OrderedDict' object has no attribute 'pk'
My DRF setup is as follows:
models.py:
def upload_to(instance, filename):
return 'post_image/{0}/{1}'.format(instance.author.id, filename)
class PostImage(models.Model):
author = models.ForeignKey(Author, blank=False, editable=False, related_name='images')
post = models.ForeignKey(Post, blank=False, editable=False, related_name='images')
image = models.ImageField(_('image'), blank=True, null=True, upload_to=upload_to)
created = models.DateTimeField(editable=False)
updated = models.DateTimeField(editable=False)
def __unicode__(self):
return self.name
def save(self, *args, **kwargs):
''' On save, update timestamps '''
if not self.id:
self.created = timezone.now()
self.updated = timezone.now()
return super(PostImage, self).save(*args, **kwargs)
serializers.py
class PostImageSerializer(serializers.HyperlinkedModelSerializer):
author = serializers.HyperlinkedRelatedField(read_only=True, view_name='author-detail')
post = serializers.HyperlinkedRelatedField(read_only=True, view_name='post-detail')
class Meta:
model = PostImage
fields = ('url', 'image', 'author', 'post', 'created', 'updated')
views.py
class PostImageView(generics.ListCreateAPIView):
"""
List and Create post image endpoint
Allowed request method: Get, Post
"""
serializer_class = PostImageSerializer
permission_classes = [permissions.IsAuthenticated]
parser_classes = (FormParser, MultiPartParser, FileUploadParser,)
def get_queryset(self):
queryset = super(PostImageView, self).get_queryset()
return queryset.filter(post__pk=self.kwargs['pk'])
def perform_create(self, serializer):
post = Post.objects.get(pk=self.kwargs['pk'])
if 'upload' in self.request.data:
file_obj = self.request.data['upload']
serializer.save(author=self.request.user, post=post, image=file_obj)
return Response(status=status.HTTP_201_CREATED)
else:
return Response(status=status.HTTP_400_BAD_REQUEST)
I am using JWT authentication:
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
) ,
}
Log error message:
Internal Server Error: /api/v1/post/22/image
Traceback (most recent call last):
File "/root/rest_drf/env/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 132, in get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/root/rest_drf/env/local/lib/python2.7/site-packages/django/views/decorators/csrf.py", line 58, in wrapped_view
return view_func(*args, **kwargs)
File "/root/rest_drf/env/local/lib/python2.7/site-packages/django/views/generic/base.py", line 71, in view
return self.dispatch(request, *args, **kwargs)
File "/root/rest_drf/env/local/lib/python2.7/site-packages/rest_framework/views.py", line 452, in dispatch
response = self.handle_exception(exc)
File "/root/rest_drf/env/local/lib/python2.7/site-packages/rest_framework/views.py", line 449, in dispatch
response = handler(request, *args, **kwargs)
File "/root/rest_drf/env/local/lib/python2.7/site-packages/rest_framework/generics.py", line 244, in post
return self.create(request, *args, **kwargs)
File "/root/rest_drf/env/local/lib/python2.7/site-packages/rest_framework/mixins.py", line 21, in create
headers = self.get_success_headers(serializer.data)
File "/root/rest_drf/env/local/lib/python2.7/site-packages/rest_framework/serializers.py", line 466, in data
ret = super(Serializer, self).data
File "/root/rest_drf/env/local/lib/python2.7/site-packages/rest_framework/serializers.py", line 215, in data
self._data = self.to_representation(self.validated_data)
File "/root/rest_drf/env/local/lib/python2.7/site-packages/rest_framework/serializers.py", line 435, in to_representation
ret[field.field_name] = field.to_representation(attribute)
File "/root/rest_drf/env/local/lib/python2.7/site-packages/rest_framework/relations.py", line 264, in to_representation
return self.get_url(value, self.view_name, request, format)
File "/root/rest_drf/env/local/lib/python2.7/site-packages/rest_framework/relations.py", line 199, in get_url
if obj.pk is None:
AttributeError: 'OrderedDict' object has no attribute 'pk'
[pid: 29484|app: 0|req: 2/4] 76.114.185.25 () {54 vars in 1242 bytes} [Sun Jan 24 16:41:13 2016] POST /api/v1/post/22/image => generated 107983 bytes in 153 msecs (HTTP/1.1 500) 2 headers in 92 bytes (1 switches on core 1)
I've been trying to use webapp2 to store user data in session.
I tried to store the Key of the parent object in session data:
self.session['client'] = client.key
But I keep getting a:
TypeError: Key('Client', 6401356696911872) is not JSON serializable
How should I store an entity key in a session?
My code fairly simple:
import os
import urllib
import logging
from google.appengine.api import users
from google.appengine.ext import ndb
import jinja2
import webapp2
from webapp2_extras import sessions
class BaseHandler(webapp2.RequestHandler):
def dispatch(self):
self.session_store = sessions.get_store(request=self.request)
try:
# dispatch the request
webapp2.RequestHandler.dispatch(self)
finally:
# save all sessions
import pdb; pdb.set_trace()
self.session_store.save_sessions(self.response)
#webapp2.cached_property
def session(self):
# Returns a session using the default cookie key.
return self.session_store.get_session()
JINJA_ENVIRONMENT = jinja2.Environment(
loader = jinja2.FileSystemLoader(os.path.dirname(__file__)),
extensions=['jinja2.ext.autoescape'],
autoescape=True)
DEFAULT_LEADBOOK_NAME = 'whatsmyname'
def leadbook_key(leadbook_name=DEFAULT_LEADBOOK_NAME):
"""Constructs a Datastore key for a LeadBook entity with leadbook_name."""
return ndb.Key('LeadBook', leadbook_name)
class Client(ndb.Model):
email = ndb.StringProperty()
name = ndb.StringProperty(indexed=True)
street1 = ndb.StringProperty()
street2 = ndb.StringProperty()
city = ndb.StringProperty()
zipcode = ndb.IntegerProperty()
phone = ndb.StringProperty()
signup = ndb.DateTimeProperty(auto_now_add=True)
# this just creates a Client to use
if not ( Client.query( Client.name == "Bryan Wheelock").get()):
logging.info("create Admin")
client = Client(
email = "bryan#mail.com",
name = "Bryan Wheelock",
street1 = "555 Main St",
street2 = "unit 1",
city = "Atlanta",
zipcode = 99999,
phone = "(888)555-1212"
).put()
class Customer(ndb.Model):
client = ndb.KeyProperty(kind=Client)
email = ndb.StringProperty(indexed=True)
name = ndb.StringProperty(indexed=True)
street1 = ndb.StringProperty()
street2 = ndb.StringProperty()
city = ndb.StringProperty()
zipcode = ndb.IntegerProperty()
phone = ndb.StringProperty()
signup = ndb.DateTimeProperty(auto_now_add=True)
class MainPage(BaseHandler):
def get(self):
leadbook_name = self.request.get('leadbook_name',
DEFAULT_LEADBOOK_NAME)
# This should be the Client record that shows the info of the owner of the local clinic
# the question is how do I get the site to show the correct Client?
client = Client.query( Client.name == "Bryan Wheelock").get()
self.session['client'] = client.key
template_values = {
'client': client,
'leadbook_name': urllib.quote_plus(leadbook_name),
}
template = JINJA_ENVIRONMENT.get_template('index.html')
self.response.write(template.render(template_values))
class LeadBook(webapp2.RequestHandler):
def post(self):
leadbook_name = self.request.get('leadbook_name',
DEFAULT_LEADBOOK_NAME)
client = self.session.get('client')
cl = Client.query(client.key )
customer = Customer( client = cl.key)
customer.name = self.request.get('id_name')
customer.street = self.request.get('id_street')
customer.phone = self.request.get('id_phone')
customer.zip = self.request.get('id_zip')
import pdb; pdb.set_trace()
# How can I see the number of Customers before and after save?
customer.put()
query_params = {'leadbook_name': leadbook_name}
self.redirect('/?' + urllib.urlencode(query_params))
config = {}
config['webapp2_extras.sessions'] = {
'secret_key': 'my-super-secret-key',
}
application = webapp2.WSGIApplication([
('/', MainPage),
('/sign', LeadBook),
], config = config,
debug=True)
Traceback (most recent call last):
File "/Users/Bryan/Desktop/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2.py", line 1535, in __call__
rv = self.handle_exception(request, response, e)
File "/Users/Bryan/Desktop/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2.py", line 1529, in __call__
rv = self.router.dispatch(request, response)
File "/Users/Bryan/Desktop/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2.py", line 1278, in default_dispatcher
return route.handler_adapter(request, response)
File "/Users/Bryan/Desktop/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2.py", line 1102, in __call__
return handler.dispatch()
File "/Users/Bryan/work/GoogleAppEngine/dermalfillersecrets/main.py", line 22, in dispatch
self.session_store.save_sessions(self.response)
File "/Users/Bryan/Desktop/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2_extras/sessions.py", line 420, in save_sessions
session.save_session(response)
File "/Users/Bryan/Desktop/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2_extras/sessions.py", line 205, in save_session
response, self.name, dict(self.session), **self.session_args)
File "/Users/Bryan/Desktop/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2_extras/sessions.py", line 423, in save_secure_cookie
value = self.serializer.serialize(name, value)
File "/Users/Bryan/Desktop/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2_extras/securecookie.py", line 47, in serialize
value = self._encode(value)
File "/Users/Bryan/Desktop/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2_extras/securecookie.py", line 92, in _encode
return json.b64encode(value)
File "/Users/Bryan/Desktop/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2_extras/json.py", line 84, in b64encode
return base64.b64encode(encode(value, *args, **kwargs))
File "/Users/Bryan/Desktop/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2_extras/json.py", line 55, in encode
return json.dumps(value, *args, **kwargs).replace("</", "<\\/")
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/__init__.py", line 250, in dumps
sort_keys=sort_keys, **kw).encode(obj)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/encoder.py", line 207, in encode
chunks = self.iterencode(o, _one_shot=True)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/encoder.py", line 270, in iterencode
return _iterencode(o, 0)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/encoder.py", line 184, in default
raise TypeError(repr(o) + " is not JSON serializable")
TypeError: Key('Client', 6401356696911872) is not JSON serializable
Use a urlsafe version of the key:
https://cloud.google.com/appengine/docs/python/ndb/entities#retrieving_entities
self.session['client'] = client.key.urlsafe()
On retrieval, use
client = ndb.Key(urlsafe=self.session['client']).get()