Comments (6)
I think to understand error you first need to understand what exactly initialiser doing:
- It connects to default database
- Runs create database for given database name (if there is
{}
in database name - it will format it with random uuid) - Populate this DB with schemas generated from your models
- Connects to newly created db
Your error occurs because it's connection to default db failed, as it not exists. For most of postgres clients default db equals to user name. If your user was postgres
it would connect
to postgres
db that usually exist, but in your case there no db with same name as user
So you have few options to workaround:
- create database
your_postgres_user
- use user
postgres
- override
PGDATABASE
with another database name - do not use initializer/finalizer at all, and manage database yourself
Note that default database can't be equal to database you want to run your tests against, as you can't create/delete database you are already connected to
from tortoise-orm.
Thanks for the pointers! The fix I made is different though so I will try to explain here (maybe it will help someone else using Fastapi with tortoise-orm and trying to write unit tests like me)
Finally got it to work changing the way I used the FastApi TestClient.
Earlier I was using it as described here: https://fastapi.tiangolo.com/tutorial/testing/#using-testclient
client = TestClient(app)
This gave me the exception:
self = <tortoise.router.ConnectionRouter object at 0x7f4c3d82a380>, model = <class 'src.models.Account'>, action = 'db_for_read'
def _router_func(self, model: Type["Model"], action: str):
> for r in self._routers:
E TypeError: 'NoneType' object is not iterable
Now I switched to using it so that startup and shutdown events get triggered as described in https://fastapi.tiangolo.com/advanced/testing-events/
with TestClient(app) as client:
This helped and my tests are running now. They run fine whether I use RegisterTortoise with lifespan or register_tortoise but with the deprecation at FastApi, the better approach is to use RegisterTortoise with lifespan as mentioned by @abondar
In 0.21 version we introduced new way to register Tortoise with fastapi -
tortoise.contrib.fastapi.RegisterTortoise
You can try it - may be it will change something
from tortoise-orm.
tortoise.exceptions.DBConnectionError: Can't establish connection to default database. Verify environment PGDATABASE. Exception: database "your_postgres_user" does not exist
Does your environment has PGDATABASE
variable?
from tortoise-orm.
no
from tortoise-orm.
Thanks for the explanation @abondar . I have changed the user to postgres
but now I get asyncpg.exceptions.ObjectInUseError: cannot drop the currently open database
even though nothing else is using the database.
Can you explain the 4th option? "do not use initializer/finalizer at all, and manage database yourself"
My fastapi application is set up using register_tortoise() function and I create a TestClient for it to run unit tests. But when any of the routes being tested read/write using a tortoise Model, I get this error:
/usr/local/lib/python3.10/site-packages/tortoise/models.py:1273: in get
db = using_db or cls._choose_db()
/usr/local/lib/python3.10/site-packages/tortoise/models.py:1010: in _choose_db
db = router.db_for_read(cls)
/usr/local/lib/python3.10/site-packages/tortoise/router.py:36: in db_for_read
return self._db_route(model, "db_for_read")
/usr/local/lib/python3.10/site-packages/tortoise/router.py:31: in _db_route
return connections.get(self._router_func(model, action))
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <tortoise.router.ConnectionRouter object at 0x7f4c3d82a380>, model = <class 'src.models.Account'>, action = 'db_for_read'
def _router_func(self, model: Type["Model"], action: str):
> for r in self._routers:
E TypeError: 'NoneType' object is not iterable
/usr/local/lib/python3.10/site-packages/tortoise/router.py:18: TypeError
This is the config dict I am passing to register_tortoise:
{'connections': {'master': {'engine': 'tortoise.backends.asyncpg', 'credentials': {'host': 'localhost', 'port': '5432', 'user': 'postgres', 'password': 'your_postgres_password', 'database': 'your_postgres_db'}}, 'slave': {'engine': 'tortoise.backends.asyncpg', 'credentials': {'host': 'localhost', 'port': '5432', 'user': 'postgres', 'password': 'your_postgres_password', 'database': 'your_postgres_db'}}}, 'apps': {'models': {'models': ['src.models', 'aerich.models'], 'default_connection': 'master'}}, 'routers': ['src.models.Router'], 'use_tz': False, 'timezone': 'UTC'}
Router definition:
from tortoise.models import Model
from typing import Type
class Router:
def db_for_read(self, model: Type[Model]):
print(model, "db_for_read")
return "slave"
def db_for_write(self, model: Type[Model]):
print(model, "db_for_write")
return "master"
These problems are all faced during unit test runs only. When I run the application and test each endpoint via swagger manually everything works perfectly with no changes in code or configuration. However, I cannot run manual tests every time so it is imperative for me to get unit tests running or else I will have to switch back to other ORM.
from tortoise-orm.
I have changed the user to postgres but now I get asyncpg.exceptions.ObjectInUseError: cannot drop the currently open database even though nothing else is using the database.
Can you try changing your database in to something like
asyncpg://postgres:your_postgres_password@localhost:5432/test_{}
?
To be sure, that db is always freshly created and not reused by anyone
That how we run tests internally and it works, at least here
My fastapi application is set up using register_tortoise()
In 0.21 version we introduced new way to register Tortoise with fastapi -
tortoise.contrib.fastapi.RegisterTortoise
You can try it - may be it will change something
Here how we use it in example
https://github.com/tortoise/tortoise-orm/blob/develop/examples/fastapi/main.py#L25
There is also simple test configuration for fast api in example
https://github.com/tortoise/tortoise-orm/blob/develop/examples/fastapi/_tests.py
But overall error you are getting indicates that for some reason tortoise wasn't properly initialised, because if it was - tortoise.router.ConnectionRouter.init_routers
should have been called and you wouldn't be having None
here.
For diagnostics - you can check in debugger if Tortoise._init
is set to true before your failing .get()
call
Can you explain the 4th option? "do not use initializer/finalizer at all, and manage database yourself"
It just means that you create database and migrate it to needed state beforehand, using some external tools or manually, and then you run tests
tortoise.contrib.fastapi.RegisterTortoise
also provides option generate_schemas
which may help preparing test env
from tortoise-orm.
Related Issues (20)
- Add proper error messages and a doc page dedicated for testing HOT 3
- Support symmetrical ManyToMany relationships HOT 2
- Bulk Create without returning objects HOT 3
- OperationalError when attempting to filter by annotated field in m2m relation HOT 1
- Refactoring pydantic_model_creator for Enhanced Code Maintainability and Reliability HOT 2
- 0.21.0 throws "IntegrityError: NOT NULL constraint failed" due to usage of 'pk' to indicate primary key HOT 3
- max recursion bug
- Feature: expose `timezone` and `use_tz` params in RegisterTortoise class HOT 5
- OperationalError while bulk updating the tortoise model. HOT 1
- [BUG] get_or_create function raises "Object does not exist" HOT 1
- DoesNotExist can be more useful HOT 2
- There is an entry for table "table", but it cannot be referenced from this part of the query HOT 2
- Is there a django similar scheme to generate model files based on the structure of the existing database python manage.py inspectdb > models.py HOT 1
- unique indexes (for unique_together) on nullable columns need to be optionable for nulls not distinct HOT 3
- [Bug] Failed to set schema for models.Model
- Custom generated primary key (Snowflake) ignored, a serial is saved in the backend HOT 1
- Have you considered allowing Tortoise to be independently initialized multiple times in different packages? HOT 3
- Generic relation field HOT 1
- Race condition bug in ConnectionWrapper HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from tortoise-orm.