`class` attribute cannot be set
Closed this issue ยท 13 comments
because it's a Python keyword...
You can use Tag.whatever(..., **{"class": value})
as a workaround
If you have a more elegant proposal, I would be happy to hear it
I was very disappointed when I found out you can't assign a class, my sadness is overwhelming, my mental state is terrible, I can't sleep at night thinking about how sad it makes me to know you can't assign a class. It's unbearably hard, but we're with you and always ready to support you in this difficult time.
But you can choose either:
- clazz (java style)
- className (js style)
- _class (mongodb style)
- $class (php style)
Also, if you don't mind an extra statement, you can write
tag = Tag.whatever(...)
tag["class"] = value
Maybe add a named parameter "attributes" that holds a dict (or is a dict view) of the attributes, so attributes = {"class": value}
- generic but verbose. Perhaps an unnamed dict parameter (..., {"class": value}, ...)
could be used to specify attributes?
JavaScript DOM API tag elements have a classList
property. classes = []
or `classes=""`` But I haven't checked whether other keywords are conflicting.
Right now Tag constructor signature is
def __init__(
self,
tag_name: str,
*children: Node,
self_closing: bool = True,
**attributes: Value,
):
So there is a parameter called attributes
which holds all named arguments (**{"class": value}
workaround works on top of that).
I'm unsure about unnamed dictionary parameter (although I considered that) because it would go to children
and it would require some additional checks on that parameter.
classes
proposal makes sense, but while soda is aimed at SVG, I aim to support arbitrary XML generation and as such I don't want to add some SVG-specific conversions of parameters.
Right now you can use something like this:
from soda import Tag
def set_class(self, *classes):
return self(**{"class": " ".join(classes)})
Tag.set_class = set_class
tag = Tag.whatever(...).set_class("some_class", "another_class")
You can create a PR with this (or I would maybe add it myself in a few days)
tag = Tag.whatever(...).set_class("some_class", "another_class")
keeps the one-line instantiation but isn't it HTML/SVG/class-attribute specific? So maybe
def set_attr(self, attribute, *classes):
return self(**{attribute: " ".join(classes)})
To add to the confusion with another option:
- expand on the
# '_' to '-' conversion
withclass_= ...
tag = Tag.whatever(...).set_class("some_class", "another_class")
keeps the one-line instantiation but isn't it HTML/SVG/class-attribute specific? So maybedef set_attr(self, attribute, *classes): return self(**{attribute: " ".join(classes)})
I think a more appropriate version of set_attr
could look like that:
def set_attr(self, attribute: str, value: Value) -> "Tag":
self[attribute] = value
return self
To add to the confusion with another option:
* expand on the `# '_' to '-' conversion` with `class_= ...`
Honestly, I got a bit confused by this part, could you please explain?
You are converting underscores in attribute names into hyphens, e.g. clip_path
becomes clip-path
.
Similarly, removing a trailing underscore from an attribute name should allow quick typing while avoiding keyword collisions, e.g. class_
becomes class
.
I totally forgot about Tag.set_attribute
method which already does roughly what proposed set_attr
should do
I will consider '_' stripping but for now you can already use
tag = Tag.whatever(...).set_attribute("class", "some_class")
Also consider namespaces, e.g. Inkscape needs obsolete <use xlink:href=""/>
...
I guess it could be done with set_attribute, or with **{"xlink:href": "your_link_here"}
Starting with 1.1.0, leading and trailing underscores are removed by default