python-escpos/src/escpos/config.py

119 lines
3.6 KiB
Python
Raw Normal View History

"""ESC/POS configuration manager.
2016-03-15 21:09:45 +00:00
This module contains the implementations of abstract base class :py:class:`Config`.
2016-03-15 21:09:45 +00:00
"""
2016-03-15 19:00:46 +00:00
import os
import pathlib
2016-03-15 19:00:46 +00:00
import appdirs
2016-03-15 20:47:23 +00:00
import yaml
2016-03-15 19:00:46 +00:00
from . import exceptions, printer
2016-03-15 19:00:46 +00:00
2016-06-19 10:25:40 +00:00
class Config:
2021-10-30 16:15:22 +00:00
"""Configuration handler class.
2016-03-15 19:00:46 +00:00
This class loads configuration from a default or specified directory. It
2016-03-15 21:09:45 +00:00
can create your defined printer and return it to you.
"""
2021-10-30 16:15:22 +00:00
_app_name = "python-escpos"
_config_file = "config.yaml"
2016-03-15 19:00:46 +00:00
def __init__(self) -> None:
2021-10-30 16:15:22 +00:00
"""Initialize configuration.
Remember to add anything that needs to be reset between configurations
to self._reset_config
"""
self._has_loaded = False
self._printer = None
self._printer_name = None
self._printer_config = None
def _reset_config(self) -> None:
2021-10-30 16:15:22 +00:00
"""Clear the loaded configuration.
If we are loading a changed config, we don't want to have leftover
data.
"""
2016-03-15 19:00:46 +00:00
self._has_loaded = False
self._printer = None
self._printer_name = None
self._printer_config = None
def load(self, config_path=None):
"""Load and parse the configuration file using pyyaml.
2016-03-15 21:09:45 +00:00
:param config_path: An optional file path, file handle, or byte string
for the configuration file.
"""
self._reset_config()
2016-03-15 19:00:46 +00:00
if not config_path:
config_path = os.path.join(
2021-10-30 16:15:22 +00:00
appdirs.user_config_dir(self._app_name), self._config_file
2016-03-15 19:00:46 +00:00
)
if isinstance(config_path, pathlib.Path):
# store string if posixpath
config_path = config_path.as_posix()
if not os.path.isfile(config_path):
# supplied path is not a file --> assume default file
config_path = os.path.join(config_path, self._config_file)
2016-03-15 19:00:46 +00:00
2016-03-15 20:47:23 +00:00
try:
with open(config_path, "rb") as config_file:
config = yaml.safe_load(config_file)
2016-03-16 20:47:51 +00:00
except EnvironmentError:
2021-10-30 16:15:22 +00:00
raise exceptions.ConfigNotFoundError(
f"Couldn't read config at {config_path}"
2021-10-30 16:15:22 +00:00
)
2016-03-16 21:28:53 +00:00
except yaml.YAMLError:
2021-10-30 16:15:22 +00:00
raise exceptions.ConfigSyntaxError("Error parsing YAML")
2016-03-15 19:00:46 +00:00
2021-10-30 16:15:22 +00:00
if "printer" in config:
self._printer_config = config["printer"]
printer_name = self._printer_config.pop("type")
class_names = {
"usb": "Usb",
"serial": "Serial",
"network": "Network",
"file": "File",
"dummy": "Dummy",
"cupsprinter": "CupsPrinter",
"lp": "LP",
"win32raw": "Win32Raw",
}
self._printer_name = class_names.get(printer_name.lower(), printer_name)
2016-03-15 19:00:46 +00:00
if not self._printer_name or not hasattr(printer, self._printer_name):
2016-03-30 20:30:44 +00:00
raise exceptions.ConfigSyntaxError(
f'Printer type "{self._printer_name}" is invalid'
2016-03-30 20:30:44 +00:00
)
2016-03-15 19:00:46 +00:00
self._has_loaded = True
def printer(self):
"""Return a printer that was defined in the config.
Throw an exception on error.
2016-03-15 21:09:45 +00:00
This method loads the default config if one has not been already loaded.
2016-03-15 21:09:45 +00:00
"""
2016-03-15 19:00:46 +00:00
if not self._has_loaded:
self.load()
if not self._printer_name:
2021-10-30 16:15:22 +00:00
raise exceptions.ConfigSectionMissingError("printer")
2016-03-15 19:00:46 +00:00
if not self._printer:
2016-03-30 20:30:44 +00:00
# We could catch init errors and make them a ConfigSyntaxError,
2016-03-15 19:00:46 +00:00
# but I'll just let them pass
self._printer = getattr(printer, self._printer_name)(**self._printer_config)
return self._printer