1212# See the License for the specific language governing permissions and
1313# limitations under the License.
1414import logging
15+ import textwrap
1516
17+ import build
1618import pretend
1719import pytest
1820
19- from twine import commands
20- from twine import package as package_file
2121from twine .commands import check
2222
2323
@@ -45,10 +45,8 @@ def test_str_representation(self):
4545 assert str (self .stream ) == "result"
4646
4747
48- def test_check_no_distributions (monkeypatch , caplog ):
49- monkeypatch .setattr (commands , "_find_dists" , lambda a : [])
50-
51- assert not check .check (["dist/*" ])
48+ def test_fails_no_distributions (caplog ):
49+ assert not check .check ([])
5250 assert caplog .record_tuples == [
5351 (
5452 "twine.commands.check" ,
@@ -58,76 +56,51 @@ def test_check_no_distributions(monkeypatch, caplog):
5856 ]
5957
6058
61- def test_check_passing_distribution (monkeypatch , capsys ):
62- renderer = pretend .stub (render = pretend .call_recorder (lambda * a , ** kw : "valid" ))
63- package = pretend .stub (
64- metadata_dictionary = lambda : {
65- "description" : "blah" ,
66- "description_content_type" : "text/markdown" ,
67- }
68- )
69- warning_stream = ""
70-
71- monkeypatch .setattr (check , "_RENDERERS" , {None : renderer })
72- monkeypatch .setattr (commands , "_find_dists" , lambda a : ["dist/dist.tar.gz" ])
73- monkeypatch .setattr (
74- package_file ,
75- "PackageFile" ,
76- pretend .stub (from_filename = lambda * a , ** kw : package ),
77- )
78- monkeypatch .setattr (check , "_WarningStream" , lambda : warning_stream )
79-
80- assert not check .check (["dist/*" ])
81- assert capsys .readouterr ().out == "Checking dist/dist.tar.gz: PASSED\n "
82- assert renderer .render .calls == [pretend .call ("blah" , stream = warning_stream )]
83-
84-
85- @pytest .mark .parametrize ("content_type" , ["text/plain" , "text/markdown" ])
86- def test_check_passing_distribution_with_none_renderer (
87- content_type ,
88- monkeypatch ,
89- capsys ,
90- ):
91- """Pass when rendering a content type can't fail."""
92- package = pretend .stub (
93- metadata_dictionary = lambda : {
94- "description" : "blah" ,
95- "description_content_type" : content_type ,
96- }
97- )
59+ def build_sdist (src_path , project_files ):
60+ """
61+ Build a source distribution similar to `python3 -m build --sdist`.
9862
99- monkeypatch .setattr (commands , "_find_dists" , lambda a : ["dist/dist.tar.gz" ])
100- monkeypatch .setattr (
101- package_file ,
102- "PackageFile" ,
103- pretend .stub (from_filename = lambda * a , ** kw : package ),
63+ Returns the absolute path of the built distribution.
64+ """
65+ project_files = {
66+ "pyproject.toml" : (
67+ """
68+ [build-system]
69+ requires = ["setuptools"]
70+ build-backend = "setuptools.build_meta"
71+ """
72+ ),
73+ ** project_files ,
74+ }
75+
76+ for filename , content in project_files .items ():
77+ (src_path / filename ).write_text (textwrap .dedent (content ))
78+
79+ builder = build .ProjectBuilder (src_path )
80+ return builder .build ("sdist" , str (src_path / "dist" ))
81+
82+
83+ @pytest .mark .parametrize ("strict" , [False , True ])
84+ def test_warns_missing_description (strict , tmp_path , capsys , caplog ):
85+ sdist = build_sdist (
86+ tmp_path ,
87+ {
88+ "setup.cfg" : (
89+ """
90+ [metadata]
91+ name = test-package
92+ version = 0.0.1
93+ """
94+ ),
95+ },
10496 )
10597
106- assert not check .check (["dist/*" ])
107- assert capsys .readouterr ().out == "Checking dist/dist.tar.gz: PASSED\n "
98+ assert check .check ([sdist ], strict = strict ) is strict
10899
109-
110- @pytest .mark .parametrize ("description" , [None , "UNKNOWN\n \n " , "UNKNOWN\n \n \n " ])
111- def test_check_no_description (description , monkeypatch , capsys , caplog ):
112- package = pretend .stub (
113- metadata_dictionary = lambda : {
114- "description" : description ,
115- "description_content_type" : None ,
116- }
117- )
118-
119- monkeypatch .setattr (commands , "_find_dists" , lambda a : ["dist/dist.tar.gz" ])
120- monkeypatch .setattr (
121- package_file ,
122- "PackageFile" ,
123- pretend .stub (from_filename = lambda * a , ** kw : package ),
100+ assert capsys .readouterr ().out == f"Checking { sdist } : " + (
101+ "FAILED due to warnings\n " if strict else "PASSED with warnings\n "
124102 )
125103
126- assert not check .check (["dist/*" ])
127-
128- assert capsys .readouterr ().out == (
129- "Checking dist/dist.tar.gz: PASSED with warnings\n "
130- )
131104 assert caplog .record_tuples == [
132105 (
133106 "twine.commands.check" ,
@@ -142,71 +115,167 @@ def test_check_no_description(description, monkeypatch, capsys, caplog):
142115 ]
143116
144117
145- def test_strict_fails_on_warnings (monkeypatch , capsys , caplog ):
146- package = pretend .stub (
147- metadata_dictionary = lambda : {
148- "description" : None ,
149- "description_content_type" : None ,
150- }
118+ def test_warns_missing_file (tmp_path , capsys , caplog ):
119+ sdist = build_sdist (
120+ tmp_path ,
121+ {
122+ "setup.cfg" : (
123+ """
124+ [metadata]
125+ name = test-package
126+ version = 0.0.1
127+ long_description = file:README.rst
128+ long_description_content_type = text/x-rst
129+ """
130+ ),
131+ },
151132 )
152133
153- monkeypatch .setattr (commands , "_find_dists" , lambda a : ["dist/dist.tar.gz" ])
154- monkeypatch .setattr (
155- package_file ,
156- "PackageFile" ,
157- pretend .stub (from_filename = lambda * a , ** kw : package ),
158- )
134+ assert not check .check ([sdist ])
159135
160- assert check . check ([ "dist/*" ], strict = True )
136+ assert capsys . readouterr (). out == f"Checking { sdist } : PASSED with warnings \n "
161137
162- assert capsys .readouterr ().out == (
163- "Checking dist/dist.tar.gz: FAILED due to warnings\n "
164- )
165138 assert caplog .record_tuples == [
166139 (
167140 "twine.commands.check" ,
168141 logging .WARNING ,
169- "`long_description_content_type ` missing. defaulting to `text/x-rst` ." ,
142+ "`long_description ` missing." ,
170143 ),
144+ ]
145+
146+
147+ def test_fails_rst_syntax_error (tmp_path , capsys , caplog ):
148+ sdist = build_sdist (
149+ tmp_path ,
150+ {
151+ "setup.cfg" : (
152+ """
153+ [metadata]
154+ name = test-package
155+ version = 0.0.1
156+ long_description = file:README.rst
157+ long_description_content_type = text/x-rst
158+ """
159+ ),
160+ "README.rst" : (
161+ """
162+ ============
163+ """
164+ ),
165+ },
166+ )
167+
168+ assert check .check ([sdist ])
169+
170+ assert capsys .readouterr ().out == f"Checking { sdist } : FAILED\n "
171+
172+ assert caplog .record_tuples == [
171173 (
172174 "twine.commands.check" ,
173- logging .WARNING ,
174- "`long_description` missing." ,
175+ logging .ERROR ,
176+ "`long_description` has syntax errors in markup "
177+ "and would not be rendered on PyPI.\n "
178+ "line 2: Error: Document or section may not begin with a transition." ,
175179 ),
176180 ]
177181
178182
179- def test_check_failing_distribution (monkeypatch , capsys , caplog ):
180- renderer = pretend .stub (render = pretend .call_recorder (lambda * a , ** kw : None ))
181- package = pretend .stub (
182- metadata_dictionary = lambda : {
183- "description" : "blah" ,
184- "description_content_type" : "text/markdown" ,
185- }
183+ def test_fails_rst_no_content (tmp_path , capsys , caplog ):
184+ sdist = build_sdist (
185+ tmp_path ,
186+ {
187+ "setup.cfg" : (
188+ """
189+ [metadata]
190+ name = test-package
191+ version = 0.0.1
192+ long_description = file:README.rst
193+ long_description_content_type = text/x-rst
194+ """
195+ ),
196+ "README.rst" : (
197+ """
198+ test-package
199+ ============
200+ """
201+ ),
202+ },
186203 )
187- warning_stream = "Syntax error"
188-
189- monkeypatch .setattr (check , "_RENDERERS" , {None : renderer })
190- monkeypatch .setattr (commands , "_find_dists" , lambda a : ["dist/dist.tar.gz" ])
191- monkeypatch .setattr (
192- package_file ,
193- "PackageFile" ,
194- pretend .stub (from_filename = lambda * a , ** kw : package ),
195- )
196- monkeypatch .setattr (check , "_WarningStream" , lambda : warning_stream )
197204
198- assert check .check (["dist/*" ])
205+ assert check .check ([sdist ])
206+
207+ assert capsys .readouterr ().out == f"Checking { sdist } : FAILED\n "
199208
200- assert capsys .readouterr ().out == "Checking dist/dist.tar.gz: FAILED\n "
201209 assert caplog .record_tuples == [
202210 (
203211 "twine.commands.check" ,
204212 logging .ERROR ,
205- "`long_description` has syntax errors in markup and would not be rendered "
206- "on PyPI.\n Syntax error " ,
213+ "`long_description` has syntax errors in markup "
214+ "and would not be rendered on PyPI.\n " ,
207215 ),
208216 ]
209- assert renderer .render .calls == [pretend .call ("blah" , stream = warning_stream )]
217+
218+
219+ def test_passes_rst_description (tmp_path , capsys , caplog ):
220+ sdist = build_sdist (
221+ tmp_path ,
222+ {
223+ "setup.cfg" : (
224+ """
225+ [metadata]
226+ name = test-package
227+ version = 0.0.1
228+ long_description = file:README.rst
229+ long_description_content_type = text/x-rst
230+ """
231+ ),
232+ "README.rst" : (
233+ """
234+ test-package
235+ ============
236+
237+ A test package.
238+ """
239+ ),
240+ },
241+ )
242+
243+ assert not check .check ([sdist ])
244+
245+ assert capsys .readouterr ().out == f"Checking { sdist } : PASSED\n "
246+
247+ assert not caplog .record_tuples
248+
249+
250+ @pytest .mark .parametrize ("content_type" , ["text/markdown" , "text/plain" ])
251+ def test_passes_markdown_description (content_type , tmp_path , capsys , caplog ):
252+ sdist = build_sdist (
253+ tmp_path ,
254+ {
255+ "setup.cfg" : (
256+ f"""
257+ [metadata]
258+ name = test-package
259+ version = 0.0.1
260+ long_description = file:README.md
261+ long_description_content_type = { content_type }
262+ """
263+ ),
264+ "README.md" : (
265+ """
266+ # test-package
267+
268+ A test package.
269+ """
270+ ),
271+ },
272+ )
273+
274+ assert not check .check ([sdist ])
275+
276+ assert capsys .readouterr ().out == f"Checking { sdist } : PASSED\n "
277+
278+ assert not caplog .record_tuples
210279
211280
212281def test_main (monkeypatch ):
0 commit comments