Coding 2022-04-17

By Max Woerner Chase

Okay, I'm trying something a bit different, where I had a short mastodon thread that I was writing as I worked on the code, and I'll start off this post with the end result, and talk about it some.

@_validators.RejectBecause
def _path_is_well_behaved(path: pathlib.Path) -> typing.Iterator[str]:
    if path.is_absolute():
        yield f"The following path is absolute: {path}"
    if any(part == os.path.pardir for part in path.parts):
        yield (
            f"The following path includes parent or current directory parts:"
            f" {path}"
        )


@attr.dataclass(frozen=True)
class PathWith(typing.Generic[T_co]):
    path: pathlib.Path = attr.field(validator=_path_is_well_behaved)
    val: T_co

So, first observation: this isn't much code. This might be from getting used to the different process, but there's also the fact that today was just kind of tiring, even if I did get some good relaxation in. I'm going to keep this up for now, and hope for better results next weekend. If that doesn't work out, I'll reconsider things.

So, that out of the way, the next question to ask is, what is most of this?

From the top:

Currently, the Installer protocol only has one implementation, which uses virtualenv and pip together. This class bundles together "what arguments get passed to pip" and "what arguments get passed to virtualenv", which turns out to be the wrong thing to do, at least for how I'm using the Installer protocol. The problem is, nothing in this system allows for multiple Python versions to be selected, which is a pretty major feature. My goal is to pull things out into a protocol for setting up the environment, and a protocol for installing stuff in the environment. (I've thought so much about trying to make this idea generic in the type of installer, but I've just confused myself, so I need a simplified prototype I can tweak.) These protocols would not be concerned with the question of "where is this done on the file system"? Instead, instance of each would be put in a PathWith[T_co], and helper functions would be written to process that concrete code, independent of how any of the protocol implementations would work; they would simply receive the calculated environment path.

So, when I pick this back up, I can write those protocols, then the helper functions to consume them, then implement the protocols, then sub the new protocols in, and chase type errors until mypy thinks it should all work. If I find myself messing with typed mappings, I will take that excuse to start using that helper class in earnest.

For now, though, I just want to publish this entry and cap off the thread.

Good night.