app integration¶
Lets discuss integrating logging-strict into your app and history dust binning hardcoded logging configuration.
app¶
An entrypoint boilerplate should be structured like, or slightly differently for an async app
def _process_args(): ...
def main():
d_out = _process_args()
...
# app logging config stuff <--- here!
app = MyApp() # <-- not within here
...
if __name__ = "__main__":
main()
This entrypoint is testable. If the argparsing is done within main, it’s time to refactor and rework the entrypoint.
An Entrypoint have defined and documented exit codes. Besides for
--help|-h, never prints a message
logging.config yaml – within logging_strict¶
from logging_strict.constants import
from logging_strict import ui_yaml_curated, LoggingState
genre = "textual"
version_no = "1"
flavor = "asz" # < -- Yet unpublished testing UI package
package_start_relative_folder = ""
LoggingState().is_state_app = True
ui_yaml_curated(
genre,
flavor,
version_no=version_no,
package_start_relative_folder=package_start_relative_folder, # <-- narrows the search
)
logging.config yaml – within another package¶
from mypackage.constants import urpackagename, package_data_folder_start
from logging_strict import setup_ui_other, LoggingState
genre = "textual"
flavor = "asz" # < -- Yet unpublished testing UI package
version_no = "1"
package_start_relative_folder = ""
LoggingState().is_state_app = True
setup_ui_other(
urpackagename, # <-- Would have been better to curate within logging_strict
package_data_folder_start,
genre,
flavor,
version_no=version_no,
package_start_relative_folder=package_start_relative_folder,
)
package
Package within which the *.[app|worker].logging.config.yaml files reside.
Which is preferrably within logging_strict. So all the logging.config yaml in the universe need not be duplicated to the point where it appears to compete with fiat currency.
package_data_folder_start
Within that package, which is the package base folder somewhere within the folder tree lies the *.[app|worker].logging.config.yaml files. This is a str, not a relative path.
One folder name. Does not assume the folder is called
data. Does assume data files are within at least one folder. And if not? G’d and Darwin. Or panties are bound to get twisted.category
The function name indicates the purpose. To setup
logging.configfor a worker, call function,setup_workergenre
From a main app’s POV, genre is the UI framework such as: pyside or textual
From a worker’s POV, genre hints at the implementation: mp (multiprocessing) or rabbitmq, …
flavor
Like a one word brand name to a particular logging.config yaml file. For the initially used the brand,
asz, a Python testing UI appversion_no
When changes have to be made either: Increment the version by 1 or if purpose is different, fork a new flavor
If no flavor, version pertains to the genre
package_start_relative_folder
Relative to package_data_folder_start, narrows search.
For example,
bad_idea/folder0/andbad_idea/folder1both contains,mp_1_shared.worker.logging.config.yaml. Which one?package_data_folder_start is
bad_idea, notconfigsordata. package_start_relative_folder could befolder0. Which is enough to identify the exact file.
LoggingState¶
A Singleton holding logging state. To know whether or not, run by app or from cli
(there is also the issue of run by: coverage, unittest, or pytest)
If run from app, and testing app component, logging is redirected to textual.logging.TextualHandler and shouldn’t be changed.
If run from cli, and testing app component, logging is redirected to logging.handlers.StreamHandler, not TextualHandler
During testing, the app and workers are run in all three scenerios.
From coverage, from unittest, and from asz.
While the logging handler is TextualHandler, changing to StreamHandler would be bad. LoggingState aim is to avoid that.
Why would want to do testing from an UI?
Speeeeeeeeeed!
Minimizing keypresses or actions required to run commands
Associating unittests to code modules
Which unittest(s) must be run to get 100% coverage for a particular code module?
Without organization, can only imagine that there must always be a 1:1 ratio between unittest and code module. And if not, the unittests folder is just a jumbled mess. And which unittests matter for a particular code module is unknown.
Give a brother a clue!
A clear easily maintainable verifiable guide is necessary.
worker¶
This is a 2 step process.
Step 1 – entrypoint
Extracts yaml from package, validates, then passes as str to the worker process
Step 2 – worker
yaml str –> logging.config.dictConfig
within entrypoint¶
The multiprocessing.pool.Pool (not ThreadPool) worker is
isolated within it’s own process. So the dirty nature of logging
configuration has no effect on other processes.
logging.config yaml file within package, logging_strict
from logging_strict import worker_yaml_curated
genre = "mp"
flavor = "asz"
str_yaml = worker_yaml_curated(genre, flavor)
logging.config yaml file within another package
from logging_strict import worker_yaml_curated
package = "someotherpackage"
package_data_folder_start = "data" # differs so need to check this folder name
genre = "mp"
flavor = "asz"
str_yaml = setup_worker_other(package, package_data_folder_start, genre, flavor)
within worker¶
entrypoint passes str_yaml to the (multiprocessing.pool.Pool)
worker. A worker calls setup_logging_yaml with the yaml str
from logging_strict import setup_logging_yaml
setup_logging_yaml(str_yaml)
To learn more about building UI apps that have multiprocessing.pool.Pool
workers, check out the asz source code