Found it: While the doco says parsers turn elements to lower-case, they don't touch the values in strings.
I missed that the input files used "Content-Type", so find_all() failed when looking for "content-type":
======
print(soup.head.prettify())
meta = soup.head.find("meta", {"http-equiv":"Content-Type"})
if not meta:
metatag = soup.new_tag('meta')
metatag.attrs['http-equiv'] = 'Content-Type'
metatag.attrs['content'] = 'text/html; charset=utf-8'
soup.head.append(metatag)
else:
#If script run more than once, BS adds line...
#! values must match upper/lowercase
metas = soup.find_all("meta", {"http-equiv":"Content-Type"})
print("Found: ",len(metas))
#skip first element, remove others
for meta in metas[1:]:
meta.decompose()
print(soup.head.prettify())
======