A failed attempt to reload gunicorn on html change (so now it's just a draft) Fixed incompatibility with reload = False Now we catch the lock getting error instead of just raising it!
144 lines
4.3 KiB
Python
144 lines
4.3 KiB
Python
from django.apps import AppConfig
|
|
from django.conf import settings
|
|
from django.apps import apps
|
|
|
|
import os, pathlib, importlib, types
|
|
import re
|
|
import tomllib
|
|
|
|
class AsyncronConfig(AppConfig):
|
|
default_auto_field = 'django.db.models.BigAutoField'
|
|
name = 'asyncron'
|
|
label = 'asyncron'
|
|
|
|
|
|
def ready( self ):
|
|
try: names = settings.ASYNCRON['IMPORT_PER_APP']
|
|
except (KeyError, AttributeError): pass
|
|
else: self.import_per_app( names )
|
|
|
|
#if settings.DEBUG:
|
|
# os.environ['PYTHONASYNCIODEBUG'] = "1"
|
|
|
|
#self.watch_templates_for_reload() Does not Work Rn.
|
|
|
|
self.load_model_auxilaries()
|
|
self.load_extensions()
|
|
|
|
#Init the asyncron worker for this process
|
|
from .workers import AsyncronWorker
|
|
#The worker should not start working until they know we're responding to requests.
|
|
AsyncronWorker.init()
|
|
|
|
def import_per_app( self, names ):
|
|
for app in apps.get_app_configs():
|
|
|
|
app_dir = pathlib.Path(app.path)
|
|
if app_dir.parent != settings.BASE_DIR: continue
|
|
|
|
for name in names:
|
|
import_file = app_dir / f"{name}.py"
|
|
if not import_file.exists() or not import_file.is_file(): continue
|
|
|
|
#print( f"Loading {app.name}.{name}:", import_file )
|
|
loader = importlib.machinery.SourceFileLoader( f"{app.name}.{name}", str(import_file) )
|
|
loader.exec_module( types.ModuleType(loader.name) )
|
|
|
|
def watch_templates_for_reload( self ):
|
|
from .gunicorn import post_fork
|
|
if not hasattr(post_fork, 'worker'): return
|
|
if not post_fork.worker.reloader: return
|
|
if not any( tconf.get('APP_DIRS', False) for tconf in settings.TEMPLATES ): return
|
|
|
|
for app in apps.get_app_configs():
|
|
app_templates_dir = pathlib.Path(app.path) / "templates"
|
|
if not app_templates_dir.exists(): continue
|
|
for dirpath, dirnames, filenames in app_templates_dir.walk():
|
|
print("D:", dirpath, dirnames, filenames )
|
|
post_fork.worker.reloader.add_extra_file( dirpath )
|
|
|
|
|
|
|
|
|
|
|
|
def load_model_auxilaries( self ):
|
|
"""
|
|
Loads auxilary (passive) data from the models.toml file of each app.
|
|
Data is either a keyword argument of a field, or an allowed Meta class value.
|
|
|
|
There should be no database defining values set the toml file:
|
|
- ModelName.Meta.verbose_name -> Allowed
|
|
- ModelName.Meta.unique_together -> Bad Idea / Undefined Behaviour
|
|
- ModelName.help_text.a_field_name -> Allowed (string)
|
|
- ModelName.null.a_field_name -> Bad Idea / Undefined Behaviour
|
|
"""
|
|
|
|
from .base.models import BaseModel
|
|
|
|
for app in apps.get_app_configs():
|
|
app_dir = pathlib.Path(app.path)
|
|
toml_file = app_dir / "models.toml"
|
|
if not toml_file.exists(): continue
|
|
|
|
with open(toml_file, 'rb') as f:
|
|
model_auxilaries = tomllib.load(f)
|
|
|
|
for model in app.get_models():
|
|
|
|
if not issubclass( model, BaseModel ): continue
|
|
if model.__name__ not in model_auxilaries: continue
|
|
aux = model_auxilaries[model.__name__]
|
|
|
|
if 'Meta' in aux:
|
|
for k, v in aux.pop('Meta').items():
|
|
setattr(model._meta, k, v)
|
|
|
|
for field_kwarg, field_nv in aux.items():
|
|
for field_name, field_kwarg_value in field_nv.items():
|
|
if not hasattr(model, field_name): continue
|
|
|
|
field = getattr(model, field_name).field
|
|
if not getattr(field, field_kwarg, None): #Set only as default or empty replacements
|
|
setattr(field, field_kwarg, field_kwarg_value)
|
|
|
|
def load_extensions( self ):
|
|
from .base.models import BaseModel
|
|
from .extender import Extender
|
|
from .gunicorn import post_fork #To add them to auto-reload watch
|
|
|
|
for app in apps.get_app_configs():
|
|
app_dir = pathlib.Path(app.path)
|
|
for model in app.get_models():
|
|
if not issubclass( model, BaseModel ): continue
|
|
|
|
ext_dir = app_dir / "extensions" / model.__name__
|
|
if not ext_dir.exists(): continue
|
|
|
|
extender = None
|
|
for import_file in ext_dir.iterdir():
|
|
if not import_file.is_file(): continue
|
|
if import_file.suffixes[-1] != ".py": continue
|
|
|
|
#So the imported module can attach it's method to the extender created last
|
|
if extender is None: extender = Extender( model )
|
|
|
|
loader = importlib.machinery.SourceFileLoader( f"{app.name}.extensions.{model.__name__}.{import_file.stem}", str(import_file) )
|
|
loader.exec_module( types.ModuleType(loader.name) )
|
|
|
|
if hasattr( post_fork, "worker" ):
|
|
try: post_fork.worker.reloader.add_extra_file( str(import_file) )
|
|
except: pass
|
|
|
|
if extender:
|
|
extender.attach( model )
|
|
|
|
Extender.stop_capturing()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#
|