How to use _GetFormatter method in autotest

Best Python code snippet using autotest_python

Hdf5Item.py

Source:Hdf5Item.py Github

copy

Full Screen

1# /*##########################################################################2#3# Copyright (c) 2016-2019 European Synchrotron Radiation Facility4#5# Permission is hereby granted, free of charge, to any person obtaining a copy6# of this software and associated documentation files (the "Software"), to deal7# in the Software without restriction, including without limitation the rights8# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell9# copies of the Software, and to permit persons to whom the Software is10# furnished to do so, subject to the following conditions:11#12# The above copyright notice and this permission notice shall be included in13# all copies or substantial portions of the Software.14#15# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR16# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,17# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE18# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER19# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,20# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN21# THE SOFTWARE.22#23# ###########################################################################*/24__authors__ = ["V. Valls"]25__license__ = "MIT"26__date__ = "17/01/2019"27import logging28import collections29import enum30from typing import Optional31from .. import qt32from .. import icons33from . import _utils34from .Hdf5Node import Hdf5Node35import silx.io.utils36from silx.gui.data.TextFormatter import TextFormatter37from ..hdf5.Hdf5Formatter import Hdf5Formatter38_logger = logging.getLogger(__name__)39_formatter = TextFormatter()40_hdf5Formatter = Hdf5Formatter(textFormatter=_formatter)41# FIXME: The formatter should be an attribute of the Hdf5Model42class DescriptionType(enum.Enum):43 """List of available kind of description.44 """45 ERROR = "error"46 DESCRIPTION = "description"47 TITLE = "title"48 PROGRAM = "program"49 NAME = "name"50 VALUE = "value"51class Hdf5Item(Hdf5Node):52 """Subclass of :class:`qt.QStandardItem` to represent an HDF5-like53 item (dataset, file, group or link) as an element of a HDF5-like54 tree structure.55 """56 def __init__(57 self,58 text: Optional[str],59 obj,60 parent,61 key=None,62 h5Class=None,63 linkClass=None,64 populateAll=False,65 openedPath: Optional[str] = None,66 ):67 """68 :param text: text displayed69 :param object obj: Pointer to a h5py-link object. See the `obj` attribute.70 :param openedPath: The path with which the item was opened if any71 """72 self.__obj = obj73 self.__key = key74 self.__h5Class = h5Class75 self.__isBroken = obj is None and h5Class is None76 self.__error = None77 self.__text = text78 self.__linkClass = linkClass79 self.__description = None80 self.__nx_class = None81 Hdf5Node.__init__(self, parent, populateAll=populateAll, openedPath=openedPath)82 def _getCanonicalName(self):83 parent = self.parent84 if parent is None:85 return self.__text86 else:87 return "%s/%s" % (parent._getCanonicalName(), self.__text)88 @property89 def obj(self):90 if self.__key:91 self.__initH5Object()92 return self.__obj93 @property94 def basename(self):95 return self.__text96 @property97 def h5Class(self):98 """Returns the class of the stored object.99 When the object is in lazy loading, this method should be able to100 return the type of the future loaded object. It allows to delay the101 real load of the object.102 :rtype: silx.io.utils.H5Type103 """104 if self.__h5Class is None and self.obj is not None:105 self.__h5Class = silx.io.utils.get_h5_class(self.obj)106 return self.__h5Class107 @property108 def h5pyClass(self):109 """Returns the class of the stored object.110 When the object is in lazy loading, this method should be able to111 return the type of the future loaded object. It allows to delay the112 real load of the object.113 :rtype: h5py.File or h5py.Dataset or h5py.Group114 """115 type_ = self.h5Class116 return silx.io.utils.h5type_to_h5py_class(type_)117 @property118 def linkClass(self):119 """Returns the link class object of this node120 :rtype: H5Type121 """122 return self.__linkClass123 def isGroupObj(self):124 """Returns true if the stored HDF5 object is a group (contains sub125 groups or datasets).126 :rtype: bool127 """128 if self.h5Class is None:129 return False130 return self.h5Class in [silx.io.utils.H5Type.GROUP, silx.io.utils.H5Type.FILE]131 def isBrokenObj(self):132 """Returns true if the stored HDF5 object is broken.133 The stored object is then an h5py-like link (external or not) which134 point to nowhere (tbhe external file is not here, the expected135 dataset is still not on the file...)136 :rtype: bool137 """138 return self.__isBroken139 def _getFormatter(self):140 """141 Returns an Hdf5Formatter142 :rtype: Hdf5Formatter143 """144 return _hdf5Formatter145 def _expectedChildCount(self):146 if self.isGroupObj():147 return len(self.obj)148 return 0149 def __initH5Object(self):150 """Lazy load of the HDF5 node. It is reached from the parent node151 with the key of the node."""152 parent_obj = self.parent.obj153 try:154 obj = parent_obj.get(self.__key)155 except Exception as e:156 _logger.error("Internal error while reaching HDF5 object: %s", str(e))157 _logger.debug("Backtrace", exc_info=True)158 try:159 self.__obj = parent_obj.get(self.__key, getlink=True)160 except Exception:161 self.__obj = None162 self.__error = e.args[0]163 self.__isBroken = True164 else:165 if obj is None:166 # that's a broken link167 self.__obj = parent_obj.get(self.__key, getlink=True)168 # TODO monkey-patch file (ask that in h5py for consistency)169 if not hasattr(self.__obj, "name"):170 parent_name = parent_obj.name171 if parent_name == "/":172 self.__obj.name = "/" + self.__key173 else:174 self.__obj.name = parent_name + "/" + self.__key175 # TODO monkey-patch file (ask that in h5py for consistency)176 if not hasattr(self.__obj, "file"):177 self.__obj.file = parent_obj.file178 class_ = silx.io.utils.get_h5_class(self.__obj)179 if class_ == silx.io.utils.H5Type.EXTERNAL_LINK:180 message = "External link broken. Path %s::%s does not exist" % (self.__obj.filename, self.__obj.path)181 elif class_ == silx.io.utils.H5Type.SOFT_LINK:182 message = "Soft link broken. Path %s does not exist" % (self.__obj.path)183 else:184 name = self.__obj.__class__.__name__.split(".")[-1].capitalize()185 message = "%s broken" % (name)186 self.__error = message187 self.__isBroken = True188 else:189 self.__obj = obj190 if silx.io.utils.get_h5_class(obj) not in [silx.io.utils.H5Type.GROUP, silx.io.utils.H5Type.FILE]:191 try:192 # pre-fetch of the data193 if obj.shape is None:194 pass195 elif obj.shape == tuple():196 obj[()]197 else:198 if obj.compression is None and obj.size > 0:199 key = tuple([0] * len(obj.shape))200 obj[key]201 except Exception as e:202 _logger.debug(e, exc_info=True)203 message = "%s broken. %s" % (self.__obj.name, e.args[0])204 self.__error = message205 self.__isBroken = True206 self.__key = None207 def _populateChild(self, populateAll=False):208 if self.isGroupObj():209 keys = []210 try:211 for name in self.obj:212 keys.append(name)213 except Exception:214 lib_name = self.obj.__class__.__module__.split(".")[0]215 _logger.error("Internal %s error. The file is corrupted.", lib_name)216 _logger.debug("Backtrace", exc_info=True)217 if keys == []:218 # If the file was open in READ_ONLY we still can reach something219 # https://github.com/silx-kit/silx/issues/2262220 try:221 for name in self.obj:222 keys.append(name)223 except Exception:224 lib_name = self.obj.__class__.__module__.split(".")[0]225 _logger.error("Internal %s error (second time). The file is corrupted.", lib_name)226 _logger.debug("Backtrace", exc_info=True)227 for name in keys:228 try:229 class_ = self.obj.get(name, getclass=True)230 link = self.obj.get(name, getclass=True, getlink=True)231 link = silx.io.utils.get_h5_class(class_=link)232 except Exception:233 lib_name = self.obj.__class__.__module__.split(".")[0]234 _logger.error("Internal %s error", lib_name)235 _logger.debug("Backtrace", exc_info=True)236 class_ = None237 try:238 link = self.obj.get(name, getclass=True, getlink=True)239 link = silx.io.utils.get_h5_class(class_=link)240 except Exception:241 _logger.debug("Backtrace", exc_info=True)242 link = silx.io.utils.H5Type.HARD_LINK243 h5class = None244 if class_ is not None:245 h5class = silx.io.utils.get_h5_class(class_=class_)246 if h5class is None:247 _logger.error("Class %s unsupported", class_)248 item = Hdf5Item(text=name, obj=None, parent=self, key=name, h5Class=h5class, linkClass=link)249 self.appendChild(item)250 def hasChildren(self):251 """Retuens true of this node have chrild.252 :rtype: bool253 """254 if not self.isGroupObj():255 return False256 return Hdf5Node.hasChildren(self)257 def _getDefaultIcon(self):258 """Returns the icon displayed by the main column.259 :rtype: qt.QIcon260 """261 # Pre-fetch the object, in case it is broken262 obj = self.obj263 style = qt.QApplication.style()264 if self.__isBroken:265 icon = style.standardIcon(qt.QStyle.SP_MessageBoxCritical)266 return icon267 class_ = self.h5Class268 if class_ == silx.io.utils.H5Type.FILE:269 return style.standardIcon(qt.QStyle.SP_FileIcon)270 elif class_ == silx.io.utils.H5Type.GROUP:271 return style.standardIcon(qt.QStyle.SP_DirIcon)272 elif class_ == silx.io.utils.H5Type.SOFT_LINK:273 return style.standardIcon(qt.QStyle.SP_DirLinkIcon)274 elif class_ == silx.io.utils.H5Type.EXTERNAL_LINK:275 return style.standardIcon(qt.QStyle.SP_FileLinkIcon)276 elif class_ == silx.io.utils.H5Type.DATASET:277 if obj.shape is None:278 name = "item-none"279 elif len(obj.shape) < 4:280 name = "item-%ddim" % len(obj.shape)281 else:282 name = "item-ndim"283 icon = icons.getQIcon(name)284 return icon285 return None286 def _createTooltipAttributes(self):287 """288 Add key/value attributes that will be displayed in the item tooltip289 :param Dict[str,str] attributeDict: Key/value attributes290 """291 attributeDict = collections.OrderedDict()292 if self.h5Class == silx.io.utils.H5Type.DATASET:293 attributeDict["#Title"] = "HDF5 Dataset"294 attributeDict["Name"] = self.basename295 attributeDict["Path"] = self.obj.name296 attributeDict["Shape"] = self._getFormatter().humanReadableShape(self.obj)297 attributeDict["Value"] = self._getFormatter().humanReadableValue(self.obj)298 attributeDict["Data type"] = self._getFormatter().humanReadableType(self.obj, full=True)299 elif self.h5Class == silx.io.utils.H5Type.GROUP:300 attributeDict["#Title"] = "HDF5 Group"301 if self.nexusClassName:302 attributeDict["NX_class"] = self.nexusClassName303 attributeDict["Name"] = self.basename304 attributeDict["Path"] = self.obj.name305 elif self.h5Class == silx.io.utils.H5Type.FILE:306 attributeDict["#Title"] = "HDF5 File"307 attributeDict["Name"] = self.basename308 attributeDict["Path"] = "/"309 elif self.h5Class == silx.io.utils.H5Type.EXTERNAL_LINK:310 attributeDict["#Title"] = "HDF5 External Link"311 attributeDict["Name"] = self.basename312 attributeDict["Path"] = self.obj.name313 attributeDict["Linked path"] = self.obj.path314 attributeDict["Linked file"] = self.obj.filename315 elif self.h5Class == silx.io.utils.H5Type.SOFT_LINK:316 attributeDict["#Title"] = "HDF5 Soft Link"317 attributeDict["Name"] = self.basename318 attributeDict["Path"] = self.obj.name319 attributeDict["Linked path"] = self.obj.path320 else:321 pass322 return attributeDict323 def _getDefaultTooltip(self):324 """Returns the default tooltip325 :rtype: str326 """327 if self.__error is not None:328 self.obj # lazy loading of the object329 return self.__error330 attrs = self._createTooltipAttributes()331 title = attrs.pop("#Title", None)332 if len(attrs) > 0:333 tooltip = _utils.htmlFromDict(attrs, title=title)334 else:335 tooltip = ""336 return tooltip337 @property338 def nexusClassName(self):339 """Returns the Nexus class name"""340 if self.__nx_class is None:341 obj = self.obj.attrs.get("NX_class", None)342 if obj is None:343 text = ""344 else:345 text = self._getFormatter().textFormatter().toString(obj)346 text = text.strip('"')347 # Check NX_class formatting348 lower = text.lower()349 formatedNX_class = ""350 if lower.startswith('nx'):351 formatedNX_class = 'NX' + lower[2:]352 if lower == 'nxcansas':353 formatedNX_class = 'NXcanSAS' # That's the only class with capital letters...354 if text != formatedNX_class:355 _logger.error("NX_class: '%s' is malformed (should be '%s')",356 text,357 formatedNX_class)358 text = formatedNX_class359 self.__nx_class = text360 return self.__nx_class361 def dataName(self, role):362 """Data for the name column"""363 if role == qt.Qt.TextAlignmentRole:364 return qt.Qt.AlignTop | qt.Qt.AlignLeft365 if role == qt.Qt.DisplayRole:366 return self.__text367 if role == qt.Qt.DecorationRole:368 return self._getDefaultIcon()369 if role == qt.Qt.ToolTipRole:370 return self._getDefaultTooltip()371 return None372 def dataType(self, role):373 """Data for the type column"""374 if role == qt.Qt.DecorationRole:375 return None376 if role == qt.Qt.TextAlignmentRole:377 return qt.Qt.AlignTop | qt.Qt.AlignLeft378 if role == qt.Qt.DisplayRole:379 if self.__error is not None:380 return ""381 class_ = self.h5Class382 if self.isGroupObj():383 text = self.nexusClassName384 elif class_ == silx.io.utils.H5Type.DATASET:385 text = self._getFormatter().humanReadableType(self.obj)386 else:387 text = ""388 return text389 return None390 def dataShape(self, role):391 """Data for the shape column"""392 if role == qt.Qt.DecorationRole:393 return None394 if role == qt.Qt.TextAlignmentRole:395 return qt.Qt.AlignTop | qt.Qt.AlignLeft396 if role == qt.Qt.DisplayRole:397 if self.__error is not None:398 return ""399 class_ = self.h5Class400 if class_ != silx.io.utils.H5Type.DATASET:401 return ""402 return self._getFormatter().humanReadableShape(self.obj)403 return None404 def dataValue(self, role):405 """Data for the value column"""406 if role == qt.Qt.DecorationRole:407 return None408 if role == qt.Qt.TextAlignmentRole:409 return qt.Qt.AlignTop | qt.Qt.AlignLeft410 if role == qt.Qt.DisplayRole:411 if self.__error is not None:412 return ""413 if self.h5Class != silx.io.utils.H5Type.DATASET:414 return ""415 return self._getFormatter().humanReadableValue(self.obj)416 return None417 _NEXUS_CLASS_TO_VALUE_CHILDREN = {418 'NXaperture': (419 (DescriptionType.DESCRIPTION, 'description'),420 ),421 'NXbeam_stop': (422 (DescriptionType.DESCRIPTION, 'description'),423 ),424 'NXdetector': (425 (DescriptionType.NAME, 'local_name'),426 (DescriptionType.DESCRIPTION, 'description')427 ),428 'NXentry': (429 (DescriptionType.TITLE, 'title'),430 ),431 'NXenvironment': (432 (DescriptionType.NAME, 'short_name'),433 (DescriptionType.NAME, 'name'),434 (DescriptionType.DESCRIPTION, 'description')435 ),436 'NXinstrument': (437 (DescriptionType.NAME, 'name'),438 ),439 'NXlog': (440 (DescriptionType.DESCRIPTION, 'description'),441 ),442 'NXmirror': (443 (DescriptionType.DESCRIPTION, 'description'),444 ),445 'NXpositioner': (446 (DescriptionType.NAME, 'name'),447 ),448 'NXprocess': (449 (DescriptionType.PROGRAM, 'program'),450 ),451 'NXsample': (452 (DescriptionType.TITLE, 'short_title'),453 (DescriptionType.NAME, 'name'),454 (DescriptionType.DESCRIPTION, 'description')455 ),456 'NXsample_component': (457 (DescriptionType.NAME, 'name'),458 (DescriptionType.DESCRIPTION, 'description')459 ),460 'NXsensor': (461 (DescriptionType.NAME, 'short_name'),462 (DescriptionType.NAME, 'name')463 ),464 'NXsource': (465 (DescriptionType.NAME, 'name'),466 ), # or its 'short_name' attribute... This is not supported467 'NXsubentry': (468 (DescriptionType.DESCRIPTION, 'definition'),469 (DescriptionType.PROGRAM, 'program_name'),470 (DescriptionType.TITLE, 'title'),471 ),472 }473 """Mapping from NeXus class to child names containing data to use as value"""474 def __computeDataDescription(self):475 """Compute the data description of this item476 :rtype: Tuple[kind, str]477 """478 if self.__isBroken or self.__error is not None:479 self.obj # lazy loading of the object480 return DescriptionType.ERROR, self.__error481 if self.h5Class == silx.io.utils.H5Type.DATASET:482 return DescriptionType.VALUE, self._getFormatter().humanReadableValue(self.obj)483 elif self.isGroupObj() and self.nexusClassName:484 # For NeXus groups, try to find a title or name485 # By default, look for a title (most application definitions should have one)486 defaultSequence = ((DescriptionType.TITLE, 'title'),)487 sequence = self._NEXUS_CLASS_TO_VALUE_CHILDREN.get(self.nexusClassName, defaultSequence)488 for kind, child_name in sequence:489 for index in range(self.childCount()):490 child = self.child(index)491 if (isinstance(child, Hdf5Item) and492 child.h5Class == silx.io.utils.H5Type.DATASET and493 child.basename == child_name):494 return kind, self._getFormatter().humanReadableValue(child.obj)495 description = self.obj.attrs.get("desc", None)496 if description is not None:497 return DescriptionType.DESCRIPTION, description498 else:499 return None, None500 def __getDataDescription(self):501 """Returns a cached version of the data description502 As the data description have to reach inside the HDF5 tree, the result503 is cached. A better implementation could be to use a MRU cache, to avoid504 to allocate too much data.505 :rtype: Tuple[kind, str]506 """507 if self.__description is None:508 self.__description = self.__computeDataDescription()509 return self.__description510 def dataDescription(self, role):511 """Data for the description column"""512 if role == qt.Qt.DecorationRole:513 kind, _label = self.__getDataDescription()514 if kind is not None:515 icon = icons.getQIcon("description-%s" % kind.value)516 return icon517 return None518 if role == qt.Qt.TextAlignmentRole:519 return qt.Qt.AlignTop | qt.Qt.AlignLeft520 if role == qt.Qt.DisplayRole:521 _kind, label = self.__getDataDescription()522 return label523 if role == qt.Qt.ToolTipRole:524 if self.__error is not None:525 self.obj # lazy loading of the object526 self.__initH5Object()527 return self.__error528 kind, label = self.__getDataDescription()529 if label is not None:530 return "<b>%s</b><br/>%s" % (kind.value.capitalize(), label)531 else:532 return ""533 return None534 def dataNode(self, role):535 """Data for the node column"""536 if role == qt.Qt.DecorationRole:537 return None538 if role == qt.Qt.TextAlignmentRole:539 return qt.Qt.AlignTop | qt.Qt.AlignLeft540 if role == qt.Qt.DisplayRole:541 if self.isBrokenObj():542 return ""543 class_ = self.obj.__class__544 text = class_.__name__.split(".")[-1]545 return text546 if role == qt.Qt.ToolTipRole:547 class_ = self.obj.__class__548 if class_ is None:549 return ""550 return "Class name: %s" % self.__class__551 return None552 def dataLink(self, role):553 """Data for the link column554 Overwrite it to implement the content of the 'link' column.555 :rtype: qt.QVariant556 """557 if role == qt.Qt.DecorationRole:558 return None559 if role == qt.Qt.TextAlignmentRole:560 return qt.Qt.AlignTop | qt.Qt.AlignLeft561 if role == qt.Qt.DisplayRole:562 # Mark as link563 link = self.linkClass564 if link is None:565 pass566 elif link == silx.io.utils.H5Type.HARD_LINK:567 pass568 elif link == silx.io.utils.H5Type.EXTERNAL_LINK:569 return "External"570 elif link == silx.io.utils.H5Type.SOFT_LINK:571 return "Soft"572 else:573 return link.__name__574 # Mark as external data575 if self.h5Class == silx.io.utils.H5Type.DATASET:576 obj = self.obj577 if hasattr(obj, "is_virtual"):578 if obj.is_virtual:579 return "Virtual"580 if hasattr(obj, "external"):581 if obj.external:582 return "ExtRaw"583 return ""584 if role == qt.Qt.ToolTipRole:585 return None...

Full Screen

Full Screen

log.py

Source:log.py Github

copy

Full Screen

1"""Loggers and utilities related to logging.2Attributes:3 logger: main logging.Logger object.4"""5import logging6from typing import Any7from funky.utils import xdg8logger = logging.getLogger("funky")9def init_logger(debug: bool = False, verbose: bool = False) -> None:10 """Initializes the main logger.11 Args:12 debug (bool): If True, then set logging level to DEBUG (unless @verbose13 is also set). Also, send log output to file in addition14 to stdout.15 verbose (bool): If True and @debug is True, then set logging level to16 VDEBUG.17 """18 _add_vdebug_level(logging)19 root = logging.getLogger()20 root.handlers.clear() # clear handlers so this function is idempotent21 if debug:22 if verbose:23 level = logging.VDEBUG # type: ignore[attr-defined]24 else:25 level = logging.DEBUG26 else:27 level = logging.INFO28 root.setLevel(level)29 sh = logging.StreamHandler()30 formatter = _getFormatter()31 sh.setFormatter(formatter)32 sh.setLevel(level)33 root.addHandler(sh)34 if debug:35 logfile_path = "{}/debug.log".format(xdg.getdir("data"))36 fh = logging.FileHandler(logfile_path)37 formatter = _getFormatter(verbose=True)38 fh.setFormatter(formatter)39 fh.setLevel(level)40 root.addHandler(fh)41 root.debug("Debug mode enabled.")42def _add_vdebug_level(logging_: Any) -> None:43 """Adds custom logging level for verbose debug logs."""44 VDEBUG_LEVEL_NUM = 545 logging_.addLevelName(VDEBUG_LEVEL_NUM, "VDEBUG")46 def vdebug(self: Any, message: str, *args: Any, **kwargs: Any) -> None:47 if self.isEnabledFor(VDEBUG_LEVEL_NUM):48 self._log( # pylint: disable=protected-access49 VDEBUG_LEVEL_NUM, message, args, **kwargs50 )51 logging_.Logger.vdebug = vdebug52 logging_.VDEBUG = VDEBUG_LEVEL_NUM53def _getFormatter(verbose: bool = False) -> logging.Formatter:54 """Get log formatter.55 Args:56 verbose: True if a more verbose log format is desired.57 Returns:58 logging.Formatter object.59 """60 base_formatting = "[%(levelname)s] %(message)s"61 if verbose:62 formatter = logging.Formatter(63 "[%(process)s] (%(asctime)s) {}".format(base_formatting),64 datefmt="%Y-%m-%d %H:%M:%S",65 )66 else:67 formatter = logging.Formatter(base_formatting)...

Full Screen

Full Screen

logger.py

Source:logger.py Github

copy

Full Screen

1from __future__ import division, absolute_import, print_function2import logging3__all__ = ['easy_setup']4def _getRootLogger():5 """Return the top-most, root python logger object."""6 log = logging.getLogger()7 return log8def _getFormatter():9 """Return a formatter that does a good job showing helpful information."""10 fmt = '%(asctime)s: %(name)-18s: %(levelname)-10s: %(message)s'11 formatter = logging.Formatter(fmt)12 return formatter13def _init():14 """Set up the root logger.15 You should call this method first before you call _addFileHandler()16 and _addStreamHandler().17 """18 log = _getRootLogger()19 log.setLevel(logging.DEBUG)20def _addFileHandler(filename, log_level, log):21 """Add a file to the list of logging destinations of the given logger.22 This is helpful for debugging crashes that happen out in the wild23 while you're not looking.24 """25 handler = logging.FileHandler(filename)26 handler.setLevel(log_level)27 handler.setFormatter(_getFormatter())28 log.addHandler(handler)29def _addStreamHandler(log_level, log):30 """Add the console (aka, terminal) as a logging destination of the given logger.31 This is helpful for debugging while you're sitting at your console.32 """33 handler = logging.StreamHandler()34 handler.setLevel(log_level)35 handler.setFormatter(_getFormatter())36 log.addHandler(handler)37def easy_setup(logger_name=None, console_output=False, filename=None):38 """Build a logger with the given name, optionally outputting to39 the console and/or to a file.40 A common use-case is to build a logger for each module by including41 a line like this at the top of each module file:42 log = logger.easy_setup(__name__, "{}_log.log".format(__name__))43 """44 _init()45 log = logging.getLogger(logger_name)46 if filename is not None:47 _addFileHandler(filename, logging.INFO, log) # <-- log to a file48 if console_output:49 _addStreamHandler(logging.INFO, log) # <-- log to the terminal...

Full Screen

Full Screen

Automation Testing Tutorials

Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.

LambdaTest Learning Hubs:

YouTube

You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.

Run autotest automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful