import asyncio
import configparser
import importlib
import inspect
import logging
import os
from asyncorm.apps.app import App
from asyncorm.apps.app_config import AppConfig
from asyncorm.exceptions import AsyncOrmAppError, AsyncOrmConfigError, AsyncOrmModelError, AsyncOrmModelNotDefined
logger = logging.getLogger("asyncorm")
DEFAULT_CONFIG_FILE = "asyncorm.ini"
[docs]class OrmApp(object):
_conf = {"apps": None, "db_config": None, "loop": asyncio.get_event_loop(), "backend": "PostgresBackend"}
def _get_declared_apps(self, app_names):
_apps = {}
app_names.append("asyncorm.migrations")
for app_name in app_names:
# its not required to include .app when the app is declared in that specific file_name
import_str = not app_name.endswith(".app") and app_name + ".app" or app_name
try:
module = importlib.import_module(import_str)
except ImportError:
try:
import_str = ".".join(import_str.split(".")[:-1])
module = importlib.import_module(import_str)
except ImportError:
logger.exception("unable to import %s", import_str)
for _, app_config in inspect.getmembers(module):
try:
if issubclass(app_config, AppConfig) and app_config is not AppConfig:
# the instance directory is the import_str without the app.py file_name
dir_name = ".".join(import_str.split(".")[:-1])
abs_path = os.sep.join(module.__file__.split(os.sep)[:-1])
app = App(app_config.name, dir_name, abs_path, self)
_apps.update({app_config.name: app})
except TypeError:
pass
return _apps
[docs] def get_model(self, model_name):
"""Get the model that is defined in the ORM.
:param model_name: name of the model to get
:type model_name: str
:raises AsyncOrmAppError: When there is no model declared
:raises AsyncOrmModelError: When model_name is not in the correct format
:raises AsyncOrmModelDoesNotExist: When the model does not exist
:return: model requested
:rtype: asyncorm.models.Model
"""
if len(self.models) == 1:
raise AsyncOrmAppError("There are no apps declared in the orm")
try:
model_split = model_name.split(".")
if len(model_split) == 2:
return self.apps[model_split[0]].models[model_split[1]]
elif len(model_split) == 1:
return self.models[model_name]
else:
raise AsyncOrmModelError('The string declared should be in format "module.Model" or "Model"')
except KeyError:
raise AsyncOrmModelNotDefined("The model does not exists")
[docs] def set_model_orm(self):
for model in self.models.values():
model.set_orm(self)
[docs] async def create_db(self):
"""
We create all tables for each of the declared models
"""
self.models_configure()
for model in self.models.values():
await model().objects.set_requirements()
for model in self.models.values():
await model().objects.create_table()
for model in self.models.values():
await model().objects.add_fk_columns()
for model in self.models.values():
await model().objects.add_m2m_columns()
for model in self.models.values():
await model().objects.add_table_indices()
for model in self.models.values():
await model().objects.unique_together()
[docs] def sync_db(self):
self.loop.run_until_complete(asyncio.gather(self.loop.create_task(self.create_db())))
orm_app = OrmApp()
[docs]def parse_config(config_file):
config_parser = configparser.ConfigParser()
config_parser.read(config_file)
# check all sections exist
for section in ["db_config", "orm"]:
if section not in config_parser.sections():
raise AsyncOrmConfigError("the file {} does not contain {} section!".format(config_file, section))
return {
"db_config": {
"database": config_parser.get("db_config", "database", fallback=None),
"host": config_parser.get("db_config", "host", fallback=None),
"port": config_parser.get("db_config", "port", fallback=None),
"user": config_parser.get("db_config", "user", fallback=None),
"password": config_parser.get("db_config", "password", fallback=None),
},
"apps": config_parser.get("orm", "apps").split() or [],
}
[docs]def get_model(model_name):
"""Wrapper around the OrmApp class method.
:param model_name: name of the model to get
:type model_name: str
:raises AsyncOrmAppError: When there is no model declared
:raises AsyncOrmModelError: When model_name is not in the correct format
:raises AsyncOrmModelDoesNotExist: When the model does not exist
:return: model requested
:rtype: asyncorm.models.Model
"""
return orm_app.get_model(model_name)