def test_nested_paths(): morePaths = dict( config="{pwd}/{there}/something", there="{somewhereElse}/theirplace", somewhereElse="{where}", where="myplace", ) assert pathLookup("{config}", **morePaths) == abs("myplace/theirplace/something")
def dataURL(file: str, _file_=None, **kwargs) -> str: """ Convert an image file into an inlined data url. """ path = Path(pathLookup(file, _file_)) if not path.exists(): raise DocumentException(f"Image file {file} can't be found") return dataUrlFromBytes(path.read_bytes(), path.suffix)
def fixup_document(document: Element): """ Apply fixups to an entire document. Determining the proper order to apply fixups has been a challenge. Originally, wanted specific document to override document type to override snippets, so we applied them snippets --> design --> our specific document. However, we had to change the order. - some fixups are "unfixable" (wrong shape or wrong element types) unless they are applied from the document level. These document fixups must be applied before all other fixups. They are based on "document type". - With fixup functions, high level fixups can impact lower level fixups, so we need to apply the design fixups before the snippet fixups. - The fixups can alter the shape of the design tree, so they have to be applied in top down manner. As a result, we now apply fixups: document type --> design --> snippets (top down). Both orderings have merit, so we may have to revisit, especially after the "unfixable" errors get fixed. """ # Apply Document Type fixups from directories of the document generator modules for module in document.document_sections: apply_fixup_function(document, document, find_section_directory(module)) apply_fixup_patches(document, document, find_section_directory(module)) # Apply Design fixups from the same directory as the document config file if document.design_file: apply_fixup_function( document.design, document, pathLookup("{design}", document.config_file) ) apply_fixup_patches( document.design, document, pathLookup("{design}", document.config_file) ) # Apply Element (snippet) to each matching element of the design. if document.snippets and document.design: scan(document.design, lambda element: fixup_snippet(element, document))
def document( *, config: str = "", output: str, design_file: str = "", sections: List[str] = None, directories: List[str] = None, values: List[str] = None, ): """ Create a document. It reads a config file which tells it where to fetch design data and which sections to process, and creates an asciidoc output file. :param config: Name of the document's configuration file :param output_file: Name of the .adoc file to create :param design_file: Name of the object model design file :param sections: A list of document section to add to the configuration. :param directories: A list of snippet directories to add to the configuration. :param values: A list of "path=value" strings to update the document """ # Default the following parameters to empty list sections = sections or [] directories = directories or [] values = values or [] # Read the configuration and prepare to create a document. doc = setup(config, output, design_file, sections, directories, values) # Pass globals as context to all subsequent sections context = doc.globals if doc.globals else {} # Open the output file for writing. with open(pathLookup(doc.output_name), "w") as f: # For each of the requested sections for section in doc.document_sections: # Process the section and save the output. for text in Section(section, doc, **context): f.write(str(text))
def test_relative_paths(): # Get pwd and our test directory. here = dirname(__file__) pwd = os.getcwd() assert isinstance(here, str) and isinstance(pwd, str) initPathInterpolation(pwd=pwd) assert pathLookup("/xxx") == "/xxx" assert pathLookup("xxx") == abs("xxx") assert pathLookup("{pwd}") == pwd assert pathLookup("{pwd}/xxx") == f"{pwd}/xxx" assert pathLookup("{here}/mystuff", here=here, extra="extra") == f"{here}/mystuff" assert pathLookup("{here}/mystuff", __file__) == f"{here}/mystuff"
def test_initial_here(): # One of the initial paths has {here} in it. here = dirname(__file__) initPathInterpolation(here, otherpath="{here}/other") assert pathLookup("{otherpath}") == f"{here}/other"
def tryit(path, expected): interpolated = pathLookup(path) assert interpolated == expected
def setup( config: str, output: str, design_file: str, sections: List[str], directories: List[str], values: List[str], ): """ Read in the document and design data needed to create a document. """ # Read in the document configuration (or start from scratch) if config: doc = Element.read(config) # config cannot have interpolations. doc.config = config else: doc = Element() # Update high level document fields if passed in command line. if design_file: doc.design_file = design_file if output: doc.output_name = output # Merge document sections and snippets from both the command line and the configuration doc.document_sections = [*sections, *doc.document_sections] doc.directories = [*directories, *doc.directories] # We should not have both a design and a design file if doc.design and doc.design_file: raise DocumentException( f"The document should not have both a design and a design file {doc.design_file}." ) # We must have at least one document section if not doc.document_sections: raise DocumentException( "The document must have at least one document-section") # Apply the command line values to the document. These override any values in the config. for assignment in values: [path, value] = assignment.split("=", 1) doc.set_path(path, value) # Set up interpolations for this document. Process {here} immediately. def dir(name): return name and dirname(name) initPathInterpolation( dir(doc.config) or "", config=dir(doc.config) or "", design=dir(doc.design_file) or "", output=dir(doc.output_name) or "", **(doc.paths or {}), ) # Read in the design file (if present) if doc.design_file: doc.design = Element.read(pathLookup(doc.design_file, doc.config)) # Add the additional document directories to sys.path so we can find sections. if doc.directories: directories = [ pathLookup(directory, doc.config) for directory in doc.directories ] addImportPath(*directories) # Keep track of which directories contain component snippets. Mainly to help with Fixups. doc.snippets = [ path for path in sys.path if Path(f"{path}/components").is_dir() ] # Prepare to load jinja2 templates as Python modules. JinjaFileLoader.install() # Add some necessary procedures so templates can access them. template.GLOBALS.update(Section=Section, Snippet=Snippet, Figure=Figure, Image=Image) # Apply fixups to the document. fixup_document(doc) # Finished. Our design/document tree is set up. No more changes to the design tree. # We can "memoize" future queries against the tree. MemoizedQueryStream.enable() return doc