prompt: pydicom should not define handler, formatter and log level.
  The `config` module (imported when pydicom is imported) defines a handler and set the log level for the pydicom logger. This should not be the case IMO. It should be the responsibility of the client code of pydicom to configure the logging module to its convenience. Otherwise one end up having multiple logs record as soon as pydicom is imported:
  
  Example:
  ```
  Could not import pillow
  2018-03-25 15:27:29,744 :: DEBUG :: pydicom 
    Could not import pillow
  Could not import jpeg_ls
  2018-03-25 15:27:29,745 :: DEBUG :: pydicom 
    Could not import jpeg_ls
  Could not import gdcm
  2018-03-25 15:27:29,745 :: DEBUG :: pydicom 
    Could not import gdcm
  ``` 
  Or am I missing something?
  
instance: {"FAIL_TO_PASS": "[\"pydicom/tests/test_config.py::TestDebug::test_default\", \"pydicom/tests/test_config.py::TestDebug::test_debug_on_handler_null\", \"pydicom/tests/test_config.py::TestDebug::test_debug_off_handler_null\", \"pydicom/tests/test_config.py::TestDebug::test_debug_on_handler_stream\", \"pydicom/tests/test_config.py::TestDebug::test_debug_off_handler_stream\"]", "PASS_TO_PASS": "[]", "base_commit": "3746878d8edf1cbda6fbcf35eec69f9ba79301ca", "created_at": "2019-07-27T00:18:11Z", "environment_setup_commit": "7241f5d9db0de589b230bb84212fbb643a7c86c3", "hints_text": "In addition, I don't understand what the purpose of the `config.debug` function since the default behavor of the logging module in absence of configuartion seems to already be the one you want.\r\n\r\nFrom https://docs.python.org/3/howto/logging.html#configuring-logging-for-a-library:\r\n\r\n> If the using application does not use logging, and library code makes logging calls, then (as described in the previous section) events of severity WARNING and greater will be printed to sys.stderr. This is regarded as the best default behaviour.\r\n\r\nand\r\n\r\n>**It is strongly advised that you do not add any handlers other than NullHandler to your library\u2019s loggers.** This is because the configuration of handlers is the prerogative of the application developer who uses your library. The application developer knows their target audience and what handlers are most appropriate for their application: if you add handlers \u2018under the hood\u2019, you might well interfere with their ability to carry out unit tests and deliver logs which suit their requirements. \r\n\nI think you make good points here.  I support changing the logging to comply with python's suggested behavior.\r\n\r\n> In addition, I don't understand what the purpose of the config.debug function\r\n\r\nOne reason is that the core loop in pydicom (data_element_generator in filereader.py) is extremely optimized for speed - it checks the `debugging` flag set by config.debug, to avoid composing messages and doing function calls to logger when not needed.", "instance_id": "pydicom__pydicom-901", "patch": "diff --git a/pydicom/config.py b/pydicom/config.py\n--- a/pydicom/config.py\n+++ b/pydicom/config.py\n@@ -62,10 +62,7 @@ def DS_decimal(use_Decimal_boolean=True):\n \n # Logging system and debug function to change logging level\n logger = logging.getLogger('pydicom')\n-handler = logging.StreamHandler()\n-formatter = logging.Formatter(\"%(message)s\")\n-handler.setFormatter(formatter)\n-logger.addHandler(handler)\n+logger.addHandler(logging.NullHandler())\n \n \n import pydicom.pixel_data_handlers.numpy_handler as np_handler  # noqa\n@@ -110,16 +107,29 @@ def get_pixeldata(ds):\n \"\"\"\n \n \n-def debug(debug_on=True):\n-    \"\"\"Turn debugging of DICOM file reading and writing on or off.\n+def debug(debug_on=True, default_handler=True):\n+    \"\"\"Turn on/off debugging of DICOM file reading and writing.\n+\n     When debugging is on, file location and details about the\n     elements read at that location are logged to the 'pydicom'\n     logger using python's logging module.\n \n-    :param debug_on: True (default) to turn on debugging,\n-    False to turn off.\n+    Parameters\n+    ----------\n+    debug_on : bool, optional\n+        If True (default) then turn on debugging, False to turn off.\n+    default_handler : bool, optional\n+        If True (default) then use ``logging.StreamHandler()`` as the handler\n+        for log messages.\n     \"\"\"\n     global logger, debugging\n+\n+    if default_handler:\n+        handler = logging.StreamHandler()\n+        formatter = logging.Formatter(\"%(message)s\")\n+        handler.setFormatter(formatter)\n+        logger.addHandler(handler)\n+\n     if debug_on:\n         logger.setLevel(logging.DEBUG)\n         debugging = True\n@@ -129,4 +139,4 @@ def debug(debug_on=True):\n \n \n # force level=WARNING, in case logging default is set differently (issue 103)\n-debug(False)\n+debug(False, False)\n", "problem_statement": "pydicom should not define handler, formatter and log level.\nThe `config` module (imported when pydicom is imported) defines a handler and set the log level for the pydicom logger. This should not be the case IMO. It should be the responsibility of the client code of pydicom to configure the logging module to its convenience. Otherwise one end up having multiple logs record as soon as pydicom is imported:\r\n\r\nExample:\r\n```\r\nCould not import pillow\r\n2018-03-25 15:27:29,744 :: DEBUG :: pydicom \r\n  Could not import pillow\r\nCould not import jpeg_ls\r\n2018-03-25 15:27:29,745 :: DEBUG :: pydicom \r\n  Could not import jpeg_ls\r\nCould not import gdcm\r\n2018-03-25 15:27:29,745 :: DEBUG :: pydicom \r\n  Could not import gdcm\r\n``` \r\nOr am I missing something?\n", "repo": "pydicom/pydicom", "test_patch": "diff --git a/pydicom/tests/test_config.py b/pydicom/tests/test_config.py\nnew file mode 100644\n--- /dev/null\n+++ b/pydicom/tests/test_config.py\n@@ -0,0 +1,107 @@\n+# Copyright 2008-2019 pydicom authors. See LICENSE file for details.\n+\"\"\"Unit tests for the pydicom.config module.\"\"\"\n+\n+import logging\n+import sys\n+\n+import pytest\n+\n+from pydicom import dcmread\n+from pydicom.config import debug\n+from pydicom.data import get_testdata_files\n+\n+\n+DS_PATH = get_testdata_files(\"CT_small.dcm\")[0]\n+PYTEST = [int(x) for x in pytest.__version__.split('.')]\n+\n+\n+@pytest.mark.skipif(PYTEST[:2] < [3, 4], reason='no caplog')\n+class TestDebug(object):\n+    \"\"\"Tests for config.debug().\"\"\"\n+    def setup(self):\n+        self.logger = logging.getLogger('pydicom')\n+\n+    def teardown(self):\n+        # Reset to just NullHandler\n+        self.logger.handlers = [self.logger.handlers[0]]\n+\n+    def test_default(self, caplog):\n+        \"\"\"Test that the default logging handler is a NullHandler.\"\"\"\n+        assert 1 == len(self.logger.handlers)\n+        assert isinstance(self.logger.handlers[0], logging.NullHandler)\n+\n+        with caplog.at_level(logging.DEBUG, logger='pydicom'):\n+            ds = dcmread(DS_PATH)\n+\n+            assert \"Call to dcmread()\" not in caplog.text\n+            assert \"Reading File Meta Information preamble...\" in caplog.text\n+            assert \"Reading File Meta Information prefix...\" in caplog.text\n+            assert \"00000080: 'DICM' prefix found\" in caplog.text\n+\n+    def test_debug_on_handler_null(self, caplog):\n+        \"\"\"Test debug(True, False).\"\"\"\n+        debug(True, False)\n+        assert 1 == len(self.logger.handlers)\n+        assert isinstance(self.logger.handlers[0], logging.NullHandler)\n+\n+        with caplog.at_level(logging.DEBUG, logger='pydicom'):\n+            ds = dcmread(DS_PATH)\n+\n+            assert \"Call to dcmread()\" in caplog.text\n+            assert \"Reading File Meta Information preamble...\" in caplog.text\n+            assert \"Reading File Meta Information prefix...\" in caplog.text\n+            assert \"00000080: 'DICM' prefix found\" in caplog.text\n+            msg = (\n+                \"00009848: fc ff fc ff 4f 42 00 00 7e 00 00 00    \"\n+                \"(fffc, fffc) OB Length: 126\"\n+            )\n+            assert msg in caplog.text\n+\n+    def test_debug_off_handler_null(self, caplog):\n+        \"\"\"Test debug(False, False).\"\"\"\n+        debug(False, False)\n+        assert 1 == len(self.logger.handlers)\n+        assert isinstance(self.logger.handlers[0], logging.NullHandler)\n+\n+        with caplog.at_level(logging.DEBUG, logger='pydicom'):\n+            ds = dcmread(DS_PATH)\n+\n+            assert \"Call to dcmread()\" not in caplog.text\n+            assert \"Reading File Meta Information preamble...\" in caplog.text\n+            assert \"Reading File Meta Information prefix...\" in caplog.text\n+            assert \"00000080: 'DICM' prefix found\" in caplog.text\n+\n+    def test_debug_on_handler_stream(self, caplog):\n+        \"\"\"Test debug(True, True).\"\"\"\n+        debug(True, True)\n+        assert 2 == len(self.logger.handlers)\n+        assert isinstance(self.logger.handlers[0], logging.NullHandler)\n+        assert isinstance(self.logger.handlers[1], logging.StreamHandler)\n+\n+        with caplog.at_level(logging.DEBUG, logger='pydicom'):\n+            ds = dcmread(DS_PATH)\n+\n+            assert \"Call to dcmread()\" in caplog.text\n+            assert \"Reading File Meta Information preamble...\" in caplog.text\n+            assert \"Reading File Meta Information prefix...\" in caplog.text\n+            assert \"00000080: 'DICM' prefix found\" in caplog.text\n+            msg = (\n+                \"00009848: fc ff fc ff 4f 42 00 00 7e 00 00 00    \"\n+                \"(fffc, fffc) OB Length: 126\"\n+            )\n+            assert msg in caplog.text\n+\n+    def test_debug_off_handler_stream(self, caplog):\n+        \"\"\"Test debug(False, True).\"\"\"\n+        debug(False, True)\n+        assert 2 == len(self.logger.handlers)\n+        assert isinstance(self.logger.handlers[0], logging.NullHandler)\n+        assert isinstance(self.logger.handlers[1], logging.StreamHandler)\n+\n+        with caplog.at_level(logging.DEBUG, logger='pydicom'):\n+            ds = dcmread(DS_PATH)\n+\n+            assert \"Call to dcmread()\" not in caplog.text\n+            assert \"Reading File Meta Information preamble...\" in caplog.text\n+            assert \"Reading File Meta Information prefix...\" in caplog.text\n+            assert \"00000080: 'DICM' prefix found\" in caplog.text\n", "version": "1.3"}
parsed_commit_content: {"file_diffs":[{"old_file_content":"# Copyright 2008-2018 pydicom authors. See LICENSE file for details.\n\"\"\"Pydicom configuration options.\"\"\"\n\n# doc strings following items are picked up by sphinx for documentation\n\nimport logging\n\n# Set the type used to hold DS values\n#    default False; was decimal-based in pydicom 0.9.7\nuse_DS_decimal = False\n\n\ndata_element_callback = None\n\"\"\"Set data_element_callback to a function to be called from read_dataset\nevery time a RawDataElement has been returned, before it is added\nto the dataset.\n\"\"\"\n\ndata_element_callback_kwargs = {}\n\"\"\"Set this to use as keyword arguments passed to the data_element_callback\nfunction\"\"\"\n\n\ndef reset_data_element_callback():\n    global data_element_callback\n    global data_element_callback_kwargs\n    data_element_callback = None\n    data_element_callback_kwargs = {}\n\n\ndef DS_decimal(use_Decimal_boolean=True):\n    \"\"\"Set DS class to be derived from Decimal (True) or from float (False)\n    If this function is never called, the default in pydicom >= 0.9.8\n    is for DS to be based on float.\n    \"\"\"\n    use_DS_decimal = use_Decimal_boolean\n    import pydicom.valuerep\n    if use_DS_decimal:\n        pydicom.valuerep.DSclass = pydicom.valuerep.DSdecimal\n    else:\n        pydicom.valuerep.DSclass = pydicom.valuerep.DSfloat\n\n\n# Configuration flags\nallow_DS_float = False\n\"\"\"Set allow_float to True to allow DSdecimal instances\nto be created with floats; otherwise, they must be explicitly\nconverted to strings, with the user explicity setting the\nprecision of digits and rounding. Default: False\"\"\"\n\nenforce_valid_values = False\n\"\"\"Raise errors if any value is not allowed by DICOM standard,\ne.g. DS strings that are longer than 16 characters;\nIS strings outside the allowed range.\n\"\"\"\n\ndatetime_conversion = False\n\"\"\"Set datetime_conversion to convert DA, DT and TM\ndata elements to datetime.date, datetime.datetime\nand datetime.time respectively. Default: False\n\"\"\"\n\n# Logging system and debug function to change logging level\nlogger = logging.getLogger('pydicom')\nhandler = logging.StreamHandler()\nformatter = logging.Formatter(\"%(message)s\")\nhandler.setFormatter(formatter)\nlogger.addHandler(handler)\n\n\nimport pydicom.pixel_data_handlers.numpy_handler as np_handler  # noqa\nimport pydicom.pixel_data_handlers.rle_handler as rle_handler  # noqa\nimport pydicom.pixel_data_handlers.pillow_handler as pillow_handler  # noqa\nimport pydicom.pixel_data_handlers.jpeg_ls_handler as jpegls_handler  # noqa\nimport pydicom.pixel_data_handlers.gdcm_handler as gdcm_handler  # noqa\n\npixel_data_handlers = [\n    np_handler,\n    rle_handler,\n    gdcm_handler,\n    pillow_handler,\n    jpegls_handler,\n]\n\"\"\"Handlers for converting (7fe0,0010) Pixel Data.\nThis is an ordered list that the dataset.convert_pixel_data()\nmethod will try to extract a correctly sized numpy array from the\nPixelData element.\n\nHanders shall have two methods:\n\ndef supports_transfer_syntax(ds)\n  This returns True if the handler might support the transfer syntax\n  indicated in the dicom_dataset\n\ndef get_pixeldata(ds):\n  This shall either throw an exception or return a correctly sized numpy\n  array derived from the PixelData.  Reshaping the array to the correct\n  dimensions is handled outside the image handler\n\nThe first handler that both announces that it supports the transfer syntax\nand does not throw an exception, either in getting the data or when the data\nis reshaped to the correct dimensions, is the handler that will provide the\ndata.\n\nIf they all fail, the last one to throw an exception gets to see its\nexception thrown up.\n\nIf no one throws an exception, but they all refuse to support the transfer\nsyntax, then this fact is announced in a NotImplementedError exception.\n\"\"\"\n\n\ndef debug(debug_on=True):\n    \"\"\"Turn debugging of DICOM file reading and writing on or off.\n    When debugging is on, file location and details about the\n    elements read at that location are logged to the 'pydicom'\n    logger using python's logging module.\n\n    :param debug_on: True (default) to turn on debugging,\n    False to turn off.\n    \"\"\"\n    global logger, debugging\n    if debug_on:\n        logger.setLevel(logging.DEBUG)\n        debugging = True\n    else:\n        logger.setLevel(logging.WARNING)\n        debugging = False\n\n\n# force level=WARNING, in case logging default is set differently (issue 103)\ndebug(False)\n","new_file_content":"# Copyright 2008-2018 pydicom authors. See LICENSE file for details.\n\"\"\"Pydicom configuration options.\"\"\"\n\n# doc strings following items are picked up by sphinx for documentation\n\nimport logging\n\n\nhave_numpy = True\ntry:\n    import numpy\nexcept ImportError:\n    have_numpy = False\n\n\n# Set the type used to hold DS values\n#    default False; was decimal-based in pydicom 0.9.7\nuse_DS_decimal = False\n\"\"\"Set using :func:`~pydicom.config.DS_decimal` to control if elements with a\nVR of **DS** are represented as :class:`~decimal.Decimal`.\n\nDefault ``False``.\n\"\"\"\n\ndata_element_callback = None\n\"\"\"Set to a callable function to be called from\n:func:`~pydicom.filereader.dcmread` every time a\n:class:`~pydicom.dataelem.RawDataElement` has been returned,\nbefore it is added to the :class:`~pydicom.dataset.Dataset`.\n\nDefault ``None``.\n\"\"\"\n\ndata_element_callback_kwargs = {}\n\"\"\"Set the keyword arguments passed to :func:`data_element_callback`.\n\nDefault ``{}``.\n\"\"\"\n\n\ndef reset_data_element_callback():\n    \"\"\"Reset the :func:`data_element_callback` function to the default.\"\"\"\n    global data_element_callback\n    global data_element_callback_kwargs\n    data_element_callback = None\n    data_element_callback_kwargs = {}\n\n\ndef DS_numpy(use_numpy=True):\n    \"\"\"Set whether multi-valued elements with VR of **DS** will be numpy arrays\n\n    .. versionadded:: 2.0\n\n    Parameters\n    ----------\n    use_numpy : bool, optional\n        ``True`` (default) to read multi-value **DS** elements\n        as :class:`~numpy.ndarray`, ``False`` to read multi-valued **DS**\n        data elements as type :class:`~python.mulitval.MultiValue`\n\n        Note: once a value has been accessed, changing this setting will\n        no longer change its type\n\n    Raises\n    ------\n    ValueError\n        If :data:`use_DS_decimal` and `use_numpy` are both True.\n\n    \"\"\"\n\n    global use_DS_numpy\n\n    if use_DS_decimal and use_numpy:\n        raise ValueError(\"Cannot use numpy arrays to read DS elements\"\n                         \"if `use_DS_decimal` is True\")\n    use_DS_numpy = use_numpy\n\n\ndef DS_decimal(use_Decimal_boolean=True):\n    \"\"\"Set DS class to be derived from :class:`decimal.Decimal` or\n    :class:`float`.\n\n    If this function is never called, the default in *pydicom* >= 0.9.8\n    is for DS to be based on :class:`float`.\n\n    Parameters\n    ----------\n    use_Decimal_boolean : bool, optional\n        ``True`` (default) to derive :class:`~pydicom.valuerep.DS` from\n        :class:`decimal.Decimal`, ``False`` to derive it from :class:`float`.\n\n    Raises\n    ------\n    ValueError\n        If `use_Decimal_boolean` and :data:`use_DS_numpy` are\n        both ``True``.\n    \"\"\"\n    global use_DS_decimal\n\n    use_DS_decimal = use_Decimal_boolean\n\n    if use_DS_decimal and use_DS_numpy:\n        raise ValueError(\"Cannot set use_DS_decimal True \"\n                         \"if use_DS_numpy is True\")\n\n    import pydicom.valuerep\n    if use_DS_decimal:\n        pydicom.valuerep.DSclass = pydicom.valuerep.DSdecimal\n    else:\n        pydicom.valuerep.DSclass = pydicom.valuerep.DSfloat\n\n\n# Configuration flags\nuse_DS_numpy = False\n\"\"\"Set using the function :func:`~pydicom.config.DS_numpy` to control\nwhether arrays of VR **DS** are returned as numpy arrays.\nDefault: ``False``.\n\n.. versionadded:: 2.0\n\"\"\"\n\nuse_IS_numpy = False\n\"\"\"Set to False to avoid IS values being returned as numpy ndarray objects.\nDefault: ``False``.\n\n.. versionadded:: 2.0\n\"\"\"\n\nallow_DS_float = False\n\"\"\"Set to ``True`` to allow :class:`~pydicom.valuerep.DSdecimal`\ninstances to be created using :class:`floats<float>`; otherwise, they must be\nexplicitly converted to :class:`str`, with the user explicity setting the\nprecision of digits and rounding.\n\nDefault ``False``.\n\"\"\"\n\nenforce_valid_values = False\n\"\"\"Raise exceptions if any value is not allowed by DICOM Standard.\n\ne.g. DS strings that are longer than 16 characters; IS strings outside\nthe allowed range.\n\nDefault ``False``.\n\"\"\"\n\ndatetime_conversion = False\n\"\"\"Set to ``True`` to convert the value(s) of elements with a VR of DA, DT and\nTM to :class:`datetime.date`, :class:`datetime.datetime` and\n:class:`datetime.time` respectively.\n\nDefault ``False``\n\"\"\"\n\nuse_none_as_empty_text_VR_value = False\n\"\"\" If ``True``, the value of a decoded empty data element with\na text VR is ``None``, otherwise (the default), it is is an empty string.\nFor all other VRs the behavior does not change - the value is en empty\nlist for VR **SQ** and ``None`` for all other VRs.\nNote that the default of this value will change to ``True`` in version 2.0.\n\n.. versionadded:: 1.4\n\"\"\"\n\nreplace_un_with_known_vr = True\n\"\"\" If ``True``, and the VR of a known data element is encoded as **UN** in\nan explicit encoding, the VR is changed to the known value.\nCan be set to ``False`` where the content of the tag shown as **UN** is\nnot DICOM conformant and would lead to a failure if accessing it.\n\n.. versionadded:: 2.0\n\"\"\"\n\nshow_file_meta = True\n\"\"\"\n.. versionadded:: 2.0\n\nIf ``True`` (default), the 'str' and 'repr' methods\nof :class:`~pydicom.dataset.Dataset` begin with a separate section\ndisplaying the file meta information data elements\n\"\"\"\n\n# Logging system and debug function to change logging level\nlogger = logging.getLogger('pydicom')\nlogger.addHandler(logging.NullHandler())\n\nimport pydicom.overlay_data_handlers.numpy_handler as overlay_np  # noqa\n\noverlay_data_handlers = [\n    overlay_np,\n]\n\"\"\"Handlers for converting (60xx,3000) *Overlay Data*\n\n.. versionadded:: 1.4\n\n.. currentmodule:: pydicom.dataset\n\nThis is an ordered list of *Overlay Data* handlers that the\n:meth:`~Dataset.overlay_array` method will use to try to extract a correctly\nsized numpy array from an *Overlay Data* element.\n\nHandlers shall have three methods:\n\ndef supports_transfer_syntax(ds)\n    Return ``True`` if the handler supports the transfer syntax indicated in\n    :class:`Dataset` `ds`, ``False`` otherwise.\n\ndef is_available():\n    Return ``True`` if the handler's dependencies are installed, ``False``\n    otherwise.\n\ndef get_overlay_array(ds, group):\n    Return a correctly shaped :class:`numpy.ndarray` derived from the\n    *Overlay Data* with element tag `group`, in :class:`Dataset` `ds` or raise\n    an exception.\n\n\nThe first handler that both announces that it supports the transfer syntax\nand does not raise an exception is the handler that will provide the\ndata.\n\nIf all handlers fail to convert the data only the last exception is raised.\n\nIf none raise an exception, but they all refuse to support the transfer\nsyntax, then a :class:`NotImplementedError` is raised.\n\"\"\"\n\nimport pydicom.pixel_data_handlers.numpy_handler as np_handler  # noqa\nimport pydicom.pixel_data_handlers.rle_handler as rle_handler  # noqa\nimport pydicom.pixel_data_handlers.pillow_handler as pillow_handler  # noqa\nimport pydicom.pixel_data_handlers.jpeg_ls_handler as jpegls_handler  # noqa\nimport pydicom.pixel_data_handlers.gdcm_handler as gdcm_handler  # noqa\n\npixel_data_handlers = [\n    np_handler,\n    rle_handler,\n    gdcm_handler,\n    pillow_handler,\n    jpegls_handler,\n]\n\"\"\"Handlers for converting (7FE0,0010) *Pixel Data*.\n\n.. versionadded:: 1.2\n\n.. currentmodule:: pydicom.dataset\n\nThis is an ordered list of *Pixel Data* handlers that the\n:meth:`~Dataset.convert_pixel_data` method will use to try to extract a\ncorrectly sized numpy array from the *Pixel Data* element.\n\nHandlers shall have four methods:\n\ndef supports_transfer_syntax(ds)\n    Return ``True`` if the handler supports the transfer syntax indicated in\n    :class:`Dataset` `ds`, ``False`` otherwise.\n\ndef is_available():\n    Return ``True`` if the handler's dependencies are installed, ``False``\n    otherwise.\n\ndef get_pixeldata(ds):\n    Return a correctly sized 1D :class:`numpy.ndarray` derived from the\n    *Pixel Data* in :class:`Dataset` `ds` or raise an exception. Reshaping the\n    returned array to the correct dimensions is handled automatically.\n\ndef needs_to_convert_to_RGB(ds):\n    Return ``True`` if the *Pixel Data* in the :class:`Dataset` `ds` needs to\n    be converted to the RGB colourspace, ``False`` otherwise.\n\nThe first handler that both announces that it supports the transfer syntax\nand does not raise an exception, either in getting the data or when the data\nis reshaped to the correct dimensions, is the handler that will provide the\ndata.\n\nIf they all fail only the last exception is raised.\n\nIf none raise an exception, but they all refuse to support the transfer\nsyntax, then this fact is announced in a :class:`NotImplementedError`\nexception.\n\"\"\"\n\n\ndef debug(debug_on=True, default_handler=True):\n    \"\"\"Turn on/off debugging of DICOM file reading and writing.\n\n    When debugging is on, file location and details about the elements read at\n    that location are logged to the 'pydicom' logger using Python's\n    :mod:`logging`\n    module.\n\n    .. versionchanged:1.4\n\n        Added `default_handler` keyword parameter.\n\n    Parameters\n    ----------\n    debug_on : bool, optional\n        If ``True`` (default) then turn on debugging, ``False`` to turn off.\n    default_handler : bool, optional\n        If ``True`` (default) then use :class:`logging.StreamHandler` as the\n        handler for log messages.\n    \"\"\"\n    global logger, debugging\n\n    if default_handler:\n        handler = logging.StreamHandler()\n        formatter = logging.Formatter(\"%(message)s\")\n        handler.setFormatter(formatter)\n        logger.addHandler(handler)\n\n    if debug_on:\n        logger.setLevel(logging.DEBUG)\n        debugging = True\n    else:\n        logger.setLevel(logging.WARNING)\n        debugging = False\n\n\n# force level=WARNING, in case logging default is set differently (issue 103)\ndebug(False, False)\n","header":{"file":{"path":"pydicom/config.py"},"misc_line":null},"index_line":null,"is_binary_file":false,"binary_line":null,"minus_file":{"path":"a/pydicom/config.py"},"plus_file":{"path":"b/pydicom/config.py"},"hunks":[{"descriptor":{"old_range":{"start":62,"length":10},"new_range":{"start":62,"length":7},"section":"def DS_decimal(use_Decimal_boolean=True):"},"line_group":{"all_lines":[{"content":"","type":"context"},{"content":"# Logging system and debug function to change logging level","type":"context"},{"content":"logger = logging.getLogger('pydicom')","type":"context"},{"content":"handler = logging.StreamHandler()","type":"deleted"},{"content":"formatter = logging.Formatter(\"%(message)s\")","type":"deleted"},{"content":"handler.setFormatter(formatter)","type":"deleted"},{"content":"logger.addHandler(handler)","type":"deleted"},{"content":"logger.addHandler(logging.NullHandler())","type":"added"},{"content":"","type":"context"},{"content":"","type":"context"},{"content":"import pydicom.pixel_data_handlers.numpy_handler as np_handler  # noqa","type":"context"}]},"modified_entities":[],"added_entities":[],"deleted_entities":[]},{"descriptor":{"old_range":{"start":110,"length":16},"new_range":{"start":107,"length":29},"section":"def get_pixeldata(ds):"},"line_group":{"all_lines":[{"content":"\"\"\"","type":"context"},{"content":"","type":"context"},{"content":"","type":"context"},{"content":"def debug(debug_on=True):","type":"deleted"},{"content":"    \"\"\"Turn debugging of DICOM file reading and writing on or off.","type":"deleted"},{"content":"def debug(debug_on=True, default_handler=True):","type":"added"},{"content":"    \"\"\"Turn on/off debugging of DICOM file reading and writing.","type":"added"},{"content":"","type":"added"},{"content":"    When debugging is on, file location and details about the","type":"context"},{"content":"    elements read at that location are logged to the 'pydicom'","type":"context"},{"content":"    logger using python's logging module.","type":"context"},{"content":"","type":"context"},{"content":"    :param debug_on: True (default) to turn on debugging,","type":"deleted"},{"content":"    False to turn off.","type":"deleted"},{"content":"    Parameters","type":"added"},{"content":"    ----------","type":"added"},{"content":"    debug_on : bool, optional","type":"added"},{"content":"        If True (default) then turn on debugging, False to turn off.","type":"added"},{"content":"    default_handler : bool, optional","type":"added"},{"content":"        If True (default) then use ``logging.StreamHandler()`` as the handler","type":"added"},{"content":"        for log messages.","type":"added"},{"content":"    \"\"\"","type":"context"},{"content":"    global logger, debugging","type":"context"},{"content":"","type":"added"},{"content":"    if default_handler:","type":"added"},{"content":"        handler = logging.StreamHandler()","type":"added"},{"content":"        formatter = logging.Formatter(\"%(message)s\")","type":"added"},{"content":"        handler.setFormatter(formatter)","type":"added"},{"content":"        logger.addHandler(handler)","type":"added"},{"content":"","type":"added"},{"content":"    if debug_on:","type":"context"},{"content":"        logger.setLevel(logging.DEBUG)","type":"context"},{"content":"        debugging = True","type":"context"}]},"modified_entities":[],"added_entities":[],"deleted_entities":[]},{"descriptor":{"old_range":{"start":129,"length":4},"new_range":{"start":139,"length":4},"section":"def debug(debug_on=True):"},"line_group":{"all_lines":[{"content":"","type":"context"},{"content":"","type":"context"},{"content":"# force level=WARNING, in case logging default is set differently (issue 103)","type":"context"},{"content":"debug(False)","type":"deleted"},{"content":"debug(False, False)","type":"added"},{"content":"","type":"context"}]},"modified_entities":[],"added_entities":[],"deleted_entities":[]}]}],"old_commit_hash":"3746878d8edf1cbda6fbcf35eec69f9ba79301ca","new_commit_hash":"2e9301e8801e6e30c71ccf6833ec2562420bfbbd","commit_message":"next() no longer starts iterator","commit_date":"2020-06-29T10:45:31+02:00","metadata":{}}