1010
1111import inline_snapshot ._inline_snapshot
1212import pytest
13+ from inline_snapshot import snapshot
14+ from inline_snapshot .extra import raises
1315
1416
1517@dataclass
@@ -20,113 +22,212 @@ class Block:
2022 line : int
2123
2224
23- def map_code_blocks (file ):
24- def w (func ):
25-
26- block_start = re .compile ("( *)``` *python(.*)" )
27- block_end = re .compile ("```.*" )
28-
29- header = re .compile ("<!--(.*)-->" )
30-
31- current_code = file .read_text ("utf-8" )
32- new_lines = []
33- block_lines = []
34- options = set ()
35- is_block = False
36- code = None
37- indent = ""
38- block_start_linenum = None
39- block_options = None
40- code_header = None
41- header_line = ""
42-
43- for linenumber , line in enumerate (current_code .splitlines (), start = 1 ):
44- m = block_start .fullmatch (line )
45- if m and not is_block :
46- # ``` python
47- block_start_linenum = linenumber
48- indent = m [1 ]
49- block_options = m [2 ]
50- block_lines = []
51- is_block = True
52- continue
53-
54- if block_end .fullmatch (line .strip ()) and is_block :
55- # ```
56- is_block = False
57-
58- code = "\n " .join (block_lines ) + "\n "
59- code = textwrap .dedent (code )
60- if file .suffix == ".py" :
61- code = code .replace ("\\ \\ " , "\\ " )
62-
63- try :
64- new_block = func (
65- Block (
66- code = code ,
67- code_header = code_header ,
68- block_options = block_options ,
69- line = block_start_linenum ,
70- )
25+ def map_code_blocks (file , func , fix = False ):
26+
27+ block_start = re .compile ("( *)``` *python(.*)" )
28+ block_end = re .compile ("```.*" )
29+
30+ header = re .compile ("<!--(.*)-->" )
31+
32+ current_code = file .read_text ("utf-8" )
33+ new_lines = []
34+ block_lines = []
35+ options = set ()
36+ is_block = False
37+ code = None
38+ indent = ""
39+ block_start_linenum = None
40+ block_options = None
41+ code_header = None
42+ header_line = ""
43+
44+ for linenumber , line in enumerate (current_code .splitlines (), start = 1 ):
45+ m = block_start .fullmatch (line )
46+ if m and not is_block :
47+ # ``` python
48+ block_start_linenum = linenumber
49+ indent = m [1 ]
50+ block_options = m [2 ]
51+ block_lines = []
52+ is_block = True
53+ continue
54+
55+ if block_end .fullmatch (line .strip ()) and is_block :
56+ # ```
57+ is_block = False
58+
59+ code = "\n " .join (block_lines ) + "\n "
60+ code = textwrap .dedent (code )
61+ if file .suffix == ".py" :
62+ code = code .replace ("\\ \\ " , "\\ " )
63+
64+ try :
65+ new_block = func (
66+ Block (
67+ code = code ,
68+ code_header = code_header ,
69+ block_options = block_options ,
70+ line = block_start_linenum ,
7171 )
72- except Exception :
73- print (f"error at block at line { block_start_linenum } " )
74- print (f"{ code_header = } " )
75- print (f"{ block_options = } " )
76- print (code )
77- raise
78-
79- if new_block .code_header is not None :
80- new_lines .append (
81- f"{ indent } <!-- { new_block .code_header .strip ()} -->"
82- )
83-
84- new_lines .append (
85- f"{ indent } ``` { ('python ' + new_block .block_options .strip ()).strip ()} "
8672 )
73+ except Exception :
74+ print (f"error at block at line { block_start_linenum } " )
75+ print (f"{ code_header = } " )
76+ print (f"{ block_options = } " )
77+ print (code )
78+ raise
79+
80+ if new_block .code_header is not None :
81+ new_lines .append (f"{ indent } <!-- { new_block .code_header .strip ()} -->" )
82+
83+ new_lines .append (
84+ f"{ indent } ``` { ('python ' + new_block .block_options .strip ()).strip ()} "
85+ )
8786
88- new_code = new_block .code .rstrip (" \n " )
89- if file .suffix == ".py" :
90- new_code = new_code .replace ("\\ " , "\\ \\ " )
91- new_code = textwrap .indent (new_code , indent )
87+ new_code = new_block .code .rstrip ()
88+ if file .suffix == ".py" :
89+ new_code = new_code .replace ("\\ " , "\\ \\ " )
90+ new_code = textwrap .indent (new_code , indent )
9291
93- new_lines .append (new_code )
92+ new_lines .append (new_code )
9493
95- new_lines .append (f"{ indent } ```" )
94+ new_lines .append (f"{ indent } ```" )
9695
97- header_line = ""
96+ header_line = ""
97+ code_header = None
98+
99+ continue
100+
101+ if is_block :
102+ block_lines .append (line )
103+ continue
104+
105+ m = header .fullmatch (line .strip ())
106+ if m :
107+ # comment <!-- ... -->
108+ header_line = line
109+ code_header = m [1 ].strip ()
110+ continue
111+ else :
112+ if header_line :
113+ new_lines .append (header_line )
98114 code_header = None
115+ header_line = ""
99116
100- continue
117+ new_lines . append ( line )
101118
102- if is_block :
103- block_lines .append (line )
104- continue
119+ new_code = "\n " .join (new_lines ) + "\n "
105120
106- m = header .fullmatch (line .strip ())
107- if m :
108- # comment <!-- ... -->
109- header_line = line
110- code_header = m [1 ].strip ()
111- continue
112- else :
113- if header_line :
114- new_lines .append (header_line )
115- code_header = None
116- header_line = ""
121+ if fix :
122+ file .write_text (new_code )
123+ else :
124+ assert current_code .splitlines () == new_code .splitlines ()
125+ assert current_code == new_code
126+
127+
128+ def test_map_code_blocks (tmp_path ):
129+
130+ file = tmp_path / "example.md"
131+
132+ def test_doc (
133+ markdown_code ,
134+ handle_block = lambda block : exec (block .code ),
135+ blocks = [],
136+ exception = "<no exception>" ,
137+ new_markdown_code = None ,
138+ ):
117139
118- if not is_block :
119- new_lines .append (line )
140+ file .write_text (markdown_code )
120141
121- new_code = " \n " . join ( new_lines ) + " \n "
142+ recorded_blocks = []
122143
123- if inline_snapshot ._inline_snapshot ._update_flags .fix :
124- file .write_text (new_code )
144+ with raises (exception ):
145+
146+ def test_block (block ):
147+ handle_block (block )
148+ recorded_blocks .append (block )
149+ return block
150+
151+ map_code_blocks (file , test_block , True )
152+ assert recorded_blocks == blocks
153+ map_code_blocks (file , test_block , False )
154+
155+ recorded_markdown_code = file .read_text ()
156+ if recorded_markdown_code != markdown_code :
157+ assert new_markdown_code == recorded_markdown_code
125158 else :
126- assert current_code .splitlines () == new_code .splitlines ()
127- assert current_code == new_code
159+ assert new_markdown_code == None
128160
129- return w
161+ test_doc (
162+ """
163+ ``` python
164+ 1 / 0
165+ ```
166+ """ ,
167+ exception = snapshot ("ZeroDivisionError: division by zero" ),
168+ )
169+
170+ test_doc (
171+ """\
172+ text
173+ ``` python
174+ print(1 + 1)
175+ ```
176+ text
177+ <!-- inline-snapshot: create test -->
178+ ``` python hl_lines="1 2 3"
179+ print(1 - 1)
180+ ```
181+ text
182+ """ ,
183+ blocks = snapshot (
184+ [
185+ Block (
186+ code = "print(1 + 1)\n " , code_header = None , block_options = "" , line = 2
187+ ),
188+ Block (
189+ code = "print(1 - 1)\n " ,
190+ code_header = "inline-snapshot: create test" ,
191+ block_options = ' hl_lines="1 2 3"' ,
192+ line = 7 ,
193+ ),
194+ ]
195+ ),
196+ )
197+
198+ def change_block (block ):
199+ block .code = "# removed"
200+ block .code_header = "header"
201+ block .block_options = "option a b c"
202+
203+ test_doc (
204+ """\
205+ text
206+ ``` python
207+ print(1 + 1)
208+ ```
209+ """ ,
210+ handle_block = change_block ,
211+ blocks = snapshot (
212+ [
213+ Block (
214+ code = "# removed" ,
215+ code_header = "header" ,
216+ block_options = "option a b c" ,
217+ line = 2 ,
218+ )
219+ ]
220+ ),
221+ new_markdown_code = snapshot (
222+ """\
223+ text
224+ <!-- header -->
225+ ``` python option a b c
226+ # removed
227+ ```
228+ """
229+ ),
230+ )
130231
131232
132233@pytest .mark .skipif (
@@ -168,8 +269,7 @@ def test_docs(project, file, subtests):
168269
169270 extra_files = defaultdict (list )
170271
171- @map_code_blocks (file )
172- def _ (block : Block ):
272+ def test_block (block : Block ):
173273 if block .code_header is None :
174274 return block
175275
@@ -264,3 +364,7 @@ def _(block: Block):
264364
265365 last_code = code
266366 return block
367+
368+ map_code_blocks (
369+ file , test_block , inline_snapshot ._inline_snapshot ._update_flags .fix
370+ )
0 commit comments