phml.core.core_lang
1from pathlib import Path 2from typing import Callable, Optional 3 4from phml.core.nodes import AST, All_Nodes 5from phml.core.valid_file_types import Formats 6from phml.utilities import filename_from_path, parse_component 7 8from .compiler import Compiler 9from .parser import Parser 10 11__all__ = ["PHML"] 12 13 14class PHML: 15 """A helper class that bundles the functionality 16 of the parser and compiler together. Allows for loading source files, 17 parsing strings and dicts, rendering to a different format, and finally 18 writing the results of a render to a file. 19 """ 20 21 parser: Parser 22 """Instance of a [Parser][phml.parser.Parser].""" 23 compiler: Compiler 24 """Instance of a [Compiler][phml.compile.Compiler].""" 25 scopes: Optional[list[str]] 26 """List of paths from cwd to auto add to python path. This helps with 27 importing inside of phml files. 28 """ 29 30 @property 31 def ast(self) -> AST: 32 """Reference to the parser attributes ast value.""" 33 return self.parser.ast 34 35 @ast.setter 36 def ast(self, _ast: AST): 37 self.parser.ast = _ast 38 39 def __init__( 40 self, 41 scopes: Optional[list[str]] = None, 42 components: Optional[dict[str, dict[str, list | All_Nodes]]] = None, 43 ): 44 self.parser = Parser() 45 self.compiler = Compiler(components=components) 46 self.scopes = scopes or [] 47 48 def add( 49 self, 50 *components: dict[str, dict[str, list | All_Nodes] | AST] 51 | tuple[str, dict[str, list | All_Nodes] | AST] 52 | Path, 53 ): 54 """Add a component to the element replacement list. 55 56 Components passed in can be of a few types. The first type it can be is a 57 pathlib.Path type. This will allow for automatic parsing of the file at the 58 path and then the filename and parsed ast are passed to the compiler. It can 59 also be a dictionary of str being the name of the element to be replaced. 60 The name can be snake case, camel case, or pascal cased. The value can either 61 be the parsed result of the component from phml.utilities.parse_component() or the 62 parsed ast of the component. Lastely, the component can be a tuple. The first 63 value is the name of the element to be replaced; with the second value being 64 either the parsed result of the component or the component's ast. 65 66 Note: 67 Any duplicate components will be replaced. 68 69 Args: 70 components: Any number values indicating 71 name of the component and the the component. The name is used 72 to replace a element with the tag==name. 73 """ 74 75 for component in components: 76 if isinstance(component, Path): 77 self.parser.load(component) 78 self.compiler.add((filename_from_path(component), parse_component(self.parser.ast))) 79 elif isinstance(component, dict): 80 self.compiler.add(*list(component.items())) 81 return self 82 83 def remove(self, *components: str | All_Nodes): 84 """Remove an element from the list of element replacements. 85 86 Takes any number of strings or node objects. If a string is passed 87 it is used as the key that will be removed. If a node object is passed 88 it will attempt to find a matching node and remove it. 89 """ 90 self.compiler.remove(*components) 91 return self 92 93 def load(self, file_path: str | Path, handler: Optional[Callable] = None): 94 """Load a source files data and parse it to phml. 95 96 Args: 97 file_path (str | Path): The file path to the source file. 98 """ 99 self.parser.load(file_path, handler) 100 return self 101 102 def parse(self, data: str | dict, handler: Optional[Callable] = None): 103 """Parse a str or dict object into phml. 104 105 Args: 106 data (str | dict): Object to parse to phml 107 """ 108 self.parser.parse(data, handler) 109 return self 110 111 def render( 112 self, 113 file_type: str = Formats.HTML, 114 indent: Optional[int] = None, 115 scopes: Optional[list[str]] = None, 116 **kwargs, 117 ) -> str: 118 """Render the parsed ast to a different format. Defaults to rendering to html. 119 120 Args: 121 file_type (str): The format to render to. Currently support html, phml, and json. 122 indent (Optional[int], optional): The number of spaces per indent. By default it will 123 use the standard for the given format. HTML has 4 spaces, phml has 4 spaces, and json 124 has 2 spaces. 125 126 Returns: 127 str: The rendered content in the appropriate format. 128 """ 129 130 scopes = scopes or ["./"] 131 for scope in self.scopes: 132 if scope not in scopes: 133 scopes.append(scope) 134 135 return self.compiler.compile( 136 self.parser.ast, 137 to_format=file_type, 138 indent=indent, 139 scopes=scopes, 140 **kwargs, 141 ) 142 143 def write( 144 self, 145 dest: str | Path, 146 file_type: str = Formats.HTML, 147 indent: Optional[int] = None, 148 scopes: Optional[list[str]] = None, 149 **kwargs, 150 ): 151 """Renders the parsed ast to a different format, then writes 152 it to a given file. Defaults to rendering and writing out as html. 153 154 Args: 155 dest (str | Path): The path to the file to be written to. 156 file_type (str): The format to render the ast as. 157 indent (Optional[int], optional): The number of spaces per indent. By default it will 158 use the standard for the given format. HTML has 4 spaces, phml has 4 spaces, and json 159 has 2 spaces. 160 kwargs: Any additional data to pass to the compiler that will be exposed to the 161 phml files. 162 """ 163 164 with open(dest, "+w", encoding="utf-8") as dest_file: 165 dest_file.write( 166 self.render(file_type=file_type, indent=indent, scopes=scopes, **kwargs) 167 ) 168 return self
15class PHML: 16 """A helper class that bundles the functionality 17 of the parser and compiler together. Allows for loading source files, 18 parsing strings and dicts, rendering to a different format, and finally 19 writing the results of a render to a file. 20 """ 21 22 parser: Parser 23 """Instance of a [Parser][phml.parser.Parser].""" 24 compiler: Compiler 25 """Instance of a [Compiler][phml.compile.Compiler].""" 26 scopes: Optional[list[str]] 27 """List of paths from cwd to auto add to python path. This helps with 28 importing inside of phml files. 29 """ 30 31 @property 32 def ast(self) -> AST: 33 """Reference to the parser attributes ast value.""" 34 return self.parser.ast 35 36 @ast.setter 37 def ast(self, _ast: AST): 38 self.parser.ast = _ast 39 40 def __init__( 41 self, 42 scopes: Optional[list[str]] = None, 43 components: Optional[dict[str, dict[str, list | All_Nodes]]] = None, 44 ): 45 self.parser = Parser() 46 self.compiler = Compiler(components=components) 47 self.scopes = scopes or [] 48 49 def add( 50 self, 51 *components: dict[str, dict[str, list | All_Nodes] | AST] 52 | tuple[str, dict[str, list | All_Nodes] | AST] 53 | Path, 54 ): 55 """Add a component to the element replacement list. 56 57 Components passed in can be of a few types. The first type it can be is a 58 pathlib.Path type. This will allow for automatic parsing of the file at the 59 path and then the filename and parsed ast are passed to the compiler. It can 60 also be a dictionary of str being the name of the element to be replaced. 61 The name can be snake case, camel case, or pascal cased. The value can either 62 be the parsed result of the component from phml.utilities.parse_component() or the 63 parsed ast of the component. Lastely, the component can be a tuple. The first 64 value is the name of the element to be replaced; with the second value being 65 either the parsed result of the component or the component's ast. 66 67 Note: 68 Any duplicate components will be replaced. 69 70 Args: 71 components: Any number values indicating 72 name of the component and the the component. The name is used 73 to replace a element with the tag==name. 74 """ 75 76 for component in components: 77 if isinstance(component, Path): 78 self.parser.load(component) 79 self.compiler.add((filename_from_path(component), parse_component(self.parser.ast))) 80 elif isinstance(component, dict): 81 self.compiler.add(*list(component.items())) 82 return self 83 84 def remove(self, *components: str | All_Nodes): 85 """Remove an element from the list of element replacements. 86 87 Takes any number of strings or node objects. If a string is passed 88 it is used as the key that will be removed. If a node object is passed 89 it will attempt to find a matching node and remove it. 90 """ 91 self.compiler.remove(*components) 92 return self 93 94 def load(self, file_path: str | Path, handler: Optional[Callable] = None): 95 """Load a source files data and parse it to phml. 96 97 Args: 98 file_path (str | Path): The file path to the source file. 99 """ 100 self.parser.load(file_path, handler) 101 return self 102 103 def parse(self, data: str | dict, handler: Optional[Callable] = None): 104 """Parse a str or dict object into phml. 105 106 Args: 107 data (str | dict): Object to parse to phml 108 """ 109 self.parser.parse(data, handler) 110 return self 111 112 def render( 113 self, 114 file_type: str = Formats.HTML, 115 indent: Optional[int] = None, 116 scopes: Optional[list[str]] = None, 117 **kwargs, 118 ) -> str: 119 """Render the parsed ast to a different format. Defaults to rendering to html. 120 121 Args: 122 file_type (str): The format to render to. Currently support html, phml, and json. 123 indent (Optional[int], optional): The number of spaces per indent. By default it will 124 use the standard for the given format. HTML has 4 spaces, phml has 4 spaces, and json 125 has 2 spaces. 126 127 Returns: 128 str: The rendered content in the appropriate format. 129 """ 130 131 scopes = scopes or ["./"] 132 for scope in self.scopes: 133 if scope not in scopes: 134 scopes.append(scope) 135 136 return self.compiler.compile( 137 self.parser.ast, 138 to_format=file_type, 139 indent=indent, 140 scopes=scopes, 141 **kwargs, 142 ) 143 144 def write( 145 self, 146 dest: str | Path, 147 file_type: str = Formats.HTML, 148 indent: Optional[int] = None, 149 scopes: Optional[list[str]] = None, 150 **kwargs, 151 ): 152 """Renders the parsed ast to a different format, then writes 153 it to a given file. Defaults to rendering and writing out as html. 154 155 Args: 156 dest (str | Path): The path to the file to be written to. 157 file_type (str): The format to render the ast as. 158 indent (Optional[int], optional): The number of spaces per indent. By default it will 159 use the standard for the given format. HTML has 4 spaces, phml has 4 spaces, and json 160 has 2 spaces. 161 kwargs: Any additional data to pass to the compiler that will be exposed to the 162 phml files. 163 """ 164 165 with open(dest, "+w", encoding="utf-8") as dest_file: 166 dest_file.write( 167 self.render(file_type=file_type, indent=indent, scopes=scopes, **kwargs) 168 ) 169 return self
A helper class that bundles the functionality of the parser and compiler together. Allows for loading source files, parsing strings and dicts, rendering to a different format, and finally writing the results of a render to a file.
List of paths from cwd to auto add to python path. This helps with importing inside of phml files.
49 def add( 50 self, 51 *components: dict[str, dict[str, list | All_Nodes] | AST] 52 | tuple[str, dict[str, list | All_Nodes] | AST] 53 | Path, 54 ): 55 """Add a component to the element replacement list. 56 57 Components passed in can be of a few types. The first type it can be is a 58 pathlib.Path type. This will allow for automatic parsing of the file at the 59 path and then the filename and parsed ast are passed to the compiler. It can 60 also be a dictionary of str being the name of the element to be replaced. 61 The name can be snake case, camel case, or pascal cased. The value can either 62 be the parsed result of the component from phml.utilities.parse_component() or the 63 parsed ast of the component. Lastely, the component can be a tuple. The first 64 value is the name of the element to be replaced; with the second value being 65 either the parsed result of the component or the component's ast. 66 67 Note: 68 Any duplicate components will be replaced. 69 70 Args: 71 components: Any number values indicating 72 name of the component and the the component. The name is used 73 to replace a element with the tag==name. 74 """ 75 76 for component in components: 77 if isinstance(component, Path): 78 self.parser.load(component) 79 self.compiler.add((filename_from_path(component), parse_component(self.parser.ast))) 80 elif isinstance(component, dict): 81 self.compiler.add(*list(component.items())) 82 return self
Add a component to the element replacement list.
Components passed in can be of a few types. The first type it can be is a pathlib.Path type. This will allow for automatic parsing of the file at the path and then the filename and parsed ast are passed to the compiler. It can also be a dictionary of str being the name of the element to be replaced. The name can be snake case, camel case, or pascal cased. The value can either be the parsed result of the component from phml.utilities.parse_component() or the parsed ast of the component. Lastely, the component can be a tuple. The first value is the name of the element to be replaced; with the second value being either the parsed result of the component or the component's ast.
Note:
Any duplicate components will be replaced.
Arguments:
- components: Any number values indicating
- name of the component and the the component. The name is used
- to replace a element with the tag==name.
84 def remove(self, *components: str | All_Nodes): 85 """Remove an element from the list of element replacements. 86 87 Takes any number of strings or node objects. If a string is passed 88 it is used as the key that will be removed. If a node object is passed 89 it will attempt to find a matching node and remove it. 90 """ 91 self.compiler.remove(*components) 92 return self
Remove an element from the list of element replacements.
Takes any number of strings or node objects. If a string is passed it is used as the key that will be removed. If a node object is passed it will attempt to find a matching node and remove it.
94 def load(self, file_path: str | Path, handler: Optional[Callable] = None): 95 """Load a source files data and parse it to phml. 96 97 Args: 98 file_path (str | Path): The file path to the source file. 99 """ 100 self.parser.load(file_path, handler) 101 return self
Load a source files data and parse it to phml.
Arguments:
- file_path (str | Path): The file path to the source file.
103 def parse(self, data: str | dict, handler: Optional[Callable] = None): 104 """Parse a str or dict object into phml. 105 106 Args: 107 data (str | dict): Object to parse to phml 108 """ 109 self.parser.parse(data, handler) 110 return self
Parse a str or dict object into phml.
Arguments:
- data (str | dict): Object to parse to phml
112 def render( 113 self, 114 file_type: str = Formats.HTML, 115 indent: Optional[int] = None, 116 scopes: Optional[list[str]] = None, 117 **kwargs, 118 ) -> str: 119 """Render the parsed ast to a different format. Defaults to rendering to html. 120 121 Args: 122 file_type (str): The format to render to. Currently support html, phml, and json. 123 indent (Optional[int], optional): The number of spaces per indent. By default it will 124 use the standard for the given format. HTML has 4 spaces, phml has 4 spaces, and json 125 has 2 spaces. 126 127 Returns: 128 str: The rendered content in the appropriate format. 129 """ 130 131 scopes = scopes or ["./"] 132 for scope in self.scopes: 133 if scope not in scopes: 134 scopes.append(scope) 135 136 return self.compiler.compile( 137 self.parser.ast, 138 to_format=file_type, 139 indent=indent, 140 scopes=scopes, 141 **kwargs, 142 )
Render the parsed ast to a different format. Defaults to rendering to html.
Arguments:
- file_type (str): The format to render to. Currently support html, phml, and json.
- indent (Optional[int], optional): The number of spaces per indent. By default it will
- use the standard for the given format. HTML has 4 spaces, phml has 4 spaces, and json
- has 2 spaces.
Returns:
str: The rendered content in the appropriate format.
144 def write( 145 self, 146 dest: str | Path, 147 file_type: str = Formats.HTML, 148 indent: Optional[int] = None, 149 scopes: Optional[list[str]] = None, 150 **kwargs, 151 ): 152 """Renders the parsed ast to a different format, then writes 153 it to a given file. Defaults to rendering and writing out as html. 154 155 Args: 156 dest (str | Path): The path to the file to be written to. 157 file_type (str): The format to render the ast as. 158 indent (Optional[int], optional): The number of spaces per indent. By default it will 159 use the standard for the given format. HTML has 4 spaces, phml has 4 spaces, and json 160 has 2 spaces. 161 kwargs: Any additional data to pass to the compiler that will be exposed to the 162 phml files. 163 """ 164 165 with open(dest, "+w", encoding="utf-8") as dest_file: 166 dest_file.write( 167 self.render(file_type=file_type, indent=indent, scopes=scopes, **kwargs) 168 ) 169 return self
Renders the parsed ast to a different format, then writes it to a given file. Defaults to rendering and writing out as html.
Arguments:
- dest (str | Path): The path to the file to be written to.
- file_type (str): The format to render the ast as.
- indent (Optional[int], optional): The number of spaces per indent. By default it will
- use the standard for the given format. HTML has 4 spaces, phml has 4 spaces, and json
- has 2 spaces.
- kwargs: Any additional data to pass to the compiler that will be exposed to the
- phml files.