1
1
import getpass
2
2
import logging
3
+ import re
3
4
4
5
import pytest
5
6
@@ -13,23 +14,23 @@ def config() -> utils.RepositoryConfig:
13
14
return dict (repository = "system" )
14
15
15
16
16
- def test_get_password_keyring_overrides_prompt (monkeypatch , config ):
17
+ def test_get_username_keyring_defers_to_prompt (monkeypatch , entered_username , config ):
17
18
class MockKeyring :
18
19
@staticmethod
19
- def get_password (system , user ):
20
- return f" { user } @ { system } sekure pa55word"
20
+ def get_credential (system , user ):
21
+ return None
21
22
22
23
monkeypatch .setattr (auth , "keyring" , MockKeyring )
23
24
24
- pw = auth .Resolver (config , auth .CredentialInput ("user" )).password
25
- assert pw == "user@system sekure pa55word "
25
+ username = auth .Resolver (config , auth .CredentialInput ()).username
26
+ assert username == "entered user "
26
27
27
28
28
29
def test_get_password_keyring_defers_to_prompt (monkeypatch , entered_password , config ):
29
30
class MockKeyring :
30
31
@staticmethod
31
32
def get_password (system , user ):
32
- return
33
+ return None
33
34
34
35
monkeypatch .setattr (auth , "keyring" , MockKeyring )
35
36
@@ -51,7 +52,7 @@ def test_empty_password_bypasses_prompt(monkeypatch, entered_password, config):
51
52
52
53
def test_no_username_non_interactive_aborts (config ):
53
54
with pytest .raises (exceptions .NonInteractive ):
54
- auth .Private (config , auth .CredentialInput ("user" )).password
55
+ auth .Private (config , auth .CredentialInput ()).username
55
56
56
57
57
58
def test_no_password_non_interactive_aborts (config ):
@@ -124,55 +125,99 @@ def test_get_password_keyring_missing_non_interactive_aborts(
124
125
auth .Private (config , auth .CredentialInput ("user" )).password
125
126
126
127
127
- @pytest .fixture
128
- def keyring_no_backends (monkeypatch ):
129
- """Simulate missing keyring backend raising RuntimeError on get_password."""
130
-
128
+ def test_get_username_keyring_runtime_error_logged (
129
+ entered_username , monkeypatch , config , caplog
130
+ ):
131
131
class FailKeyring :
132
+ """Simulate missing keyring backend raising RuntimeError on get_credential."""
133
+
132
134
@staticmethod
133
- def get_password (system , username ):
135
+ def get_credential (system , username ):
134
136
raise RuntimeError ("fail!" )
135
137
136
- monkeypatch .setattr (auth , "keyring" , FailKeyring () )
138
+ monkeypatch .setattr (auth , "keyring" , FailKeyring )
137
139
140
+ assert auth .Resolver (config , auth .CredentialInput ()).username == "entered user"
138
141
139
- @pytest .fixture
140
- def keyring_no_backends_get_credential (monkeypatch ):
141
- """Simulate missing keyring backend raising RuntimeError on get_credential."""
142
+ assert re .search (
143
+ r"Error getting username from keyring.+Traceback.+RuntimeError: fail!" ,
144
+ caplog .text ,
145
+ re .DOTALL ,
146
+ )
142
147
148
+
149
+ def test_get_password_keyring_runtime_error_logged (
150
+ entered_username , entered_password , monkeypatch , config , caplog
151
+ ):
143
152
class FailKeyring :
153
+ """Simulate missing keyring backend raising RuntimeError on get_password."""
154
+
144
155
@staticmethod
145
- def get_credential (system , username ):
156
+ def get_password (system , username ):
146
157
raise RuntimeError ("fail!" )
147
158
148
- monkeypatch .setattr (auth , "keyring" , FailKeyring () )
159
+ monkeypatch .setattr (auth , "keyring" , FailKeyring )
149
160
161
+ assert auth .Resolver (config , auth .CredentialInput ()).password == "entered pw"
150
162
151
- def test_get_username_runtime_error_suppressed (
152
- entered_username , keyring_no_backends_get_credential , caplog , config
153
- ):
154
- assert auth . Resolver ( config , auth . CredentialInput ()). username == "entered user"
155
- assert caplog . messages == [ "fail!" ]
163
+ assert re . search (
164
+ r"Error getting password from keyring.+Traceback.+RuntimeError: fail!" ,
165
+ caplog . text ,
166
+ re . DOTALL ,
167
+ )
156
168
157
169
158
- def test_get_password_runtime_error_suppressed (
159
- entered_password , keyring_no_backends , caplog , config
160
- ) :
161
- assert auth . Resolver ( config , auth . CredentialInput ( "user" )). password == "entered pw"
162
- assert caplog . messages == [ "fail!" ]
163
-
170
+ def _raise_home_key_error ():
171
+ """Simulate environment from https://github.com/pypa/twine/issues/889."""
172
+ try :
173
+ raise KeyError ( "HOME" )
174
+ except KeyError :
175
+ raise KeyError ( "uid not found: 999" )
164
176
165
- def test_get_username_return_none (entered_username , monkeypatch , config ):
166
- """Prompt for username when it's not in keyring."""
167
177
178
+ def test_get_username_keyring_key_error_logged (
179
+ entered_username , monkeypatch , config , caplog
180
+ ):
168
181
class FailKeyring :
169
182
@staticmethod
170
183
def get_credential (system , username ):
171
- return None
184
+ _raise_home_key_error ()
185
+
186
+ monkeypatch .setattr (auth , "keyring" , FailKeyring )
172
187
173
- monkeypatch .setattr (auth , "keyring" , FailKeyring ())
174
188
assert auth .Resolver (config , auth .CredentialInput ()).username == "entered user"
175
189
190
+ assert re .search (
191
+ r"Error getting username from keyring"
192
+ r".+Traceback"
193
+ r".+KeyError: 'HOME'"
194
+ r".+KeyError: 'uid not found: 999'" ,
195
+ caplog .text ,
196
+ re .DOTALL ,
197
+ )
198
+
199
+
200
+ def test_get_password_keyring_key_error_logged (
201
+ entered_username , entered_password , monkeypatch , config , caplog
202
+ ):
203
+ class FailKeyring :
204
+ @staticmethod
205
+ def get_password (system , username ):
206
+ _raise_home_key_error ()
207
+
208
+ monkeypatch .setattr (auth , "keyring" , FailKeyring )
209
+
210
+ assert auth .Resolver (config , auth .CredentialInput ()).password == "entered pw"
211
+
212
+ assert re .search (
213
+ r"Error getting password from keyring"
214
+ r".+Traceback"
215
+ r".+KeyError: 'HOME'"
216
+ r".+KeyError: 'uid not found: 999'" ,
217
+ caplog .text ,
218
+ re .DOTALL ,
219
+ )
220
+
176
221
177
222
def test_logs_cli_values (caplog ):
178
223
caplog .set_level (logging .INFO , "twine" )
0 commit comments