def test_custom_pydistutils(self): if os.name == 'posix': user_filename = '.pydistutils.cfg' else: user_filename = 'pydistutils.cfg' temp_dir = self.mkdtemp() user_filename = os.path.join(temp_dir, user_filename) f = open(user_filename, 'w') try: f.write('.') finally: f.close() try: dist = Distribution() if sys.platform in ('linux', 'darwin'): os.environ['HOME'] = temp_dir files = dist.find_config_files() self.assertIn(user_filename, files) if sys.platform == 'win32': os.environ['HOME'] = temp_dir files = dist.find_config_files() self.assertIn(user_filename, files, '%r not found in %r' % (user_filename, files)) finally: os.remove(user_filename)
def test_custom_pydistutils(self): # fixes #2166 # make sure pydistutils.cfg is found if os.name == 'posix': user_filename = ".pydistutils.cfg" else: user_filename = "pydistutils.cfg" temp_dir = self.mkdtemp() user_filename = os.path.join(temp_dir, user_filename) f = open(user_filename, 'w') try: f.write('.') finally: f.close() try: dist = Distribution() # linux-style if sys.platform in ('linux', 'darwin'): os.environ['HOME'] = temp_dir files = dist.find_config_files() self.assertIn(user_filename, files) # win32-style if sys.platform == 'win32': # home drive should be found os.environ['USERPROFILE'] = temp_dir files = dist.find_config_files() self.assertIn(user_filename, files, '%r not found in %r' % (user_filename, files)) finally: os.remove(user_filename)
def test_find_config_files_disable(self): # Ticket #1180: Allow user to disable their home config file. temp_home = self.mkdtemp() if os.name == 'posix': user_filename = os.path.join(temp_home, ".pydistutils.cfg") else: user_filename = os.path.join(temp_home, "pydistutils.cfg") with open(user_filename, 'w') as f: f.write('[distutils]\n') def _expander(path): return temp_home old_expander = os.path.expanduser os.path.expanduser = _expander try: d = Distribution() all_files = d.find_config_files() d = Distribution(attrs={'script_args': ['--no-user-cfg']}) files = d.find_config_files() finally: os.path.expanduser = old_expander # make sure --no-user-cfg disables the user cfg file self.assertEqual(len(all_files)-1, len(files))
def test_custom_pydistutils(self): # fixes #2166 # make sure pydistutils.cfg is found if os.name == 'posix': user_filename = ".pydistutils.cfg" else: user_filename = "pydistutils.cfg" temp_dir = self.mkdtemp() user_filename = os.path.join(temp_dir, user_filename) f = open(user_filename, 'w') try: f.write('.') finally: f.close() try: dist = Distribution() # linux-style if sys.platform in ('linux', 'darwin'): os.environ['HOME'] = temp_dir files = dist.find_config_files() self.assertIn(user_filename, files) # win32-style if sys.platform == 'win32': # home drive should be found os.environ['HOME'] = temp_dir files = dist.find_config_files() self.assertIn(user_filename, files, '%r not found in %r' % (user_filename, files)) finally: os.remove(user_filename)
def test_find_config_files_disable(self): # Ticket #1180: Allow user to disable their home config file. temp_home = self.mkdtemp() if os.name == 'posix': user_filename = os.path.join(temp_home, ".pydistutils.cfg") else: user_filename = os.path.join(temp_home, "pydistutils.cfg") with open(user_filename, 'w') as f: f.write('[distutils]\n') def _expander(path): return temp_home old_expander = os.path.expanduser os.path.expanduser = _expander try: d = Distribution() all_files = d.find_config_files() d = Distribution(attrs={'script_args': ['--no-user-cfg']}) files = d.find_config_files() finally: os.path.expanduser = old_expander # make sure --no-user-cfg disables the user cfg file self.assertEqual(len(all_files) - 1, len(files))
def test_custom_pydistutils(self): # fixes #2166 # make sure pydistutils.cfg is found if os.name == "posix": user_filename = ".pydistutils.cfg" else: user_filename = "pydistutils.cfg" temp_dir = self.mkdtemp() user_filename = os.path.join(temp_dir, user_filename) f = open(user_filename, "w") try: f.write(".") finally: f.close() try: dist = Distribution() # linux-style if sys.platform in ("linux", "darwin"): os.environ["HOME"] = temp_dir files = dist.find_config_files() self.assertIn(user_filename, files) # win32-style if sys.platform == "win32": # home drive should be found os.environ["HOME"] = temp_dir files = dist.find_config_files() self.assertIn(user_filename, files, "%r not found in %r" % (user_filename, files)) finally: os.remove(user_filename)
def handle(self, *args, **options): cmd = ('python setup.py {quiet} extract_messages ' '-F babel-{domain}.cfg ' '--input-dirs {module} ' '-o {potfile}') distribution = Distribution() distribution.parse_config_files(distribution.find_config_files()) quiet = '-q' if int(options['verbosity']) == 0 else '' if options['check_only']: cmd += " ; rm {potfile}" for module in options['module']: for domain in options['domain']: potfile = '{module}/locale/{domain}.pot'.format(module=module, domain=domain) if not os.path.exists(potfile): with open(potfile, 'wb') as f: f.write(b'') call(cmd.format(module=module, domain=domain, potfile=potfile, quiet=quiet), shell=True)
def handle_makemessages(self, **options): locale_paths = list(settings.LOCALE_PATHS) domain = options.pop('domain') locales = options.pop('locale') # support for mapping file specification via setup.cfg # TODO: Try to support all possible options. distribution = Distribution() distribution.parse_config_files(distribution.find_config_files()) mapping_file = options.pop('mapping_file', None) has_extract = 'extract_messages' in distribution.command_options if mapping_file is None and has_extract: opts = distribution.command_options['extract_messages'] try: mapping_file = opts['mapping_file'][1] except (IndexError, KeyError): mapping_file = None for path in locale_paths: potfile = os.path.join(path, '%s.pot' % domain) if not os.path.exists(path): os.makedirs(path) if not os.path.exists(potfile): with open(potfile, 'wb') as fobj: fobj.write(b'') cmd = ['pybabel', 'extract', '-o', potfile] if mapping_file is not None: cmd.extend(['-F', mapping_file]) cmd.append(os.path.dirname(os.path.relpath(path))) call(cmd) for locale in locales: pofile = os.path.join( os.path.dirname(potfile), locale, 'LC_MESSAGES', '%s.po' % domain) if not os.path.isdir(os.path.dirname(pofile)): os.makedirs(os.path.dirname(pofile)) if not os.path.exists(pofile): with open(pofile, 'wb') as fobj: fobj.write(b'') cmd = ['pybabel', 'update', '-D', domain, '-i', potfile, '-d', os.path.relpath(path), '-l', locale] call(cmd)
def build_so(module_name, sources, setup_args=None): from distutils.dist import Distribution from distutils.errors import DistutilsArgError from distutils.extension import Extension from shutil import copy2 setup_args = generate_setup_args(setup_args) dist = Distribution(setup_args) ext = Extension( name = module_name, sources = sources, include_dirs = [ find_handsome_include_dir() ], extra_compile_args = [ '-std=c++11' ], ) if dist.ext_modules is None: dist.ext_modules = [ ext ] else: dist.ext_modules.append(ext) target_dir, _ = os.path.split(os.path.abspath(__file__)) build = dist.get_command_obj('build') build.build_base = os.path.join(target_dir, 'build') cfgfiles = dist.find_config_files() dist.parse_config_files(cfgfiles) try: ok = dist.parse_command_line() except DistutilsArgError: raise if not ok: raise RuntimeError('Build cannot continue') command = dist.get_command_obj("build_ext") dist.run_commands() so_path = os.path.abspath(command.get_outputs()[0]) _, so_name = os.path.split(so_path) target_path = os.path.join(target_dir, so_name) if os.path.isfile(target_path): os.unlink(target_path) copy2(so_path, target_path) return target_path
def find_config_files(self): """Search for additional `setup.cfg` file in source directory.""" files = _Distribution.find_config_files(self) # Handle source-directory setup.cfg local_file = "setup.cfg" filename = os.path.join(self.srcdir, local_file) if os.path.isfile(filename): if local_file in files: files.insert(-1, filename) else: files.append(filename) return files
def _read_artifactory_config_section(): dist = Distribution() file_names = dist.find_config_files() dist.parse_config_files(filenames=file_names) artifactory_config_key = "artifactory" artifactory_opts = dist.get_option_dict(artifactory_config_key) if not artifactory_opts: raise DistutilsOptionError('Could not find a {} section in {}'.format( artifactory_config_key, file_names)) return artifactory_opts
def test_find_config_files_disable(self): temp_home = self.mkdtemp() if os.name == 'posix': user_filename = os.path.join(temp_home, '.pydistutils.cfg') else: user_filename = os.path.join(temp_home, 'pydistutils.cfg') with open(user_filename, 'w') as f: f.write('[distutils]\n') def _expander(path): return temp_home old_expander = os.path.expanduser os.path.expanduser = _expander try: d = Distribution() all_files = d.find_config_files() d = Distribution(attrs={'script_args': ['--no-user-cfg']}) files = d.find_config_files() finally: os.path.expanduser = old_expander self.assertEqual(len(all_files) - 1, len(files))
def _read_artifactory_config_section(): dist = Distribution() file_names = dist.find_config_files() dist.parse_config_files(filenames=file_names) artifactory_config_key = "artifactory" artifactory_opts = dist.get_option_dict(artifactory_config_key) if not artifactory_opts: raise DistutilsOptionError( 'Could not find a {} section in {}'.format( artifactory_config_key, file_names)) return artifactory_opts
def handle(self, *args, **options): cmd = ('python setup.py extract_messages -F babel-{domain}.cfg ' '-o {module}/locale/{domain}.pot') distribution = Distribution() distribution.parse_config_files(distribution.find_config_files()) if options['check_only']: cmd += " ; rm {module}/locale/{domain}.pot" for module in options['module']: for domain in options['domain']: potfile = '{module}/locale/{domain}.pot'.format(module=module, domain=domain) if not os.path.exists(potfile): with open(potfile, 'wb') as f: f.write(b'') call(cmd.format(module=module, domain=domain, potfile=potfile), shell=True)
def compile_with_distutils(extension_name, src_filename, extra_objects = [], extra_compiler_flags = [], extra_link_flags = [], print_commands = False): # copied largely from pyxbuild from distutils.dist import Distribution from distutils.extension import Extension compiler_flags = get_compiler_flags(extra_compiler_flags) # don't need -shared in the flags since the default CC on Mac OS # might specify -bundle instead and the two are mutually exclusive linker_flags = get_linker_flags(extra_link_flags, shared=False) ext = Extension(name=extension_name, sources=[src_filename], include_dirs = include_dirs, extra_objects=extra_objects, extra_compile_args=compiler_flags, extra_link_args=linker_flags) script_args = ['build_ext', '--quiet'] setup_args = {"script_name": None, "script_args": script_args, } dist = Distribution(setup_args) if not dist.ext_modules: dist.ext_modules = [] dist.ext_modules.append(ext) # I have no idea how distutils works or why I have to do any of this config_files = dist.find_config_files() try: config_files.remove('setup.cfg') except ValueError: pass dist.parse_config_files(config_files) dist.parse_command_line() obj_build_ext = dist.get_command_obj("build_ext") dist.run_commands() shared_name = obj_build_ext.get_outputs()[0] return shared_name
def pyx_to_dll(filename, ext=None, force_rebuild=0, build_in_temp=False, pyxbuild_dir=None, setup_args={}, reload_support=False): """Compile a PYX file to a DLL and return the name of the generated .so or .dll .""" assert os.path.exists( filename), "Could not find %s" % os.path.abspath(filename) path, name = os.path.split(filename) if not ext: modname, extension = os.path.splitext(name) assert extension in (".pyx", ".py"), extension if not HAS_CYTHON: filename = filename[:-len(extension)] + '.c' ext = Extension(name=modname, sources=[filename]) if not pyxbuild_dir: pyxbuild_dir = os.path.join(path, "_pyxbld") script_args = setup_args.get("script_args", []) if DEBUG or "--verbose" in script_args: quiet = "--verbose" else: quiet = "--quiet" args = [quiet, "build_ext"] if force_rebuild: args.append("--force") if HAS_CYTHON and build_in_temp: args.append("--pyrex-c-in-temp") sargs = setup_args.copy() sargs.update({"script_name": None, "script_args": args + script_args}) dist = Distribution(sargs) if not dist.ext_modules: dist.ext_modules = [] dist.ext_modules.append(ext) if HAS_CYTHON: dist.cmdclass = {'build_ext': build_ext} build = dist.get_command_obj('build') build.build_base = pyxbuild_dir config_files = dist.find_config_files() try: config_files.remove('setup.cfg') except ValueError: pass dist.parse_config_files(config_files) cfgfiles = dist.find_config_files() try: cfgfiles.remove('setup.cfg') except ValueError: pass dist.parse_config_files(cfgfiles) try: ok = dist.parse_command_line() except DistutilsArgError: raise if DEBUG: print("options (after parsing command line):") dist.dump_option_dicts() assert ok try: dist.run_commands() obj_build_ext = dist.get_command_obj("build_ext") so_path = obj_build_ext.get_outputs()[0] if obj_build_ext.inplace: # Python distutils get_outputs()[ returns a wrong so_path # when --inplace ; see http://bugs.python.org/issue5977 # workaround: so_path = os.path.join(os.path.dirname(filename), os.path.basename(so_path)) if reload_support: org_path = so_path timestamp = os.path.getmtime(org_path) global _reloads last_timestamp, last_path, count = _reloads.get( org_path, (None, None, 0)) if last_timestamp == timestamp: so_path = last_path else: basename = os.path.basename(org_path) while count < 100: count += 1 r_path = os.path.join(obj_build_ext.build_lib, basename + '.reload%s' % count) try: import shutil # late import / reload_support is: debugging shutil.copy2(org_path, r_path) so_path = r_path except IOError: continue break else: # used up all 100 slots raise ImportError("reload count for %s reached maximum" % org_path) _reloads[org_path] = (timestamp, so_path, count) return so_path except KeyboardInterrupt: sys.exit(1) except (IOError, os.error): exc = sys.exc_info()[1] error = grok_environment_error(exc) if DEBUG: sys.stderr.write(error + "\n") raise
def pyx_to_dll( filename, ext=None, force_rebuild=0, build_in_temp=False, pyxbuild_dir=None, setup_args={}, reload_support=False ): """Compile a PYX file to a DLL and return the name of the generated .so or .dll .""" assert os.path.exists(filename), "Could not find %s" % os.path.abspath(filename) path, name = os.path.split(filename) if not ext: modname, extension = os.path.splitext(name) assert extension in (".pyx", ".py"), extension if not HAS_CYTHON: filename = filename[: -len(extension)] + ".c" ext = Extension(name=modname, sources=[filename]) if not pyxbuild_dir: pyxbuild_dir = os.path.join(path, "_pyxbld") script_args = setup_args.get("script_args", []) if DEBUG or "--verbose" in script_args: quiet = "--verbose" else: quiet = "--quiet" args = [quiet, "build_ext"] if force_rebuild: args.append("--force") if HAS_CYTHON and build_in_temp: args.append("--pyrex-c-in-temp") sargs = setup_args.copy() sargs.update({"script_name": None, "script_args": args + script_args}) dist = Distribution(sargs) if not dist.ext_modules: dist.ext_modules = [] dist.ext_modules.append(ext) if HAS_CYTHON: dist.cmdclass = {"build_ext": build_ext} build = dist.get_command_obj("build") build.build_base = pyxbuild_dir config_files = dist.find_config_files() try: config_files.remove("setup.cfg") except ValueError: pass dist.parse_config_files(config_files) cfgfiles = dist.find_config_files() try: cfgfiles.remove("setup.cfg") except ValueError: pass dist.parse_config_files(cfgfiles) try: ok = dist.parse_command_line() except DistutilsArgError: raise if DEBUG: print("options (after parsing command line):") dist.dump_option_dicts() assert ok try: dist.run_commands() obj_build_ext = dist.get_command_obj("build_ext") so_path = obj_build_ext.get_outputs()[0] if obj_build_ext.inplace: # Python distutils get_outputs()[ returns a wrong so_path # when --inplace ; see http://bugs.python.org/issue5977 # workaround: so_path = os.path.join(os.path.dirname(filename), os.path.basename(so_path)) if reload_support: org_path = so_path timestamp = os.path.getmtime(org_path) global _reloads last_timestamp, last_path, count = _reloads.get(org_path, (None, None, 0)) if last_timestamp == timestamp: so_path = last_path else: basename = os.path.basename(org_path) while count < 100: count += 1 r_path = os.path.join(obj_build_ext.build_lib, basename + ".reload%s" % count) try: import shutil # late import / reload_support is: debugging shutil.copy2(org_path, r_path) so_path = r_path except IOError: continue break else: # used up all 100 slots raise ImportError("reload count for %s reached maximum" % org_path) _reloads[org_path] = (timestamp, so_path, count) return so_path except KeyboardInterrupt: sys.exit(1) except (IOError, os.error): exc = sys.exc_info()[1] error = grok_environment_error(exc) if DEBUG: sys.stderr.write(error + "\n") raise
def pyx_to_dll(filename, ext=None, force_rebuild=0, build_in_temp=False, pyxbuild_dir=None, setup_args={}, reload_support=False, inplace=False): """Compile a PYX file to a DLL and return the name of the generated .so or .dll .""" assert os.path.exists( filename), "Could not find %s" % os.path.abspath(filename) path, name = os.path.split(os.path.abspath(filename)) if not ext: modname, extension = os.path.splitext(name) assert extension in (".pyx", ".py"), extension if not HAS_CYTHON: filename = filename[:-len(extension)] + '.c' ext = Extension(name=modname, sources=[filename]) if not pyxbuild_dir: pyxbuild_dir = os.path.join(path, "_pyxbld") package_base_dir = path for package_name in ext.name.split('.')[-2::-1]: package_base_dir, pname = os.path.split(package_base_dir) if pname != package_name: # something is wrong - package path doesn't match file path package_base_dir = None break script_args = setup_args.get("script_args", []) if DEBUG or "--verbose" in script_args: quiet = "--verbose" else: quiet = "--quiet" args = [quiet, "build_ext"] if force_rebuild: args.append("--force") if inplace and package_base_dir: args.extend(['--build-lib', package_base_dir]) if ext.name == '__init__' or ext.name.endswith('.__init__'): # package => provide __path__ early if not hasattr(ext, 'cython_directives'): ext.cython_directives = {'set_initial_path': 'SOURCEFILE'} elif 'set_initial_path' not in ext.cython_directives: ext.cython_directives['set_initial_path'] = 'SOURCEFILE' if HAS_CYTHON and build_in_temp: args.append("--pyrex-c-in-temp") sargs = setup_args.copy() sargs.update({"script_name": None, "script_args": args + script_args}) dist = Distribution(sargs) if not dist.ext_modules: dist.ext_modules = [] dist.ext_modules.append(ext) if HAS_CYTHON: dist.cmdclass = {'build_ext': build_ext} build = dist.get_command_obj('build') build.build_base = pyxbuild_dir cfgfiles = dist.find_config_files() dist.parse_config_files(cfgfiles) try: ok = dist.parse_command_line() except DistutilsArgError: raise if DEBUG: print("options (after parsing command line):") dist.dump_option_dicts() assert ok try: obj_build_ext = dist.get_command_obj("build_ext") dist.run_commands() so_path = obj_build_ext.get_outputs()[0] if obj_build_ext.inplace: # Python distutils get_outputs()[ returns a wrong so_path # when --inplace ; see http://bugs.python.org/issue5977 # workaround: so_path = os.path.join(os.path.dirname(filename), os.path.basename(so_path)) if reload_support: org_path = so_path timestamp = os.path.getmtime(org_path) global _reloads last_timestamp, last_path, count = _reloads.get( org_path, (None, None, 0)) if last_timestamp == timestamp: so_path = last_path else: basename = os.path.basename(org_path) while count < 100: count += 1 r_path = os.path.join(obj_build_ext.build_lib, basename + '.reload%s' % count) try: import shutil # late import / reload_support is: debugging try: # Try to unlink first --- if the .so file # is mmapped by another process, # overwriting its contents corrupts the # loaded image (on Linux) and crashes the # other process. On Windows, unlinking an # open file just fails. if os.path.isfile(r_path): os.unlink(r_path) except OSError: continue shutil.copy2(org_path, r_path) so_path = r_path except IOError: continue break else: # used up all 100 slots raise ImportError("reload count for %s reached maximum" % org_path) _reloads[org_path] = (timestamp, so_path, count) return so_path except KeyboardInterrupt: sys.exit(1) except (IOError, os.error): exc = sys.exc_info()[1] error = grok_environment_error(exc) if DEBUG: sys.stderr.write(error + "\n") raise
def c_to_dll(filename, ext = None, force_rebuild = 0, build_in_temp=False, cbuild_dir=None, setup_args={}, reload_support=False, inplace=False): """Compile a C file to a DLL and return the name of the generated .so or .dll .""" assert os.path.exists(filename), "Could not find %s" % os.path.abspath(filename) path, name = os.path.split(os.path.abspath(filename)) if not ext: modname, extension = os.path.splitext(name) assert extension in (".c", ".py"), extension if not HAS_CYTHON: filename = filename[:-len(extension)] + '.c' ext = Extension(name=modname, sources=[filename]) if not cbuild_dir: cbuild_dir = os.path.join(path, "_cbld") package_base_dir = path for package_name in ext.name.split('.')[-2::-1]: package_base_dir, pname = os.path.split(package_base_dir) if pname != package_name: # something is wrong - package path doesn't match file path package_base_dir = None break script_args=setup_args.get("script_args",[]) if DEBUG or "--verbose" in script_args: quiet = "--verbose" else: quiet = "--quiet" args = [quiet, "build_ext"] if force_rebuild: args.append("--force") if inplace and package_base_dir: args.extend(['--build-lib', package_base_dir]) if ext.name == '__init__' or ext.name.endswith('.__init__'): # package => provide __path__ early if not hasattr(ext, 'cython_directives'): ext.cython_directives = {'set_initial_path' : 'SOURCEFILE'} elif 'set_initial_path' not in ext.cython_directives: ext.cython_directives['set_initial_path'] = 'SOURCEFILE' if HAS_CYTHON and build_in_temp: args.append("--pyrex-c-in-temp") sargs = setup_args.copy() sargs.update({ "script_name": None, "script_args": args + script_args, }) # late import, in case setuptools replaced it from distutils.dist import Distribution dist = Distribution(sargs) if not dist.ext_modules: dist.ext_modules = [] dist.ext_modules.append(ext) if HAS_CYTHON: dist.cmdclass = {'build_ext': build_ext} build = dist.get_command_obj('build') build.build_base = cbuild_dir cfgfiles = dist.find_config_files() dist.parse_config_files(cfgfiles) try: ok = dist.parse_command_line() except DistutilsArgError: raise if DEBUG: print("options (after parsing command line):") dist.dump_option_dicts() assert ok try: obj_build_ext = dist.get_command_obj("build_ext") dist.run_commands() so_path = obj_build_ext.get_outputs()[0] if obj_build_ext.inplace: # Python distutils get_outputs()[ returns a wrong so_path # when --inplace ; see http://bugs.python.org/issue5977 # workaround: so_path = os.path.join(os.path.dirname(filename), os.path.basename(so_path)) if reload_support: org_path = so_path timestamp = os.path.getmtime(org_path) global _reloads last_timestamp, last_path, count = _reloads.get(org_path, (None,None,0) ) if last_timestamp == timestamp: so_path = last_path else: basename = os.path.basename(org_path) while count < 100: count += 1 r_path = os.path.join(obj_build_ext.build_lib, basename + '.reload%s'%count) try: import shutil # late import / reload_support is: debugging try: # Try to unlink first --- if the .so file # is mmapped by another process, # overwriting its contents corrupts the # loaded image (on Linux) and crashes the # other process. On Windows, unlinking an # open file just fails. if os.path.isfile(r_path): os.unlink(r_path) except OSError: continue shutil.copy2(org_path, r_path) so_path = r_path except IOError: continue break else: # used up all 100 slots raise ImportError("reload count for %s reached maximum"%org_path) _reloads[org_path]=(timestamp, so_path, count) return so_path except KeyboardInterrupt: sys.exit(1) except (IOError, os.error): exc = sys.exc_info()[1] error = grok_environment_error(exc) if DEBUG: sys.stderr.write(error + "\n") raise
def distutils_scheme( dist_name: str, user: bool = False, home: str = None, root: str = None, isolated: bool = False, prefix: str = None, *, ignore_config_files: bool = False, ) -> Dict[str, str]: """ Return a distutils install scheme """ from distutils.dist import Distribution dist_args: Dict[str, Union[str, List[str]]] = {"name": dist_name} if isolated: dist_args["script_args"] = ["--no-user-cfg"] d = Distribution(dist_args) if not ignore_config_files: try: d.parse_config_files() except UnicodeDecodeError: # Typeshed does not include find_config_files() for some reason. paths = d.find_config_files() # type: ignore logger.warning( "Ignore distutils configs in %s due to encoding errors.", ", ".join(os.path.basename(p) for p in paths), ) obj: Optional[DistutilsCommand] = None obj = d.get_command_obj("install", create=True) assert obj is not None i = cast(distutils_install_command, obj) # NOTE: setting user or home has the side-effect of creating the home dir # or user base for installations during finalize_options() # ideally, we'd prefer a scheme class that has no side-effects. assert not (user and prefix), f"user={user} prefix={prefix}" assert not (home and prefix), f"home={home} prefix={prefix}" i.user = user or i.user if user or home: i.prefix = "" i.prefix = prefix or i.prefix i.home = home or i.home i.root = root or i.root i.finalize_options() scheme = {} for key in SCHEME_KEYS: scheme[key] = getattr(i, "install_" + key) # install_lib specified in setup.cfg should install *everything* # into there (i.e. it takes precedence over both purelib and # platlib). Note, i.install_lib is *always* set after # finalize_options(); we only want to override here if the user # has explicitly requested it hence going back to the config if "install_lib" in d.get_option_dict("install"): scheme.update(dict(purelib=i.install_lib, platlib=i.install_lib)) if running_under_virtualenv(): scheme["headers"] = os.path.join( i.prefix, "include", "site", f"python{get_major_minor_version()}", dist_name, ) if root is not None: path_no_drive = os.path.splitdrive( os.path.abspath(scheme["headers"]))[1] scheme["headers"] = os.path.join( root, path_no_drive[1:], ) return scheme