You can try instantiating a Tag object directly, with the constructor. I don't generally recommend this because there are a large number of subtle rules about how different tags and attributes should be treated, rules which are managed by the TreeBuilder object (BeautifulSoup.builder). That's the thing that really needs to be passed into the Tag constructor. new_tag is an instance method of BeautifulSoup mainly so we can guarantee that a TreeBuilder is available when Tag needs it.
If you invoke the Tag constructor without passing in a TreeBuilder, you'll get a Tag, but it will probably behave very slightly differently from Tags that were created when a TreeBuilder was available, which can lead to subtle problems.
Here's a simple example. TreeBuilders designed to parse HTML have special rules for handling HTML multi-valued attributes such as "class":
>>> html_soup = BeautifulSoup("", "html.parser")
>>> html_soup.new_tag(name="a", attrs={"class": "class1 class2"})['class']
['class1', 'class2']
TreeBuilders designed to parse XML don't have those rules:
>>> xml_soup = BeautifulSoup("", "lxml-xml")
>>> xml_soup.new_tag(name="a", attrs={"class": "class1 class2"})['class']
'class1 class2'
If you invoke the Tag constructor with no builder, Beautiful Soup won't know which set of rules to apply, so you'll always get the "no rules" behavior:
>>> Tag(name="a", attrs={"class": "class1 class2"})['class']
'class1 class2'
Leonard