'''odoo'''
this is the odoo http.py file where i try to modify the code for session logout
def session_gc(session_store):
if random.random() < 0.001: ###!!! 0.001:
# we keep session one week
last_week = time.time() - 601 ###!!! 6060247
for fname in os.listdir(session_store.path):
path = os.path.join(session_store.path, fname)
try:
if os.path.getmtime(path) < last_week:
os.unlink(path)
except OSError:
pass
Create a py file eg session.py and add the following code:
import psycopg2
import os
import json
import random
import werkzeug.contrib.sessions
import time
import odoo
from odoo import http
from odoo.tools.func import lazy_property
def with_cursor(func):
def wrapper(self, *args, **kwargs):
tries = 0
while True:
tries += 1
try:
return func(self, *args, **kwargs)
except psycopg2.InterfaceError as e:
if tries>4:
raise e
self._open_connection()
return wrapper
class PGSessionStore(werkzeug.contrib.sessions.SessionStore):
# FIXME This class is NOT thread-safe. Only use in worker mode
def __init__(self, uri, session_class=None):
super(PGSessionStore, self).__init__(session_class)
self._uri = uri
self._open_connection()
self._setup_db()
def __del__(self):
self._cr.close()
def _open_connection(self):
cnx = odoo.sql_db.db_connect(self._uri, allow_uri=True)
self._cr = cnx.cursor()
self._cr.autocommit(True)
#with_cursor
def _setup_db(self):
self._cr.execute("""
CREATE TABLE IF NOT EXISTS http_sessions (
sid varchar PRIMARY KEY,
write_date timestamp without time zone NOT NULL,
payload text NOT NULL
)
""")
#with_cursor
def save(self, session):
payload = json.dumps(dict(session))
self._cr.execute("""
INSERT INTO http_sessions(sid, write_date, payload)
VALUES (%(sid)s, now() at time zone 'UTC', %(payload)s)
ON CONFLICT (sid)
DO UPDATE SET payload = %(payload)s,
write_date = now() at time zone 'UTC'
""", dict(sid=session.sid, payload=payload))
#with_cursor
def delete(self, session):
self._cr.execute("DELETE FROM http_sessions WHERE sid=%s", [session.sid])
#with_cursor
def get(self, sid):
self._cr.execute("UPDATE http_sessions SET write_date = now() at time zone 'UTC' WHERE sid=%s", [sid])
self._cr.execute("SELECT payload FROM http_sessions WHERE sid=%s", [sid])
try:
data = json.loads(self._cr.fetchone()[0])
except Exception:
return self.new()
return self.session_class(data, sid, False)
#with_cursor
def gc(self):
self._cr.execute(
"DELETE FROM http_sessions WHERE now() at time zone 'UTC' - write_date > '2 hours'"
)
def session_gc(session_store):
"""
Global cleaning of sessions using either the standard way (delete session files),
Or the DB way.
"""
if random.random() < 0.001:
# we keep session two hours
if hasattr(session_store, 'gc'):
session_store.gc()
return
two_hours = time.time() - 60*60*2
for fname in os.listdir(session_store.path):
path = os.path.join(session_store.path, fname)
try:
if os.path.getmtime(path) < two_hours:
os.unlink(path)
except OSError:
pass
class Root(http.Root):
#lazy_property
def session_store(self):
"""
Store sessions in DB rather than on FS if parameter permit so
"""
# Setup http sessions
session_db = odoo.tools.config.get('session_db')
if session_db:
return PGSessionStore(session_db, session_class=http.OpenERPSession)
path = odoo.tools.config.session_dir
return werkzeug.contrib.sessions.FilesystemSessionStore(path, session_class=http.OpenERPSession)
http.session_gc = session_gc
http.root = Root()
The following code will inherit from the http file in odoo module. The configured time for timeout is 2 hours and can be changed within the session_gc function.
Related
I am trying to get when a user pings another user! Get the users mention and add a point into the database! Although User is not defined! And cant register any points for the user getting pinged!
import sqlite3
from discord.ext import commands
client = commands.Bot(command_prefix = "ping")
POINTS = 0
#client.event
async def on_ready():
db = sqlite3.connect("ping.sqlite")
cursor = db.cursor()
cursor.execute('''
CREATE TABLE IF NOT EXISTS main(
user_id TEXT,
points INTERGER
)
''')
print("Looking for Pings!")
#client.event
async def on_message(message):
USER = user.mention.id
db = sqlite3.connect("ping.sqlite")
cursor = db.cursor()
cursor.execute(f"SELECT user_id FROM main WHERE user_id = {USER}")
result = cursor.fetchone()
if result is None:
sql = ("INSERT INTO main(user_id, points) VALUES(?,?)")
val = (USER, POINTS)
elif result is not None:
sql = ("UPDATE main SET channel_id = ? WHERE guild_id = ?")
val = (ctx.guild.id, channel.id)
cursor.execute(sql, val)
db.commit()
cursor.close()
db.close()
client.run(TOKEN)
if len(message.mentions) > 0:
all_pinged_users = [user for user in message.mentions]
#it will give all pinged user object in all_pinged_users and you can do anything with that!
else:
#no user is pinged
you can use this simple if statement to find if any user is pinged in the message! and the message.mentions is in the type of list of all pinged users in that specific message
you can also iterate through the message.mentions to get all pinged user
I'm trying to build a Giphy cog for my discord.py bot and it's throwing the following error
Unclosed client session
client_session: <aiohttp.client.ClientSession object at 0x000001CA509CDA60>
Unclosed connector
connections: ['[(<aiohttp.client_proto.ResponseHandler object at 0x000001CA51897BE0>, 77055.671)]']
connector: <aiohttp.connector.TCPConnector object at 0x000001CA509CDA30>
Does anyone know what is causing this and how I would fix it?
Here is my code:
import os
import aiohttp
import random
import discord
from discord.ext import commands
from dotenv import load_dotenv
load_dotenv()
prefix = os.getenv("CLIENT_PREFIX")
giphy_api = os.getenv("GIPHY_API_KEY")
command_attrs = {'hidden': False}
class FunCog(commands.Cog, name='Fun Commands', command_attrs=command_attrs):
def __init__(self, client):
self.client = client
#commands.command(name='gif')
async def _gif(self, ctx, *, search, json=None):
embed = discord.Embed(colour=discord.Colour.blue())
session = aiohttp.ClientSession()
if search == '':
response = await session.get('https://api.giphy.com/v1/gifs/random?api_key=' + giphy_api)
data = json.loads(await response.text())
embed.set_image(url=data['data']['images']['original']['url'])
else:
search.replace(' ', '+')
response = await session.get(
'http://api.giphy.com/v1/gifs/search?q=' + search + '&api_key=' + giphy_api + '&limit=10')
data = json.loads(await response.text())
gif_choice = random.randint(0, 9)
embed.set_image(url=data['data'][gif_choice]['images']['original']['url'])
await session.close()
await ctx.send(embed=embed)
def setup(client):
client.add_cog(FunCog(client))
I omitted my Giphy API Key for security reasons.
I'm using discord.py rewrite and python 3.8.6if it helps.
Basically I want to be able to search a gif with it by tag and it will respond with a random gif from giphy for the specified tag.
--EDIT--
Moved the error logging to my Events.py file
Moved the API Keys to my .env file
Removed the tenor_api env since it won't be getting used and has nothing to do with this question
Updated the code a bit to resolve a few missing parameters.
---EDIT---
Thanks to Fixator10 for the response that fixed the issue I was having in this post.
Here is my working code if anyone wants to use it:
import os
import aiohttp
import random
import discord
import json
from discord.ext import commands
from dotenv import load_dotenv
load_dotenv()
prefix = os.getenv("CLIENT_PREFIX")
giphy_api = os.getenv("GIPHY_API_KEY")
command_attrs = {'hidden': False}
class FunCog(commands.Cog, name='Fun Commands', command_attrs=command_attrs):
def __init__(self, client):
self.client = client
self.session = aiohttp.ClientSession()
def cog_unload(self):
self.client.loop.create_task(self.session.close())
#commands.command(name='gif')
async def _gif(self, ctx, *, search):
session = self.session
embed = discord.Embed(colour=discord.Color.dark_gold())
if search == '':
response = await session.get('https://api.giphy.com/v1/gifs/random?api_key=' + giphy_api)
data = json.loads(await response.text())
embed.set_image(url=data['data']['images']['original']['url'])
else:
search.replace(' ', '+')
response = await session.get(
'http://api.giphy.com/v1/gifs/search?q=' + search + '&api_key=' + giphy_api + '&limit=10')
data = json.loads(await response.text())
gif_choice = random.randint(0, 9)
embed.set_image(url=data['data'][gif_choice]['images']['original']['url'])
await ctx.send(embed=embed)
def setup(client):
client.add_cog(FunCog(client))
It's probably not the best since it only uses a single tag but I'll probably improve that at another time xD
This is caused by your session behavior. You dont close session if search is empty. In two words: you should close session after usage.
The most simple solution - is to use context manager:
# https://docs.aiohttp.org/en/stable/#client-example
async with aiohttp.ClientSession() as session:
async with session.get('http://python.org') as response:
Otherwise, you can create a session for your Cog and close it on unload:
class MyCog(commands.Cog):
def __init__(client):
self.client = client
self.session = aiohttp.ClientSession()
# https://discordpy.readthedocs.io/en/stable/ext/commands/api.html#discord.ext.commands.Cog.cog_unload
def cog_unload(self):
# since close is coroutine,
# and we need to call it in sync func
# lets create asyncio task
self.client.loop.create_task(self.session.close())
# or, we can use detach:
# self.session.detach()
#commands.command()
async def mycmd(ctx):
async with self.session.get("https://example.com") as response:
await ctx.send(response.status)
I am deplying a python program on Heroku. Everything works fine locally, but it doesn't seem to run on Heroku
The bot.py file contains two variables which are saved as config in Heroku: TOKEN and SPREADSHEET, these are the Token of the telegram bot and the ID of the google Spreadsheet I am trying to access.
When the code is running on Heroku, I get this:
The code seems to be running on the Heroku server, but when I try to send the command on the Telegram bot, it doesn't work
at=info method=POST path="/" host=fff-transparency-wg.herokuapp.com request_id=d883bfc2-24a3-4cb5-b638-36b310726780 fwd="91.108.6.81" dyno=web.1 connect=1ms service=5ms status=200 bytes=172 protocol=https
The program contains the files:
bot.py
client_secret.json
Procfile
requirements.txt
runtime.txt
BOT.PY
from telegram.ext import Updater, CommandHandler, CallbackQueryHandler
from telegram import InlineKeyboardButton, InlineKeyboardMarkup
import logging
import os
import json
import gspread
from oauth2client.service_account import ServiceAccountCredentials
from datetime import datetime
from itertools import permutations
import re
logging.basicConfig(
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO)
logger = logging.getLogger("telegram.bot")
def start(update, context):
context.bot.send_message(
chat_id=update.effective_chat.id, text="I'm a bot, please talk to me!")
# def help(update, context):
def call(update, context):
"""
Save Message ID, Title, Date, Time, Duration, Description, Link, Group ID, Group name, Saved by Name, Username
Expected inputs (in order): Date, Time, Duration, Title, Description, Link
Send variables to Google Sheet
Send variables to Trello Board
Send variables to Google Calendar
OPTIONAL:
Notification System
"""
message_id = update.message.message_id
user = update.message.from_user
username = user['username']
full_name = "{} {}".format(user['first_name'], user['last_name'])
groupchat = update.message.chat
message_text = update.message.text
text = format_string(message_text, "/call")
if (text == -1):
groupchat.send_message(
text="Please make sure all arguments are inserted in the correct order and separated by semicolomns:\n\n- Date (dd/mm/yy) \n- Time (GMT) \n- Duration (hour:min) \n- Title \n- Description(optional) \n- Agenda Link(optional)")
call_date = text[0]
call_time = text[1]
call_duration = text[2]
call_title = text[3]
#if text[4]: call_description = text[4]
#if text[5]: call_agenda = text[5]
calls.append_row(
[message_id, call_title, call_date, call_time, call_duration])
# def group(update, context):
def str2date(string):
"Parse a string into a datetime object."
for fmt in dateformats():
try:
return datetime.strptime(string, fmt)
except ValueError:
pass
raise ValueError("'%s' is not a recognized date/time" % string)
def format_string(message, command):
message = re.sub(command, '', message)
message.strip()
message = message.split(';')
if not(len(message) >= 4):
return -1
if command == "/call":
message[0: 1] = [' '.join(message[0: 1])]
s = message[0].strip()
try:
message[0] = str2date(s)
except ValueError:
print("invalid date/time")
return message
def dateformats():
"Yield all combinations of valid date formats."
years = ("%Y",)
months = ("%b", "%B")
days = ("%d",)
times = ("%I%p", "%I:%M%p", "%H:%M", "")
for year in years:
for month in months:
for day in days:
for args in ((day, month), (month, day)):
date = " ".join(args)
for time in times:
for combo in permutations([year, date, time]):
yield " ".join(combo).strip()
def error(update, context):
logger.warning('Update "%s" caused error "%s"', update, context.error)
def main():
TOKEN = os.environ['TOKEN']
updater = Updater(token=TOKEN, use_context=True)
dp = updater.dispatcher
PORT = int(os.environ.get('PORT', '8443'))
updater.start_webhook(listen="0.0.0.0", port=PORT, url_path=TOKEN)
updater.bot.set_webhook("https://fff-transparency-wg.herokuapp.com/" + TOKEN)
updater.idle()
# use creds to create a client to interact with the Google Drive API
scope = ['https://spreadsheets.google.com/feeds', 'https://www.googleapis.com/auth/drive', 'https://www.googleapis.com/auth/drive.file', 'https://www.googleapis.com/auth/drive']
creds = ServiceAccountCredentials.from_json_keyfile_name(
'client_secret.json', scope)
client = gspread.authorize(creds)
# Find a workbook by name and open the first sheet
SPREADSHEET = os.environ['SPREADSHEET']
spreadsheet = client.open_by_key(
SPREADSHEET)
groupchats = spreadsheet.get_worksheet(0)
calls = spreadsheet.get_worksheet(1)
# Commands
dp.add_handler(CommandHandler("start", start))
#dp.add_handler(CommandHandler("help", help))
dp.add_handler(CommandHandler("call", call))
#dp.add_handler(CommandHandler("group", group))
dp.add_error_handler(error)
if __name__ == '__main__':
main()
PROCFILE
web: python3 bot.py
worker: python3 bot.py
REQUIREMENTS.TXT
certifi==2019.11.28
cffi==1.14.0
chardet==3.0.4
cryptography==2.9
decorator==4.4.2
future==0.18.2
gspread==3.3.1
httplib2==0.17.1
idna==2.9
oauth2client==4.1.3
pyasn1==0.4.8
pyasn1-modules==0.2.8
pycparser==2.20
python-telegram-bot==12.5.1
requests==2.23.0
rsa==4.0
six==1.14.0
tornado==6.0.4
urllib3==1.25.8
RUNTIME.TXT
python-3.8.2
I had the same issue with my telegram bot.
I added the actual bot token string to the TOKEN variable and uploaded it to Heroku.
Then I used os.environ.get('TOKEN') command for the version that I pushed on GitHub.
I am still just a beginner in python, I don't know if this posses security issues but it removed the error code and allowed my bot to work
I'm using Django and Python 3.7 and tryihng to tests an AJAX request from a view, located at web/views/tax_calculator.py
# Basic function that serves the default page
def get(request):
return render(request, "web/template/tax_calculator.html", {})
# This is an Ajax call that will calculate the overall taxes you pay for
# an S-Corp vs a sole proprietorship
def post(request):
state = request.GET.get('state', None)
gross_income = request.GET.get('gross', None)
owner_salary = request.GET.get('salary', None)
data = {
'sole_pr_taxes': TaxCalculatorService.calc_sole_pr_taxes(state, gross_income),
's_corp_taxes': TaxCalculatorService.calc_s_corp_taxes(state, gross_income, owner_salary),
}
return JsonResponse(data)
Here is my test file, located at web/tests/test_views.py
from django.test.client import Client
import json
from web.models import *
c = Client()
class ViewTests(TestCase):
# Basic test to verify we can get valid return data
def test_calculate_tax(self):
state = 'MN'
gross = 100000
salary = 75000
json_data = json.dumps({'state': state,
'gross': gross,
'salary': salary})
response = c.post('/content/vote/', json_data,
content_type='application/json',
HTTP_X_REQUESTED_WITH='XMLHttpRequest')
self.assertEqual(response.status_code, 302) # this is OK.
print(response.content)
self.assertEqual(response.content, 2)
This results in the error below. What else do I need to do to make my test understand my Ajax request?
======================================================================
ERROR: test_calculate_tax (web.tests.test_views.ViewTests)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/davea/Documents/workspace/myproject/web/tests/test_views.py", line 20, in test_calculate_tax
response = c.post('/content/vote/', json_data,
AttributeError: 'Client' object has no attribute 'post'
----------------------------------------------------------------------
Ran 2 tests in 0.010s
I'm trying to make a function that runs a ttk progressbar until a file is created. It seems that Widget.after is causing the APPCRASH but I don't know why. Please help!
def FilePgBar(title, file):
if root:
root.withdraw()
boxRoot = Toplevel(master=root)
boxRoot.withdraw()
else:
boxRoot = Tk()
boxRoot.withdraw()
boxRoot.protocol('WM_DELETE_WINDOW', denyWindowManagerClose )
boxRoot.title(title)
boxRoot.iconname('Dialog')
boxRoot.geometry(rootWindowPosition)
boxRoot.minsize(400, 100)
pgBar = ttk.Progressbar(boxRoot, orient=HORIZONTAL, length=300, mode='indeterminate')
pgBar.grid(row=1, column=0)
pgBar.pack()
pgBar.start()
def checkfile():
if os.path.exists(file):
pgBar.stop()
pgBar.destroy()
boxRoot.deiconify()
boxRoot.mainloop()
boxRoot.destroy()
if root: root.deiconify()
else:
boxRoot.after(100, checkfile)
checkfile()
I want to call this function from others scripts, so I'm not sure about using a class
EDIT: I edited the code. I no longer get an APPCRASH, but nothing happens when I run the program.
Python evaluates the arguments before passing them to a function. So when it encounters
boxRoot.after(100, checkfile(file))
it evaluates checkfile(file) -- calling checkfile -- and replaces checkfile(file) with the value returned by the function before calling boxRoot.after.
Since checkfile(file) has no return statement, None is returned by default. Thus
boxRoot.after(100, None)
gets called. This raises an error since the second argument to boxRoot.after should be a callable.
Instead, pass the function object checkfile itself:
def checkfile():
if os.path.exists(file):
pgBar.stop()
pgBar.destroy()
boxRoot.destroy()
if root: root.deiconify()
else:
# You need to update the progress bar
boxRoot.after(100, checkfile)
This allows the boxRoot.after function to call the function from within boxRoot.after instead of before after is called.
You might do something like this:
import os
import Tkinter as tk
import ttk
class App(object):
def __init__(self, master, *args, **kwargs):
self.master = master
self.button = tk.Button(master, text='Stop', command=self.stop)
self.button.pack()
self.progress = ttk.Progressbar(master, orient="horizontal",
length=200, mode="determinate")
self.progress.pack()
self.progress["value"] = 0
self.progress["maximum"] = 100
self.filename = '/tmp/out'
if os.path.exists(self.filename):
os.unlink(self.filename)
self.checkfile()
def checkfile(self):
self.progress["value"] += 1
if (not os.path.exists(self.filename)
and self.progress["value"] < self.progress["maximum"]):
self.master.after(100, self.checkfile)
def stop(self):
with open(self.filename, 'w') as f: pass
root = tk.Tk()
app = App(root)
root.mainloop()