Skip to content

Commit

Permalink
Output formatting (f-strings).
Browse files Browse the repository at this point in the history
  • Loading branch information
peteradrichem committed Jan 8, 2025
1 parent 1013b0f commit 805d7e7
Show file tree
Hide file tree
Showing 13 changed files with 76 additions and 74 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/code-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: code checks

on:
push:
branches: [ "py3k" ]
branches: [ "main", "py3k" ]
pull_request:
branches: [ "main" ]

Expand All @@ -27,7 +27,7 @@ jobs:
pip install .[test]
- name: Lint checks (Ruff)
run: |
ruff check --output-format=github --diff
ruff check --output-format=github
- name: Import sort checks (isort)
run: |
isort --check --diff .
Expand Down
2 changes: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ Xul -- XML Utilities
:alt: Documentation

.. image:: https://github.com/peteradrichem/Xul/actions/workflows/code-checks.yml/badge.svg
:target: https://github.com/peteradrichem/Xul/
:target: https://github.com/peteradrichem/Xul/actions/workflows/code-checks.yml
:alt: Code checks

Xul is a set of XML scripts written in Python.
Expand Down
8 changes: 6 additions & 2 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,14 @@ Changelog

This document records all notable changes to `Xul <https://xul.readthedocs.io/>`_.

`Unreleased <https://github.com/peteradrichem/Xul/compare/2.5.1...py3k>`_ (2025-01-04)
`Unreleased <https://github.com/peteradrichem/Xul/compare/2.5.1...py3k>`_ (2025-01-08)
--------------------------------------------------------------------------------------
* Drop support for Python < 3.9.
* Tooling: ruff, black, isort, mypy.
* Code checks: ruff, black, isort, mypy.
* Updated Sphinx configuration.
* Test script for local testing with Docker Compose.
* GitHub Action: code checks.
* Output formatting (f-strings).

`2.5.1 <https://github.com/peteradrichem/Xul/compare/2.5.0...2.5.1>`_ (2024-12-26)
----------------------------------------------------------------------------------
Expand Down
9 changes: 5 additions & 4 deletions docs/conf.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# Configuration file for the Sphinx documentation builder.
#
# For the full list of built-in configuration values, see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html
"""Configuration file for the Sphinx documentation builder.
For the full list of built-in configuration values, see the documentation:
https://www.sphinx-doc.org/en/master/usage/configuration.html
"""

from datetime import datetime

Expand Down
2 changes: 1 addition & 1 deletion docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ Current version: |release|
:alt: Documentation

.. image:: https://github.com/peteradrichem/Xul/actions/workflows/code-checks.yml/badge.svg
:target: https://github.com/peteradrichem/Xul/
:target: https://github.com/peteradrichem/Xul/actions/workflows/code-checks.yml
:alt: Code checks

.. index::
Expand Down
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ test = [
"lxml-stubs~=0.5.1",
"mypy~=1.14.1",
"ruff~=0.8.6",
"types-Pygments~=2.18",
"types-Pygments~=2.19",
]
syntax = [
"Pygments>=2.7"
Expand Down Expand Up @@ -85,6 +85,7 @@ pretty = true

[tool.ruff]
cache-dir = "/tmp/.ruff_cache"
exclude = ["build/"]
include = ["pyproject.toml", "*.py"]
line-length = 100

Expand Down
2 changes: 1 addition & 1 deletion src/xul/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@
"""

# Xul version.
__version_info__ = ("3", "0", "0-beta")
__version_info__ = ("3", "0", "0-beta1")
__version__ = ".".join(__version_info__)
4 changes: 2 additions & 2 deletions src/xul/cmd/transform.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ def print_result(result):
pass
except LookupError as e:
# LookupError: unknown encoding: UCS-4.
sys.stderr.write("Cannot print XSLT result (LookupError): %s\n" % e)
sys.stderr.write(f"Cannot print XSLT result (LookupError): {e}\n")


def save_to_file(result, target_file):
Expand All @@ -63,7 +63,7 @@ def save_to_file(result, target_file):
with open(target_file, file_mode) as file_object:
file_object.write(result)
except OSError as e:
sys.stderr.write("Saving result to %s failed: %s\n" % (target_file, e.strerror))
sys.stderr.write(f"Saving result to {target_file} failed: {e.strerror}\n")
sys.exit(80)


Expand Down
87 changes: 44 additions & 43 deletions src/xul/cmd/xp.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,25 +100,22 @@ def parse_cl():

def xpath_class(el_tree, xpath_exp, ns_map):
"""XPath with lxml.etree.XPath class."""
xpath_obj = build_xpath(xpath_exp, ns_map)
if not xpath_obj:
return None
return etree_xpath(el_tree, xpath_obj)
if xpath_obj := build_xpath(xpath_exp, ns_map):
return etree_xpath(el_tree, xpath_obj)
return None


def eltree_xpath(el_tree, xpath_exp, ns_map):
"""XPath with lxml.etree.ElementTree.xpath method."""
try:
xp_result = el_tree.xpath(xpath_exp, namespaces=ns_map)
return el_tree.xpath(xpath_exp, namespaces=ns_map)
except XPathEvalError as e:
sys.stderr.write("XPath '%s' evaluation error: %s\n" % (xpath_exp, e))
sys.stderr.write(f"{e}: {xpath_exp}\n")
return None
# EXSLT function call errors (re:test positional arguments).
except TypeError as e:
sys.stderr.write("XPath '%s' type error: %s\n" % (xpath_exp, e))
sys.stderr.write(f"Type error {e}: {xpath_exp}\n")
return None
else:
return xp_result


def xp_prepare(args):
Expand All @@ -145,12 +142,12 @@ def xp_prepare(args):
def print_xmlns(ns_map, root):
"""Print XML namespaces."""
if None in root.nsmap:
print("Default XML namespace URI: %s" % root.nsmap[None])
print(f"Default XML namespace URI: {root.nsmap[None]}")
if ns_map:
# Print all XML namespaces -- prefix: namespace URI.
print("XML namespaces:")
for key in ns_map:
print("%8s: %s" % (key, ns_map[key]))
print(f"{key:>9}: {ns_map[key]}")


def element_repr(node, content=True):
Expand All @@ -170,13 +167,13 @@ def element_repr(node, content=True):
elif node.tag is Comment:
elem_str = node.tag(" comment ")
else:
elem_str = "<%s>" % node.tag
elem_str = f"<{node.tag}>"
return elem_str

# node.tag is lxml.etree.PI (is lxml.etree.ProcessingInstruction).
if node.tag is PI:
# Processing instruction node - node.target -- node.tag(): <? ?>
return "%s value: '%s'" % (node.tag(node.target), node.text)
return f"{node.tag(node.target)} value: '{node.text}'"

# node.tag is lxml.etree.Comment.
if node.tag is Comment:
Expand All @@ -186,15 +183,13 @@ def element_repr(node, content=True):
# node.tag: string.
if node.text:
if node.text.isspace():
elem_str = "<%s> contains whitespace" % node.tag
elif not isinstance(node.text, str):
return f"<{node.tag}> contains whitespace"
if not isinstance(node.text, str):
# Python 2 Unicode naar Bytestring.
elem_str = "<%s> contains '%s'" % (node.tag, node.text.encode("utf-8"))
else:
# node.text is a Python string.
elem_str = "<%s> contains '%s'" % (node.tag, node.text)
return elem_str
return "<%s> is empty" % node.tag
return f"<{node.tag}> contains {node.text.encode('utf-8')}"
# node.text is a Python string.
return f"<{node.tag}> contains whitespace"
return f"<{node.tag}> is empty"


def print_elem(node, pretty=False, xpath_exp=None):
Expand All @@ -208,16 +203,15 @@ def print_elem(node, pretty=False, xpath_exp=None):
"""
if pretty:
if xpath_exp:
print("XPath %s (line %d):" % (xpath_exp, node.sourceline))
print(f"XPath {xpath_exp} (line {node.sourceline}):")
else:
print("line %d:" % node.sourceline)
print(f"line {node.sourceline}:")
prettyprint(node, xml_declaration=False)
else:
if xpath_exp:
print("XPath %s (line %d):" % (xpath_exp, node.sourceline))
print(" %s" % element_repr(node))
print(f"XPath {xpath_exp} (line {node.sourceline}):\n {element_repr(node)}")
else:
print("line %4d: %s" % (node.sourceline, element_repr(node)))
print(f"line {node.sourceline:<4d}: {element_repr(node)}")


def smart_with_parent(smart_string):
Expand All @@ -233,22 +227,22 @@ def smart_with_parent(smart_string):
# ATTRIBUTE node -- @ -- .is_attribute
if smart_string.is_attribute:
parent_rel = "of"
smart_repr = "@%s = '%s'" % (smart_string.attrname, smart_string)
smart_repr = f"@{smart_string.attrname} = '{smart_string}'"
# TEXT node -- text() -- .is_text
elif smart_string.is_text:
parent_rel = "in"
# Python str.isspace()
if smart_string.isspace():
smart_repr = "whitespace"
else:
smart_repr = "'%s'" % smart_string
smart_repr = f"'{smart_string}'"
# TAIL node -- text() -- .is_tail
elif smart_string.is_tail:
parent_rel = "after"
if smart_string.isspace():
smart_repr = "tail whitespace"
else:
smart_repr = "tail '%s'" % smart_string
smart_repr = f"tail '{smart_string}'"

return (smart_repr, parent_rel)

Expand All @@ -266,7 +260,7 @@ def print_smart_string(smart_string, el_tree, args):
par_el = smart_string.getparent()
# string() and concat() results do not have an origin.
if par_el is None:
print("XPath string: '%s'" % smart_string)
print(f"XPath string: '{smart_string}'")
return
# Parent is an lxml.etree._Element instance.
par_el_str = element_repr(par_el, content=False)
Expand All @@ -276,12 +270,14 @@ def print_smart_string(smart_string, el_tree, args):
if smart_repr:
if args.result_xpath:
# Print the absolute XPath expression of the parent element.
print("line %d, parent XPath %s" % (par_el.sourceline, el_tree.getpath(par_el)))
print(" %s %s %s" % (smart_repr, parent_rel, par_el_str))
print(
f"line {par_el.sourceline}, parent XPath {el_tree.getpath(par_el)}\n"
f" {smart_repr} {parent_rel} {par_el_str}"
)
else:
print("line %4d: %s %s %s" % (par_el.sourceline, smart_repr, parent_rel, par_el_str))
print(f"line {par_el.sourceline:<4d}: {smart_repr} {parent_rel} {par_el_str}")
else:
print("**smart string DEBUG fallback**")
sys.stderr.write("Unable to print smart string\n")
print_elem(par_el, pretty=args.pretty_element)


Expand All @@ -306,8 +302,9 @@ def print_result_list(result_list, el_tree, args):

# Namespaces -- namespace::
elif isinstance(node, tuple):
prefix, uri = node
# No line number.
print("prefix: %-8s URI: %s" % node)
print(f"prefix: {str(prefix):<8} URI: {uri}")

# ?
else:
Expand All @@ -318,15 +315,17 @@ def print_result_list(result_list, el_tree, args):

def print_result_header(source_name, xp_result):
"""Print header with XPath result summary."""
print("%s:" % source_name, end=" ")
# XPath result summary.
# Result count.
if isinstance(xp_result, list):
list_result = xp_result
xp_r_len = len(list_result)
else:
# String, number, boolean.
list_result = [xp_result]
xp_r_len = 1

# XPath result summary.
print(f"{source_name}:", end=" ")
if xp_r_len == 0:
print("no results.")
elif xp_r_len == 1:
Expand All @@ -336,9 +335,9 @@ def print_result_header(source_name, xp_result):
print("1 result.")
else:
if isinstance(list_result[0], tuple):
print("%d XML namespace results." % xp_r_len)
print(f"{xp_r_len} XML namespace results.")
else:
print("%d results." % xp_r_len)
print(f"{xp_r_len} results.")


def print_xp_result(xp_result, el_tree, ns_map, args):
Expand Down Expand Up @@ -381,19 +380,21 @@ def print_xp_result(xp_result, el_tree, ns_map, args):
elif hasattr(xp_result, "is_integer"):
# pylint: disable=comparison-with-itself ## NaN elif.
if xp_result.is_integer():
print("XPath number: %i" % xp_result)
# count() => integer
print(f"XPath number: {int(xp_result)}")
# float('nan') != float('nan') -- IEEE 754.
elif xp_result != xp_result:
print("XPath result: NaN (not a number)")
# float.
else:
print("XPath number: %s" % xp_result)
print(f"XPath number: {xp_result}")

# BOOLEAN - bool - boolean.
elif isinstance(xp_result, bool):
print("XPath test: %s" % xp_result)
print(f"XPath test: {xp_result}")

else:
print("Unknown XPath result: %s" % xp_result)
print(f"Unknown XPath result: {xp_result}")


def xpath_on_xml(xml_source, parser, xpath_fn, args):
Expand Down
8 changes: 5 additions & 3 deletions src/xul/log.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ def lvl_name2num(name):


def setup_logger(log_level="debug", propagate=True):
"""Configureer threshold log level van de root logger.
"""Configure the rool logger.
Configureer threshold log level van de root logger.
log_level -- threshold log level
propagate -- messages doorgeven naar boven [default: ja]
Expand All @@ -50,7 +52,7 @@ def setup_logger(log_level="debug", propagate=True):


def customize_handler(handler, level, fmt=None, datefmt=None):
"""Configureer level en formatering van een log message handler.
"""Configure log level and formatting of the log message handler.
handler -- log message handler (StreamHandler, FileHandler ...)
level -- log level voor de handler
Expand All @@ -70,7 +72,7 @@ def customize_handler(handler, level, fmt=None, datefmt=None):


def setup_logger_console(log_level="info"):
"""Setup de root logger en koppel de console handler.
"""Set up the root logger and add console handler.
log_level -- console log level [default 'info']
Expand Down
2 changes: 1 addition & 1 deletion src/xul/validate.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ def xml_validator(xml_source, validator, lenient=True):
val_logger("line %i, column %i: %s", e.line, e.column, e.message)
# Return the status string: first validation error.
e = validator.error_log[0]
return (False, "line %i, column %i: %s" % (e.line, e.column, e.message))
return (False, f"line {e.line}, column {e.column}: {e.message}")


def build_relaxng(relaxng_file):
Expand Down
Loading

0 comments on commit 805d7e7

Please sign in to comment.