We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
AttributeError during logging setup with Python 2.7
Hi,

I upgraded to luigi 2.8.0 and experience an `AttributeError` that occurs within the new `setup_logging.py`. Here is the important part of the stack trace:

```
  File ".../lib/python2.7/site-packages/luigi/cmdline.py", line 9, in luigi_run
    run_with_retcodes(argv)
  File ".../lib/python2.7/site-packages/luigi/retcodes.py", line 81, in run_with_retcodes
    InterfaceLogging.setup(env_params)
  File ".../lib/python2.7/site-packages/luigi/setup_logging.py", line 74, in setup
    configured = cls._section(opts)
  File ".../lib/python2.7/site-packages/luigi/setup_logging.py", line 42, in _section
    logging_config = cls.config['logging']
AttributeError: LuigiConfigParser instance has no attribute '__getitem__'
```

`cls.config` is a `ConfigParser` instance which does not implement `__getitem__` in Python 2.7 (which I'm forced to use -.-). This could be fixed by using `cls.config.options('logging')` instead. I checked, and this is the only place where items are used.

https://github.com/spotify/luigi/blob/0a098f6f99da0bad03af56a057b9a15254d1a957/luigi/setup_logging.py#L42

Adding @orsinium here who is maybe faster to fix this. I could create a PR on Friday.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `luigi/setup_logging.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 #
3 # Copyright 2018 Vote Inc.
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16 #
17 """
18 This module contains helper classes for configuring logging for luigid and
19 workers via command line arguments and options from config files.
20 """
21 
22 import logging
23 import logging.config
24 import os.path
25 from luigi.configuration import get_config
26 
27 # In python3 ConfigParser was renamed
28 # https://stackoverflow.com/a/41202010
29 try:
30     from ConfigParser import NoSectionError
31 except ImportError:
32     from configparser import NoSectionError
33 
34 
35 class BaseLogging(object):
36     config = get_config()
37 
38     @classmethod
39     def _section(cls, opts):
40         """Get logging settings from config file section "logging"."""
41         try:
42             logging_config = cls.config['logging']
43         except (TypeError, KeyError, NoSectionError):
44             return False
45         logging.config.dictConfig(logging_config)
46         return True
47 
48     @classmethod
49     def setup(cls, opts):
50         """Setup logging via CLI params and config."""
51         logger = logging.getLogger('luigi')
52 
53         if cls._configured:
54             logger.info('logging already configured')
55             return False
56         cls._configured = True
57 
58         if cls.config.getboolean('core', 'no_configure_logging', False):
59             logger.info('logging disabled in settings')
60             return False
61 
62         configured = cls._cli(opts)
63         if configured:
64             logger = logging.getLogger('luigi')
65             logger.info('logging configured via special settings')
66             return True
67 
68         configured = cls._conf(opts)
69         if configured:
70             logger = logging.getLogger('luigi')
71             logger.info('logging configured via *.conf file')
72             return True
73 
74         configured = cls._section(opts)
75         if configured:
76             logger = logging.getLogger('luigi')
77             logger.info('logging configured via config section')
78             return True
79 
80         configured = cls._default(opts)
81         if configured:
82             logger = logging.getLogger('luigi')
83             logger.info('logging configured by default settings')
84         return configured
85 
86 
87 class DaemonLogging(BaseLogging):
88     """Configure logging for luigid
89     """
90     _configured = False
91     _log_format = "%(asctime)s %(name)s[%(process)s] %(levelname)s: %(message)s"
92 
93     @classmethod
94     def _cli(cls, opts):
95         """Setup logging via CLI options
96 
97         If `--background` -- set INFO level for root logger.
98         If `--logdir` -- set logging with next params:
99             default Luigi's formatter,
100             INFO level,
101             output in logdir in `luigi-server.log` file
102         """
103         if opts.background:
104             logging.getLogger().setLevel(logging.INFO)
105             return True
106 
107         if opts.logdir:
108             logging.basicConfig(
109                 level=logging.INFO,
110                 format=cls._log_format,
111                 filename=os.path.join(opts.logdir, "luigi-server.log"))
112             return True
113 
114         return False
115 
116     @classmethod
117     def _conf(cls, opts):
118         """Setup logging via ini-file from logging_conf_file option."""
119         logging_conf = cls.config.get('core', 'logging_conf_file', None)
120         if logging_conf is None:
121             return False
122 
123         if not os.path.exists(logging_conf):
124             # FileNotFoundError added only in Python 3.3
125             # https://docs.python.org/3/whatsnew/3.3.html#pep-3151-reworking-the-os-and-io-exception-hierarchy
126             raise OSError("Error: Unable to locate specified logging configuration file!")
127 
128         logging.config.fileConfig(logging_conf)
129         return True
130 
131     @classmethod
132     def _default(cls, opts):
133         """Setup default logger"""
134         logging.basicConfig(level=logging.INFO, format=cls._log_format)
135         return True
136 
137 
138 # Part of this logic taken for dropped function "setup_interface_logging"
139 class InterfaceLogging(BaseLogging):
140     """Configure logging for worker"""
141     _configured = False
142 
143     @classmethod
144     def _cli(cls, opts):
145         return False
146 
147     @classmethod
148     def _conf(cls, opts):
149         """Setup logging via ini-file from logging_conf_file option."""
150         if not opts.logging_conf_file:
151             return False
152 
153         if not os.path.exists(opts.logging_conf_file):
154             # FileNotFoundError added only in Python 3.3
155             # https://docs.python.org/3/whatsnew/3.3.html#pep-3151-reworking-the-os-and-io-exception-hierarchy
156             raise OSError("Error: Unable to locate specified logging configuration file!")
157 
158         logging.config.fileConfig(opts.logging_conf_file, disable_existing_loggers=False)
159         return True
160 
161     @classmethod
162     def _default(cls, opts):
163         """Setup default logger"""
164         level = getattr(logging, opts.log_level, logging.DEBUG)
165 
166         logger = logging.getLogger('luigi-interface')
167         logger.setLevel(level)
168 
169         stream_handler = logging.StreamHandler()
170         stream_handler.setLevel(level)
171 
172         formatter = logging.Formatter('%(levelname)s: %(message)s')
173         stream_handler.setFormatter(formatter)
174 
175         logger.addHandler(stream_handler)
176         return True
177
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/luigi/setup_logging.py b/luigi/setup_logging.py
--- a/luigi/setup_logging.py
+++ b/luigi/setup_logging.py
@@ -22,7 +22,7 @@
 import logging
 import logging.config
 import os.path
-from luigi.configuration import get_config
+from luigi.configuration import get_config, LuigiConfigParser
 
 # In python3 ConfigParser was renamed
 # https://stackoverflow.com/a/41202010
@@ -38,6 +38,8 @@
     @classmethod
     def _section(cls, opts):
         """Get logging settings from config file section "logging"."""
+        if isinstance(cls.config, LuigiConfigParser):
+            return False
         try:
             logging_config = cls.config['logging']
         except (TypeError, KeyError, NoSectionError):

{"golden_diff": "diff --git a/luigi/setup_logging.py b/luigi/setup_logging.py\n--- a/luigi/setup_logging.py\n+++ b/luigi/setup_logging.py\n@@ -22,7 +22,7 @@\n import logging\n import logging.config\n import os.path\n-from luigi.configuration import get_config\n+from luigi.configuration import get_config, LuigiConfigParser\n \n # In python3 ConfigParser was renamed\n # https://stackoverflow.com/a/41202010\n@@ -38,6 +38,8 @@\n     @classmethod\n     def _section(cls, opts):\n         \"\"\"Get logging settings from config file section \"logging\".\"\"\"\n+        if isinstance(cls.config, LuigiConfigParser):\n+            return False\n         try:\n             logging_config = cls.config['logging']\n         except (TypeError, KeyError, NoSectionError):\n", "issue": "AttributeError during logging setup with Python 2.7\nHi,\r\n\r\nI upgraded to luigi 2.8.0 and experience an `AttributeError` that occurs within the new `setup_logging.py`. Here is the important part of the stack trace:\r\n\r\n```\r\n  File \".../lib/python2.7/site-packages/luigi/cmdline.py\", line 9, in luigi_run\r\n    run_with_retcodes(argv)\r\n  File \".../lib/python2.7/site-packages/luigi/retcodes.py\", line 81, in run_with_retcodes\r\n    InterfaceLogging.setup(env_params)\r\n  File \".../lib/python2.7/site-packages/luigi/setup_logging.py\", line 74, in setup\r\n    configured = cls._section(opts)\r\n  File \".../lib/python2.7/site-packages/luigi/setup_logging.py\", line 42, in _section\r\n    logging_config = cls.config['logging']\r\nAttributeError: LuigiConfigParser instance has no attribute '__getitem__'\r\n```\r\n\r\n`cls.config` is a `ConfigParser` instance which does not implement `__getitem__` in Python 2.7 (which I'm forced to use -.-). This could be fixed by using `cls.config.options('logging')` instead. I checked, and this is the only place where items are used.\r\n\r\nhttps://github.com/spotify/luigi/blob/0a098f6f99da0bad03af56a057b9a15254d1a957/luigi/setup_logging.py#L42\r\n\r\nAdding @orsinium here who is maybe faster to fix this. I could create a PR on Friday.\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\n#\n# Copyright 2018 Vote Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\"\"\"\nThis module contains helper classes for configuring logging for luigid and\nworkers via command line arguments and options from config files.\n\"\"\"\n\nimport logging\nimport logging.config\nimport os.path\nfrom luigi.configuration import get_config\n\n# In python3 ConfigParser was renamed\n# https://stackoverflow.com/a/41202010\ntry:\n    from ConfigParser import NoSectionError\nexcept ImportError:\n    from configparser import NoSectionError\n\n\nclass BaseLogging(object):\n    config = get_config()\n\n    @classmethod\n    def _section(cls, opts):\n        \"\"\"Get logging settings from config file section \"logging\".\"\"\"\n        try:\n            logging_config = cls.config['logging']\n        except (TypeError, KeyError, NoSectionError):\n            return False\n        logging.config.dictConfig(logging_config)\n        return True\n\n    @classmethod\n    def setup(cls, opts):\n        \"\"\"Setup logging via CLI params and config.\"\"\"\n        logger = logging.getLogger('luigi')\n\n        if cls._configured:\n            logger.info('logging already configured')\n            return False\n        cls._configured = True\n\n        if cls.config.getboolean('core', 'no_configure_logging', False):\n            logger.info('logging disabled in settings')\n            return False\n\n        configured = cls._cli(opts)\n        if configured:\n            logger = logging.getLogger('luigi')\n            logger.info('logging configured via special settings')\n            return True\n\n        configured = cls._conf(opts)\n        if configured:\n            logger = logging.getLogger('luigi')\n            logger.info('logging configured via *.conf file')\n            return True\n\n        configured = cls._section(opts)\n        if configured:\n            logger = logging.getLogger('luigi')\n            logger.info('logging configured via config section')\n            return True\n\n        configured = cls._default(opts)\n        if configured:\n            logger = logging.getLogger('luigi')\n            logger.info('logging configured by default settings')\n        return configured\n\n\nclass DaemonLogging(BaseLogging):\n    \"\"\"Configure logging for luigid\n    \"\"\"\n    _configured = False\n    _log_format = \"%(asctime)s %(name)s[%(process)s] %(levelname)s: %(message)s\"\n\n    @classmethod\n    def _cli(cls, opts):\n        \"\"\"Setup logging via CLI options\n\n        If `--background` -- set INFO level for root logger.\n        If `--logdir` -- set logging with next params:\n            default Luigi's formatter,\n            INFO level,\n            output in logdir in `luigi-server.log` file\n        \"\"\"\n        if opts.background:\n            logging.getLogger().setLevel(logging.INFO)\n            return True\n\n        if opts.logdir:\n            logging.basicConfig(\n                level=logging.INFO,\n                format=cls._log_format,\n                filename=os.path.join(opts.logdir, \"luigi-server.log\"))\n            return True\n\n        return False\n\n    @classmethod\n    def _conf(cls, opts):\n        \"\"\"Setup logging via ini-file from logging_conf_file option.\"\"\"\n        logging_conf = cls.config.get('core', 'logging_conf_file', None)\n        if logging_conf is None:\n            return False\n\n        if not os.path.exists(logging_conf):\n            # FileNotFoundError added only in Python 3.3\n            # https://docs.python.org/3/whatsnew/3.3.html#pep-3151-reworking-the-os-and-io-exception-hierarchy\n            raise OSError(\"Error: Unable to locate specified logging configuration file!\")\n\n        logging.config.fileConfig(logging_conf)\n        return True\n\n    @classmethod\n    def _default(cls, opts):\n        \"\"\"Setup default logger\"\"\"\n        logging.basicConfig(level=logging.INFO, format=cls._log_format)\n        return True\n\n\n# Part of this logic taken for dropped function \"setup_interface_logging\"\nclass InterfaceLogging(BaseLogging):\n    \"\"\"Configure logging for worker\"\"\"\n    _configured = False\n\n    @classmethod\n    def _cli(cls, opts):\n        return False\n\n    @classmethod\n    def _conf(cls, opts):\n        \"\"\"Setup logging via ini-file from logging_conf_file option.\"\"\"\n        if not opts.logging_conf_file:\n            return False\n\n        if not os.path.exists(opts.logging_conf_file):\n            # FileNotFoundError added only in Python 3.3\n            # https://docs.python.org/3/whatsnew/3.3.html#pep-3151-reworking-the-os-and-io-exception-hierarchy\n            raise OSError(\"Error: Unable to locate specified logging configuration file!\")\n\n        logging.config.fileConfig(opts.logging_conf_file, disable_existing_loggers=False)\n        return True\n\n    @classmethod\n    def _default(cls, opts):\n        \"\"\"Setup default logger\"\"\"\n        level = getattr(logging, opts.log_level, logging.DEBUG)\n\n        logger = logging.getLogger('luigi-interface')\n        logger.setLevel(level)\n\n        stream_handler = logging.StreamHandler()\n        stream_handler.setLevel(level)\n\n        formatter = logging.Formatter('%(levelname)s: %(message)s')\n        stream_handler.setFormatter(formatter)\n\n        logger.addHandler(stream_handler)\n        return True\n", "path": "luigi/setup_logging.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\n#\n# Copyright 2018 Vote Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\"\"\"\nThis module contains helper classes for configuring logging for luigid and\nworkers via command line arguments and options from config files.\n\"\"\"\n\nimport logging\nimport logging.config\nimport os.path\nfrom luigi.configuration import get_config, LuigiConfigParser\n\n# In python3 ConfigParser was renamed\n# https://stackoverflow.com/a/41202010\ntry:\n    from ConfigParser import NoSectionError\nexcept ImportError:\n    from configparser import NoSectionError\n\n\nclass BaseLogging(object):\n    config = get_config()\n\n    @classmethod\n    def _section(cls, opts):\n        \"\"\"Get logging settings from config file section \"logging\".\"\"\"\n        if isinstance(cls.config, LuigiConfigParser):\n            return False\n        try:\n            logging_config = cls.config['logging']\n        except (TypeError, KeyError, NoSectionError):\n            return False\n        logging.config.dictConfig(logging_config)\n        return True\n\n    @classmethod\n    def setup(cls, opts):\n        \"\"\"Setup logging via CLI params and config.\"\"\"\n        logger = logging.getLogger('luigi')\n\n        if cls._configured:\n            logger.info('logging already configured')\n            return False\n        cls._configured = True\n\n        if cls.config.getboolean('core', 'no_configure_logging', False):\n            logger.info('logging disabled in settings')\n            return False\n\n        configured = cls._cli(opts)\n        if configured:\n            logger = logging.getLogger('luigi')\n            logger.info('logging configured via special settings')\n            return True\n\n        configured = cls._conf(opts)\n        if configured:\n            logger = logging.getLogger('luigi')\n            logger.info('logging configured via *.conf file')\n            return True\n\n        configured = cls._section(opts)\n        if configured:\n            logger = logging.getLogger('luigi')\n            logger.info('logging configured via config section')\n            return True\n\n        configured = cls._default(opts)\n        if configured:\n            logger = logging.getLogger('luigi')\n            logger.info('logging configured by default settings')\n        return configured\n\n\nclass DaemonLogging(BaseLogging):\n    \"\"\"Configure logging for luigid\n    \"\"\"\n    _configured = False\n    _log_format = \"%(asctime)s %(name)s[%(process)s] %(levelname)s: %(message)s\"\n\n    @classmethod\n    def _cli(cls, opts):\n        \"\"\"Setup logging via CLI options\n\n        If `--background` -- set INFO level for root logger.\n        If `--logdir` -- set logging with next params:\n            default Luigi's formatter,\n            INFO level,\n            output in logdir in `luigi-server.log` file\n        \"\"\"\n        if opts.background:\n            logging.getLogger().setLevel(logging.INFO)\n            return True\n\n        if opts.logdir:\n            logging.basicConfig(\n                level=logging.INFO,\n                format=cls._log_format,\n                filename=os.path.join(opts.logdir, \"luigi-server.log\"))\n            return True\n\n        return False\n\n    @classmethod\n    def _conf(cls, opts):\n        \"\"\"Setup logging via ini-file from logging_conf_file option.\"\"\"\n        logging_conf = cls.config.get('core', 'logging_conf_file', None)\n        if logging_conf is None:\n            return False\n\n        if not os.path.exists(logging_conf):\n            # FileNotFoundError added only in Python 3.3\n            # https://docs.python.org/3/whatsnew/3.3.html#pep-3151-reworking-the-os-and-io-exception-hierarchy\n            raise OSError(\"Error: Unable to locate specified logging configuration file!\")\n\n        logging.config.fileConfig(logging_conf)\n        return True\n\n    @classmethod\n    def _default(cls, opts):\n        \"\"\"Setup default logger\"\"\"\n        logging.basicConfig(level=logging.INFO, format=cls._log_format)\n        return True\n\n\n# Part of this logic taken for dropped function \"setup_interface_logging\"\nclass InterfaceLogging(BaseLogging):\n    \"\"\"Configure logging for worker\"\"\"\n    _configured = False\n\n    @classmethod\n    def _cli(cls, opts):\n        return False\n\n    @classmethod\n    def _conf(cls, opts):\n        \"\"\"Setup logging via ini-file from logging_conf_file option.\"\"\"\n        if not opts.logging_conf_file:\n            return False\n\n        if not os.path.exists(opts.logging_conf_file):\n            # FileNotFoundError added only in Python 3.3\n            # https://docs.python.org/3/whatsnew/3.3.html#pep-3151-reworking-the-os-and-io-exception-hierarchy\n            raise OSError(\"Error: Unable to locate specified logging configuration file!\")\n\n        logging.config.fileConfig(opts.logging_conf_file, disable_existing_loggers=False)\n        return True\n\n    @classmethod\n    def _default(cls, opts):\n        \"\"\"Setup default logger\"\"\"\n        level = getattr(logging, opts.log_level, logging.DEBUG)\n\n        logger = logging.getLogger('luigi-interface')\n        logger.setLevel(level)\n\n        stream_handler = logging.StreamHandler()\n        stream_handler.setLevel(level)\n\n        formatter = logging.Formatter('%(levelname)s: %(message)s')\n        stream_handler.setFormatter(formatter)\n\n        logger.addHandler(stream_handler)\n        return True\n", "path": "luigi/setup_logging.py"}]}