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