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
class PHML:
 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.

PHML( scopes: Optional[list[str]] = None, components: Optional[dict[str, dict[str, list | phml.core.nodes.root.Root | phml.core.nodes.element.Element | phml.core.nodes.text.Text | phml.core.nodes.comment.Comment | phml.core.nodes.doctype.DocType | phml.core.nodes.parent.Parent | phml.core.nodes.node.Node | phml.core.nodes.literal.Literal]]] = None)
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 []

Instance of a [Parser][phml.parser.Parser].

Instance of a [Compiler][phml.compile.Compiler].

scopes: Optional[list[str]]

List of paths from cwd to auto add to python path. This helps with importing inside of phml files.

Reference to the parser attributes ast value.

def add( self, *components: dict[str, dict[str, list | phml.core.nodes.root.Root | phml.core.nodes.element.Element | phml.core.nodes.text.Text | phml.core.nodes.comment.Comment | phml.core.nodes.doctype.DocType | phml.core.nodes.parent.Parent | phml.core.nodes.node.Node | phml.core.nodes.literal.Literal] | phml.core.nodes.AST.AST] | tuple[str, dict[str, list | phml.core.nodes.root.Root | phml.core.nodes.element.Element | phml.core.nodes.text.Text | phml.core.nodes.comment.Comment | phml.core.nodes.doctype.DocType | phml.core.nodes.parent.Parent | phml.core.nodes.node.Node | phml.core.nodes.literal.Literal] | phml.core.nodes.AST.AST] | pathlib.Path):
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.
def remove( self, *components: str | phml.core.nodes.root.Root | phml.core.nodes.element.Element | phml.core.nodes.text.Text | phml.core.nodes.comment.Comment | phml.core.nodes.doctype.DocType | phml.core.nodes.parent.Parent | phml.core.nodes.node.Node | phml.core.nodes.literal.Literal):
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.

def load( self, file_path: str | pathlib.Path, handler: Optional[Callable] = None):
 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.
def parse(self, data: str | dict, handler: Optional[Callable] = None):
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
def render( self, file_type: str = 'html', indent: Optional[int] = None, scopes: Optional[list[str]] = None, **kwargs) -> str:
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.

def write( self, dest: str | pathlib.Path, file_type: str = 'html', indent: Optional[int] = None, scopes: Optional[list[str]] = None, **kwargs):
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.