diff --git a/meta/generate_tag_defs.py b/meta/generate_tag_defs.py
index c45e81d..19c6182 100644
--- a/meta/generate_tag_defs.py
+++ b/meta/generate_tag_defs.py
@@ -30,6 +30,12 @@ def generate_tag_class(output: TextIO, tag: TagInfo):
"""
text = get_template_class(tag.base)
+ # Generate default attributes dictionary
+ default_attrs = repr({
+ attr.name: attr.default
+ for attr in tag.attributes
+ })
+
# Generate attribute arguments, unions and documentation
# To get a better idea of these, look inside the template files to see
# what would be replaced
@@ -41,10 +47,15 @@ def generate_tag_class(output: TextIO, tag: TagInfo):
# Yucky hard-coded spaces, I can't be bothered to fix this
# Also making everything optional for the sake of users always
# being able to remove an attribute
- f" {attr.name}: Optional[{attr.type}] = {attr.default!r},"
+ f" {attr.name}: Optional[{attr.type}] = None,"
)
attr_unions_gen.append(f" '{attr.name}': {attr.name},")
- attr_docs_gen.append(f"* {attr.name}: {attr.doc}")
+ # Also mention default value if applicable
+ if attr.default is not None:
+ attr_docs_gen.append(
+ f"* {attr.name}: {attr.doc} (defaults to {attr.default})")
+ else:
+ attr_docs_gen.append(f"* {attr.name}: {attr.doc}")
attr_args = '\n'.join(attr_args_gen).strip()
attr_unions = '\n'.join(attr_unions_gen).strip()
@@ -70,7 +81,8 @@ def generate_tag_class(output: TextIO, tag: TagInfo):
.replace("{attr_unions}", attr_unions)\
.replace("{attr_docs_outer}", attr_docs_outer)\
.replace("{attr_docs_inner}", attr_docs_inner)\
- .replace("{kw_only}", kw_only)
+ .replace("{kw_only}", kw_only)\
+ .replace("{default_attrs}", default_attrs)
print(text, file=output)
# And a nice trailing newline to make flake8 happy
diff --git a/meta/templates/class_attrs_SelfClosingTag.py b/meta/templates/class_attrs_SelfClosingTag.py
index 4eb656c..c369b93 100644
--- a/meta/templates/class_attrs_SelfClosingTag.py
+++ b/meta/templates/class_attrs_SelfClosingTag.py
@@ -41,3 +41,6 @@ def __call__(
{attr_unions}
}
return super().__call__(**attributes)
+
+ def _get_default_attributes(self) -> dict[str, Any]:
+ return {default_attrs}
diff --git a/meta/templates/class_attrs_StylableTag.py b/meta/templates/class_attrs_StylableTag.py
index c41d44c..f6c8c77 100644
--- a/meta/templates/class_attrs_StylableTag.py
+++ b/meta/templates/class_attrs_StylableTag.py
@@ -53,3 +53,6 @@ def __call__(
{attr_unions}
}
return super().__call__(*children, **attributes)
+
+ def _get_default_attributes(self) -> dict[str, Any]:
+ return {default_attrs}
diff --git a/meta/templates/class_attrs_Tag.py b/meta/templates/class_attrs_Tag.py
index 3e057de..9353c32 100644
--- a/meta/templates/class_attrs_Tag.py
+++ b/meta/templates/class_attrs_Tag.py
@@ -41,3 +41,6 @@ def __call__(
{attr_unions}
}
return super().__call__(*children, **attributes)
+
+ def _get_default_attributes(self) -> dict[str, Any]:
+ return {default_attrs}
diff --git a/pyhtml/__tag_base.py b/pyhtml/__tag_base.py
index 93e1a44..eb8c4ac 100644
--- a/pyhtml/__tag_base.py
+++ b/pyhtml/__tag_base.py
@@ -45,15 +45,29 @@ def _get_tag_name(self) -> str:
"""
return type(self).__name__.removesuffix('_')
+ def _get_default_attributes(self) -> dict[str, Any]:
+ """
+ Returns the default attributes for the tag
+
+ This is overridden by child classes to return a dictionary of default
+ attributes that are applied to the class.
+ """
+ return {}
+
def _render(self) -> list[str]:
"""
Renders tag and its children to a list of strings where each string is
a single line of output
"""
+ attributes = util.filter_attributes(util.dict_union(
+ self._get_default_attributes(),
+ self.attributes,
+ ))
+
# Tag and attributes
opening = f"<{self._get_tag_name()}"
- if len(self.attributes):
- opening += f" {util.render_tag_attributes(self.attributes)}>"
+ if len(attributes):
+ opening += f" {util.render_tag_attributes(attributes)}>"
else:
opening += ">"
diff --git a/pyhtml/__tags/generated.py b/pyhtml/__tags/generated.py
index f1fbfba..a6cee83 100644
--- a/pyhtml/__tags/generated.py
+++ b/pyhtml/__tags/generated.py
@@ -16,46 +16,49 @@ class html(Tag):
"""
Represents the root (top-level element) of an HTML document, so it is also referred to as the _root element_. All other elements must be descendants of this element.
-
+
[View full documentation](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/html)
"""
def __init__(
self,
*children: Any,
-
+
**attributes: Any,
) -> None:
"""
Represents the root (top-level element) of an HTML document, so it is also referred to as the _root element_. All other elements must be descendants of this element.
-
+
[View full documentation](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/html)
"""
attributes |= {
-
+
}
super().__init__(*children, **attributes)
def __call__(
self,
*children: Any,
-
+
**attributes: Any,
):
"""
Represents the root (top-level element) of an HTML document, so it is also referred to as the _root element_. All other elements must be descendants of this element.
-
+
[View full documentation](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/html)
"""
attributes |= {
-
+
}
return super().__call__(*children, **attributes)
+ def _get_default_attributes(self) -> dict[str, Any]:
+ return {}
+
class base(SelfClosingTag):
"""
@@ -108,51 +111,57 @@ def __call__(
}
return super().__call__(**attributes)
+ def _get_default_attributes(self) -> dict[str, Any]:
+ return {'href': None, 'target': None}
+
class head(Tag):
"""
Contains machine-readable information (metadata) about the document, like its [title](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/title), [scripts](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script), and [style sheets](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/style).
-
+
[View full documentation](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/head)
"""
def __init__(
self,
*children: Any,
-
+
**attributes: Any,
) -> None:
"""
Contains machine-readable information (metadata) about the document, like its [title](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/title), [scripts](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script), and [style sheets](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/style).
-
+
[View full documentation](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/head)
"""
attributes |= {
-
+
}
super().__init__(*children, **attributes)
def __call__(
self,
*children: Any,
-
+
**attributes: Any,
):
"""
Contains machine-readable information (metadata) about the document, like its [title](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/title), [scripts](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script), and [style sheets](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/style).
-
+
[View full documentation](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/head)
"""
attributes |= {
-
+
}
return super().__call__(*children, **attributes)
+ def _get_default_attributes(self) -> dict[str, Any]:
+ return {}
+
class link(SelfClosingTag):
"""
@@ -205,70 +214,76 @@ def __call__(
}
return super().__call__(**attributes)
+ def _get_default_attributes(self) -> dict[str, Any]:
+ return {'href': None, 'rel': None}
+
class meta(Tag):
"""
Represents [metadata](https://developer.mozilla.org/en-US/docs/Glossary/Metadata) that cannot be represented by other HTML meta-related elements, like [`