1# -*- encoding: utf8 -*- 2"""Tests for distutils.command.register.""" 3import os 4import unittest 5import getpass 6import urllib2 7import warnings 8 9from test.test_support import check_warnings, run_unittest 10 11from distutils.command import register as register_module 12from distutils.command.register import register 13from distutils.errors import DistutilsSetupError 14 15from distutils.tests.test_config import PyPIRCCommandTestCase 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 RawInputs(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): 63 self.reqs.append(req) 64 return self 65 66 def read(self): 67 return 'xxx' 68 69class RegisterTestCase(PyPIRCCommandTestCase): 70 71 def setUp(self): 72 super(RegisterTestCase, self).setUp() 73 # patching the password prompt 74 self._old_getpass = getpass.getpass 75 def _getpass(prompt): 76 return 'password' 77 getpass.getpass = _getpass 78 self.old_opener = urllib2.build_opener 79 self.conn = urllib2.build_opener = FakeOpener() 80 81 def tearDown(self): 82 getpass.getpass = self._old_getpass 83 urllib2.build_opener = self.old_opener 84 super(RegisterTestCase, self).tearDown() 85 86 def _get_cmd(self, metadata=None): 87 if metadata is None: 88 metadata = {'url': 'xxx', 'author': 'xxx', 89 'author_email': 'xxx', 90 'name': 'xxx', 'version': 'xxx'} 91 pkg_info, dist = self.create_dist(**metadata) 92 return register(dist) 93 94 def test_create_pypirc(self): 95 # this test makes sure a .pypirc file 96 # is created when requested. 97 98 # let's create a register instance 99 cmd = self._get_cmd() 100 101 # we shouldn't have a .pypirc file yet 102 self.assertFalse(os.path.exists(self.rc)) 103 104 # patching raw_input and getpass.getpass 105 # so register gets happy 106 # 107 # Here's what we are faking : 108 # use your existing login (choice 1.) 109 # Username : 'tarek' 110 # Password : 'password' 111 # Save your login (y/N)? : 'y' 112 inputs = RawInputs('1', 'tarek', 'y') 113 register_module.raw_input = inputs.__call__ 114 # let's run the command 115 try: 116 cmd.run() 117 finally: 118 del register_module.raw_input 119 120 # we should have a brand new .pypirc file 121 self.assertTrue(os.path.exists(self.rc)) 122 123 # with the content similar to WANTED_PYPIRC 124 f = open(self.rc) 125 try: 126 content = f.read() 127 self.assertEqual(content, WANTED_PYPIRC) 128 finally: 129 f.close() 130 131 # now let's make sure the .pypirc file generated 132 # really works : we shouldn't be asked anything 133 # if we run the command again 134 def _no_way(prompt=''): 135 raise AssertionError(prompt) 136 register_module.raw_input = _no_way 137 138 cmd.show_response = 1 139 cmd.run() 140 141 # let's see what the server received : we should 142 # have 2 similar requests 143 self.assertEqual(len(self.conn.reqs), 2) 144 req1 = dict(self.conn.reqs[0].headers) 145 req2 = dict(self.conn.reqs[1].headers) 146 self.assertEqual(req2['Content-length'], req1['Content-length']) 147 self.assertIn('xxx', self.conn.reqs[1].data) 148 149 def test_password_not_in_file(self): 150 151 self.write_file(self.rc, PYPIRC_NOPASSWORD) 152 cmd = self._get_cmd() 153 cmd._set_config() 154 cmd.finalize_options() 155 cmd.send_metadata() 156 157 # dist.password should be set 158 # therefore used afterwards by other commands 159 self.assertEqual(cmd.distribution.password, 'password') 160 161 def test_registering(self): 162 # this test runs choice 2 163 cmd = self._get_cmd() 164 inputs = RawInputs('2', 'tarek', 'tarek@ziade.org') 165 register_module.raw_input = inputs.__call__ 166 try: 167 # let's run the command 168 cmd.run() 169 finally: 170 del register_module.raw_input 171 172 # we should have send a request 173 self.assertEqual(len(self.conn.reqs), 1) 174 req = self.conn.reqs[0] 175 headers = dict(req.headers) 176 self.assertEqual(headers['Content-length'], '608') 177 self.assertIn('tarek', req.data) 178 179 def test_password_reset(self): 180 # this test runs choice 3 181 cmd = self._get_cmd() 182 inputs = RawInputs('3', 'tarek@ziade.org') 183 register_module.raw_input = inputs.__call__ 184 try: 185 # let's run the command 186 cmd.run() 187 finally: 188 del register_module.raw_input 189 190 # we should have send a request 191 self.assertEqual(len(self.conn.reqs), 1) 192 req = self.conn.reqs[0] 193 headers = dict(req.headers) 194 self.assertEqual(headers['Content-length'], '290') 195 self.assertIn('tarek', req.data) 196 197 @unittest.skipUnless(docutils is not None, 'needs docutils') 198 def test_strict(self): 199 # testing the script option 200 # when on, the register command stops if 201 # the metadata is incomplete or if 202 # long_description is not reSt compliant 203 204 # empty metadata 205 cmd = self._get_cmd({}) 206 cmd.ensure_finalized() 207 cmd.strict = 1 208 self.assertRaises(DistutilsSetupError, cmd.run) 209 210 # metadata are OK but long_description is broken 211 metadata = {'url': 'xxx', 'author': 'xxx', 212 'author_email': u'éxéxé', 213 'name': 'xxx', 'version': 'xxx', 214 'long_description': 'title\n==\n\ntext'} 215 216 cmd = self._get_cmd(metadata) 217 cmd.ensure_finalized() 218 cmd.strict = 1 219 self.assertRaises(DistutilsSetupError, cmd.run) 220 221 # now something that works 222 metadata['long_description'] = 'title\n=====\n\ntext' 223 cmd = self._get_cmd(metadata) 224 cmd.ensure_finalized() 225 cmd.strict = 1 226 inputs = RawInputs('1', 'tarek', 'y') 227 register_module.raw_input = inputs.__call__ 228 # let's run the command 229 try: 230 cmd.run() 231 finally: 232 del register_module.raw_input 233 234 # strict is not by default 235 cmd = self._get_cmd() 236 cmd.ensure_finalized() 237 inputs = RawInputs('1', 'tarek', 'y') 238 register_module.raw_input = inputs.__call__ 239 # let's run the command 240 try: 241 cmd.run() 242 finally: 243 del register_module.raw_input 244 245 # and finally a Unicode test (bug #12114) 246 metadata = {'url': u'xxx', 'author': u'\u00c9ric', 247 'author_email': u'xxx', u'name': 'xxx', 248 'version': u'xxx', 249 'description': u'Something about esszet \u00df', 250 'long_description': u'More things about esszet \u00df'} 251 252 cmd = self._get_cmd(metadata) 253 cmd.ensure_finalized() 254 cmd.strict = 1 255 inputs = RawInputs('1', 'tarek', 'y') 256 register_module.raw_input = inputs.__call__ 257 # let's run the command 258 try: 259 cmd.run() 260 finally: 261 del register_module.raw_input 262 263 @unittest.skipUnless(docutils is not None, 'needs docutils') 264 def test_register_invalid_long_description(self): 265 description = ':funkie:`str`' # mimic Sphinx-specific markup 266 metadata = {'url': 'xxx', 'author': 'xxx', 267 'author_email': 'xxx', 268 'name': 'xxx', 'version': 'xxx', 269 'long_description': description} 270 cmd = self._get_cmd(metadata) 271 cmd.ensure_finalized() 272 cmd.strict = True 273 inputs = RawInputs('2', 'tarek', 'tarek@ziade.org') 274 register_module.raw_input = inputs 275 self.addCleanup(delattr, register_module, 'raw_input') 276 self.assertRaises(DistutilsSetupError, cmd.run) 277 278 def test_check_metadata_deprecated(self): 279 # makes sure make_metadata is deprecated 280 cmd = self._get_cmd() 281 with check_warnings() as w: 282 warnings.simplefilter("always") 283 cmd.check_metadata() 284 self.assertEqual(len(w.warnings), 1) 285 286def test_suite(): 287 return unittest.makeSuite(RegisterTestCase) 288 289if __name__ == "__main__": 290 run_unittest(test_suite()) 291