Skip to content
71 changes: 44 additions & 27 deletions src/escpos/config.py
Comment thread
Elias0419 marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

This module contains the implementations of abstract base class :py:class:`Config`.
"""

import os
import pathlib

Expand Down Expand Up @@ -30,7 +31,7 @@ def __init__(self) -> None:
self._has_loaded = False
self._printer = None

self._printer_name = None
self._printer_name = ""
self._printer_config = None

def _reset_config(self) -> None:
Expand All @@ -41,17 +42,43 @@ def _reset_config(self) -> None:
"""
self._has_loaded = False
self._printer = None

self._printer_name = None
self._printer_name = ""
self._printer_config = None

def load(self, config_path=None):
def _set_config(self, config) -> None:
"""Set configuration variables.

:param config: config object loaded from file or string.
"""
self._printer_config = config.get("printer", None)
if self._printer_config is None:
self._has_loaded = True
return
printer_name = self._printer_config.get("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)
if not self._printer_name or not hasattr(printer, self._printer_name):
raise exceptions.ConfigSyntaxError(
f'Printer type "{self._printer_name}" is invalid'
)

self._has_loaded = True

def load(self, config_path=None) -> None:
"""Load and parse the configuration file using pyyaml.

:param config_path: An optional file path, file handle, or byte string
for the configuration file.
"""
self._reset_config()

if not config_path:
config_path = os.path.join(
Expand All @@ -66,35 +93,25 @@ def load(self, config_path=None):

try:
with open(config_path, "rb") as config_file:
config = yaml.safe_load(config_file)
self.load_yaml_string(config_file)
except EnvironmentError:
raise exceptions.ConfigNotFoundError(
f"Couldn't read config at {config_path}"
)

def load_yaml_string(self, yaml_string) -> None:
"""Load and parse a yaml configuration string or file-like object.

:param yaml_string: A string or file-like object containing yaml formatted configuration.
"""
self._reset_config()

try:
config = yaml.safe_load(yaml_string)
except yaml.YAMLError:
raise exceptions.ConfigSyntaxError("Error parsing YAML")

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)

if not self._printer_name or not hasattr(printer, self._printer_name):
raise exceptions.ConfigSyntaxError(
f'Printer type "{self._printer_name}" is invalid'
)

self._has_loaded = True
self._set_config(config)

def printer(self):
"""Return a printer that was defined in the config.
Expand Down
60 changes: 53 additions & 7 deletions test/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
import escpos.exceptions


def generate_dummy_config(path, content=None):
def generate_dummy_config(path, content=None) -> None:
"""Generate a dummy config in path"""
dummy_config_content = content
if not content:
Expand All @@ -23,15 +23,15 @@ def generate_dummy_config(path, content=None):
assert path.read_text() == dummy_config_content


def simple_printer_test(config):
def simple_printer_test(config) -> None:
"""Simple test for the dummy printer."""
p = config.printer()
p._raw(b"1234")

assert p.output == b"1234"


def test_config_load_with_invalid_config_yaml(tmp_path):
def test_config_load_with_invalid_config_yaml(tmp_path) -> None:
"""Test the loading of a config with a invalid config file (yaml issue)."""
# generate a dummy config
config_file = tmp_path / "config.yaml"
Expand All @@ -45,7 +45,7 @@ def test_config_load_with_invalid_config_yaml(tmp_path):
c.load(config_path=config_file)


def test_config_load_with_invalid_config_content(tmp_path):
def test_config_load_with_invalid_config_content(tmp_path) -> None:
"""Test the loading of a config with a invalid config file (content issue)."""
# generate a dummy config
config_file = tmp_path / "config.yaml"
Expand All @@ -61,7 +61,7 @@ def test_config_load_with_invalid_config_content(tmp_path):
c.load(config_path=config_file)


def test_config_load_with_missing_config(tmp_path):
def test_config_load_with_missing_config(tmp_path) -> None:
"""Test the loading of a config that does not exist."""
# test the config loading
from escpos import config
Expand Down Expand Up @@ -94,7 +94,7 @@ def test_config_load_from_appdir() -> None:
simple_printer_test(c)


def test_config_load_with_file(tmp_path):
def test_config_load_with_file(tmp_path) -> None:
"""Test the loading of a config with a config file."""
# generate a dummy config
config_file = tmp_path / "config.yaml"
Expand All @@ -110,7 +110,7 @@ def test_config_load_with_file(tmp_path):
simple_printer_test(c)


def test_config_load_with_path(tmp_path):
def test_config_load_with_path(tmp_path) -> None:
"""Test the loading of a config with a config path."""
# generate a dummy config
config_file = tmp_path / "config.yaml"
Expand All @@ -124,3 +124,49 @@ def test_config_load_with_path(tmp_path):

# test the resulting printer object
simple_printer_test(c)


def test_config_load_yaml_string_with_invalid_config_yaml() -> None:
"""Invalid YAML string should raise ConfigSyntaxError."""
from escpos import config

c = config.Config()
with pytest.raises(escpos.exceptions.ConfigSyntaxError):
c.load_yaml_string("}invalid}yaml}")


def test_config_load_yaml_string_with_invalid_config_content() -> None:
"""Invalid content should raise ConfigSyntaxError."""
from escpos import config

c = config.Config()
with pytest.raises(escpos.exceptions.ConfigSyntaxError):
c.load_yaml_string("printer:\n type: NoPrinterWithThatName\n")


def test_config_load_yaml_string_with_valid_config() -> None:
"""Valid YAML string should produce a Dummy printer."""
from escpos import config

c = config.Config()
c.load_yaml_string("printer:\n type: Dummy\n")
simple_printer_test(c)


def test_config_load_with_empty_printer_section() -> None:
"""Config with an empty printer section should raise ConfigSyntaxError."""
from escpos import config

c = config.Config()
with pytest.raises(escpos.exceptions.ConfigSyntaxError):
c.load_yaml_string("printer: {}")


def test_config_load_yaml_string_without_printer_section() -> None:
"""Config without a printer section should raise ConfigSectionMissingError."""
from escpos import config

c = config.Config()
c.load_yaml_string("{}")
with pytest.raises(escpos.exceptions.ConfigSectionMissingError):
c.printer()
Loading