Command raised an exception: TypeError: Object of type File is not JSON serializable but no other solution working for me - discord

The Function of discord command named server
#bot.command(name = 'server')
async def _minecraftserverinfo(ctx, ip:str, port:str, servername:str):
if servername == "survival":
svname = "Survival"
elif servername == "lobby":
svname = "Lobby"
#serverembed = createEmbed(ip, port)
#value = f"The server has {status.players.online} players and replied in {status.latency} ms\nThe server replied in {latency} ms\nThe server has the following players online: {','.join(query.players.names)}"
server = MinecraftServer.lookup(ip+':'+port)
#=======================================
#=======================================
# 'status' is supported by all Minecraft servers that are version 1.7 or higher.
status = server.status()
latency = server.ping()
query = server.query()
serverembed = discord.Embed(title = ip, url = "https://www.zer02infinity.com/",description = f"Zero To Infinity Minecraft {svname} Server")#\nThe server has the following players online: {','.join(query.players.names)}")
serverembed.set_thumbnail(url="https://cdn.discordapp.com/attachments/833829693588373534/920017091325747220/2021-12-13_11.png")
serverembed.add_field(name="Players Count", value=f"{status.players.online}/{query.players.max}", inline=True)
serverembed.add_field(name="Direct Connect:", value=f"```mc.zer02infinity.com```", inline=True)
#serverembed.add_field(name="Names:", value=f"{latency} ms", inline=True)
#nl = '\n'
#serverembed.add_field(name="Names:", value=f"{nl}{nl.join(query.players.names)}", inline=False)
#serverembed.add_field(name="Names:", value={'\n'.join(query.players.ping)}, inline=True)
#sending embed
embed = await ctx.send(embed=serverembed)
await embed.add_reaction(emoji)
message_id = embed.id
while True:
server = MinecraftServer.lookup(ip+':'+port)
# 'status' is supported by all Minecraft servers that are version 1.7 or higher.
status = server.status()
latency = server.ping()
query = server.query()
serverembed = discord.Embed(title = ip, url = "https://www.zer02infinity.com/",description = f"Zero To Infinity Minecraft {svname} Server")#\nThe server has the following players online: {','.join(query.players.names)}")
serverembed.set_thumbnail(url="https://cdn.discordapp.com/attachments/833829693588373534/920017091325747220/2021-12-13_11.png")
serverembed.add_field(name="Players Count", value=f"{status.players.online}/{query.players.max}", inline=True)
serverembed.add_field(name="Direct Connect:", value=f"```mc.zer02infinity.com```", inline=True)
#serverembed.add_field(name="Names:", value=f"{latency} ms", inline=True)
#nl = '\n'
problem started after i added a image from local file
file = discord.File("./foo.png", filename="foo.png")
serverembed.add_field(name="Names:", value={','.join(query.players.names)}, inline=False)
serverembed.set_image(url="attachment://foo.png")
#print('Winners are:', *names, sep='\n')
serverembed = await embed.edit(file=file, embed = serverembed)
await asyncio.sleep(60)
pass
So this is the recent code i added where foo.png is maintained by graph.py given below
import discord
from discord.ext import commands
import matplotlib.pyplot as plt
class Equations(commands.Cog):
def __init__(self, bot):
self.bot = bot
def plotlineareq(self, a, b, clr):
x = [0, 10]
y = [(a * i + b) for i in x]
plt.figure(figsize=(10, 10)) # #Size of Graph
plt.xlim(x) # #X Range [-6,6]
plt.ylim(x) # #Y Range [-6,6]
axis = plt.gca() # #Get Current Axis
plt.plot(axis.get_xlim(), [0, 0], 'k--') # #X Axis Plots Line Across
plt.plot([0, 0], axis.get_ylim(), 'k--') # #Y Axis Plots Line Across
plt.locator_params(axis="x", nbins=20)
plt.locator_params(axis="y", nbins=20)
plt.plot(x, y, label='linear', linestyle='solid', color=clr)
plt.ylabel('Players')
plt.xlabel('Time')
mm = str(a)
bb = str(b)
plt.title('Live Status')
#plt.grid()
plt.savefig("foo.png")
#commands.command()
async def linear(self, ctx, equation):
try:
equation = equation.replace(" ", "")
mx = equation.split("x")[0]
mx = equation.replace("x", "").replace("y=", "")
bx = equation.split("+")[1]
self.plotlineareq(mx, bx, 'b')
file = discord.File("foo.png", filename='foo.png')
embed = discord.Embed(color=0xff0000)
embed = embed.set_image(url="attachment://foo.png")
await ctx.send(file=file, embed=embed)
except Exception as e:
await ctx.send(f"An error occured: {e}")
def setup(bot):
bot.add_cog(Equations(bot))
After executing it gives the following error in error log-
Command raised an exception: TypeError: Object of type File is not JSON serializable

Related

How to solve bot abandoning previously started game from a different user

I am currently in the process of making a blackjack / gambling bot for me and my friends and the bot works, only the problem(screenshot) is that when user A makes a game and user B makes a Game when user A responds after that user User B has started a game, the original game from user A gets abandoned and takes Users A's response and applies to User
I currently have an active game list which tracks who is in an active game and puts them in/out of one when they complete or start a game but this only solves it when a users is not an in game.
I have edited the code down below to make it less obstructed by a lot of repetitive code
any suggestions on how to fix this code for this problem will be welcome.
from datetime import datetime
import string
import discord
from discord.ext import commands
import random
import sqlite3
class BlackjackCog(commands.Cog):
def __init__(self, bot):
self.bot = bot
self.game_id = "AAAAAAAA"
self.players_in_game = {}
self.deck = []
self.reset_deck()
self.player_hand = None
self.dealer_hand = None
self.outcome = ""
self.timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
self.bet = None
self.conn = sqlite3.connect("credits.db")
self.conn2 = sqlite3.connect("logs.db")
self.cursor = self.conn.cursor()
self.cursor2 =self.conn2.cursor()
def unload(self):
self.conn.close()
self.conn2.close()
def check_hand_value(self, hand)
# game logic to count cards
def reset_deck
# game logic to prevent the deck from going empty
def draw_card
# game logic to append a card to the current player or reset the deck if its empty
#commands.command(name="bj", aliases=["Bj", "blackjack", "BJ" , "Blackjack"])
async def blackjack(self, ctx, bet_amount: int = None):
user_id = ctx.author.id
if bet_amount is None:
embed=discord.Embed(title="Example Higher Lower" , color=0x3498db)
embed.add_field(name="How to Play", value="`You need to get higher amount of card total than the dealer's hand`", inline=False)
embed.add_field(name="Aliases", value="`!hit , !stand`", inline=False)
embed.add_field(name="Win value", value="`x2`", inline=False)
embed.add_field(name="Example command", value="`!bj <credit amount>`", inline=False)
embed.set_footer(text='Do !bj for this message')
await ctx.send(embed=embed)
return
if bet_amount <= 0:
await ctx.send("Invalid bet amount. Please enter a positive number.")
return
self.cursor.execute("SELECT credits FROM credits WHERE user_id=?", (ctx.author.id,))
result = self.cursor.fetchone()
if result is None:
await ctx.send("You do not have any credits use !daily ")
return
self.player_credits = result[0]
if result is None:
await ctx.send("You do not have any credits. Please add some with !daily")
return
if bet_amount > result[0]:
await ctx.send("You do not have enough credits to make that bet.")
return
if ctx.author.id in self.players_in_game:
await ctx.send("You are already in a game. Please finish your current game before starting a new one.")
return
self.bet_amount = bet_amount
self.player_hand = [self.draw_card(), self.draw_card()]
self.dealer_hand = [self.draw_card(), self.draw_card()]
player_total = self.check_hand_value(self.player_hand)
dealer_total = self.check_hand_value([self.dealer_hand[0]])
bet_amount = "{:,}".format(bet_amount)
player_credits = "{:,}".format(self.player_credits)
self.game_id = "BJ" + "".join(random.choices(string.ascii_uppercase + string.digits, k=6))
self.msg = await ctx.send(embed=discord.Embed(title="Blackjack | " + 'User: ' + ctx.author.display_name + " - ID: " + self.game_id, color=0x3498db)
.add_field(name="Your hand", value=' '.join(self.player_hand) + f"\nTotal: **{player_total}**", inline=True)
.add_field(name="Dealers hand", value=' '.join([self.dealer_hand[0]])+ f"\nTotal: **{dealer_total}**", inline=True)
.add_field(name="Bet", value=f"**{bet_amount}** credits", inline=False)
.add_field(name="Credits", value=f"You have **{player_credits}** credits", inline=False)
.add_field(name="Options", value="Use !hit \nUse !stand \nUse !split\n Use !dd", inline=False)
.set_footer(text='Active game')
)
self.players_in_game[user_id] = {}
#commands.command(names="hit", aliases=["h", "Hit" , "H"])
async def hit(self, ctx):
user_id = ctx.author.id
if user_id not in self.players_in_game:
await ctx.send("You don't have an active game to stand in.")
return
game_id = self.players_in_game[user_id]
player_hand = self.player_hand
player_hand.append(self.draw_card())
player_total = self.check_hand_value(player_hand)
dealer_total = self.check_hand_value([self.dealer_hand[0]])
self.player_hand2 = "Empty"
self.player_hand_str = " ".join(self.player_hand)
self.dealer_hand_str = " ".join(self.dealer_hand)
if player_total > 21:
self.outcome = "Lost hit"
self.player_credits -= self.bet_amount
bet_amount = "{:,}".format(self.bet_amount)
player_credits = "{:,}".format(self.player_credits)
self.cursor.execute(f"UPDATE credits SET credits = {self.player_credits} WHERE user_id=?", (ctx.author.id,))
self.conn.commit()
self.cursor2.execute("""INSERT INTO blackjack_logs (game_id, player_hand, player_hand2 ,dealer_hand, player_credits ,bet_amount, outcome, timestamp) VALUES (?, ?, ?, ?, ?, ?, ?, ?)""", (self.game_id, self.player_hand_str, self.player_hand2, self.dealer_hand_str, self.player_credits ,self.bet_amount,self.outcome, self.timestamp,))
self.conn2.commit()
await self.msg.edit(embed=discord.Embed(title="Blackjack | " + 'User: ' + ctx.author.display_name+ " - ID: " + self.game_id , color=0xe74c3c)
.add_field(name="Your hand", value=' '.join(self.player_hand) + f"\nTotal: **{player_total}**", inline=True)
.add_field(name="Dealers hand", value=' '.join([self.dealer_hand[0]])+ f"\nTotal: **{dealer_total}**", inline=True)
.add_field(name="Lost", value=f"**{bet_amount}** credits", inline=False)
.add_field(name="Credits", value=f"You have **{player_credits}** credits", inline=False)
.set_footer(text='Finished game')
)
del self.players_in_game[ctx.author.id]
self.player_hand = None
self.dealer_hand = None
self.bet_amount = None
elif player_total == 21:
self.outcome = "Won hit"
self.player_credits += self.bet_amount
bet_amount = "{:,}".format(self.bet_amount)
player_credits = "{:,}".format(self.player_credits)
self.cursor.execute(f"UPDATE credits SET credits = {self.player_credits} WHERE user_id=?", (ctx.author.id,))
self.conn.commit()
self.cursor2.execute("""INSERT INTO blackjack_logs (game_id, player_hand, player_hand2 ,dealer_hand, player_credits ,bet_amount, outcome, timestamp) VALUES (?, ?, ?, ?, ?, ?, ?, ?)""", (self.game_id, self.player_hand_str, self.player_hand2, self.dealer_hand_str, self.player_credits ,self.bet_amount,self.outcome, self.timestamp,))
self.conn2.commit()
await self.msg.edit(embed=discord.Embed(title="Blackjack | " + 'User: ' + ctx.author.display_name + " - ID: " + self.game_id, color=0x109319)
.add_field(name="Your hand", value=' '.join(self.player_hand) + f"\nTotal: **{player_total}**", inline=True)
.add_field(name="Dealers hand", value=' '.join([self.dealer_hand[0]])+ f"\nTotal: **{dealer_total}**", inline=True)
.add_field(name="Win", value=f"**{bet_amount}** credits", inline=False)
.add_field(name="Credits", value=f"You have **{player_credits}** credits", inline=False)
.set_footer(text='Finished game')
)
del self.players_in_game[ctx.author.id]
self.player_hand = None
self.dealer_hand = None
self.bet_amount = None
else:
bet_amount = "{:,}".format(self.bet_amount)
player_credits = "{:,}".format(self.player_credits)
await self.msg.edit(embed=discord.Embed(title="Blackjack | " + 'User: ' + ctx.author.display_name + " - ID: " + self.game_id, color=0x3498db)
.add_field(name="Your hand", value=' '.join(self.player_hand) + f"\n**Total: **{player_total}", inline=True)
.add_field(name="Dealers hand", value=' '.join([self.dealer_hand[0]])+ f"\n**Total: **{dealer_total}", inline=True)
.add_field(name="Bet", value=f"**{bet_amount}** credits", inline=False)
.add_field(name="Credits", value=f"You have **{player_credits}** credits", inline=False)
.add_field(name="Options", value="Use !hit \n Use !stand\nUse !dd", inline=False)
.set_footer(text='Active game')
)
I also have stand, split and dd command but this amount of code should be enough to give suggestions/edits I believe.
I have tried to edit and add multiple active game lists and assigned an id to to player in the active game list but that also hasn't worked and I tried looking for a basic solution only
So far my conclusion is that I will need to implement a while loop and edit standard bj function and make it all run in 1 command instead of multiple.
The game itself works fine if you are playing solo the problem is really the screenshot.
As far as I can tell, these are all the class variables you have (that are important to a "game"):
game_id
players_in_game
deck
player_hand
dealer_hand
outcome
Now, let's run through some players playing your game. Player A comes along and does blackjack. This initialises all those above variables with values for them. If they were to keep playing by themselves - it would work just fine. However, before Player A can do anything, Player B comes along and runs the blackjack command. This overwrites all the values you had for Player A stored in those variables. If Player A now calls one of your other commands, they'll be using game state from Player B's game.
There's a fundamental flaw in your logic and saving of game state that'll always fail when more than one player tries to play at the same time.
What you need to do, is create some sort of game state object that can be used for that. This can be as simple as a dict, a custom class, DB entry, etc. But it needs to be something.
Using the dict idea:
# when a user uses the `blackjack` command
player_game_state = {"game_id": game_id, "user_id": user_id, "player_hand": player_hand, "dealer_hand": dealer_hand, "bet": bet} # etc, etc, etc
Then, we actually use your self.players_in_game class variable to keep track of all these game states.
# still in the blackjack command - once you setup everything
self.players_in_game[user_id] = game_state
Now, when they call one of the other commands, like hit:
# at the start of the command
player_game_state = self.players_in_game[user_id]
# instead of doing self.player_hand
player_game_state["player_hand"].append(self.draw_card())
Though, maybe your draw_card method, and reset_deck methods need to take the game state as a parameter and modify them. As I'd wager they're currently resetting your class variables as well.
Does that make sense? Hopefully enough that you can try to apply some of it.
TLDR; stop using class variables for storing individual parts of your game state.

How do I create a timestamp in an embed with pycord?

I would like my sent msg log which is an embedded msg to have a timestamp, so it would have a footing like bot_name • Today at 10:48 PM
Here is my current code,
#bot.event
async def on_message(ctx):
if ctx.author.bot: return
else:
log_msg = bot.get_channel(1023451687857442828)
embed = discord.Embed(
title = "Sent Message",
description = f"""This message was sent by{ctx.author.mention}, in {ctx.channel}\n**Message:** "{ctx.content}" """,
color = discord.Colour.green(),
)
embed.set_author(name=ctx.author)
embed.set_footer(text="bot_name")
await log_msg.send(embed=embed)```
You could do the following:
(remaining of your code)
now = datetime.now() # Gets your current time as a datetime object
embed.set_footer(text=f'bot_name • Today at {now.strftime("%H:%M")}') # Set your embed footer with the formatted time
await log_msg.send(embed=embed) # Sends your footer (already present in your original code)
If you don't have it imported already, you'll have to import datetime from datetime, or import datetime and do datetime.datetime.now() instead of just datetime.now()
You can use ctx.message.created_at to add a timestamp. That would look like this in the context of your code:
#bot.event
async def on_message(ctx):
if ctx.author.bot: return
else:
log_msg = bot.get_channel(1023451687857442828)
embed = discord.Embed(
title = "Sent Message",
description = f"""This message was sent by{ctx.author.mention}, in {ctx.channel}\n**Message:** "{ctx.content}" """,
color = discord.Colour.green(),
# message created at code below
timestamp = ctx.message.created_at
)
embed.set_author(name=ctx.author)
embed.set_footer(text="bot_name")
await log_msg.send(embed=embed)
Hope this helps

discord bot. database. embed doesn't appear

I want my bot react to a command.
If ?2 print line 2 of database
?3 print line 3 of database
etc...
I don't know why my embed doesn't appear I have no console errors...
My bot is connected and respond. My database is ok
if message.content.startswith('$'):
arg_id = message.content
conn = None
try:
conn = sqlite3.connect(database_file)
except Error as e:
print(e)
req = conn.cursor()
req.execute("SELECT * FROM space2 WHERE id=?", (arg_id,))
rows = req.fetchall()
for row in rows:
embed = discord.Embed(title='test', color=0x0000FF)
embed.set_thumbnail(url='https://www.pngkit.com/png/detail/231-2316751_database-database-icon-png.png')
embed.add_field(name='id', value=row[0], inline=False)
embed.add_field(name='CATEGORIE', value=row[1], inline=False)
embed.add_field(name='RANK', value=row[2], inline=False)
embed.add_field(name='SCORE', value=row[3], inline=False)
embed.add_field(name='POWER AREA GRAVITY 0', value=row[4], inline=False)
embed.add_field(name='POWER EYES WEAPONS', value=row[5], inline=False)
embed.set_footer(icon_url='https://pbs.twimg.com/profile_images/1325672283881484289/oaGtVIOD_400x400.png', text='Created by #Expected')
msg = await message.channel.send(embed=embed)
print(row)
NEW VERSION
there are advances but still mistakes...a little help would be appreciated...thanks
#client.event
async def on_message(message):
if message.author == client.user:
return
if message.content.startswith('$'):
message_slices = message.content.split()
try:
arg_id = int(message_slices[0][1:])
except ValueError:
embed = discord.Embed(title="Invalid argument", color=0x0000FF)
embed.set_footer(icon_url='https://pbs.twimg.com/profile_images/1325672283881484289/oaGtVIOD_400x400.png', text='Created by #Expected')
await message.channel.send(embed=embed)
else:
conn = None
try:
conn = sqlite3.connect(database_file)
except Error as e:
print(e)
exit(-1)
req = conn.cursor()
try:
req.execute("SELECT * FROM space2 WHERE id=?", (arg_id,))
except Error as e:
print(e)
else:
row = req.fetchone()
if row is not None:
embed = discord.Embed(title='NFT', color=0x0000FF)
embed.set_thumbnail(url='https://www.pngkit.com/png/detail/231-2316751_database-database-icon-png.png')
embed.add_field(name='id', value=str(row[0]), inline=False)
embed.add_field(name='CATEGORIE', value=str(row[1]), inline=False)
embed.add_field(name='RANK', value=str(row[2]), inline=False)
embed.add_field(name='SCORE', value=str(row[3]), inline=False)
embed.add_field(name='POWER AREA GRAVITY 0', value=str(row[4]), inline=False)
embed.add_field(name='POWER EYES WEAPONS', value=str(row[5]), inline=False)
embed.set_footer(icon_url='https://pbs.twimg.com/profile_images/1325672283881484289/oaGtVIOD_400x400.png', text='Created by #Expected')
await message.channel.send(embed=embed)
else:
embed = discord.Embed(title="Not found", color=0x0000FF)
embed.set_footer(icon_url='https://pbs.twimg.com/profile_images/1325672283881484289/oaGtVIOD_400x400.png', text='Created by #Expected')
await message.channel.send(embed=embed)
req.close()
conn.close()```
enter code here

WatsonApiException: Error: invalid-api-key, Code: 401

I cant find Alchemy Language API in IBM Watson.
Can I do this with natural-language-understanding service and how?
When I add
from watson_developer_cloud import NaturalLanguageUnderstandingV1
from watson_developer_cloud.natural_language_understanding_v1 \
import Features, EntitiesOptions, KeywordsOptions
It shows some error with combined keyword
# In[]:
import tweepy
import re
import time
import math
import pandas as pd
from watson_developer_cloud import AlchemyLanguageV1
def initAlchemy():
al = AlchemyLanguageV1(api_key='GRYVUMdBbOtJXxNOIs1aopjjaiyOmLG7xJBzkAnvvwLh')
return al
def initTwitterApi():
consumer_key = 'OmK1RrZCVJSRmKxIuQqkBExvw'
consumer_secret = 'VWn6OR4rRgSi7qGnZHCblJMhrSvj1QbJmf0f62uX6ZQWZUUx5q'
access_token = '4852231552-adGooMpTB3EJYPHvs6oGZ40qlo3d2JbVjqUUWkJ'
access_token_secret = 'm9hgeM9p0r1nn8IoQWJYBs5qUQu56XmrAhsDSYKjuiVA4'
auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
auth.set_access_token(access_token, access_token_secret)
api = tweepy.API(auth)
return api
'''This function is implemented to handle tweepy exception errors
because search is rate limited at 180 queries per 15 minute window by twitter'''
def limit(cursor):
while True:
try:
yield cursor.next()
except tweepy.TweepError as error:
print(repr(error))
print("Twitter Request limit error reached sleeping for 15 minutes")
time.sleep(16*60)
except tweepy.RateLimitError:
print("Rate Limit Error occurred Sleeping for 16 minutes")
time.sleep(16*60)
def retrieveTweets(api, search, lim):
if(lim == ""):
lim = math.inf
else:
lim = int(lim)
text = []
for tweet in limit(tweepy.Cursor(api.search, q=search).items(limit = lim)):
t = re.sub('\s+', ' ', tweet.text)
text.append(t)
data = {"Tweet":text,
"Sentiment":"",
"Score":""}
dataFrame = pd.DataFrame(data, columns=["Tweet","Sentiment","Score"])
return dataFrame
def analyze(al,dataFrame):
sentiment = []
score = []
for i in range(0, dataFrame["Tweet"].__len__()):
res = al.combined(text=dataFrame["Tweet"][i],
extract="doc-sentiment",
sentiment=1)
sentiment.append(res["docSentiment"]["type"])
if(res["docSentiment"]["type"] == "neutral"):
score.append(0)
else:
score.append(res["docSentiment"]["score"])
dataFrame["Sentiment"] = sentiment
dataFrame["Score"] = score
return dataFrame
def main():
#Initialse Twitter Api
api = initTwitterApi()
#Retrieve tweets
dataFrame = retrieveTweets(api,input("Enter the search query (e.g. #hillaryclinton ) : "), input("Enter limit for number of tweets to be searched or else just hit enter : "))
#Initialise IBM Watson Alchemy Language Api
al = initAlchemy()
#Do Document Sentiment analysis
dataFrame = analyze(al, dataFrame)
#Save tweets, sentiment, and score data frame in csv file
dataFrame.to_csv(input("Enter the name of the file (with .csv extension) : "))
if __name__ == '__main__':
main()# -*- coding: utf-8 -*-
The Watson Natural Language Understanding only has a combined call, but since it is the only call, it isn't called combined, its actually analyze. Best place to go for details would be the API documentation - https://www.ibm.com/watson/developercloud/natural-language-understanding/api/v1/?python#post-analyze

SQLAlchemy and QThread: Session handling in multi-thread

I have a problem: I don't know how to work with session, in combination with multi-thread, efficiently. Well you can see that I use scoped_session. It will transparently creates a thread-local session - so its threadsafe.
My below and executable example works, as long as the interval of QTimeris 1000, but if you set the value to 1, then there are some problems. On GUI-site, there a 8 QComboBox()-objects, and I will start 8 threads. In this example, I work with one table. When I run this program, not all QComboBox()-objects are filled. Sometimes there is only one QComboBox()-object blank or more. In addition, it happens once in a while that I am told by SQLAlchemy that the connection was closed. For this I have an error message:
Traceback (most recent call last):
File "D:\Dan\Python\Xarphus\xarphus\subclass_master_data_load_data_item.py", line 151, in populate_item
self.populate_item_signal.emit(next(self._element))
File "D:\Dan\Python\Xarphus\xarphus\core\manage_data_manipulation_master_data.py", line 232, in select_all
yield record.id, record.relationship
File "D:\Dan\Python\Xarphus\xarphus\core\manage_db_connection.py", line 245, in __exit__
self.session.commit()
File "C:\Python27\lib\site-packages\sqlalchemy\orm\session.py", line 906, in commit
self.transaction.commit()
File "C:\Python27\lib\site-packages\sqlalchemy\orm\session.py", line 465, in commit
t[1].commit()
File "C:\Python27\lib\site-packages\sqlalchemy\engine\base.py", line 1632, in commit
self._do_commit()
File "C:\Python27\lib\site-packages\sqlalchemy\engine\base.py", line 1663, in _do_commit
self.connection._commit_impl()
File "C:\Python27\lib\site-packages\sqlalchemy\engine\base.py", line 726, in _commit_impl
self.connection._reset_agent is self.__transaction:
File "C:\Python27\lib\site-packages\sqlalchemy\engine\base.py", line 351, in connection
self._handle_dbapi_exception(e, None, None, None, None)
File "C:\Python27\lib\site-packages\sqlalchemy\engine\base.py", line 1405, in _handle_dbapi_exception
util.reraise(*exc_info)
File "C:\Python27\lib\site-packages\sqlalchemy\engine\base.py", line 349, in connection
return self._revalidate_connection()
File "C:\Python27\lib\site-packages\sqlalchemy\engine\base.py", line 429, in _revalidate_connection
raise exc.ResourceClosedError("This Connection is closed")
ResourceClosedError: This Connection is closed
And, if I run my program several times, I get, among other things sometimes the following message:
Traceback (most recent call last):
File "C:\Users\Sophus\Desktop\ver_2_simple_problem.py", line 83, in init_object
self._element = self.master_data_manipulation.select_all()
File "C:\Users\Sophus\Desktop\ver_2_simple_problem.py", line 178, in __exit__
self.session.commit()
File "C:\Python27\lib\site-packages\sqlalchemy\orm\session.py", line 906, in commit
self.transaction.commit()
File "C:\Python27\lib\site-packages\sqlalchemy\orm\session.py", line 459, in commit
self._assert_active(prepared_ok=True)
File "C:\Python27\lib\site-packages\sqlalchemy\orm\session.py", line 258, in _assert_active
"This session is in 'committed' state; no further "
sqlalchemy.exc.InvalidRequestError: This session is in 'committed' state; no further SQL can be emitted within this transaction.
Here is my example code: Is there a better and more elegant source code on how to work with SQLAlchemy in multiple threads? Becaouse I'm not sure if this is the right way.
from PyQt4.QtCore import QObject, QThread, pyqtSignal, pyqtSlot, QTimer
from PyQt4.QtGui import QApplication, QPushButton, QVBoxLayout, QDialog, \
QComboBox, QLabel
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import create_engine
from sqlalchemy.exc import SQLAlchemyError
from sqlalchemy.orm import sessionmaker, scoped_session
from sqlalchemy import Table, Column, Integer, String, MetaData
from traceback import format_exc
from sys import exc_info
''' setting up root class for declarative declaration '''
Base = declarative_base()
class PERSON_SALUTATION(Base):
__tablename__ = "person_salutation"
id = Column(Integer, primary_key=True)
salutation = Column(String(50), nullable=False, unique=True)
class MasterDataManipulation(object):
def __init__(self, session_object=None):
self._session_scope = session_object
def select_all(self):
try:
with self._session_scope as session:
for record in session.query(PERSON_SALUTATION):
yield record.id, record.salutation
except AttributeError:
print "select all, desired_trace", format_exc(exc_info())
return
class Worker(QObject):
finish_progress = pyqtSignal()
populate_item_signal = pyqtSignal(object, object)
def __init__(self,
combo_box=None,
query_data=None,
parent=None):
QObject.__init__(self, parent)
self.query_data = query_data
self.combo_box=combo_box
''' Create attributes '''
self._run_semaphore = 1
def init_object(self):
self._element = self.query_data()
self.timer = QTimer()
self.timer.setSingleShot(False)
self.timer.setInterval(1)
self.timer.timeout.connect(self.populate_item)
self.timer.start()
def populate_item(self):
try:
if self._run_semaphore == 0:
self._run_semaphore = 1
raise StopIteration
else:
self.populate_item_signal.emit(next(self._element), self.combo_box)
except StopIteration:
print "StopIteration is raised"
self.timer.stop()
def stop(self):
self._run_semaphore == 0
self.timer.stop()
class SessionScope(object):
def __init__(self, dbms=None, dbdriver=None,
dbuser=None, dbuser_pwd=None,
db_server_host=None, dbport=None, db_name=None,
admin_database=None):
self.dbms = dbms
self.dbdriver = dbdriver
self.dbuser = dbuser
self.dbuser_pwd = dbuser_pwd
self.db_server_host = db_server_host
self.dbport = dbport
self.db_name = db_name
self.admin_database = admin_database
url = '{}+{}://{}:{}#{}:{}/{}'.format(
self.dbms, self.dbdriver, self.dbuser, self.dbuser_pwd, self.db_server_host, self.dbport, self.db_name)
self._Engine = create_engine(url, encoding='utf8', echo=True)
self.session = None
self._session_factory = sessionmaker(bind=self._Engine)
self._Session = scoped_session(sessionmaker(bind=self._Engine, expire_on_commit=False))
''' create tables '''
Base.metadata.create_all(self._Engine)
def __enter__(self):
self.session = self._Session()
return self.session
def __exit__(self, exception, exc_value, traceback):
try:
if exception:
self.session.rollback()
else:
self.session.commit()
finally:
self.session.close()
class MyCustomDialog(QDialog):
finish = pyqtSignal()
def __init__(self, scoped_session=None, parent=None):
QDialog.__init__(self, parent)
self._session_scope = scoped_session
self._list_threads = []
self.init_ui()
self.start_all_selection()
def init_ui(self):
layout = QVBoxLayout(self)
self.combo_person_title = QComboBox(self)
self.combo_person_salutation = QComboBox(self)
self.combo_person_gender = QComboBox(self)
self.combo_person_religion = QComboBox(self)
self.combo_person_relationship_status = QComboBox(self)
self.combo_person_nationality = QComboBox(self)
self.combo_person_eye_color = QComboBox(self)
self.combo_person_hair_color = QComboBox(self)
self.pushButton_populate_combo = QPushButton("Re-populate", self)
self.pushButton_stopp = QPushButton("Stopp", self)
self.pushButton_close = QPushButton("Close", self)
layout.addWidget(self.combo_person_title)
layout.addWidget(self.combo_person_salutation)
layout.addWidget(self.combo_person_gender)
layout.addWidget(self.combo_person_religion)
layout.addWidget(self.combo_person_nationality)
layout.addWidget(self.combo_person_relationship_status)
layout.addWidget(self.combo_person_eye_color)
layout.addWidget(self.combo_person_hair_color)
layout.addWidget(self.pushButton_populate_combo)
layout.addWidget(self.pushButton_stopp)
layout.addWidget(self.pushButton_close)
self.pushButton_stopp.clicked.connect(self.on_finish)
self.pushButton_populate_combo.clicked.connect(self.start_all_selection)
self.pushButton_close.clicked.connect(self.close)
def start_all_selection(self):
list_comboxes = self.findChildren(QComboBox)
for combo_box in list_comboxes:
combo_box.clear()
self.start_thread(combo_box=combo_box)
def fill_combo_boxt(self, item, combo_box):
id, text = item
combo_box.addItem(text)
def on_label(self, i):
self.label.setText("Result: {}".format(i))
def start_thread(self, combo_box=None):
master_data_manipulation = MasterDataManipulation(session_object=self._session_scope)
query_data=master_data_manipulation.select_all
task_thread = QThread(self)
task_thread.work = Worker(query_data=query_data,
combo_box=combo_box,)
''' We need to store threads '''
self._list_threads.append(task_thread)
task_thread.work.moveToThread(task_thread)
task_thread.work.populate_item_signal.connect(self.fill_combo_boxt)
self.finish.connect(task_thread.work.stop)
task_thread.started.connect(task_thread.work.init_object)
task_thread.finished.connect(task_thread.deleteLater)
''' This will emit 'started' and start thread's event loop '''
task_thread.start()
#pyqtSlot()
def abort_workers(self):
self.finish.emit()
for thread in self._list_threads:
''' this will quit **as soon as thread event loop unblocks** '''
thread.quit()
''' so you need to wait for it to *actually* quit'''
thread.wait()
def on_finish(self):
self.finish.emit()
def closeEvent(self, event):
''' Re-implementaate to handle with created threads '''
self.abort_workers()
sys.exit()
def populate_database(sess=None):
try:
with sess as session:
salutations = [PERSON_SALUTATION(salutation="Mister"),
PERSON_SALUTATION(salutation="Miss"),
PERSON_SALUTATION(salutation="Lady"),
PERSON_SALUTATION(salutation="Ma'am"),
PERSON_SALUTATION(salutation="Sir"),
PERSON_SALUTATION(salutation="Queen"),
PERSON_SALUTATION(salutation="Grandma"),]
session.add_all(salutations)
session.commit()
except SQLAlchemyError:
print "SQLAlchemyError", format_exc(exc_info())
def main():
dbms = raw_input('Enter database type: ')
dbdriver = raw_input('Enter database driver: ')
dbuser = raw_input('Enter user name: ')
dbuser_pwd = raw_input('Enter user password: ')
db_server_host = raw_input('Enter server host: ')
dbport = raw_input('Enter port: ')
db_name = raw_input('Enter database name: ')
try:
''' create_engine and scoped_session once per process (per database). '''
session_scope = SessionScope(dbms = dbms,
dbdriver = dbdriver,
dbuser = dbuser,
dbuser_pwd = dbuser_pwd,
db_server_host = db_server_host,
dbport = dbport,
db_name = db_name)
answer = raw_input('Do you want to populate database? Type yes or no: ')
if answer.lower() == 'yes':
populate_database(sess=session_scope)
app = QApplication(sys.argv)
window = MyCustomDialog(scoped_session = session_scope)
window.show()
sys.exit(app.exec_())
except TypeError:
print "ERROR", format_exc(exc_info())
if __name__ == "__main__":
main()

Resources