def __init__()

in src/asfquart/base.py [0:0]


    def __init__(self, app_id: str, /, app_dir: str | None = None, cfg_file: str | None = None, *args, **kw):
        """Construct an ASFQuart web application.

        Arguments:
            app_id: The name of the application, usually ``__name__``.
            app_dir: Optional application directory, defaults to ``os.getcwd()`` if none is provided.
            cfg_file: Optional config file name, defaults to ``config.yaml`` if none is provided.
        """
        super().__init__(app_id, *args, **kw)

        self.app_id = app_id
        self.app_dir = pathlib.Path(app_dir or os.getcwd())
        self.cfg_path = self.app_dir / (cfg_file or CONFIG_FNAME)

        # Most apps will require a watcher for their EZT templates.
        self.tw = asfpy.twatcher.TemplateWatcher()
        self.add_runner(self.tw.watch_forever, name=f"TW:{app_id}")

        # use an easydict for config values
        self.cfg = easydict.EasyDict()

        # token handler callback for PATs - see docs/sessions.md
        self.token_handler = None  # Default to no PAT handler available.

        # Read, or set and write, the application secret token for
        # session encryption. We prefer permanence for the session
        # encryption, but will fall back to a new secret if we
        # cannot write a permanent token to disk...with a warning!
        _token_filename = self.app_dir / "apptoken.txt"

        if os.path.isfile(_token_filename):  # Token file exists, try to read it
            # Test that permissions are as we want them, warn if not, but continue
            st = os.stat(_token_filename)
            file_mode = st.st_mode & 0o777
            if file_mode != SECRETS_FILE_MODE:
                sys.stderr.write(
                    f"WARNING: Secrets file {_token_filename} has file mode {oct(file_mode)}, we were expecting {oct(SECRETS_FILE_MODE)}\n"
                )
            self.secret_key = open(_token_filename).read()
        else:  # No token file yet, try to write, warn if we cannot
            self.secret_key = secrets.token_hex()
            ### TBD: throw the PermissionError once we stabilize how to locate
            ### the APP directory (which can be thrown off during testing)
            try:
                # New secrets files should be created with chmod 600, to ensure that only
                # the app has access to them. umask is recorded and changed during this, to 
                # ensure we don't have umask overriding what we want to achieve.
                umask_original = os.umask(SECRETS_FILE_UMASK)  # Set new umask, log the old one
                try:
                    fd = os.open(_token_filename, flags=(os.O_WRONLY | os.O_CREAT | os.O_EXCL), mode=SECRETS_FILE_MODE)
                finally:
                    os.umask(umask_original)  # reset umask to the original setting
                with open(fd, "w") as sfile:
                    sfile.write(self.secret_key)
            except PermissionError:
                LOGGER.error(f"Could not open {_token_filename} for writing. Session permanence cannot be guaranteed!")