txtresults.py 3.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. from __future__ import annotations
  2. from io import StringIO
  3. from typing import IO, List, Optional, Union
  4. from rdflib.namespace import NamespaceManager
  5. from rdflib.query import ResultSerializer
  6. from rdflib.term import BNode, Literal, URIRef, Variable
  7. def _termString(
  8. t: Optional[Union[URIRef, Literal, BNode]],
  9. namespace_manager: Optional[NamespaceManager],
  10. ) -> str:
  11. if t is None:
  12. return "-"
  13. if namespace_manager:
  14. if isinstance(t, URIRef):
  15. return namespace_manager.normalizeUri(t)
  16. elif isinstance(t, BNode):
  17. return t.n3()
  18. elif isinstance(t, Literal):
  19. return t._literal_n3(qname_callback=namespace_manager.normalizeUri)
  20. else:
  21. return t.n3()
  22. class TXTResultSerializer(ResultSerializer):
  23. """
  24. A write-only QueryResult serializer for text/ascii tables
  25. """
  26. def serialize(
  27. self,
  28. stream: IO,
  29. encoding: str = "utf-8",
  30. *,
  31. namespace_manager: Optional[NamespaceManager] = None,
  32. **kwargs,
  33. ) -> None:
  34. """
  35. return a text table of query results
  36. """
  37. def c(s, w):
  38. """
  39. center the string s in w wide string
  40. """
  41. w -= len(s)
  42. h1 = h2 = w // 2
  43. if w % 2:
  44. h2 += 1
  45. return " " * h1 + s + " " * h2
  46. if self.result.type != "SELECT":
  47. raise Exception("Can only pretty print SELECT results!")
  48. string_stream = StringIO()
  49. if not self.result:
  50. string_stream.write("(no results)\n")
  51. else:
  52. keys: List[Variable] = self.result.vars # type: ignore[assignment]
  53. maxlen = [0] * len(keys)
  54. b = [
  55. # type error: Value of type "Union[Tuple[Node, Node, Node], bool, ResultRow]" is not indexable
  56. # type error: Argument 1 to "_termString" has incompatible type "Union[Node, Any]"; expected "Union[URIRef, Literal, BNode, None]" [arg-type]
  57. # type error: No overload variant of "__getitem__" of "tuple" matches argument type "Variable"
  58. # NOTE on type error: The problem here is that r can be more types than _termString expects because result can be a result of multiple types.
  59. [_termString(r[k], namespace_manager) for k in keys] # type: ignore[index, arg-type, call-overload]
  60. for r in self.result
  61. ]
  62. for r in b:
  63. for i in range(len(keys)):
  64. maxlen[i] = max(maxlen[i], len(r[i]))
  65. string_stream.write(
  66. "|".join([c(k, maxlen[i]) for i, k in enumerate(keys)]) + "\n"
  67. )
  68. string_stream.write("-" * (len(maxlen) + sum(maxlen)) + "\n")
  69. for r in sorted(b):
  70. string_stream.write(
  71. "|".join([t + " " * (i - len(t)) for i, t in zip(maxlen, r)]) + "\n"
  72. )
  73. text_val = string_stream.getvalue()
  74. try:
  75. stream.write(text_val.encode(encoding))
  76. except (TypeError, ValueError):
  77. stream.write(text_val)