How to use AsyncElasticsearch Connection Pool in FastApi? - elasticsearch

The relevant parts of my code are as follows:
#app.on_event("startup")
async def startup():
es = Translator()
app.state.es_conn = es.connect()
#app.on_event('shutdown')
async def shutdown_event():
es = Translator()
await es.close(app.state.es_conn)
#app.post('/query')
async def query(req: Request):
es = Translator()
es.set_conn(req.app.state.es_conn)
return await es.search()
from elasticsearch import AsyncElasticsearch, AsyncTransport
class Translator(object):
def __init__(self):
self.__es = None
def connect(self):
return AsyncElasticsearch(
hosts='http://192.168.0.2:9200/',
transport_class=AsyncTransport)
def set_conn(self, conn):
self.__es = conn
async def close(self, conn):
await conn.close()
self.__es = None
async def search(self):
return await self.__es.search(index=index, body=body)
It runs in the following environment:
PyPy 7.3.7
fastapi 0.73.0
Elasticsearch 7.10.1
My question are:
Although the code can work normally, how can I detect whether it uses connection pool?
How to use connection pool correctly when asynchronous?
Can anyone help me? Thank you!

Related

How to test fastapi with oracle, sql alchemy?

I have a fastapi application where I use sqlalchemy and stored procedures.
Now I want to test my endpoints like in the documentation
import pytest
from fastapi.testclient import TestClient
from fastapi import FastAPI
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from ..dependencies import get_db
import cx_Oracle
host = 'xxxx'
port = 1111
sid = 'FUU'
user = 'bar'
password = 'fuubar'
sid = cx_Oracle.makedsn(host, port, sid=sid)
database_url = 'oracle://{user}:{password}#{sid}'.format(
user=user,
password=password,
sid=sid,
)
engine = create_engine(database_url, connect_args={"check_same_thread": False})
TestingSessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
app = FastAPI()
init_router(app)
#pytest.fixture()
def session():
db = TestingSessionLocal()
try:
yield db
finally:
db.close()
#pytest.fixture()
def client(session):
# Dependency override
def override_get_db():
try:
yield session
finally:
session.close()
app.dependency_overrides[get_db] = override_get_db
yield TestClient(app)
def test_index(client):
res = client.get("/")
assert res.text
assert res.status_code == 200
def test_search_course_by_verid_exist():
response = client.get(
'search', params={"search_query": "1111", "semester": "S2022"})
# course exist
assert response.status_code == 200
I've tried it with creating a new app and/or importing it via getting the app from the main.py
from ..main import app
The method is in my courses router.
#router.get("/search", status_code=status.HTTP_200_OK)
async def search_course(
response: Response,
search_query: Union[str, None] = None,
semester: Union[int, None] = None,
db: Session = Depends(get_db),
):
.....
return response
The index test already failes by returning assert 400 == 200. For the 2nd (test_search_course_by_verid_exist) I'll get
AttributeError: 'function' object has no attribute 'get'
My main has some middleware settings like
app.add_middleware(
SessionMiddleware, secret_key="fastAPI"
) # , max_age=300 this should match Login action timeout in token-settings of a realm
app.add_middleware(
TrustedHostMiddleware,
allowed_hosts=settings.ALLOWED_HOSTS,
)
# MIDDLEWARE
#app.middleware("http")
async def check_route(request: Request, call_next):
....
I'm clueless what I'm missing or if things are just different with cx_Oracle
I've tried changing the testclient from fastapi to the starlette one. I've tried not overriding the db and just import the original db settings (which are basically the same). But nothing works.
I'm not sure if this is the proper way to test FastAPI application, https://fastapi.tiangolo.com/tutorial/testing/
Why you didn't declare client as :
client = TestClient(app)
?
Idk if this was the root problem. But naming my fixtures solved the problem and the db connection is working.
conftest.py
#pytest.fixture(name="db_session", scope="session")
def db_session(app: FastAPI) -> Generator[TestingSessionLocal, Any, None]:
Also created the app fixture
#pytest.fixture(name="app", scope="session")
def app() -> Generator[FastAPI, Any, None]:
"""
Create a fresh database on each test case.
"""
_app = start_application()
yield _app

How to fix "ERROR - No error handlers are registered, logging exception." with telegram.ext.dispatcher?

I downloaded bot which copy messages from telegram group and sending to my discord channel.
But when I am trying to send a message in a group, I am getting this error.
2022-12-31 08:25:19,877 - telegram.ext.dispatcher - ERROR - No error handlers are registered, logging exception.
Traceback (most recent call last):
File "C:\Python310\lib\site-packages\telegram\ext\dispatcher.py", line 557, in process_update
handler.handle_update(update, self, check, context)
File "C:\Python310\lib\site-packages\telegram\ext\handler.py", line 199, in handle_update
return self.callback(update, context)
File "C:\Discord-Telegram-Bot-main 1\main.py", line 46, in getTgAnnouncement
textUpdate = update.channel_post.text
AttributeError: 'NoneType' object has no attribute 'text'
I am using python 3.10
Python-telegram-bot 13.15
Below i will add the code
import requests
import json
import asyncio
import os
import json
import logging
from dotenv import load_dotenv
import discord
from discord.ext import commands
from telegram import Update
from telegram.ext import Updater,CallbackContext,MessageHandler,Filters
from telegram.utils import helpers
from telegram.ext.dispatcher import run_async
load_dotenv('token.env')
discordToken = os.getenv('DCTOKEN')# discord bot token
telegramToken = os.getenv('TGTOKEN')# telegram bot token
discordChannelId = os.getenv('DCCID')# discord announcement channel id
loop = asyncio.get_event_loop()
#--------------------------------------------------------------------------------------------------------------
bot = commands.Bot(
command_prefix="k!",
case_insensitive=True,
intents=discord.Intents.all(),
help_command=None
)
async def sendDcAnnouncement(textUpdate,nonTextUpdate):
announcementChannel = bot.get_channel(int(discordChannelId))
if textUpdate != None and nonTextUpdate != None:
await announcementChannel.send(textUpdate,file=discord.File(nonTextUpdate))
os.remove(nonTextUpdate)
elif textUpdate == None:
await announcementChannel.send(file=discord.File(nonTextUpdate))
os.remove(nonTextUpdate)
elif nonTextUpdate == None:
await announcementChannel.send(textUpdate)
def getTgAnnouncement(update: Update, context: CallbackContext):
textUpdate = None
nonTextUpdate = None
updateType = helpers.effective_message_type(update)
if updateType == 'text':
textUpdate = update.channel_post.text
else:
textUpdate = update.channel_post.caption
if updateType == 'photo':
nonTextUpdate = update.channel_post.photo[-1].get_file()['file_path']
elif updateType == 'video':
nonTextUpdate = update.channel_post.video.get_file()['file_path']
elif updateType == 'document':
nonTextUpdate = update.channel_post.document.get_file()['file_path']
elif updateType == 'voice':
nonTextUpdate = update.channel_post.voice.get_file()['file_path']
loop.create_task(sendDcAnnouncement(textUpdate,nonTextUpdate))
#bot.event
async def on_ready():
print(f'logged in as {bot.user}')
updater = Updater(token=telegramToken,use_context=True)
dispatcher = updater.dispatcher
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
level=logging.INFO)
getTgAnnouncement_handler = MessageHandler((~Filters.command),getTgAnnouncement)
dispatcher.add_handler(getTgAnnouncement_handler)
updater.start_polling()
bot.run(discordToken)
#--------------------------------------------------------------------------------------------------------------
I expect that this bot will send messages and that I will not get these errors.
MessageHandler handles all updates that have one of the fields message, edited_message, channel_post or edited_channel_post. So in getTGAnnouncement, it may very well be the case that update.channel_post is None.
If you want that handler to only handle channel_post update, please use Filters.update.channel_post.
As a side note: I see that you're using python-telegram-bot v13.x. Support for that version is ending soon in favor of the new v20.x.
Disclaimer: I'm currently the maintainer of python-telegram-bot.

How to create user of elastic using flask

I want to create a user | role | privilege of elastic using API in flask
Documentation for creating user provided an example
it's working fine in elastic Dev Tools
but how can I convert it into a python POST request?
My Code
from flask import Flask, request, jsonify, render_template
from elasticsearch import Elasticsearch
CLOUD_ID = "myfirstdeployment:XXX"
ELASTIC_PASS = 'XXX'
ELASTIC_USER = 'XXX'
client = Elasticsearch(cloud_id=CLOUD_ID, basic_auth=(ELASTIC_USER, ELASTIC_PASS))
app = Flask(__name__)
import requests
from requests.structures import CaseInsensitiveDict
#app.route('/get')
def getting():
data = client.search(index="kibana_sample_data_ecommerce", body={"query" :{"match_all":{}}})
return f'{[x["_source"]["category"] for x in data["hits"]["hits"]]}'
es = Elasticsearch(hosts="https://localhost:9200", basic_auth=('elastic', 'zoU_Ec8JjbPnQNG4b8kY'), verify_certs=False)
#app.route('/local')
def local():
return f'{es.info()}'
#app.route('/users')
def getAllUser():
uri = 'https://localhost:9200/_security/user/'
es = Elasticsearch(hosts=uri, basic_auth=('elastic', 'zoU_Ec8JjbPnQNG4b8kY'), ca_certs="872ee6c0879fc0cfe73054c3ba7afb5902dbb171a2c215af35a5faab1206b924", verify_certs=False)
return f'{es.info()}'
#app.route('/users/<name>')
def getSingleUser(name):
try:
uri = f'https://localhost:9200/_security/user/{name}'
es = Elasticsearch(hosts=uri, basic_auth=('elastic', 'zoU_Ec8JjbPnQNG4b8kY'), ca_certs="872ee6c0879fc0cfe73054c3ba7afb5902dbb171a2c215af35a5faab1206b924", verify_certs=False)
return f'{es.info()}'
except:
content = {'error':'User Not Found'}
return content, 404
#app.route('/create-new-user', methods=['GET','POST'])
def createUser():
if request.method == 'POST':
username = request.form.get('username')
password = request.form.get('password')
email = request.form.get('email')
fullname = request.form.get('fullname')
role = request.form.getlist('role')
body ={"password":password, "username":username, "email":email, "fullname":fullname, "role":role}
try:
uri = f'https://localhost:9200/_security/user/{username}'
es = Elasticsearch(hosts=uri, basic_auth=('elastic', 'zoU_Ec8JjbPnQNG4b8kY'), ca_certs="872ee6c0879fc0cfe73054c3ba7afb5902dbb171a2c215af35a5faab1206b924", verify_certs=False)
return f'{es.info()}'
except:
content = {'error':'something went wrong'}
return content, 501
return render_template('add_user.html')
if __name__ == "__main__":
app.run(debug=True)
when I create a user from Stack Management > Security > User > Create
POST request send to security/user/new_user_username
post data = {password=password, username=username, email=email, role=[], fullname=fullname
first Thanks to Paulo
Using put_user() method we can easily create user
username, password & email fields are mandatory when creating a user using API
#app.route('/create-new-user', methods=['GET','POST'])
def createUser():
if request.method == 'POST':
username = request.form.get('username')
password = request.form.get('password')
email = request.form.get('email')
fullname = request.form.get('fullname')
roles = request.form.getlist('role')
body ={"password":password, "username":username, "email":email, "fullname":fullname, "roles":roles}
try:
client = Elasticsearch(hosts=https://localhost:9200/, basic_auth=(ELASTIC_USERNAME, ELASTIC_PASSWORD), ca_certs=CERTIFICATE, verify_certs=False)
es = SecurityClient(client)
es.put_user(**body)
return {'message':'User created'}, 201
except:
return {'message':'something went wrong'}, 501
return render_template('add_user.html')
Remember to pass keyword args of roles in put_user
Edited if someone experimenting can also try perform_request
Edited 2 Simple and better solution
body ={"password":password, "username":username, "email":email, "full_name":fullname, 'enabled':True, 'roles':role}
uri = f'https://localhost:9200/'
client = Elasticsearch(hosts=uri, basic_auth=(ELASTIC_USER, ELASTIC_PASS), ca_certs=CERTIFICATE, verify_certs=False)
client.perform_request(body=body, method='POST', path=f'/_security/user/{username}', headers={'content-type':'application/json', 'accept':'application/json'})

Delete outgoing message sent by telegram bot (Telegram, python)

i am stuck in my code as i do not know how to input/derive the message_id of the outgoing message forwarded by my bot.
Background: This is just a part of my code which i would subsequently integrate into the main code. Here, i am testing the functionality of forwarding messages + deleting them. I am able to successfully forward them out but i am stuck at deleting them. i am able to give the input of the chat_id but not able to do so for the message_id to delete. Is there a way to do it especially when i am gonna integrate to my main script which can have a few groups to manage. Please assist the noob in me. Thank you!
My script:
import logging
from telegram import ReplyKeyboardMarkup, ReplyKeyboardRemove, Update
from telegram.ext import (
Updater,
CommandHandler,
MessageHandler,
Filters,
ConversationHandler,
CallbackContext,
)
TOKEN = "PUT TOKEN HERE" #INPUT HERE
# Enable logging
logging.basicConfig(
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO)
logger = logging.getLogger(__name__)
MSG, DELETE_MSG = range(2)
def start(update: Update, context: CallbackContext) -> int:
update.message.reply_text(
'Hi! Please post the message you would like to share:')
return MSG
def send(update: Update, context: CallbackContext) -> int:
user = update.message.from_user
logger.info("Message of %s: %s", user.first_name, update.message.text)
print(update.message.message_id)
send = update.message.forward(chat_id= 'PUT CHAT ID OF OUTGOING GROUP HERE') #INPUT HERE
update.message.reply_text("Please delete")
return DELETE_MSG
def delete_msg(update: Update, context: CallbackContext) -> int:
user = update.message.from_user
logger.info("edit of %s: %s", user.first_name, update.message.text)
update.message.delete(chat_id='PUT CHAT ID OF OUTGOING GROUP HERE',
message_id='IM STUCK HERE') #INPUT HERE
return ConversationHandler.END
def cancel(update: Update, context: CallbackContext) -> int:
user = update.message.from_user
logger.info("User %s canceled the conversation.", user.first_name)
update.message.reply_text('Bye! I hope we can talk again some day.', reply_markup=ReplyKeyboardRemove())
return ConversationHandler.END
def main() -> None:
updater = Updater(TOKEN, use_context=True)
dispatcher = updater.dispatcher
conv_handler = ConversationHandler(
entry_points=[CommandHandler('start', start)],
states={
MSG: [MessageHandler(~Filters.command, send)],
DELETE_MSG: [MessageHandler(~Filters.command, delete_msg)]
},
fallbacks=[CommandHandler('cancel', cancel)],
)
dispatcher.add_handler(conv_handler)
updater.start_polling()
updater.idle()
if __name__ == '__main__':
main()
update.message.reply_text("Please delete") must be a variable and, then, you'll be able to context.bot.deleteMessage the message_id of that. Just like this:
must_delete = update.message.reply_text("Please delete")
context.bot.deleteMessage (message_id = must_delete.message_id,
chat_id = update.message.chat_id)
Give it a try and let me know if this worked for you!!

How to forward a websocket server in localhost with ngrok

I' trying to run a websocket server on local host and forward it to web using ngrok. But couldn't figure it how. These are the original code's from AutobahnPython git repository https://github.com/tavendo/AutobahnPython.
Server code:
from autobahn.twisted.websocket import WebSocketServerProtocol, \
WebSocketServerFactory
class MyServerProtocol(WebSocketServerProtocol):
def onConnect(self, request):
print("Client connecting: {0}".format(request.peer))
def onOpen(self):
print("WebSocket connection open.")
def onMessage(self, payload, isBinary):
if isBinary:
print("Binary message received: {0} bytes".format(len(payload)))
else:
print("Text message received: {0}".format(payload.decode('utf8')))
## echo back message verbatim
self.sendMessage(payload, isBinary)
def onClose(self, wasClean, code, reason):
print("WebSocket connection closed: {0}".format(reason))
if __name__ == '__main__':
import sys
from twisted.python import log
from twisted.internet import reactor
log.startLogging(sys.stdout)
factory = WebSocketServerFactory("ws://localhost:9000", debug = False)
factory.protocol = MyServerProtocol
reactor.listenTCP(9000, factory)
reactor.run()
Client Code:
from autobahn.twisted.websocket import WebSocketClientProtocol, \
WebSocketClientFactory
class MyClientProtocol(WebSocketClientProtocol):
def onConnect(self, response):
print("Server connected: {0}".format(response.peer))
def onOpen(self):
print("WebSocket connection open.")
def hello():
self.sendMessage(u"Hello, world!".encode('utf8'))
self.sendMessage(b"\x00\x01\x03\x04", isBinary = True)
self.factory.reactor.callLater(1, hello)
## start sending messages every second ..
hello()
def onMessage(self, payload, isBinary):
if isBinary:
print("Binary message received: {0} bytes".format(len(payload)))
else:
print("Text message received: {0}".format(payload.decode('utf8')))
def onClose(self, wasClean, code, reason):
print("WebSocket connection closed: {0}".format(reason))
if __name__ == '__main__':
import sys
from twisted.python import log
from twisted.internet import reactor
log.startLogging(sys.stdout)
factory = WebSocketClientFactory("ws://localhost:9000", debug = False)
factory.protocol = MyClientProtocol
reactor.connectTCP("127.0.0.1", 9000, factory)
reactor.run()
This is the changed code:
from autobahn.twisted.websocket import WebSocketClientProtocol, \
WebSocketClientFactory
class MyClientProtocol(WebSocketClientProtocol):
def onConnect(self, response):
print("Server connected: {0}".format(response.peer))
def onOpen(self):
print("WebSocket connection open.")
def hello():
self.sendMessage(u"Hello, world!".encode('utf8'))
self.sendMessage(b"\x00\x01\x03\x04", isBinary = True)
self.factory.reactor.callLater(1, hello)
## start sending messages every second ..
hello()
def onMessage(self, payload, isBinary):
if isBinary:
print("Binary message received: {0} bytes".format(len(payload)))
else:
print("Text message received: {0}".format(payload.decode('utf8')))
def onClose(self, wasClean, code, reason):
print("WebSocket connection closed: {0}".format(reason))
if __name__ == '__main__':
import sys
from twisted.python import log
from twisted.internet import reactor
log.startLogging(sys.stdout)
#~ factory = WebSocketClientFactory("ws://localhost:9000", debug = False)
factory = WebSocketClientFactory("ws://ngrok.com:xxxxx", debug = False)
factory.protocol = MyClientProtocol
reactor.connectTCP("ws://ngrok.com", xxxxx, factory)
reactor.run()
This is the ngrok command: ./ngrok -proto=tcp 9000
What am I doing wrong here?
I tried using
ngrok http 8091
(where 8091 is the port where my WebsocketServer is running using Racthet IO) and it works. I can still connect to the Websocket replacing the http with ws on the connection.
Try using this command:
ngrok tcp 8091
It works perfectly for me.

Resources