prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  UnboundLocalError: local variable 'distutils' referenced before assignment
  This error happens building from source in Linux. Introduced in https://github.com/pytorch/pytorch/pull/3993
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `tools/setup_helpers/ninja_builder.py`
  Content:
  ```
  1 import re
  2 import os
  3 import sys
  4 import setuptools
  5 import distutils
  6 from contextlib import contextmanager
  7 import subprocess
  8 
  9 BUILD_DIR = 'build'
  10 
  11 
  12 # on the fly create a ninja file in build/ and then
  13 # run it when run() is called.
  14 class NinjaBuilder(object):
  15     def __init__(self, name):
  16         import ninja
  17         if not os.path.exists(BUILD_DIR):
  18             os.mkdir(BUILD_DIR)
  19         self.ninja_program = os.path.join(ninja.BIN_DIR, 'ninja')
  20         self.name = name
  21         self.filename = os.path.join(BUILD_DIR, 'build.{}.ninja'.format(name))
  22         self.writer = ninja.Writer(open(self.filename, 'w'))
  23         self.writer.rule('do_cmd', '$cmd')
  24         self.writer.rule('compile', '$cmd')
  25         self.compdb_targets = []
  26 
  27     def run(self):
  28         import ninja
  29         self.writer.close()
  30         try:
  31             subprocess.check_call([self.ninja_program, '-f', self.filename])
  32         except subprocess.CalledProcessError as err:
  33             # avoid printing the setup.py stack trace because it obscures the
  34             # C++ errors.
  35             sys.stderr.write(str(err) + '\n')
  36             sys.exit(1)
  37         compile_db_path = os.path.join(BUILD_DIR, '{}_compile_commands.json'.format(self.name))
  38         with open(compile_db_path, 'w') as compile_db:
  39             subprocess.check_call([self.ninja_program, '-f', self.filename,
  40                                    '-t', 'compdb', 'compile'], stdout=compile_db)
  41 
  42         # weird build logic in build develop causes some things to be run
  43         # twice so make sure even after we run the command we still
  44         # reset this to a valid state
  45         # don't use the same name or you can't inspect the real ninja files
  46         self.__init__(self.name + "_")
  47 
  48 
  49 class ninja_build_ext(setuptools.command.build_ext.build_ext):
  50     def _build_default(self, ext):
  51         return setuptools.command.build_ext.build_ext.build_extension(self, ext)
  52 
  53     def build_extension(self, ext):
  54         builder = NinjaBuilder(ext.name)
  55 
  56         @contextmanager
  57         def patch(obj, attr_name, val):
  58             orig_val = getattr(obj, attr_name)
  59             setattr(obj, attr_name, val)
  60             try:
  61                 yield
  62             finally:
  63                 setattr(obj, attr_name, orig_val)
  64 
  65         if self.compiler.compiler_type == 'msvc':
  66             import distutils.msvccompiler
  67             import distutils.msvc9compiler
  68             if sys.version[0] == 2:
  69                 orig_compiler = distutils.msvc9compiler.MSVCCompiler
  70             else:
  71                 orig_compiler = distutils._msvccompiler.MSVCCompiler
  72             orig_compile = orig_compiler.compile
  73             orig_link = orig_compiler.link
  74             orig_spawn = orig_compiler.spawn
  75         else:
  76             orig_compiler = distutils.unixccompiler.UnixCCompiler
  77             orig_compile = orig_compiler._compile
  78             orig_link = orig_compiler.link
  79 
  80         def win_compile(self, sources,
  81                         output_dir=None, macros=None, include_dirs=None, debug=0,
  82                         extra_preargs=None, extra_postargs=None, depends=None):
  83 
  84             def spawn(cmd):
  85                 # Using regex to match src and obj
  86 
  87                 src_regex = re.compile('/T(p|c)(.*)')
  88                 src_list = [m.group(2) for m in (
  89                     src_regex.match(elem) for elem in cmd) if m]
  90 
  91                 obj_regex = re.compile('/Fo(.*)')
  92                 obj_list = [m.group(1) for m in (
  93                     obj_regex.match(elem) for elem in cmd) if m]
  94 
  95                 if len(src_list) >= 1 and len(obj_list) >= 1:
  96                     src = src_list[0]
  97                     obj = obj_list[0]
  98                 else:
  99                     # Cannot find src or obj, revert back to original style
  100                     return orig_spawn(cmd)
  101 
  102                 builder.writer.build(
  103                     [obj], 'compile', [src],
  104                     variables={
  105                         'cmd': cmd,
  106                         'deps': 'msvc'
  107                     })
  108 
  109             with patch(self, 'spawn', spawn):
  110                 orig_compile(self, sources,
  111                              output_dir, macros, include_dirs, debug,
  112                              extra_preargs, extra_postargs, depends)
  113 
  114         def unix_compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts):
  115             depfile = os.path.splitext(obj)[0] + '.d'
  116 
  117             def spawn(cmd):
  118                 builder.writer.build(
  119                     [obj], 'compile', [src],
  120                     variables={
  121                         'cmd': cmd,
  122                         'depfile': depfile,
  123                         'deps': 'gcc'
  124                     })
  125 
  126             extra_postargs = extra_postargs + ['-MMD', '-MF', depfile]
  127             with patch(self, 'spawn', spawn):
  128                 orig_compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts)
  129 
  130         def link(self, target_desc, objects,
  131                  output_filename, output_dir=None, libraries=None,
  132                  library_dirs=None, runtime_library_dirs=None,
  133                  export_symbols=None, debug=0, extra_preargs=None,
  134                  extra_postargs=None, build_temp=None, target_lang=None):
  135 
  136             builder.run()
  137             orig_link(self, target_desc, objects,
  138                       output_filename, output_dir, libraries,
  139                       library_dirs, runtime_library_dirs,
  140                       export_symbols, debug, extra_preargs,
  141                       extra_postargs, build_temp, target_lang)
  142 
  143         if self.compiler.compiler_type == 'msvc':
  144             _compile_func = win_compile
  145             _compile_func_name = 'compile'
  146         else:
  147             _compile_func = unix_compile
  148             _compile_func_name = '_compile'
  149 
  150         with patch(orig_compiler, _compile_func_name, _compile_func):
  151             with patch(orig_compiler, 'link', link):
  152                 with patch(self, 'force', True):
  153                     self._build_default(ext)
  154
  ```
  --- 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()
  
  ```
  
golden_diff: diff --git a/tools/setup_helpers/ninja_builder.py b/tools/setup_helpers/ninja_builder.py
  --- a/tools/setup_helpers/ninja_builder.py
  +++ b/tools/setup_helpers/ninja_builder.py
  @@ -73,6 +73,7 @@
               orig_link = orig_compiler.link
               orig_spawn = orig_compiler.spawn
           else:
  +            import distutils.unixccompiler
               orig_compiler = distutils.unixccompiler.UnixCCompiler
               orig_compile = orig_compiler._compile
               orig_link = orig_compiler.link
  
verification_info: {"golden_diff": "diff --git a/tools/setup_helpers/ninja_builder.py b/tools/setup_helpers/ninja_builder.py\n--- a/tools/setup_helpers/ninja_builder.py\n+++ b/tools/setup_helpers/ninja_builder.py\n@@ -73,6 +73,7 @@\n             orig_link = orig_compiler.link\n             orig_spawn = orig_compiler.spawn\n         else:\n+            import distutils.unixccompiler\n             orig_compiler = distutils.unixccompiler.UnixCCompiler\n             orig_compile = orig_compiler._compile\n             orig_link = orig_compiler.link\n", "issue": "UnboundLocalError: local variable 'distutils' referenced before assignment\nThis error happens building from source in Linux. Introduced in https://github.com/pytorch/pytorch/pull/3993\n", "before_files": [{"content": "import re\nimport os\nimport sys\nimport setuptools\nimport distutils\nfrom contextlib import contextmanager\nimport subprocess\n\nBUILD_DIR = 'build'\n\n\n# on the fly create a ninja file in build/ and then\n# run it when run() is called.\nclass NinjaBuilder(object):\n    def __init__(self, name):\n        import ninja\n        if not os.path.exists(BUILD_DIR):\n            os.mkdir(BUILD_DIR)\n        self.ninja_program = os.path.join(ninja.BIN_DIR, 'ninja')\n        self.name = name\n        self.filename = os.path.join(BUILD_DIR, 'build.{}.ninja'.format(name))\n        self.writer = ninja.Writer(open(self.filename, 'w'))\n        self.writer.rule('do_cmd', '$cmd')\n        self.writer.rule('compile', '$cmd')\n        self.compdb_targets = []\n\n    def run(self):\n        import ninja\n        self.writer.close()\n        try:\n            subprocess.check_call([self.ninja_program, '-f', self.filename])\n        except subprocess.CalledProcessError as err:\n            # avoid printing the setup.py stack trace because it obscures the\n            # C++ errors.\n            sys.stderr.write(str(err) + '\\n')\n            sys.exit(1)\n        compile_db_path = os.path.join(BUILD_DIR, '{}_compile_commands.json'.format(self.name))\n        with open(compile_db_path, 'w') as compile_db:\n            subprocess.check_call([self.ninja_program, '-f', self.filename,\n                                   '-t', 'compdb', 'compile'], stdout=compile_db)\n\n        # weird build logic in build develop causes some things to be run\n        # twice so make sure even after we run the command we still\n        # reset this to a valid state\n        # don't use the same name or you can't inspect the real ninja files\n        self.__init__(self.name + \"_\")\n\n\nclass ninja_build_ext(setuptools.command.build_ext.build_ext):\n    def _build_default(self, ext):\n        return setuptools.command.build_ext.build_ext.build_extension(self, ext)\n\n    def build_extension(self, ext):\n        builder = NinjaBuilder(ext.name)\n\n        @contextmanager\n        def patch(obj, attr_name, val):\n            orig_val = getattr(obj, attr_name)\n            setattr(obj, attr_name, val)\n            try:\n                yield\n            finally:\n                setattr(obj, attr_name, orig_val)\n\n        if self.compiler.compiler_type == 'msvc':\n            import distutils.msvccompiler\n            import distutils.msvc9compiler\n            if sys.version[0] == 2:\n                orig_compiler = distutils.msvc9compiler.MSVCCompiler\n            else:\n                orig_compiler = distutils._msvccompiler.MSVCCompiler\n            orig_compile = orig_compiler.compile\n            orig_link = orig_compiler.link\n            orig_spawn = orig_compiler.spawn\n        else:\n            orig_compiler = distutils.unixccompiler.UnixCCompiler\n            orig_compile = orig_compiler._compile\n            orig_link = orig_compiler.link\n\n        def win_compile(self, sources,\n                        output_dir=None, macros=None, include_dirs=None, debug=0,\n                        extra_preargs=None, extra_postargs=None, depends=None):\n\n            def spawn(cmd):\n                # Using regex to match src and obj\n\n                src_regex = re.compile('/T(p|c)(.*)')\n                src_list = [m.group(2) for m in (\n                    src_regex.match(elem) for elem in cmd) if m]\n\n                obj_regex = re.compile('/Fo(.*)')\n                obj_list = [m.group(1) for m in (\n                    obj_regex.match(elem) for elem in cmd) if m]\n\n                if len(src_list) >= 1 and len(obj_list) >= 1:\n                    src = src_list[0]\n                    obj = obj_list[0]\n                else:\n                    # Cannot find src or obj, revert back to original style\n                    return orig_spawn(cmd)\n\n                builder.writer.build(\n                    [obj], 'compile', [src],\n                    variables={\n                        'cmd': cmd,\n                        'deps': 'msvc'\n                    })\n\n            with patch(self, 'spawn', spawn):\n                orig_compile(self, sources,\n                             output_dir, macros, include_dirs, debug,\n                             extra_preargs, extra_postargs, depends)\n\n        def unix_compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts):\n            depfile = os.path.splitext(obj)[0] + '.d'\n\n            def spawn(cmd):\n                builder.writer.build(\n                    [obj], 'compile', [src],\n                    variables={\n                        'cmd': cmd,\n                        'depfile': depfile,\n                        'deps': 'gcc'\n                    })\n\n            extra_postargs = extra_postargs + ['-MMD', '-MF', depfile]\n            with patch(self, 'spawn', spawn):\n                orig_compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts)\n\n        def link(self, target_desc, objects,\n                 output_filename, output_dir=None, libraries=None,\n                 library_dirs=None, runtime_library_dirs=None,\n                 export_symbols=None, debug=0, extra_preargs=None,\n                 extra_postargs=None, build_temp=None, target_lang=None):\n\n            builder.run()\n            orig_link(self, target_desc, objects,\n                      output_filename, output_dir, libraries,\n                      library_dirs, runtime_library_dirs,\n                      export_symbols, debug, extra_preargs,\n                      extra_postargs, build_temp, target_lang)\n\n        if self.compiler.compiler_type == 'msvc':\n            _compile_func = win_compile\n            _compile_func_name = 'compile'\n        else:\n            _compile_func = unix_compile\n            _compile_func_name = '_compile'\n\n        with patch(orig_compiler, _compile_func_name, _compile_func):\n            with patch(orig_compiler, 'link', link):\n                with patch(self, 'force', True):\n                    self._build_default(ext)\n", "path": "tools/setup_helpers/ninja_builder.py"}], "after_files": [{"content": "import re\nimport os\nimport sys\nimport setuptools\nimport distutils\nfrom contextlib import contextmanager\nimport subprocess\n\nBUILD_DIR = 'build'\n\n\n# on the fly create a ninja file in build/ and then\n# run it when run() is called.\nclass NinjaBuilder(object):\n    def __init__(self, name):\n        import ninja\n        if not os.path.exists(BUILD_DIR):\n            os.mkdir(BUILD_DIR)\n        self.ninja_program = os.path.join(ninja.BIN_DIR, 'ninja')\n        self.name = name\n        self.filename = os.path.join(BUILD_DIR, 'build.{}.ninja'.format(name))\n        self.writer = ninja.Writer(open(self.filename, 'w'))\n        self.writer.rule('do_cmd', '$cmd')\n        self.writer.rule('compile', '$cmd')\n        self.compdb_targets = []\n\n    def run(self):\n        import ninja\n        self.writer.close()\n        try:\n            subprocess.check_call([self.ninja_program, '-f', self.filename])\n        except subprocess.CalledProcessError as err:\n            # avoid printing the setup.py stack trace because it obscures the\n            # C++ errors.\n            sys.stderr.write(str(err) + '\\n')\n            sys.exit(1)\n        compile_db_path = os.path.join(BUILD_DIR, '{}_compile_commands.json'.format(self.name))\n        with open(compile_db_path, 'w') as compile_db:\n            subprocess.check_call([self.ninja_program, '-f', self.filename,\n                                   '-t', 'compdb', 'compile'], stdout=compile_db)\n\n        # weird build logic in build develop causes some things to be run\n        # twice so make sure even after we run the command we still\n        # reset this to a valid state\n        # don't use the same name or you can't inspect the real ninja files\n        self.__init__(self.name + \"_\")\n\n\nclass ninja_build_ext(setuptools.command.build_ext.build_ext):\n    def _build_default(self, ext):\n        return setuptools.command.build_ext.build_ext.build_extension(self, ext)\n\n    def build_extension(self, ext):\n        builder = NinjaBuilder(ext.name)\n\n        @contextmanager\n        def patch(obj, attr_name, val):\n            orig_val = getattr(obj, attr_name)\n            setattr(obj, attr_name, val)\n            try:\n                yield\n            finally:\n                setattr(obj, attr_name, orig_val)\n\n        if self.compiler.compiler_type == 'msvc':\n            import distutils.msvccompiler\n            import distutils.msvc9compiler\n            if sys.version[0] == 2:\n                orig_compiler = distutils.msvc9compiler.MSVCCompiler\n            else:\n                orig_compiler = distutils._msvccompiler.MSVCCompiler\n            orig_compile = orig_compiler.compile\n            orig_link = orig_compiler.link\n            orig_spawn = orig_compiler.spawn\n        else:\n            import distutils.unixccompiler\n            orig_compiler = distutils.unixccompiler.UnixCCompiler\n            orig_compile = orig_compiler._compile\n            orig_link = orig_compiler.link\n\n        def win_compile(self, sources,\n                        output_dir=None, macros=None, include_dirs=None, debug=0,\n                        extra_preargs=None, extra_postargs=None, depends=None):\n\n            def spawn(cmd):\n                # Using regex to match src and obj\n\n                src_regex = re.compile('/T(p|c)(.*)')\n                src_list = [m.group(2) for m in (\n                    src_regex.match(elem) for elem in cmd) if m]\n\n                obj_regex = re.compile('/Fo(.*)')\n                obj_list = [m.group(1) for m in (\n                    obj_regex.match(elem) for elem in cmd) if m]\n\n                if len(src_list) >= 1 and len(obj_list) >= 1:\n                    src = src_list[0]\n                    obj = obj_list[0]\n                else:\n                    # Cannot find src or obj, revert back to original style\n                    return orig_spawn(cmd)\n\n                builder.writer.build(\n                    [obj], 'compile', [src],\n                    variables={\n                        'cmd': cmd,\n                        'deps': 'msvc'\n                    })\n\n            with patch(self, 'spawn', spawn):\n                orig_compile(self, sources,\n                             output_dir, macros, include_dirs, debug,\n                             extra_preargs, extra_postargs, depends)\n\n        def unix_compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts):\n            depfile = os.path.splitext(obj)[0] + '.d'\n\n            def spawn(cmd):\n                builder.writer.build(\n                    [obj], 'compile', [src],\n                    variables={\n                        'cmd': cmd,\n                        'depfile': depfile,\n                        'deps': 'gcc'\n                    })\n\n            extra_postargs = extra_postargs + ['-MMD', '-MF', depfile]\n            with patch(self, 'spawn', spawn):\n                orig_compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts)\n\n        def link(self, target_desc, objects,\n                 output_filename, output_dir=None, libraries=None,\n                 library_dirs=None, runtime_library_dirs=None,\n                 export_symbols=None, debug=0, extra_preargs=None,\n                 extra_postargs=None, build_temp=None, target_lang=None):\n\n            builder.run()\n            orig_link(self, target_desc, objects,\n                      output_filename, output_dir, libraries,\n                      library_dirs, runtime_library_dirs,\n                      export_symbols, debug, extra_preargs,\n                      extra_postargs, build_temp, target_lang)\n\n        if self.compiler.compiler_type == 'msvc':\n            _compile_func = win_compile\n            _compile_func_name = 'compile'\n        else:\n            _compile_func = unix_compile\n            _compile_func_name = '_compile'\n\n        with patch(orig_compiler, _compile_func_name, _compile_func):\n            with patch(orig_compiler, 'link', link):\n                with patch(self, 'force', True):\n                    self._build_default(ext)\n", "path": "tools/setup_helpers/ninja_builder.py"}]}