Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 44 additions & 27 deletions src/escpos/config.py
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()