Funktionierender Prototyp des Serious Games zur Vermittlung von Wissen zu Software-Engineering-Arbeitsmodellen.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1 year ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. # -*- test-case-name: twisted.logger.test.test_io -*-
  2. # Copyright (c) Twisted Matrix Laboratories.
  3. # See LICENSE for details.
  4. """
  5. File-like object that logs.
  6. """
  7. import sys
  8. from typing import AnyStr, Iterable, Optional
  9. from constantly import NamedConstant # type: ignore[import]
  10. from incremental import Version
  11. from twisted.python.deprecate import deprecatedProperty
  12. from ._levels import LogLevel
  13. from ._logger import Logger
  14. class LoggingFile:
  15. """
  16. File-like object that turns C{write()} calls into logging events.
  17. Note that because event formats are L{str}, C{bytes} received via C{write()}
  18. are converted to C{str}, which is the opposite of what C{file} does.
  19. @ivar softspace: Attribute to make this class more file-like under Python 2;
  20. value is zero or one. Do not use.
  21. """
  22. _softspace = 0
  23. @deprecatedProperty(Version("Twisted", 21, 2, 0))
  24. def softspace(self):
  25. return self._softspace
  26. @softspace.setter # type: ignore[no-redef]
  27. def softspace(self, value):
  28. self._softspace = value
  29. def __init__(
  30. self,
  31. logger: Logger,
  32. level: NamedConstant = LogLevel.info,
  33. encoding: Optional[str] = None,
  34. ) -> None:
  35. """
  36. @param logger: the logger to log through.
  37. @param level: the log level to emit events with.
  38. @param encoding: The encoding to expect when receiving bytes via
  39. C{write()}. If L{None}, use C{sys.getdefaultencoding()}.
  40. """
  41. self.level = level
  42. self.log = logger
  43. if encoding is None:
  44. self._encoding = sys.getdefaultencoding()
  45. else:
  46. self._encoding = encoding
  47. self._buffer = ""
  48. self._closed = False
  49. @property
  50. def closed(self) -> bool:
  51. """
  52. Read-only property. Is the file closed?
  53. @return: true if closed, otherwise false.
  54. """
  55. return self._closed
  56. @property
  57. def encoding(self) -> str:
  58. """
  59. Read-only property. File encoding.
  60. @return: an encoding.
  61. """
  62. return self._encoding
  63. @property
  64. def mode(self) -> str:
  65. """
  66. Read-only property. File mode.
  67. @return: "w"
  68. """
  69. return "w"
  70. @property
  71. def newlines(self) -> None:
  72. """
  73. Read-only property. Types of newlines encountered.
  74. @return: L{None}
  75. """
  76. return None
  77. @property
  78. def name(self) -> str:
  79. """
  80. The name of this file; a repr-style string giving information about its
  81. namespace.
  82. @return: A file name.
  83. """
  84. return "<{} {}#{}>".format(
  85. self.__class__.__name__,
  86. self.log.namespace,
  87. self.level.name,
  88. )
  89. def close(self) -> None:
  90. """
  91. Close this file so it can no longer be written to.
  92. """
  93. self._closed = True
  94. def flush(self) -> None:
  95. """
  96. No-op; this file does not buffer.
  97. """
  98. pass
  99. def fileno(self) -> int:
  100. """
  101. Returns an invalid file descriptor, since this is not backed by an FD.
  102. @return: C{-1}
  103. """
  104. return -1
  105. def isatty(self) -> bool:
  106. """
  107. A L{LoggingFile} is not a TTY.
  108. @return: C{False}
  109. """
  110. return False
  111. def write(self, message: AnyStr) -> None:
  112. """
  113. Log the given message.
  114. @param message: The message to write.
  115. """
  116. if self._closed:
  117. raise ValueError("I/O operation on closed file")
  118. if isinstance(message, bytes):
  119. text = message.decode(self._encoding)
  120. else:
  121. text = message
  122. lines = (self._buffer + text).split("\n")
  123. self._buffer = lines[-1]
  124. lines = lines[0:-1]
  125. for line in lines:
  126. self.log.emit(self.level, format="{log_io}", log_io=line)
  127. def writelines(self, lines: Iterable[AnyStr]) -> None:
  128. """
  129. Log each of the given lines as a separate message.
  130. @param lines: Data to write.
  131. """
  132. for line in lines:
  133. self.write(line)
  134. def _unsupported(self, *args: object) -> None:
  135. """
  136. Template for unsupported operations.
  137. @param args: Arguments.
  138. """
  139. raise OSError("unsupported operation")
  140. read = _unsupported
  141. next = _unsupported
  142. readline = _unsupported
  143. readlines = _unsupported
  144. xreadlines = _unsupported
  145. seek = _unsupported
  146. tell = _unsupported
  147. truncate = _unsupported