diff --git a/docs/changelog.rst b/docs/changelog.rst index df84de5..10e77fc 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -5,9 +5,10 @@ Changelog 0.9.1 - TBC ----------- -Docs: +Bugs: * Fix incorrect tutorial syntax (#15) +* Fix instance name detection (#21, #22) Thanks to: diff --git a/nanodjango/app.py b/nanodjango/app.py index fdee1f1..edbdbc4 100644 --- a/nanodjango/app.py +++ b/nanodjango/app.py @@ -41,9 +41,12 @@ class Django: # Class variable to ensure there can be only one _instantiated = False - #: Name of the app script + #: Name of the app script, eg counter.py has app_name == "counter" app_name: str + #: Cached name of this app instance - see self.instance_name + _instance_name: str | None = None + #: Reference to the app script's module app_module: ModuleType @@ -56,9 +59,6 @@ class Django: #: Whether this app has any async views _has_async_view: bool = False - #: Variable name for this current app - _instance_name: str - # Settings cache to aid ``convert`` _settings: dict[str, Any] @@ -136,6 +136,30 @@ def _config(self, _settings): # Ready for Django's standard setup setup() + @property + def instance_name(self): + """ + Variable name of this instance in the module it's defined in + + If this instance is assigned to multiple names, the first name will be used + Example: + + foobar = Django + foobar.instance_name == "foobar" + """ + if not self._instance_name: + for var, val in self.app_module.__dict__.items(): + if val == self: + self._instance_name = var + break + + if not self._instance_name: + raise UsageError( + f"Could not find Django instance name in {self.app_module.__name__}" + ) + return self._instance_name + + def route(self, pattern: str, *, re=False, include=None, name=None): """ Decorator to add a view to the urls @@ -292,7 +316,7 @@ def _prepare(self, is_prod=False): # Hasn't been run through the ``nanodjango`` command if ( "__main__" not in sys.modules - or getattr(sys.modules["__main__"], self._instance_name) != self + or getattr(sys.modules["__main__"], self.instance_name) != self ): # Doesn't look like it was run directly either raise UsageError("App module not initialised") @@ -378,7 +402,7 @@ def run(self, host: str | None = None): raise UsageError("Install uvicorn to use async views") uvicorn.run( - f"{self.app_name}:{self._instance_name}", + f"{self.app_name}:{self.instance_name}", host=host, port=port, log_level="info", @@ -407,7 +431,7 @@ def serve(self, host: str | None = None): port = int(port) uvicorn.run( - f"{self.app_name}:{self._instance_name}", + f"{self.app_name}:{self.instance_name}", host=host, port=port, log_level="info", diff --git a/nanodjango/commands.py b/nanodjango/commands.py index 45fc23a..d9fb225 100644 --- a/nanodjango/commands.py +++ b/nanodjango/commands.py @@ -54,7 +54,8 @@ def load_app(ctx: click.Context, param: str, value: str) -> Django: if app_name is None or app is None: raise click.UsageError(f"App {value} has no Django instances") - + + # This would get picked up by app.instance_name, but we have it already app._instance_name = app_name return app