1"""Tests for distutils.command.register.""" 2import os 3import unittest 4import getpass 5import urllib 6import warnings 7 8from test.support import run_unittest 9from test.support.warnings_helper import check_warnings 10 11from distutils.command import register as register_module 12from distutils.command.register import register 13from distutils.errors import DistutilsSetupError 14from distutils.log import INFO 15 16from distutils.tests.test_config import BasePyPIRCCommandTestCase 17 18try: 19 import docutils 20except ImportError: 21 docutils = None 22 23PYPIRC_NOPASSWORD = """\ 24[distutils] 25 26index-servers = 27 server1 28 29[server1] 30username:me 31""" 32 33WANTED_PYPIRC = """\ 34[distutils] 35index-servers = 36 pypi 37 38[pypi] 39username:tarek 40password:password 41""" 42 43class Inputs(object): 44 """Fakes user inputs.""" 45 def __init__(self, *answers): 46 self.answers = answers 47 self.index = 0 48 49 def __call__(self, prompt=''): 50 try: 51 return self.answers[self.index] 52 finally: 53 self.index += 1 54 55class FakeOpener(object): 56 """Fakes a PyPI server""" 57 def __init__(self): 58 self.reqs = [] 59 60 def __call__(self, *args): 61 return self 62 63 def open(self, req, data=None, timeout=None): 64 self.reqs.append(req) 65 return self 66 67 def read(self): 68 return b'xxx' 69 70 def getheader(self, name, default=None): 71 return { 72 'content-type': 'text/plain; charset=utf-8', 73 }.get(name.lower(), default) 74 75 76class RegisterTestCase(BasePyPIRCCommandTestCase): 77 78 def setUp(self): 79 super(RegisterTestCase, self).setUp() 80 # patching the password prompt 81 self._old_getpass = getpass.getpass 82 def _getpass(prompt): 83 return 'password' 84 getpass.getpass = _getpass 85 urllib.request._opener = None 86 self.old_opener = urllib.request.build_opener 87 self.conn = urllib.request.build_opener = FakeOpener() 88 89 def tearDown(self): 90 getpass.getpass = self._old_getpass 91 urllib.request._opener = None 92 urllib.request.build_opener = self.old_opener 93 super(RegisterTestCase, self).tearDown() 94 95 def _get_cmd(self, metadata=None): 96 if metadata is None: 97 metadata = {'url': 'xxx', 'author': 'xxx', 98 'author_email': 'xxx', 99 'name': 'xxx', 'version': 'xxx'} 100 pkg_info, dist = self.create_dist(**metadata) 101 return register(dist) 102 103 def test_create_pypirc(self): 104 # this test makes sure a .pypirc file 105 # is created when requested. 106 107 # let's create a register instance 108 cmd = self._get_cmd() 109 110 # we shouldn't have a .pypirc file yet 111 self.assertFalse(os.path.exists(self.rc)) 112 113 # patching input and getpass.getpass 114 # so register gets happy 115 # 116 # Here's what we are faking : 117 # use your existing login (choice 1.) 118 # Username : 'tarek' 119 # Password : 'password' 120 # Save your login (y/N)? : 'y' 121 inputs = Inputs('1', 'tarek', 'y') 122 register_module.input = inputs.__call__ 123 # let's run the command 124 try: 125 cmd.run() 126 finally: 127 del register_module.input 128 129 # we should have a brand new .pypirc file 130 self.assertTrue(os.path.exists(self.rc)) 131 132 # with the content similar to WANTED_PYPIRC 133 f = open(self.rc) 134 try: 135 content = f.read() 136 self.assertEqual(content, WANTED_PYPIRC) 137 finally: 138 f.close() 139 140 # now let's make sure the .pypirc file generated 141 # really works : we shouldn't be asked anything 142 # if we run the command again 143 def _no_way(prompt=''): 144 raise AssertionError(prompt) 145 register_module.input = _no_way 146 147 cmd.show_response = 1 148 cmd.run() 149 150 # let's see what the server received : we should 151 # have 2 similar requests 152 self.assertEqual(len(self.conn.reqs), 2) 153 req1 = dict(self.conn.reqs[0].headers) 154 req2 = dict(self.conn.reqs[1].headers) 155 156 self.assertEqual(req1['Content-length'], '1374') 157 self.assertEqual(req2['Content-length'], '1374') 158 self.assertIn(b'xxx', self.conn.reqs[1].data) 159 160 def test_password_not_in_file(self): 161 162 self.write_file(self.rc, PYPIRC_NOPASSWORD) 163 cmd = self._get_cmd() 164 cmd._set_config() 165 cmd.finalize_options() 166 cmd.send_metadata() 167 168 # dist.password should be set 169 # therefore used afterwards by other commands 170 self.assertEqual(cmd.distribution.password, 'password') 171 172 def test_registering(self): 173 # this test runs choice 2 174 cmd = self._get_cmd() 175 inputs = Inputs('2', 'tarek', 'tarek@ziade.org') 176 register_module.input = inputs.__call__ 177 try: 178 # let's run the command 179 cmd.run() 180 finally: 181 del register_module.input 182 183 # we should have send a request 184 self.assertEqual(len(self.conn.reqs), 1) 185 req = self.conn.reqs[0] 186 headers = dict(req.headers) 187 self.assertEqual(headers['Content-length'], '608') 188 self.assertIn(b'tarek', req.data) 189 190 def test_password_reset(self): 191 # this test runs choice 3 192 cmd = self._get_cmd() 193 inputs = Inputs('3', 'tarek@ziade.org') 194 register_module.input = inputs.__call__ 195 try: 196 # let's run the command 197 cmd.run() 198 finally: 199 del register_module.input 200 201 # we should have send a request 202 self.assertEqual(len(self.conn.reqs), 1) 203 req = self.conn.reqs[0] 204 headers = dict(req.headers) 205 self.assertEqual(headers['Content-length'], '290') 206 self.assertIn(b'tarek', req.data) 207 208 @unittest.skipUnless(docutils is not None, 'needs docutils') 209 def test_strict(self): 210 # testing the script option 211 # when on, the register command stops if 212 # the metadata is incomplete or if 213 # long_description is not reSt compliant 214 215 # empty metadata 216 cmd = self._get_cmd({}) 217 cmd.ensure_finalized() 218 cmd.strict = 1 219 self.assertRaises(DistutilsSetupError, cmd.run) 220 221 # metadata are OK but long_description is broken 222 metadata = {'url': 'xxx', 'author': 'xxx', 223 'author_email': 'éxéxé', 224 'name': 'xxx', 'version': 'xxx', 225 'long_description': 'title\n==\n\ntext'} 226 227 cmd = self._get_cmd(metadata) 228 cmd.ensure_finalized() 229 cmd.strict = 1 230 self.assertRaises(DistutilsSetupError, cmd.run) 231 232 # now something that works 233 metadata['long_description'] = 'title\n=====\n\ntext' 234 cmd = self._get_cmd(metadata) 235 cmd.ensure_finalized() 236 cmd.strict = 1 237 inputs = Inputs('1', 'tarek', 'y') 238 register_module.input = inputs.__call__ 239 # let's run the command 240 try: 241 cmd.run() 242 finally: 243 del register_module.input 244 245 # strict is not by default 246 cmd = self._get_cmd() 247 cmd.ensure_finalized() 248 inputs = Inputs('1', 'tarek', 'y') 249 register_module.input = inputs.__call__ 250 # let's run the command 251 try: 252 cmd.run() 253 finally: 254 del register_module.input 255 256 # and finally a Unicode test (bug #12114) 257 metadata = {'url': 'xxx', 'author': '\u00c9ric', 258 'author_email': 'xxx', 'name': 'xxx', 259 'version': 'xxx', 260 'description': 'Something about esszet \u00df', 261 'long_description': 'More things about esszet \u00df'} 262 263 cmd = self._get_cmd(metadata) 264 cmd.ensure_finalized() 265 cmd.strict = 1 266 inputs = Inputs('1', 'tarek', 'y') 267 register_module.input = inputs.__call__ 268 # let's run the command 269 try: 270 cmd.run() 271 finally: 272 del register_module.input 273 274 @unittest.skipUnless(docutils is not None, 'needs docutils') 275 def test_register_invalid_long_description(self): 276 description = ':funkie:`str`' # mimic Sphinx-specific markup 277 metadata = {'url': 'xxx', 'author': 'xxx', 278 'author_email': 'xxx', 279 'name': 'xxx', 'version': 'xxx', 280 'long_description': description} 281 cmd = self._get_cmd(metadata) 282 cmd.ensure_finalized() 283 cmd.strict = True 284 inputs = Inputs('2', 'tarek', 'tarek@ziade.org') 285 register_module.input = inputs 286 self.addCleanup(delattr, register_module, 'input') 287 288 self.assertRaises(DistutilsSetupError, cmd.run) 289 290 def test_check_metadata_deprecated(self): 291 # makes sure make_metadata is deprecated 292 cmd = self._get_cmd() 293 with check_warnings() as w: 294 warnings.simplefilter("always") 295 cmd.check_metadata() 296 self.assertEqual(len(w.warnings), 1) 297 298 def test_list_classifiers(self): 299 cmd = self._get_cmd() 300 cmd.list_classifiers = 1 301 cmd.run() 302 results = self.get_logs(INFO) 303 self.assertEqual(results, ['running check', 'xxx']) 304 305 def test_show_response(self): 306 # test that the --show-response option return a well formatted response 307 cmd = self._get_cmd() 308 inputs = Inputs('1', 'tarek', 'y') 309 register_module.input = inputs.__call__ 310 cmd.show_response = 1 311 try: 312 cmd.run() 313 finally: 314 del register_module.input 315 316 results = self.get_logs(INFO) 317 self.assertEqual(results[3], 75 * '-' + '\nxxx\n' + 75 * '-') 318 319 320def test_suite(): 321 return unittest.makeSuite(RegisterTestCase) 322 323if __name__ == "__main__": 324 run_unittest(test_suite()) 325