What is the correct way to pass in parameters in a SET query?
this will return asyncpg.exceptions.PostgresSyntaxError: syntax error at or near "$1"
import asyncio
import asyncpg
async def main():
conn = await asyncpg.connect(user="xx", password="yy", host="127.0.0.1", database="my_db")
# works
await conn.execute("select $1", "1")
identity = "arn:aws:sts::123456:assumed-role/thing_1"
# fails
await conn.execute("set session iam.identity = $1", identity)
asyncio.run(main())
asyncpg has a function for this:
await conn.execute("select set_config('iam.identity', $1, false)", identity)
Related
I've adjusted the main file and added a prefix "?" to my commands
import discord
from discord.ext import commands
import os
import asyncio
client = commands.Bot(command_prefix="?", intents = discord.Intents.all())
async def load():
for filename in os.listdir("./cogs"):
if filename.endswith(".py"):
await client.load_extension(f"cogs.{filename[:-3]}")
async def main():
async with client:
await load()
await client.start(TOKEN)
asyncio.run(main())
and added a simple ping command to test if the bot was working in discord. unfortunately all the commands except for ping does not work
import discord
from discord.ext import commands
from pymongo import MongoClient
bot_channel = BOTCHANNELID
talk_channels = [TALKCHANNELID]
level = ["test1", "test2", "test3"]
levelnum = [2,4,6]
cluster = MongoClient("MONGODBCODE")
levelling = cluster["NAME"]["NAME2"]
class levelsys(commands.Cog):
def __init__(self,client):
self.client = client
#commands.Cog.listener()
async def on_ready(self):
print("Ready!")
#commands.Cog.listener()
async def on_message(self, message):
if message.channel.id in talk_channels:
stats = levelling.find_one({"id" : message.author.id})
if not message.author.bot:
if stats is None:
newuser = {"id" : message.author.id, "xp" : 1}
levelling.insert_one(newuser)
else:
xp = stats["xp"] + 5
levelling.update_one({"id":message.author.id}, {"$set":{"xp":xp}})
lvl = 0
while True:
if xp < ((50*(lvl**2))+(50*(lvl-1))):
break
lvl += 1
xp -= ((50*((lvl-1)**2))+(50*(lvl-1)))
if xp == 0:
await message.channel.send(f"gz {message.author.mention} ! you lvled up to **level: {lvl}**")
for i in range(len(level)):
if lvl == levelnum[i]:
await message.author.add_roles(discord.utils.get(message.author.guild.roles, name=level[i]))
embed = discord.Embed(description=f"{message.author.mention} you have gotten role **{level[i]}**")
embed.set_thumbnail(url=message.author.avatar_url)
await message.channel.send(embed=embed)
#commands.command()
async def rank(self, ctx):
if ctx.channel.id == bot_channel:
stats = levelling.find_one({"id" : ctx.author.id})
if stats is None:
embed = discord.Embed(description="you haven't been studying lil bro")
await ctx.channel.send(embed=embed)
else:
xp = stats["xp"]
lvl = 0
rank = 0
while True:
if xp < ((50*(lvl**2))+(50*lvl)):
break
lvl += 1
xp -= ((50*((lvl-1)**2))+(50*(lvl-1)))
boxes = int((xp/(200*((1/2) * lvl)))*20)
rankings = levelling.find().sort("xp",-1)
for x in rankings:
rank += 1
if stats["id"] == x["id"]:
break
embed = discord.Embed(title="{}'s level stats".format(ctx.author.name))
embed.add_field(name="Name", value=ctx.author.mention, inline=True)
embed.add_field(name="XP", value=f"{xp}/{int(200*((1/2)*lvl))}", inline=True)
embed.add_field(name="Rank", value=f"{rank}/{ctx.guild.member_count}", inline=True)
embed.add_field(name="Progress Bar [lvl]", value=boxes * ":blue_square:" + (20-boxes) * ":white_large_squares:", inline = False)
embed.add_field(name='Level', value=f'{lvl}', inline=True)
embed.set_thumbnail(url=ctx.author.avatar_url)
await ctx.channel.send(embed=embed)
#commands.command()
async def dashboard(self, ctx):
if (ctx.channel.id == bot_channel):
rankings = levelling.find().sort("xp",-1)
i = 1
embed = discord.Embed(title="Rankings:")
for x in rankings:
try:
temp = ctx.guild.get_member(x["id"])
tempxp = x["xp"]
embed.add_field(name=f"{i}: {temp.name}", value=f"Total XP: {tempxp}", inline=False)
i += 1
except:
pass
if i == 11:
break
await ctx.channel.send(embed=embed)
#commands.command()
async def ping(self, ctx):
bot_latency = round(self.client.latency * 1000)
await ctx.send(f"Your ping is {bot_latency} ms !.")
async def setup(client):
await client.add_cog(levelsys(client))
I'm not too sure how I would go about fixing all the other commands to get them working. All help is much appreciated !
I just updated my app with sqlalchemy to create an async connections, no problem, but when writing tests, I can't do the update as opposed to create:
affected function:
#function
#classmethod
async def update_instance(
cls,
instance: InstanceInputOnUpdate
) -> Union['EdaNCEInstance', EdaNCEInstanceOperationError]:
async with get_session() as conn:
result = await conn.execute(
select(Instance).where(Instance.id==eda_nce_instance.id)
)
instance_to_update = result.scalars().unique().first()
if instance_to_update is not None:
instance_to_update.name = instance.name
instance_to_update.host = instance.host
await conn.commit()
return instance_to_update
else:
return InstanceOperationError(
result= False,
message= f"Can't find the instance ID '{instance.id}'"
)
test:
#pytest.mark.asyncio
async def test_04_update_instance():
async with AsyncClient(app=app, base_url="http://test") as c:
res = await Instance.update_eda_nce_instance(
instance=InstanceInputOnUpdate(
id=DUMMY_ID,
name="test_server1",
host="123.123.123.123",
)
)
assert isinstance(res, Instance) == True
assert res.host == "124.123.144.144"
return res
errors:
#...
E sqlalchemy.dialects.postgresql.asyncpg.AsyncAdapt_asyncpg_dbapi.InterfaceError: <class 'asyncpg.exceptions._base.InterfaceError'>: cannot perform operation: another operation is in progress
venv/lib/python3.9/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py:682: InterfaceError
my db.py
SQLALCHEMY_DATABASE_URL = settings.get_settings().postgresql_conn_url
engine = create_async_engine(SQLALCHEMY_DATABASE_URL, echo=False, future=True)
async_session = sessionmaker(engine, expire_on_commit=False, class_=AsyncSession)
Base = declarative_base()
async def init_db():
async with engine.begin() as conn:
await conn.run_sync(Base.metadata.create_all)
#asynccontextmanager
async def get_session() -> AsyncGenerator[AsyncSession, None]:
async with async_session() as session:
async with session.begin():
try:
yield session
finally:
await session.close()
In creation I have no problem, and it doesn't change much from the update
#classmethod
async def create_instance(
cls,
instance: InstanceInputOnCreate
) -> Union['Instance', InstanceOperationError]:
async with get_session() as conn:
new_instance = Instance(
name=instance.name,
host=instance.host
)
conn.add(new_instance)
try:
await conn.commit()
return new_instance
except Exception:
conn.rollback()
return InstanceOperationError(
result=False,
message=f"Instance '{instance.name}' already exists"
)
I didn't create mocks, because CI/CDs are set up to create a test database where Alembic can be started first for migrations, then the database is ready to test on it
sqlalchemy==1.4.46
fastapi-utils==0.2.1
aiosqlite==0.18.0
asyncpg==0.27.0
sqlalchemy-utils==0.39.0
pytest==7.2.1
pytest-asyncio==0.20.3
pytest-mock==3.10.0
pydantic~=1.10.4
aiokafka~=0.8.0
requests~=2.28.1
fastapi==0.70.1
If there are typo in the code, it's not a problem I had to change the names to create this question.
I wrote a socket server and client package with asyncio that happens to be a single module with two classes Server and Client. The intention is to have the code check if the specified port is in use on the same device, and if so, it will choose the use the Client class instead of the Server class. I am doing this to enable local testing between client and server for a larger goal.
I wrote my unit test with pytest and I can get it to pass if I run the server in its own process first, then run the client in another process.
However, I want to test both server and client together in the same process using pytest. The test never completes this way, however.
Am I running into an issue with asyncio here? Or is it an issue with pytest? Or is it something I am doing wrong in my code?
WebSockets.websocket
import asyncio
class Server:
def __init__(self, host, port):
self.host = host
self.port = port
self.server = None
self.connections = {}
async def start(self):
self.server = server = await asyncio.start_server(self.handle_client, self.host, self.port)
addr = server.sockets[0].getsockname()
print(f'Serving on {addr}')
async with server:
await server.serve_forever()
async def handle_client(self, reader, writer):
addr = writer.get_extra_info('peername')
print(f'New connection from {addr}')
self.connections[addr] = writer
try:
while not reader.at_eof():
data = await reader.read(100)
message = data.decode()
if message:
print(f'Received {message!r} from {addr}')
await self.send(message, addr)
finally:
del self.connections[addr]
writer.close()
async def send(self, message, addr):
writer = self.connections.get(addr)
if not writer:
return
writer.write(message.encode())
await writer.drain()
async def recv(self, addr):
reader, _ = await asyncio.open_connection(addr[0], addr[1])
data = await reader.read(100)
return data.decode()
async def stop(self):
await self.server.close()
class Client:
def __init__(self, host, port):
self.host = host
self.port = port
self.reader = None
self.writer = None
async def connect(self):
self.reader, self.writer = await asyncio.open_connection(self.host, self.port)
async def send(self, message):
self.writer.write(message.encode())
async def recv(self):
data = await self.reader.read(100)
return data.decode()
async def close(self):
self.writer.close()
Test
import socket
import asyncio
from WebSockets.websocket import Server, Client
import pytest
def check_port(address, port):
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((address, port))
s.close()
return "server"
except OSError:
return "client"
async def serve():
server = Server('localhost', 8910)
await server.start()
async def client_connect():
client = Client('localhost', 8910)
await client.connect()
await client.send("Hello world!")
message = await client.recv()
if message:
print(f"Received {message!r} from server")
assert message == "Hello world!"
await client.close()
#pytest.mark.asyncio
async def test_sockets():
if check_port("localhost", 8910) == "server":
await serve()
# for reference on how to use in non pytest module
# loop = asyncio.new_event_loop()
# loop.run_until_complete(serve())
# loop.close()
else:
await client_connect()
# for reference on how to use in non pytest module
# loop = asyncio.new_event_loop()
# loop.run_until_complete(client_connect())
# loop.close()
I'm trying to implement a simple async test suite. If my understanding is correct of async, the tests below should only take about 2 seconds to run. However, it's taking 6 seconds. What am I missing to make these test to run async ("at the same time")?
import logging
import pytest
import asyncio
MSG_FORMAT = "%(asctime)s.%(msecs)03d %(module)s->%(funcName)-15s |%(levelname)s| %(message)s"
MSG_DATE_FORMAT = "%Y-%m-%d %H:%M:%S"
LOG_LEVEL = logging.INFO
# Create logger
logger = logging.getLogger(__name__)
logger.setLevel(LOG_LEVEL)
# Create Stream Handler
log_stream = logging.StreamHandler()
log_format = logging.Formatter(fmt=MSG_FORMAT, datefmt=MSG_DATE_FORMAT)
log_stream.setFormatter(log_format)
log_stream.setLevel(LOG_LEVEL)
logger.addHandler(log_stream)
class TestMyStuff:
#staticmethod
async def foo(seconds):
await asyncio.sleep(seconds)
return 1
#pytest.mark.asyncio
async def test_1(self, event_loop):
logger.info("start")
assert await event_loop.create_task(self.foo(2)) == 1
logger.info("end")
#pytest.mark.asyncio
async def test_2(self, event_loop):
logger.info("start")
assert await event_loop.create_task(self.foo(2)) == 1
logger.info("end")
#pytest.mark.asyncio
async def test_3(self, event_loop):
logger.info("start")
# assert await event_loop.run_in_executor(None, self.foo) == 1
assert await event_loop.create_task(self.foo(2)) == 1
logger.info("end")
pytest extras:
plugins: asyncio-0.18.3, aiohttp-1.0.4
pytest-asyncio runs asynchronous tests serially. That plugin's goal is to make testing asynchronous code more convenient.
pytest-asyncio-cooperative on the other hand has the goal of running asyncio tests concurrently via cooperative multitasking (ie. all async coroutines sharing the same event loop and yielding to each other).
To try out pytest-asyncio-cooperative do the following:
Install the plugin
pip install pytest-asyncio-cooperative
Replace the #pytest.mark.asyncio marks with #pytest.mark.asyncio_cooperative
Remove all references to event_loop. pytest-asyncio-cooperative uses a single implicit event loop for asyncio interactions.
Run pytest with pytest-asyncio disabled. It is not compatible with pytest-asyncio-cooperative
pytest -p no:asyncio test_mytestfile.py
Here is the original code snippet with these modifications:
import logging
import pytest
import asyncio
MSG_FORMAT = "%(asctime)s.%(msecs)03d %(module)s->%(funcName)-15s |%(levelname)s| %(message)s"
MSG_DATE_FORMAT = "%Y-%m-%d %H:%M:%S"
LOG_LEVEL = logging.INFO
# Create logger
logger = logging.getLogger(__name__)
logger.setLevel(LOG_LEVEL)
# Create Stream Handler
log_stream = logging.StreamHandler()
log_format = logging.Formatter(fmt=MSG_FORMAT, datefmt=MSG_DATE_FORMAT)
log_stream.setFormatter(log_format)
log_stream.setLevel(LOG_LEVEL)
logger.addHandler(log_stream)
class TestMyStuff:
#staticmethod
async def foo(seconds):
await asyncio.sleep(seconds)
return 1
#pytest.mark.asyncio_cooperative
async def test_1(self):
logger.info("start")
assert await self.foo(2) == 1
logger.info("end")
#pytest.mark.asyncio_cooperative
async def test_2(self):
logger.info("start")
assert await self.foo(2) == 1
logger.info("end")
#pytest.mark.asyncio_cooperative
async def test_3(self):
logger.info("start")
# assert await event_loop.run_in_executor(None, self.foo) == 1
assert await self.foo(2) == 1
logger.info("end")
And here are the test results:
plugins: hypothesis-6.39.4, asyncio-cooperative-0.28.0, anyio-3.4.0, typeguard-2.12.1, Faker-8.1.0
collected 3 items
test_mytestfile.py ... [100%]
================================ 3 passed in 2.18s =================================
Please checkout the README of pytest-asyncio-cooperative. Now that tests are run in a concurrent way you need to be wary of shared resources (eg. mocking)
I try to test fastAPI get route with pytest and the problem is how i can pass params to client.get
main.py
#app.get('/purpose'):
async def read_purpose(name, date):
"""some logic"""
return {'ok':'ok'}
test.py
client = TestClient(app)
def test_purpose():
response = client.get("/purpose", json={"name":"test_name", "date":"01.01.2020"})
assert response.status_code = 200
My test is failed. it can not find name, and date arguments.
How i can pass this arguments to my test.
Thank you
I have same problem when writing pytest for my first FastAPI demo.
#router.post('/item', tags=['items'], response_model=ShowItem)
async def create_item(item: ItemCreate,
user_id: int,
db: Session = Depends(get_db)):
date_posted = datetime.now().date()
# owner_id = 1
item = Items(**item.dict(),
date_posted=date_posted,
owner_id=user_id)
db.add(item)
db.commit()
db.refresh(item)
return item
You can try "params" instead of "json", because you are passing isolated query parameters
def test_create_item():
# wrong
data = {'title': 'Hot Boat', 'description': 'This is a boat', 'user_id': 1}
resp = client.post('/item', json.dumps(data))
# correct
data = {'title': 'Hot Boat', 'description': 'This is a boat'}
resp = client.post('/item', json.dumps(data), params={"user_id": 2})
assert resp.status_code == 200
Then i can by pass above error.
Try this fix:
client = TestClient(app)
def test_purpose():
response = client.get("/purpose", params={"name":"test_name", "date":"01.01.2020"})
assert response.status_code = 200
More detail refer Question 61383179