> ## Documentation Index
> Fetch the complete documentation index at: https://site.aspect.build/llms.txt
> Use this file to discover all available pages before exploring further.

# Python toolchains in rules_python

> Bazel is supposed to be repeatable, right? Your teammate runs the tests on her computer and should get the same result as you did. A build from a commit last mo

export const BlogPost = ({title, date, authors, tags, image, children}) => {
  const tagList = tags ? tags.split(", ").filter(Boolean) : [];
  const tagSlug = t => t.toLowerCase().replace(/&/g, "").replace(/\+/g, "").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
  const formattedDate = date ? new Date(date + "T00:00:00").toLocaleDateString("en-US", {
    year: "numeric",
    month: "long",
    day: "numeric"
  }) : "";
  return <section className="w-full flex justify-center px-4 py-12 md:py-16">
      <div style={{
    maxWidth: "800px",
    width: "100%"
  }}>
        {image && (typeof image === "string" ? <img noZoom src={image} alt={title} className="w-full rounded-xl mb-8" style={{
    maxHeight: "400px",
    objectFit: "cover"
  }} /> : <div className="blog-post-hero-image">{image}</div>)}
        <h1 className="text-3xl md:text-4xl font-bold text-zinc-900 dark:text-white">
          {title}
        </h1>
        <div className="flex flex-wrap items-center gap-3 mt-4 text-sm text-zinc-500 dark:text-zinc-400">
          {authors && <span>{authors}</span>}
          {authors && formattedDate && <span>·</span>}
          {formattedDate && <span>{formattedDate}</span>}
        </div>
        {tagList.length > 0 && <div className="flex flex-wrap gap-2 mt-3">
            {tagList.map(tag => <a key={tag} href={"/blog/tags/" + tagSlug(tag)} className="px-2 py-0.5 rounded-full text-xs bg-zinc-100 dark:bg-zinc-800 text-zinc-600 dark:text-zinc-400 hover:bg-blue-100 dark:hover:bg-blue-900/40 hover:text-blue-700 dark:hover:text-blue-300 transition">
                {tag}
              </a>)}
          </div>}
        <hr className="my-8 border-zinc-200 dark:border-zinc-700" />
        <div className="prose dark:prose-invert max-w-none">{children}</div>
      </div>
    </section>;
};

export const MarketingPage = () => <div className="marketing-page-marker" style={{
  display: "none"
}} />;

export const Section = ({children, className = "", gray = false, dark = false, id}) => <section id={id} className={`w-full flex justify-center px-4 py-16 md:py-24 ${gray ? "bg-gray-50 dark:bg-zinc-900" : dark ? "bg-zinc-900 dark:bg-zinc-950" : ""} ${className}`}>
    <div className="w-full" style={{
  maxWidth: "1140px"
}}>
      {children}
    </div>
  </section>;

<MarketingPage />

<BlogPost title="Python toolchains in rules_python" date="2022-03-11" authors="Thulio Ferraz Assis" tags="Python, Bazel">
  <img noZoom src="https://mintcdn.com/aspectbuild/x1L7Iep716jCyJVo/images/blog/hashnode/hn-2e33cf2afe.jpeg?fit=max&auto=format&n=x1L7Iep716jCyJVo&q=85&s=0562ad9f4fe4470a06be27feb022fbc0" alt="" className="blog-post-cover" width="1600" height="1200" data-path="images/blog/hashnode/hn-2e33cf2afe.jpeg" />

  Bazel is supposed to be repeatable, right? Your teammate runs the tests on her computer and should get the same result as you did. A build from a commit last month should be the same if you re-build it today. But in practice, this only works when we declare a hermetic build, where all the tools used are declared to Bazel using some pinned version. Bazel fetches these tools for us so that developers don't even have to think about whether they have the right version.

  This has not been the case for Python, where we've seen clients trip over having different python interpreter versions in different environments.

  Toolchains play a critical role in Bazel for achieving deterministic and hermetic builds. Today the team at Aspect has reached an important goal in rules\_python when we landed the support for toolchains in the latest [0.7.0 release](https://github.com/bazelbuild/rules_python/releases/tag/0.7.0).

  Here's how you start using it, based on the [upstream example](https://github.com/bazelbuild/rules_python/blob/0.7.0/examples/pip_parse/WORKSPACE):

  ```python theme={null}
  load(
      "@rules_python//python:repositories.bzl",
      "python_register_toolchains",
  )

  # Build steps will discover the right python via
  # Bazel's toolchain support
  python_register_toolchains(
      name = "python310",
      # Available versions are in
      # https://github.com/bazelbuild/rules_python/blob/0.7.0/python/versions.bzl#L39
      python_version = "3.10",
  )

  # However, repository rules run before toolchain resolution,
  # so we explicitly load the "resolved" interpreter
  # for the host platform...
  load("@python310_resolved_interpreter//:defs.bzl", "interpreter")

  load("@rules_python//python:pip.bzl", "pip_parse")

  pip_parse(
      ...
      # ...and pass that interpreter to be used when
      # dependencies are resolved.
      python_interpreter_target = interpreter,
      ...
  )
  ```

  Any build or test actions using `py_binary` or `py_test` will pick up the hermetic toolchain automatically via [https://bazel.build/docs/toolchains#toolchain-resolution](https://bazel.build/docs/toolchains#toolchain-resolution). However, repository rules like `pip_parse` run prior to that resolution, so we've used a trick here to load the resolved toolchain for the host platform, where the repository rules run.

  It relies on the fantastic work from [https://github.com/indygreg](https://github.com/indygreg) in [https://github.com/indygreg/python-build-standalone](https://github.com/indygreg/python-build-standalone). Consider sponsoring him on GitHub!

  We encourage everyone to try the feature out.

  A special thanks to [https://github.com/UebelAndre](https://github.com/UebelAndre) and [https://github.com/alexeagle](https://github.com/alexeagle) for helping out.
</BlogPost>
