Application =========== .. py:currentmodule:: asab .. py:class:: Application() The :py:class:`Application` class maintains the global application state. You can provide your own implementation by creating a subclass. There should be only one :py:class:`Application` object in the process. Subclassing: .. code:: python import asab class MyApplication(asab.Application): pass if __name__ == '__main__': app = MyApplication() app.run() Direct use of :py:class:`Application` object: .. code:: python import asab if __name__ == '__main__': app = asab.Application() app.run() Event Loop ---------- .. py:attribute:: Application.Loop The :py:mod:`asyncio` event loop that is used by this application. .. code:: python asyncio.ensure_future(my_coro()) Application Lifecycle --------------------- The ASAB is designed around the `Inversion of control `_ principle. It means that the ASAB is in control of the application lifecycle. The custom-written code receives the flow from ASAB via callbacks or handlers. Inversion of control is used to increase modularity of the code and make it extensible. The application lifecycle is divided into 3 phases: init-time, run-time and exit-time. Init-time ^^^^^^^^^ .. py:method:: Application.__init__() The init-time happens during :py:class:`Application` constructor call. The Publish-Subscribe message :any:`Application.init!` is published during init-time. The :class:`Config` is loaded during init-time. .. py:method:: Application.initialize() The application object executes asynchronous callback ``Application.initialize()``, which can be overriden by an user. .. code:: python class MyApplication(asab.Application): async def initialize(self): # Custom initialization from module_sample import Module self.add_module(Module) Run-time ^^^^^^^^ .. py:method:: Application.run() Enter a run-time. This is where the application spends the most time typically. The Publish-Subscribe message :any:`Application.run!` is published when run-time begins. The method returns the value of :any:`Application.ExitCode`. .. py:method:: Application.main() The application object executes asynchronous callback ``Application.main()``, which can be overriden. If ``main()`` method is completed without calling ``stop()``, then the application server will run forever (this is the default behaviour). .. code:: python class MyApplication(asab.Application): async def main(self): print("Hello world!") self.stop() .. py:method:: Application.stop(exit_code:int=None) The method ``Application.stop()`` gracefully terminates the run-time and commence the exit-time. This method is automatically called by ``SIGINT`` and ``SIGTERM``. It also includes a response to ``Ctrl-C`` on UNIX-like system. When this method is called 3x, it abruptly exits the application (aka emergency abort). The parameter ``exit_code`` allows you to specify the application exit code (see *Exit-Time* chapter). *Note:* You need to install :py:mod:`win32api` module to use ``Ctrl-C`` or an emergency abord properly with ASAB on Windows. It is an optional dependency of ASAB. Exit-time ^^^^^^^^^ .. py:method:: Application.finalize() The application object executes asynchronous callback ``Application.finalize()``, which can be overriden by an user. .. code:: python class MyApplication(asab.Application): async def finalize(self): # Custom finalization ... The Publish-Subscribe message :any:`Application.exit!` is published when exit-time begins. .. py:method:: Application.set_exit_code(exit_code:int, force:bool=False) Set the exit code of the application, see ``os.exit()`` in the Python documentation. If ``force`` is ``False``, the exit code will be set only if the previous value is lower than the new one. If ``force`` is ``True``, the exit code value is set to a ``exit_code`` disregarding the previous value. .. py:attribute:: Application.ExitCode The actual value of the exit code. The example of the exit code handling in the ``main()`` function of the application. .. code:: python if __name__ == '__main__': app = asab.Application() exit_code = app.run() sys.exit(exit_code) Module registry --------------- For more details see :py:class:`Module` class. .. py:method:: Application.add_module(module_class) Initialize and add a new module. The ``module_class`` class will be instantiated during the method call. .. code:: python class MyApplication(asab.Application): async def initialize(self): from my_module import MyModule self.add_module(MyModule) .. py:attribute:: Application.Modules A list of modules that has been added to the application. Service registry ---------------- Each service is identified by its unique service name. For more details see :py:class:`Service` class. .. py:method:: Application.get_service(service_name) Locate a service by its service name in a registry and return the ``Service`` object. .. code:: python svc = app.get_service("service_sample") svc.hello() .. py:attribute:: Application.Services A dictionary of registered services. Command-line parser ------------------- .. py:method:: Application.create_argument_parser(prog=None, usage=None, description=None, epilog=None, prefix_chars='-', fromfile_prefix_chars=None, argument_default=None, conflict_handler='error', add_help=True ) -> argparse.ArgumentParser Creates an ``argparse.ArgumentParser``. This method can be overloaded to adjust command-line argument parser. Please refer to Python standard library ``argparse`` for more details about function arguments. .. py:method:: Application.parse_args() The application object calls this method during init-time to process a command-line arguments. :py:mod:`argparse` is used to process arguments. You can overload this method to provide your own implementation of command-line argument parser. .. py:data:: Application.Description The :py:data:`Description` attribute is a text that will be displayed in a help text (``--help``). It is expected that own value will be provided. The default value is ``""`` (empty string). UTC Time -------- .. py:method:: Application.time() -> float Return the current "event loop time" in seconds since the epoch as a floating point number. The specific date of the epoch and the handling of leap seconds is platform dependent. On Windows and most Unix systems, the epoch is January 1, 1970, 00:00:00 (UTC) and leap seconds are not counted towards the time in seconds since the epoch. This is commonly referred to as Unix time. A call of the ``time.time()`` function could be expensive. This method provides a cheaper version of the call that returns a current wall time in UTC.