55import pytest
66
77from substack import Api , cli
8- from substack .mdrender import parse_node_marker , markdown_to_doc
8+ from substack .mdrender import markdown_to_doc , parse_node_marker
99
1010
1111def test_parse_node_marker_valid ():
12- node = {"type" : "button" , "attrs" : {"text" : "Click me" , "url" : "https://example.com" }}
13- payload = json .dumps (node , ensure_ascii = False , separators = ("," , ":" ), sort_keys = True ).encode ("utf-8" )
12+ node = {
13+ "type" : "button" ,
14+ "attrs" : {"text" : "Click me" , "url" : "https://example.com" },
15+ }
16+ payload = json .dumps (
17+ node , ensure_ascii = False , separators = ("," , ":" ), sort_keys = True
18+ ).encode ("utf-8" )
1419 encoded = base64 .urlsafe_b64encode (payload ).decode ("ascii" ).rstrip ("=" )
1520 comment = f"<!-- python-substack-node:v1 { encoded } -->"
16-
21+
1722 parsed = parse_node_marker (comment )
1823 assert parsed == node
1924
@@ -63,15 +68,22 @@ def test_parse_node_marker_ordinary_comment():
6368
6469def test_markdown_to_doc_preserves_block_and_inline_markers ():
6570 # Build a button node
66- btn = {"type" : "button" , "attrs" : {"text" : "Click me" , "url" : "https://example.com" }}
71+ btn = {
72+ "type" : "button" ,
73+ "attrs" : {"text" : "Click me" , "url" : "https://example.com" },
74+ }
6775 btn_payload = json .dumps (btn , separators = ("," , ":" ), sort_keys = True ).encode ("utf-8" )
6876 btn_encoded = base64 .urlsafe_b64encode (btn_payload ).decode ("ascii" ).rstrip ("=" )
6977 btn_comment = f"<!-- python-substack-node:v1 { btn_encoded } -->"
7078
7179 # Build an inline recipe node
7280 recipe = {"type" : "recipe" , "attrs" : {"id" : 123 }}
73- recipe_payload = json .dumps (recipe , separators = ("," , ":" ), sort_keys = True ).encode ("utf-8" )
74- recipe_encoded = base64 .urlsafe_b64encode (recipe_payload ).decode ("ascii" ).rstrip ("=" )
81+ recipe_payload = json .dumps (recipe , separators = ("," , ":" ), sort_keys = True ).encode (
82+ "utf-8"
83+ )
84+ recipe_encoded = (
85+ base64 .urlsafe_b64encode (recipe_payload ).decode ("ascii" ).rstrip ("=" )
86+ )
7587 recipe_comment = f"<!-- python-substack-node:v1 { recipe_encoded } -->"
7688
7789 markdown = f"""# Heading 1
@@ -83,11 +95,11 @@ def test_markdown_to_doc_preserves_block_and_inline_markers():
8395<!-- ordinary comment should be ignored -->
8496"""
8597 doc = markdown_to_doc (markdown )
86-
98+
8799 # doc should have heading, paragraph (with text, recipe inline node, text), and the button block node
88100 assert len (doc ) == 3
89101 assert doc [0 ]["type" ] == "heading"
90-
102+
91103 p = doc [1 ]
92104 assert p ["type" ] == "paragraph"
93105 inline_content = p ["content" ]
@@ -105,24 +117,37 @@ def test_update_draft_from_markdown_preservation(monkeypatch):
105117 monkeypatch .setattr (api , "get_user_id" , lambda : 1 )
106118
107119 # Remote draft contains an unsupported "button" node
108- remote_btn = {"type" : "button" , "attrs" : {"text" : "Click" , "url" : "https://example.com" }}
120+ remote_btn = {
121+ "type" : "button" ,
122+ "attrs" : {"text" : "Click" , "url" : "https://example.com" },
123+ }
109124 remote_body = {
110125 "type" : "doc" ,
111126 "content" : [
112- {"type" : "heading" , "attrs" : {"level" : 1 }, "content" : [{"type" : "text" , "text" : "Hello" }]},
113- remote_btn
114- ]
127+ {
128+ "type" : "heading" ,
129+ "attrs" : {"level" : 1 },
130+ "content" : [{"type" : "text" , "text" : "Hello" }],
131+ },
132+ remote_btn ,
133+ ],
115134 }
116- mock_get_draft = Mock (return_value = {"id" : 42 , "draft_body" : json .dumps (remote_body )})
135+ mock_get_draft = Mock (
136+ return_value = {"id" : 42 , "draft_body" : json .dumps (remote_body )}
137+ )
117138 monkeypatch .setattr (api , "get_draft" , mock_get_draft )
118-
139+
119140 mock_put_draft = Mock (return_value = {"id" : 42 })
120141 monkeypatch .setattr (api , "put_draft" , mock_put_draft )
121142
122143 # 1. Update with correct marker matches and succeeds
123- btn_payload = json .dumps (remote_btn , separators = ("," , ":" ), sort_keys = True ).encode ("utf-8" )
144+ btn_payload = json .dumps (remote_btn , separators = ("," , ":" ), sort_keys = True ).encode (
145+ "utf-8"
146+ )
124147 btn_encoded = base64 .urlsafe_b64encode (btn_payload ).decode ("ascii" ).rstrip ("=" )
125- submitted_markdown = f"# New Title\n \n <!-- python-substack-node:v1 { btn_encoded } -->\n "
148+ submitted_markdown = (
149+ f"# New Title\n \n <!-- python-substack-node:v1 { btn_encoded } -->\n "
150+ )
126151
127152 res = api .update_draft_from_markdown (42 , submitted_markdown )
128153 assert res ["action" ] == "update"
@@ -137,23 +162,30 @@ def test_update_draft_from_markdown_preservation(monkeypatch):
137162
138163 # 3. Update without marker succeeds when allow_unsupported_change is True
139164 mock_put_draft .reset_mock ()
140- res = api .update_draft_from_markdown (42 , "# New Title without button" , allow_unsupported_change = True )
165+ res = api .update_draft_from_markdown (
166+ 42 , "# New Title without button" , allow_unsupported_change = True
167+ )
141168 assert res ["action" ] == "update"
142169 assert mock_put_draft .called
143170
144171
145- def test_cli_update_requires_yes_for_allow_unsupported_change (tmp_path , monkeypatch , capsys ):
172+ def test_cli_update_requires_yes_for_allow_unsupported_change (
173+ tmp_path , monkeypatch , capsys
174+ ):
146175 # Mocking UpdateOperationsApi
147176 class MockApi :
148177 def update_draft_from_markdown (self , * args , ** kwargs ):
149178 return {"action" : "update" }
150-
179+
151180 monkeypatch .setattr (cli , "_api_from_env" , lambda ** kw : MockApi ())
152-
181+
153182 md_file = tmp_path / "test.md"
154183 md_file .write_text ("# Test" , encoding = "utf-8" )
155-
184+
156185 # If passing --allow-unsupported-change without --yes, it must raise CLIUsageError
157- assert cli .main (["drafts" , "update" , "42" , str (md_file ), "--allow-unsupported-change" ]) == 2
186+ assert (
187+ cli .main (["drafts" , "update" , "42" , str (md_file ), "--allow-unsupported-change" ])
188+ == 2
189+ )
158190 err = capsys .readouterr ().err
159191 assert "--yes is required when using --allow-unsupported-change" in err
0 commit comments