Index: Misc/NEWS =================================================================== --- Misc/NEWS (revision 62554) +++ Misc/NEWS (working copy) @@ -282,6 +282,9 @@ - Issue #1747858: Fix chown to work with large uid's and gid's on 64-bit platforms. +- 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 62554) +++ 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 62554) +++ Doc/ACKS.txt (working copy) @@ -201,6 +201,7 @@ * Mats Wichmann * Gerry Wiener * Timothy Wild + * Paul Winkler * Collin Winter * Blake Winton * Dan Wolfe Index: Doc/install/index.rst =================================================================== --- Doc/install/index.rst (revision 62554) +++ Doc/install/index.rst (working copy) @@ -694,6 +694,9 @@ | local | :file:`setup.cfg` | \(3) | +--------------+-------------------------------------------------+-------+ +On all platforms, the "personal" file can be temporarily disabled by +passing the `--no-user-cfg` option. + Notes: (1) Index: Lib/distutils/core.py =================================================================== --- Lib/distutils/core.py (revision 62554) +++ 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 62554) +++ Lib/distutils/tests/test_dist.py (working copy) @@ -21,6 +21,100 @@ self.sample_option = None +class DistributionConfigFileTestCase(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 that would require more changes to dist.py to allow + # some dependency injection, which is arguably out of scope for #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(files, []) + + def test_find_config_files_posix_no_home(self): + d = distutils.dist.Distribution() + os.name = 'posix' + 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): + d = distutils.dist.Distribution() + os.name = 'posix' + os.environ['HOME'] = '/home/gilliam' + 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_no_home(self): + d = distutils.dist.Distribution() + os.name = 'nt' + 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): + d = distutils.dist.Distribution() + os.name = 'nt' + os.environ['HOME'] = 'gilliam' + 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: Allow user to disable their home config file. + d = distutils.dist.Distribution(attrs={'script_args': + ['--no-user-cfg']}) + os.name = 'posix' + os.environ['HOME'] = '/home/gilliam' + 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 +278,5 @@ suite = unittest.TestSuite() suite.addTest(unittest.makeSuite(DistributionTestCase)) suite.addTest(unittest.makeSuite(MetadataTestCase)) + suite.addTest(unittest.makeSuite(DistributionConfigFileTestCase)) return suite Index: Lib/distutils/dist.py =================================================================== --- Lib/distutils/dist.py (revision 62554) +++ 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. @@ -264,6 +266,12 @@ else: sys.stderr.write(msg + "\n") + # 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. + # If attrs['script_args'] wasn't passed, assume false. + self.want_user_cfg = '--no-user-cfg' not in (self.script_args or []) + self.finalize_options() # __init__ () @@ -321,9 +329,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() @@ -343,7 +354,7 @@ user_filename = "pydistutils.cfg" # And look for the user config file - if 'HOME' in os.environ: + if self.want_user_cfg and '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) @@ -353,6 +364,8 @@ 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 +460,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)