55import os
66import pwd
77import subprocess
8- from dataclasses import dataclass
98from functools import partial
109from pathlib import Path , PurePath
11- from typing import Any , Dict , Tuple , Optional , Set , List
10+ from typing import Any , Dict , Tuple , Optional , Set , List , Iterable
1211from typing_extensions import Protocol
1312import docutils .utils
14- import toml
1513
1614from . import gizaparser , rstparser , util
17- from .flutter import check_type , checked
1815from .gizaparser .nodes import GizaCategory
19- from .types import Diagnostic , SerializableType , EmbeddedRstParser , Page , StaticAsset
16+ from .types import Diagnostic , SerializableType , EmbeddedRstParser , Page , \
17+ StaticAsset , ProjectConfigError , ProjectConfig
2018
2119RST_EXTENSIONS = {'.rst' , '.txt' }
2220logger = logging .getLogger (__name__ )
@@ -171,6 +169,9 @@ def add_static_asset(self, path: PurePath) -> StaticAsset:
171169 self .static_assets .add (static_asset )
172170 return static_asset
173171
172+ def add_diagnostics (self , diagnostics : Iterable [Diagnostic ]) -> None :
173+ self .diagnostics .extend (diagnostics )
174+
174175 def __make_child_visitor (self ) -> 'JSONVisitor' :
175176 visitor = type (self )(self .project_root , self .docpath , self .document )
176177 visitor .diagnostics = self .diagnostics
@@ -193,12 +194,9 @@ def dispatch_departure(self, node: docutils.nodes.Node) -> None:
193194
194195
195196def parse_rst (parser : rstparser .Parser [JSONVisitor ],
196- path : PurePath ,
197+ path : Path ,
197198 text : Optional [str ] = None ) -> Tuple [Page , List [Diagnostic ]]:
198- if text is None :
199- with open (path , 'r' ) as f :
200- text = f .read ()
201- visitor = parser .parse (path , text )
199+ visitor , text = parser .parse (path , text )
202200
203201 return Page (
204202 path ,
@@ -207,7 +205,7 @@ def parse_rst(parser: rstparser.Parser[JSONVisitor],
207205 visitor .static_assets ), visitor .diagnostics
208206
209207
210- def make_embedded_rst_parser (project_root : Path ,
208+ def make_embedded_rst_parser (project_config : ProjectConfig ,
211209 page : Page ,
212210 diagnostics : List [Diagnostic ]) -> EmbeddedRstParser :
213211 def parse_embedded_rst (rst : str ,
@@ -216,8 +214,8 @@ def parse_embedded_rst(rst: str,
216214 # Crudely make docutils line numbers match
217215 text = '\n ' * lineno + rst .strip ()
218216 visitor_class = InlineJSONVisitor if inline else JSONVisitor
219- parser = rstparser .Parser (project_root , visitor_class )
220- visitor = parser .parse (page .source_path , text )
217+ parser = rstparser .Parser (project_config , visitor_class )
218+ visitor , _ = parser .parse (page .source_path , text )
221219 children : List [SerializableType ] = visitor .state [- 1 ]['children' ]
222220
223221 diagnostics .extend (visitor .diagnostics )
@@ -242,55 +240,38 @@ def on_update(self, prefix: List[str], page_id: str, page: Page) -> None: ...
242240 def on_delete (self , page_id : str ) -> None : ...
243241
244242
245- @checked
246- @dataclass
247- class ProjectConfig :
248- name : str
249-
250- @classmethod
251- def open (cls , root : Path ) -> Tuple [Path , 'ProjectConfig' ]:
252- path = root
253- while path .parent != path :
254- try :
255- with open (path .joinpath ('snooty.toml' ), 'r' ) as f :
256- return path , check_type (ProjectConfig , toml .load (f ))
257- except FileNotFoundError :
258- pass
259- path = path .parent
260-
261- return root , cls ('untitled' )
262-
263-
264243class Project :
265244 def __init__ (self ,
266245 root : Path ,
267246 backend : ProjectBackend ) -> None :
268247 root = root .resolve (strict = True )
269- root , config = ProjectConfig .open (root )
248+ root , self .config , config_diagnostics = ProjectConfig .open (root )
249+
250+ if config_diagnostics :
251+ backend .on_diagnostics (root , config_diagnostics )
252+ raise ProjectConfigError ()
270253
271254 self .root = root
272- self .parser = rstparser .Parser (self .root , JSONVisitor )
255+ self .parser = rstparser .Parser (self .config , JSONVisitor )
273256 self .static_assets : Dict [PurePath , Set [StaticAsset ]] = collections .defaultdict (set )
274257 self .backend = backend
275258
276- self .steps_category = gizaparser .steps .GizaStepsCategory ()
277- self .extracts_category = gizaparser .extracts .GizaExtractsCategory ()
278259 self .yaml_mapping : Dict [str , GizaCategory [Any ]] = {
279- 'steps' : self .steps_category ,
280- 'extracts' : self .extracts_category
260+ 'steps' : gizaparser . steps . GizaStepsCategory ( self .config ) ,
261+ 'extracts' : gizaparser . extracts . GizaExtractsCategory ( self .config )
281262 }
282263
283264 username = pwd .getpwuid (os .getuid ()).pw_name
284265 branch = subprocess .check_output (
285266 ['git' , 'rev-parse' , '--abbrev-ref' , 'HEAD' ],
286267 encoding = 'utf-8' ).strip ()
287- self .prefix = [config .name , username , branch ]
268+ self .prefix = [self . config .name , username , branch ]
288269
289270 def get_page_id (self , path : PurePath ) -> str :
290271 page_id = path .with_suffix ('' ).relative_to (self .root ).as_posix ()
291272 return '/' .join (self .prefix + [page_id ])
292273
293- def update (self , path : PurePath , optional_text : Optional [str ] = None ) -> None :
274+ def update (self , path : Path , optional_text : Optional [str ] = None ) -> None :
294275 diagnostics : Dict [PurePath , List [Diagnostic ]] = {path : []}
295276 prefix = get_giza_category (path )
296277 _ , ext = os .path .splitext (path )
@@ -302,9 +283,8 @@ def update(self, path: PurePath, optional_text: Optional[str] = None) -> None:
302283 elif ext == '.yaml' and prefix in self .yaml_mapping :
303284 file_id = os .path .basename (path )
304285 giza_category = self .yaml_mapping [prefix ]
305- needs_rebuild = self .steps_category .dg .dependents [file_id ].union (
306- self .extracts_category .dg .dependents [file_id ]).union (
307- set ([file_id ]))
286+ needs_rebuild = set ((file_id )).union (* (
287+ category .dg .dependents [file_id ] for category in self .yaml_mapping .values ()))
308288 logger .debug ('needs_rebuild: %s' , ',' .join (needs_rebuild ))
309289 for file_id in needs_rebuild :
310290 file_diagnostics : List [Diagnostic ] = []
@@ -319,7 +299,7 @@ def update(self, path: PurePath, optional_text: Optional[str] = None) -> None:
319299
320300 def create_page () -> Tuple [Page , EmbeddedRstParser ]:
321301 page = Page (giza_node .path , text , {})
322- return page , make_embedded_rst_parser (self .root , page , file_diagnostics )
302+ return page , make_embedded_rst_parser (self .config , page , file_diagnostics )
323303
324304 giza_category .add (path , text , steps )
325305 pages = giza_category .to_pages (create_page , giza_node .data )
@@ -352,7 +332,7 @@ def build(self) -> None:
352332
353333 # Categorize our YAML files
354334 logger .debug ('Categorizing YAML files' )
355- categorized : Dict [str , List [PurePath ]] = collections .defaultdict (list )
335+ categorized : Dict [str , List [Path ]] = collections .defaultdict (list )
356336 for path in util .get_files (self .root , ('.yaml' ,)):
357337 prefix = get_giza_category (path )
358338 if prefix in self .yaml_mapping :
@@ -373,7 +353,7 @@ def build(self) -> None:
373353 def create_page () -> Tuple [Page , EmbeddedRstParser ]:
374354 page = Page (giza_node .path , giza_node .text , {})
375355 return page , make_embedded_rst_parser (
376- self .root , page , all_yaml_diagnostics .setdefault (giza_node .path , []))
356+ self .config , page , all_yaml_diagnostics .setdefault (giza_node .path , []))
377357
378358 for page in giza_category .to_pages (create_page , giza_node .data ):
379359 self .backend .on_update (self .prefix , self .get_page_id (page .get_id ()), page )
0 commit comments