After much agonizing over the way to make my new code work with doctests, I got something together that works for the existing tests without compromising normal functionality. It's... only a little cursed.
DESTRUCTURE_ALIAS = r"^([^*)(\[.*\])?$" LIST_ALIASES = frozenset([canonical_alias(list), canonical_alias(List)]) def get_all(alias: Alias) -> bool: match = re.match(DESTRUCTURE_ALIAS, alias) if not match: return False if not match.group(2): return False if match.group(1) not in LIST_ALIASES: return False return True
Basically... doctests don't create bindings at module scope, so I had to avoid the code paths that queried for classes defined in the doctest, because those are local variables, I think. To figure out what I'm good to do, I had to define the Alias newtype to track whether a string was a canonical alias. While it's safe to call canonical_alias repeatedly on normal aliases, it really expects to get references to module globals, and so barfs on these kinds of edge cases.
Anyway, with this, and some minor test fixes, I'm back to all tests passing, and can now focus on patching up the coverage holes introduced by my additions. My new code takes the coverage from 100% to 87%, and I know the error handling in the new sections is shaky at best, except where it was covered by existing tests.
While implementing the ideas that I came up with was... an ordeal, it was nice to be rewriting code primarily to change the functionality, rather than because I didn't like the design. It was also nice to have tests that worked right off the bat.
Anyway, better wrap up for now.