Index: Misc/NEWS =================================================================== --- Misc/NEWS (revision 61524) +++ Misc/NEWS (working copy) @@ -44,6 +44,9 @@ Library ------- +- Issue #1180: Add a --no-user-cfg option to distutils, allowing the + user to disable ~/.pydistutils.cfg. + - Issue #1202: zlib.crc32 and zlib.adler32 no longer return different values on 32-bit vs. 64-bit python interpreters. Both were correct, but they now both return a signed integer object for consistency. Index: Doc/distutils/builtdist.rst =================================================================== --- Doc/distutils/builtdist.rst (revision 61524) +++ Doc/distutils/builtdist.rst (working copy) @@ -238,7 +238,8 @@ configuration file, :file:`setup.cfg`\ ---see section :ref:`setup-config`. If you distribute or package many Python module distributions, you might want to put options that apply to all of them in your personal Distutils configuration -file (:file:`~/.pydistutils.cfg`). +file (:file:`~/.pydistutils.cfg`). If you want to temporarily disable +this file, you can pass the --no-user-cfg option to setup.py. There are three steps to building a binary RPM package, all of which are handled automatically by the Distutils: Index: Doc/ACKS.txt =================================================================== --- Doc/ACKS.txt (revision 61524) +++ Doc/ACKS.txt (working copy) @@ -199,6 +199,7 @@ * Mats Wichmann * Gerry Wiener * Timothy Wild + * Paul Winkler * Collin Winter * Blake Winton * Dan Wolfe Index: Lib/distutils/core.py =================================================================== --- Lib/distutils/core.py (revision 61524) +++ Lib/distutils/core.py (working copy) @@ -131,8 +131,9 @@ if _setup_stop_after == "config": return dist - # Parse the command line; any command-line errors are the end user's - # fault, so turn them into SystemExit to suppress tracebacks. + # Parse the command line and override config files; any + # command-line errors are the end user's fault, so turn them into + # SystemExit to suppress tracebacks. try: ok = dist.parse_command_line() except DistutilsArgError, msg: Index: Lib/distutils/tests/test_dist.py =================================================================== --- Lib/distutils/tests/test_dist.py (revision 61524) +++ Lib/distutils/tests/test_dist.py (working copy) @@ -21,6 +21,91 @@ self.sample_option = None +class DistributionCfgFileTestCase(unittest.TestCase): + + """Tests for the Distribution.find_config_files method.""" + + def setUp(self): + self.distutilsdir = os.path.dirname(sys.modules['distutils'].__file__) + # Faking out the environment to get control of + # the find_config_files behavior. + # This is horrible; so much monkeypatching! + # Martin Loewis suggested: Leave all these modules alone, + # think of ways to hack the Disribution instance instead so it + # gets into the states I want. That way, it's totally safe. + # But I don't see how to get through all the branches of find_config_files + # that way, without changing a lot beyond the scope of #1180. + # Another possibility: Don't test this function at all :( + self.old_osname = os.name + self.old_environ = os.environ + os.environ = {} + + self.old_isfile = os.path.isfile + os.path.isfile = lambda name: True + + # check_environ adds HOME if it's not there, which would + # prevent us from testing some cases. + self.old_check_environ = distutils.dist.check_environ + distutils.dist.check_environ = lambda: None + + def tearDown(self): + os.name = self.old_osname + os.path.isfile = self.old_isfile + os.environ = self.old_environ + distutils.dist.check_environ = self.old_check_environ + + def test_find_config_nofiles(self): + # No files will be used if they don't actually exist. + os.path.isfile = lambda name: False + d = distutils.dist.Distribution() + files = d.find_config_files() + self.assertEqual(len(files), 0) + + def test_find_config_files_posix_no_home(self): + d = distutils.dist.Distribution() + files = d.find_config_files() + self.assertEqual(len(files), 2) + self.assertEqual(files[0], os.path.join(self.distutilsdir, 'distutils.cfg')) + self.assertEqual(files[1], 'setup.cfg') + + def test_find_config_files_posix_home(self): + os.name = 'posix' + os.environ['HOME'] = '/home/gilliam' + d = distutils.dist.Distribution() + files = d.find_config_files() + self.assertEqual(len(files), 3) + self.assertEqual(files[0], os.path.join(self.distutilsdir, 'distutils.cfg')) + self.assertEqual(files[1], os.path.join('/home', 'gilliam', '.pydistutils.cfg')) + self.assertEqual(files[2], 'setup.cfg') + + def test_find_config_files_win_nohome(self): + os.name = 'nt' + d = distutils.dist.Distribution() + files = d.find_config_files() + self.assertEqual(len(files), 2) + self.assertEqual(files[0], os.path.join(self.distutilsdir, 'distutils.cfg')) + self.assertEqual(files[1], 'setup.cfg') + + def test_find_config_files_win_home(self): + os.name = 'nt' + os.environ['HOME'] = 'gilliam' + d = distutils.dist.Distribution() + files = d.find_config_files() + self.assertEqual(len(files), 3) + self.assertEqual(files[0], os.path.join(self.distutilsdir, 'distutils.cfg')) + self.assertEqual(files[1], os.path.join('gilliam', 'pydistutils.cfg')) + self.assertEqual(files[2], 'setup.cfg') + + def test_find_config_files_disable(self): + # Ticket #1180. + d = distutils.dist.Distribution() + d.no_user_cfg = True + files = d.find_config_files() + self.assertEqual(len(files), 2) + self.assertEqual(files[0], os.path.join(self.distutilsdir, 'distutils.cfg')) + self.assertEqual(files[1], 'setup.cfg') + + class TestDistribution(distutils.dist.Distribution): """Distribution subclasses that avoids the default search for configuration files. @@ -184,4 +269,5 @@ suite = unittest.TestSuite() suite.addTest(unittest.makeSuite(DistributionTestCase)) suite.addTest(unittest.makeSuite(MetadataTestCase)) + suite.addTest(unittest.makeSuite(DistributionCfgFileTestCase)) return suite Index: Lib/distutils/dist.py =================================================================== --- Lib/distutils/dist.py (revision 61524) +++ Lib/distutils/dist.py (working copy) @@ -57,7 +57,9 @@ ('quiet', 'q', "run quietly (turns verbosity off)"), ('dry-run', 'n', "don't actually do anything"), ('help', 'h', "show detailed help message"), - ] + ('no-user-cfg', None, + 'ignore pydistutils.cfg in your home directory'), + ] # 'common_usage' is a short (2-3 line) string describing the common # usage of the setup script. @@ -137,6 +139,11 @@ self.verbose = 1 self.dry_run = 0 self.help = 0 + # no-user-cfg is handled before other command line args + # because other args override the config files, and this + # one is needed before we can load the config files. + self.no_user_cfg = '--no-user-cfg' in sys.argv + for attr in self.display_option_names: setattr(self, attr, 0) @@ -321,9 +328,12 @@ There are three possible config files: distutils.cfg in the Distutils installation directory (ie. where the top-level - Distutils __inst__.py file lives), a file in the user's home + Distutils __inst__.py file lives); a file in the user's home directory named .pydistutils.cfg on Unix and pydistutils.cfg - on Windows/Mac, and setup.cfg in the current directory. + on Windows/Mac; and setup.cfg in the current directory. + + The file in the user's home directory can be disabled with the + --no-user-cfg option. """ files = [] check_environ() @@ -336,23 +346,28 @@ if os.path.isfile(sys_file): files.append(sys_file) - # What to call the per-user config file - if os.name == 'posix': - user_filename = ".pydistutils.cfg" + # Find the per-user config file, if wanted. + if self.no_user_cfg: + # User explicitly disabled it. + pass else: - user_filename = "pydistutils.cfg" + # Find it in the user's home dir. + if os.name == 'posix': + user_filename = ".pydistutils.cfg" + else: + user_filename = "pydistutils.cfg" + if 'HOME' in os.environ: + user_file = os.path.join(os.environ.get('HOME'), user_filename) + if os.path.isfile(user_file): + files.append(user_file) - # And look for the user config file - if 'HOME' in os.environ: - user_file = os.path.join(os.environ.get('HOME'), user_filename) - if os.path.isfile(user_file): - files.append(user_file) - # All platforms support local setup.cfg local_file = "setup.cfg" if os.path.isfile(local_file): files.append(local_file) + if DEBUG: + print "using config files: %s" % ', '.join(files) return files # find_config_files () @@ -447,6 +462,7 @@ parser = FancyGetopt(toplevel_options + self.display_options) parser.set_negative_aliases(self.negative_opt) parser.set_aliases({'licence': 'license'}) + # Parse each option and store as name-mangled attributes of self. args = parser.getopt(args=self.script_args, object=self) option_order = parser.get_option_order() log.set_verbosity(self.verbose)