diff --git a/src/midgy/language/python.py b/src/midgy/language/python.py
index 590c739..5a1bb0b 100644
--- a/src/midgy/language/python.py
+++ b/src/midgy/language/python.py
@@ -3,6 +3,7 @@
 
 from collections import deque
 from dataclasses import dataclass, field
+from functools import wraps
 from io import StringIO
 from itertools import pairwise, zip_longest
 from re import sub
@@ -45,7 +46,10 @@ class Python(Markdown, type="text/x-python", language="ipython3"):
         front_matter="midgy.front_matter:load",
         css="midgy.language.python:Css",
         html="midgy.language.python:HTML",
+        markdown="midgy.language.python:Markdown",
         javascript="midgy.language.python:Script",
+        graphviz="midgy.language.python:DOT",
+        dot="midgy.language.python:DOT",
         md="midgy.language.python:Markdown",
         **{
             "!": "midgy.language.python:_shell_out",
@@ -229,8 +233,6 @@ def fence_noncode(self, token, env):
         else:
             yield from rest
         env.update(continued=False if method else env.get("continued"))
-        
-
 
     def front_matter(self, token, env):
         """render front matter as python code with an optional variable name"""
@@ -478,16 +480,42 @@ def is_urls(tokens):
     return True
 
 
+def enforce_cls(callable):
+    @wraps(callable)
+    def main(self, *args, **kwargs):
+        return type(self)(callable(self, *args, **kwargs))
+
+    return main
+
+
 class String(str):
     @property
     def data(self):
         return self
 
-    def __add__(self, b):
-        return type(self)(super().__add__(b))
-
-    def __mul__(self, b):
-        return type(self)(super().__mul__(b))
+    __add__ = enforce_cls(str.__add__)
+    __mul__ = enforce_cls(str.__mul__)
+    __rmul__ = enforce_cls(str.__rmul__)
+    capitalize = enforce_cls(str.capitalize)
+    format = enforce_cls(str.format)
+    removeprefix = enforce_cls(str.removeprefix)
+    removesuffix = enforce_cls(str.removesuffix)
+    replace = enforce_cls(str.replace)
+    strip = enforce_cls(str.strip)
+    lstrip = enforce_cls(str.lstrip)
+    rstrip = enforce_cls(str.rstrip)
+    upper = enforce_cls(str.upper)
+    lower = enforce_cls(str.lower)
+
+    @enforce_cls
+    def render(self, *args, **kwargs):
+        from IPython import get_ipython
+
+        shell = get_ipython()
+        if shell:
+            if shell.has_trait("environment"):
+                return shell.environment.from_string(self).render(*args, **kwargs)
+        object.__getattribute__(self, "render")
 
 
 class HTML(String):
@@ -514,3 +542,23 @@ class Script(HTML):
 class Markdown(str):
     def _repr_markdown_(self):
         return self
+
+
+class SVG(HTML):
+    def _repr_svg_(self):
+        return self
+
+
+class DOT(String):
+    def graphviz(
+        self,
+    ):
+        from graphviz import Source
+
+        return Source(self)
+
+    def _repr_svg_(self):
+        try:
+            return self.graphviz()._repr_image_svg_xml()
+        except (ModuleNotFoundError, ImportError):
+            pass