{"action":"created","comment":{"url":"https://api.github.com/repos/conda/conda-docs/pulls/comments/123612622","pull_request_review_id":45835141,"id":123612622,"diff_hunk":"@@ -0,0 +1,1230 @@\n+Build Variants\n+==============\n+\n+\n+The nature of binary compatibility (or lack thereof) means that unfortunately,\n+we need to build binary packages (and any package containing binaries) with\n+potentially several variants to support different usage environments. For\n+example, using Numpy's C API means that a package must be used with the same\n+version of Numpy at runtime that was used at build time.\n+\n+There has been limited support for this for a long time: Python in both build\n+and run requirements resulted in a package that had python pinned to the version\n+of Python used at build time (with a corresponding addition to the filename like\n+py27). Similar support existed for numpy with the addition of an ``x.x`` pin in\n+the recipe after `Conda-build PR\n+573 <https://github.com/conda/conda-build/pull/573>`_ was merged. However, there\n+has not been general support until conda-build version 3.0, though there have\n+been many proposals (`Conda-build issue\n+1142 <https://github.com/conda/conda-build/issues/1142>`_).\n+\n+As of conda-build 3.0, a new configuration scheme has been added, dubbed\n+\"variants.\" Conceptually, this decouples pinning values from recipes, replacing\n+them with Jinja2 template variables. It adds support for the notion of\n+\"compatible\" pinnings, though that concept is currently still under heavy\n+development, to be integrated with ABI compatibility databases, such as `ABI\n+Laboratory <https://abi-laboratory.pro/>`_.\n+\n+Variant input is ultimately a dictionary. They're mostly very flat. Keys are\n+made directly available in Jinja2 templates. As a result, keys in the dictionary\n+(and in files read into dictionaries) must be valid jinja2 variable names (no ``-``\n+characters allowed). This example builds python 2.7 and 3.5 packages in one\n+build command:\n+\n+conda_build_config.yaml like:\n+\n+.. code-block:: yaml\n+\n+   python:\n+       - 2.7\n+       - 3.5\n+\n+\n+meta.yaml contents like:\n+\n+.. code-block:: yaml\n+\n+   package:\n+       name: compiled-code\n+       version: 1.0\n+\n+   requirements:\n+       build:\n+           - python {{ python }}\n+       run:\n+           - python\n+\n+\n+The command to build recipes is unchanged relative to earlier conda-build\n+versions. For example, with our shell in the same folder as meta.yaml and\n+conda_build_config.yaml, we just call the ``conda build .`` command.\n+\n+\n+General pinning examples\n+------------------------\n+\n+There are a few characteristic use cases for pinning.  Please consider this a map for the content below.\n+\n+1. Shared library providing a binary interface. All uses of this library use the\n+   binary interface.  It is convenient to apply the same pin to all of your builds.\n+   Example: boost\n+\n+\n+conda_build_config.yaml in your HOME folder:\n+\n+.. code-block:: yaml\n+\n+  boost:\n+    - 1.61\n+    - 1.63\n+  pin_run_as_build:\n+    boost: x.x\n+\n+\n+meta.yaml:\n+\n+.. code-block:: yaml\n+\n+   package:\n+       name: compiled-code\n+       version: 1.0\n+\n+   requirements:\n+       build:\n+           - boost  {{ boost }}\n+       run:\n+           - boost\n+\n+This example demonstrates several features:\n+  * user-wide configuration with a specifically named config file\n+    (conda_build_config.yaml in your home folder). More options below in\n+    `Creating conda-build variant config files`_.\n+  * building against multiple versions of a single library (set versions\n+    installed at build time)\n+  * pinning runtime requirements to the version used at build time. More\n+    information below at `Pinning at the variant level`_.\n+  * specify granularity of pinning. ``x.x`` pins major and minor version. More\n+    information at `Pinning expressions`_.\n+\n+\n+2. Python package with externally accessible binary component. Not all uses of\n+   this library use the binary interface (some only use pure python). Example:\n+   numpy\n+\n+conda_build_config.yaml in your recipe folder (alongside meta.yaml:\n+\n+.. code-block:: yaml\n+\n+  numpy:\n+    - 1.11\n+    - 1.12\n+\n+\n+meta.yaml:\n+\n+.. code-block:: yaml\n+\n+   package:\n+       name: numpy_using_pythonAPI_thing\n+       version: 1.0\n+\n+   requirements:\n+       build:\n+           - python\n+           - numpy\n+       run:\n+           - python\n+           - numpy\n+\n+This example demonstrates a particular feature: reduction of builds when pins\n+are unnecessary. Since the example recipe above only requires the Python API to\n+numpy, we will only build the package once and the version of numpy will not be pinned\n+at runtime to match the compile-time version.  There's more information at `Avoiding unnecessary builds`_.\n+\n+For a different package that makes use of the numpy C API, we will need to\n+actually pin numpy in this recipe (and only in this recipe, so that other\n+recipes don't unnecessarily build lots of variants).  To pin numpy, you can\n+use the variant key directly in meta.yaml:\n+\n+.. code-block:: yaml\n+\n+   package:\n+       name: numpy_using_cAPI_thing\n+       version: 1.0\n+\n+   requirements:\n+       build:\n+           - numpy  {{ numpy }}\n+       run:\n+           - numpy  {{ numpy }}\n+\n+For legacy compatibility, python is pinned implicitly without specifying {{ python }}\n+in your recipe. This is generally intractable to extend to all package\n+names, so in general, try to get in the habit of always using the jinja2\n+variable substitution for pinning using versions from your\n+conda_build_config.yaml file.\n+\n+There are also more flexible ways to pin, using the `Pinning expressions`_. See\n+`Pinning at the recipe level`_ for examples.\n+\n+\n+3. One recipe splits into multiple packages, and package dependencies need to be\n+   dynamically pinned among one another. Example:\n+   GCC/libgcc/libstdc++/gfortran/etc.\n+\n+The dynamic pinning is the tricky part.  Conda-build provides new ways to refer to other subpackages within a single recipe.\n+\n+.. code-block:: yaml\n+\n+   package:\n+       name: dynamic_supackage\n+       version: 1.0\n+\n+   requirements:\n+       run:\n+           - {{ pin_subpackage('my_awesome_subpackage') }}\n+\n+   outputs:\n+     - name: my_awesome_subpackage\n+       version: 2.0\n+\n+by referring to subpackages this way, you don't need to worry about what the end\n+version of my_awesome_subpackage will be. Update it independently and just let\n+conda build figure it out and keep things consistent. There's more information\n+below in the `Referencing subpackages`_ section below.\n+\n+\n+Transition guide\n+----------------\n+\n+Let's say we have a set of recipes that currently builds a C library, as well as\n+python and R bindings to that C library. xgboost, a recent machine learning\n+library, is one such example. Under conda-build 2.0 and earlier, you needed to\n+have three recipes - one for each component. Let's go over some simplified\n+meta.yaml files.  First, the C library:\n+\n+.. code-block:: yaml\n+\n+   package:\n+       name: libxgboost\n+       version: 1.0\n+\n+\n+Next, the python bindings:\n+\n+\n+.. code-block:: yaml\n+\n+   package:\n+       name: py-xgboost\n+       version: 1.0\n+\n+   requirements:\n+       build:\n+           - libxgboost  # you probably want to pin the version here, but there's no dynamic way to do it\n+           - python\n+       run:\n+           - libxgboost  # you probably want to pin the version here, but there's no dynamic way to do it\n+           - python\n+\n+\n+.. code-block:: yaml\n+\n+   package:\n+       name: r-xgboost\n+       version: 1.0\n+\n+   requirements:\n+       build:\n+           - libxgboost  # you probably want to pin the version here, but there's no dynamic way to do it\n+           - r-base\n+       run:\n+           - libxgboost  # you probably want to pin the version here, but there's no dynamic way to do it\n+           - r-base\n+\n+To build these, you'd need several conda-build commands, or a tool like\n+conda-build-all to build out the various python versions. With conda-build 3.0\n+and split packages from conda-build 2.1, we can simplify this to one coherent\n+recipe that also includes the matrix of all desired python and R builds.\n+\n+First, the meta.yaml file:\n+\n+.. code-block:: yaml\n+\n+   package:\n+       name: xgboost\n+       version: 1.0\n+\n+   outputs:\n+       - name: libxgboost\n+       - name: py-xgboost\n+         requirements:\n+             - {{ pin_subpackage('libxgboost', exact=True) }}\n+             - python  {{ python }}\n+\n+       - name: r-xgboost\n+         requirements:\n+             - {{ pin_subpackage('libxgboost', exact=True)\n+             - r-base  {{ r_base }}\n+\n+\n+next, the conda_build_config.yaml file, specifying our build matrix:\n+\n+.. code-block:: yaml\n+\n+    python:\n+        - 2.7\n+        - 3.5\n+        - 3.6\n+    r_base:\n+        - 3.3.2\n+        - 3.4.0\n+\n+\n+With this updated method, you get a complete build matrix: 6 builds total. One\n+libxgboost library, 3 python versions, and 2 R versions. Additionally, the\n+python and R packages will have exact pins to the libxgboost package that was\n+built by this recipe.\n+\n+\n+Creating conda-build variant config files\n+-----------------------------------------\n+\n+\n+Variant input files are yaml files.  Search order for these files is the following:\n+\n+1. a file named ``conda_build_config.yaml`` in the user's HOME folder\n+2. an arbitrarily named file specified as the value for the\n+   ``conda_build_config`` key in your .condarc file\n+3. a file named ``conda_build_config.yaml`` in the same folder as ``meta.yaml``\n+   with your recipe\n+4. Any additional files specified on the command line with the\n+   ``--variant-config-files`` or ``-m`` command line flags, which can be passed\n+   multiple times for multiple files. The ``conda build`` and ``conda render``\n+   commands accept these arguments.\n+\n+Files found later in this search order clobber the values from earlier files.\n+\n+\n+Using variants with the conda-build API\n+---------------------------------------\n+\n+\n+Ultimately, a variant is just a dictionary. This dictionary is provided directly\n+to Jinja2 - you can use any declared key from your variant configuration in your\n+Jinja2 templates. There are two ways that you can feed this information into the\n+API:\n+\n+1. pass the ``variants`` keyword argument to API functions. Currently, the\n+   ``build``, ``render``, ``get_output_file_path``, and ``check`` functions\n+   accept this argument. ``variants`` should be a dictionary with values being\n+   lists of versions to iterate over. These are aggregated as detailed in the\n+   Aggregation of multiple variants section below.\n+\n+2. Set the ``variant`` member of a Config object. This is just a dictionary. The\n+   values for fields should be strings or lists of strings, except \"extended\n+   keys\", which are documented in the `Extended keys`_ section below.\n+\n+\n+Again, with meta.yaml contents like:\n+\n+.. code-block:: yaml\n+\n+   package:\n+       name: compiled-code\n+       version: 1.0\n+\n+   requirements:\n+       build:\n+           - python {{ python }}\n+       run:\n+           - python {{ python }}\n+\n+You could supply a variant to build this recipe like so:\n+\n+.. code-block:: python\n+\n+   variants = {'python': ['2.7', '3.5']}\n+   api.build(path_to_recipe, variants=variants)\n+\n+\n+Note that these Jinja2 variable substitutions are not limited to version\n+numbers. You can use them anywhere, for any string value. For example, to build\n+against different MPI implementations:\n+\n+With meta.yaml contents like:\n+\n+.. code-block:: yaml\n+\n+   package:\n+       name: compiled-code\n+       version: 1.0\n+\n+   requirements:\n+       build:\n+           - {{ mpi }}\n+       run:\n+           - {{ mpi }}\n+\n+\n+You could supply a variant to build this recipe like this (conda_build_config.yaml):\n+\n+\n+.. code-block:: yaml\n+\n+    mpi:\n+        - openmpi  # version spec here is totally valid, and will apply in the recipe\n+        - mpich  # version spec here is totally valid, and will apply in the recipe\n+\n+\n+Selectors are not currently valid in conda_build_config.yaml, but we plan on\n+adding them soon.\n+\n+\n+About reproducibility\n+---------------------\n+\n+A critical part of any build system is ensuring that you can reproduce the same\n+output at some future point in time. This is often essential for troubleshooting\n+bugs. For example, if a package contains only binaries, it is helpful to\n+understand what source code created those binaries, and thus what bugs might be\n+present.\n+\n+Since conda-build 2.0, conda-build has recorded its rendered meta.yaml files\n+into the ``info/recipe`` folder of each package it builds. Conda-build 3.0 is no\n+different in this regard, but the meta.yaml that is recorded is a frozen set of\n+the variables that make up the variant for that build.\n+\n+Note that package builders may disable including the recipe with the\n+``build/include_recipe`` key in meta.yaml. If the recipe is omitted from the\n+package, then the package is not reproducible without the source recipe.\n+\n+\n+Special variant keys\n+--------------------\n+\n+There are some special keys that behave differently and can be more nested:\n+\n+* ``zip_keys``: a list of strings or a list of lists of strings. Strings are\n+  keys in variant. These couple groups of keys, so that particular keys are\n+  paired, rather than forming a matrix. This is useful, for example, to couple\n+  vc version to python version on Windows. More info below in the `Coupling\n+  keys`_ section.\n+* ``pin_run_as_build``: should be a dictionary. Keys are package names. Values\n+  are \"pinning expressions\" - explained in more detail in `Customizing\n+  compatibility`_. This is a generalization of the ``numpy x.x`` spec, so that\n+  you can pin your packages dynamically based on the versions used at build\n+  time.\n+* ``extend_keys``: specifies keys that should be aggregated, rather than\n+  clobbered, by later variants. These are detailed below in the `Extended keys`_\n+  section.\n+* ``ignore_version``: list of package names whose versions should be excluded\n+  from meta.yaml's requirements/build when computing hash. Described further in\n+  `Avoiding unnecessary builds`_.\n+\n+\n+Coupling keys\n+-------------\n+\n+Sometimes particular versions need to be tied to other versions. For example, on\n+Windows, we generally follow the upstream Python.org association of Visual\n+Studio compiler version with Python version. Python 2.7 is always compiled with\n+Visual Studio 2008 (a.k.a. MSVC 9). We don't want a conda_build_config.yaml like\n+the following to create a matrix of python/MSVC versions:\n+\n+\n+.. code-block:: yaml\n+\n+   python:\n+     - 2.7\n+     - 3.5\n+   vc:\n+     - 9\n+     - 14\n+\n+\n+Instead, we want 2.7 to be associated with 9, and 3.5 to be associated with 14.\n+The ``zip_keys`` key in conda_build_config.yaml is the way to achieve this:\n+\n+\n+.. code-block:: yaml\n+\n+   python:\n+     - 2.7\n+     - 3.5\n+   vc:\n+     - 9\n+     - 14\n+   zip_keys:\n+     - python\n+     - vc\n+\n+\n+You can also have nested lists to achieve multiple groups of ``zip_keys``:\n+\n+\n+.. code-block:: yaml\n+\n+   zip_keys:\n+     -\n+       - python\n+       - vc\n+     -\n+       - numpy\n+       - blas\n+\n+\n+The rules for ``zip_keys`` are:\n+\n+  1. Every list in a group must be the same length. This is because without\n+     similar length, there is no way to associate earlier elements from the\n+     shorter list with later elements in the longer list. For example, this is\n+     invalid, and will raise an error:\n+\n+.. code-block:: yaml\n+\n+   python:\n+     - 2.7\n+     - 3.5\n+   vc:\n+     - 9\n+   zip_keys:\n+     - python\n+     - vc\n+\n+\n+  2. ``zip_keys`` must be either a list of strings, or a list of lists of\n+     strings. You can't mix them.  For example, this is an error:\n+\n+\n+.. code-block:: yaml\n+\n+   zip_keys:\n+     -\n+       - python\n+       - vc\n+     - numpy\n+     - blas\n+\n+\n+Rule #1 presents an interesting use case: how does one combine CLI flags\n+like --python with ``zip_keys``? Such a CLI flag will change the variant so that\n+it has only a single entry, but it will not change the ``vc`` entry in the\n+variant configuration. We'll end up with mismatched list lengths, and an error.\n+Sad day. To overcome this, you should instead write a very simple YAML file with\n+all involved keys. Let's call it ``python27.yaml``, to reflect its intent:\n+\n+.. code-block:: yaml\n+\n+   python:\n+     - 2.7\n+   vc:\n+     - 9\n+\n+\n+and provide this file as a command-line argument:\n+\n+\n+.. code-block:: shell\n+\n+    conda build recipe -m python27.yaml\n+\n+\n+You can also specify variants in JSON notation from the CLI as detailed in the\n+ :ref:`CLI_vars` section. For example:\n+\n+\n+.. code-block:: shell\n+\n+    conda build recipe --variants \"{'python': ['2.7', '3.5'], 'vc': ['9', '14']}\"\n+\n+\n+Avoiding unnecessary builds\n+---------------------------\n+\n+\n+To avoid building variants of packages where pinning does not necessitate having\n+different builds, you can use the ``ignore_version`` key in your\n+variant. The way this works is that all variants are evaluated, but if any\n+hashes are the same, then they are considered duplicates, and are deduplicated.\n+By omitting some packages from the build dependencies, we can avoid creating\n+unnecessarily specific hashes, and allow this deduplication.\n+\n+For example, let's consider a package that uses numpy in both run and build\n+requirements, and a variant that includes two numpy versions:\n+\n+\n+.. code-block:: python\n+\n+    variants = [{'numpy': ['1.10', '1.11'], 'ignore_version': ['numpy']}]\n+\n+meta.yaml:\n+\n+.. code-block:: yaml\n+\n+   requirements:\n+       build:\n+           - numpy {{ numpy }}\n+       run:\n+           - numpy\n+\n+\n+Here, the variant says that we'll have two builds - one for each numpy version.\n+However, since this recipe does not pin numpy's run requirement (because it\n+doesn't utilize numpy's C API), it is unnecessary to build it against both numpy\n+1.10 and 1.11.\n+\n+The rendered form of this recipe, with conda-build ignoring numpy's value in the\n+recipe, is going to be just one build, that looks like:\n+\n+meta.yaml:\n+\n+.. code-block:: yaml\n+\n+   requirements:\n+       build:\n+           - numpy\n+       run:\n+           - numpy\n+\n+\n+``ignore_version`` is an empty list by default. The actual build performed is\n+probably done with the last 'numpy' list element in the variant, but that's more\n+of an implementation detail that you should not depend on. The order is\n+considered unspecified behavior, because the output should be independent of the\n+input versions. If the output is not independent of input versions, don't use\n+this key!\n+\n+Any pinning done in the run requirements will affect the hash, and thus builds\n+will be done for each variant in the matrix. Any package that sometimes is used\n+for its compiled interface and sometimes used for only its python interface may\n+benefit from careful use of ``ignore_version`` in the latter case.\n+\n+Note: ``pin_run_as_build`` is kind of the opposite of ``ignore_version``. Where\n+they conflict, ``pin_run_as_build`` takes priority.\n+\n+\n+.. _CLI_vars:\n+\n+CONDA_* variables and command line arguments to conda-build\n+-----------------------------------------------------------\n+\n+To ensure consistency with existing users of conda-build, environment variables\n+such as CONDA_PY behave as they always have, and they clobber all variants set\n+in files or passed to the API.\n+\n+The full list of respected environment variables are:\n+\n+* CONDA_PY\n+* CONDA_NPY\n+* CONDA_R\n+* CONDA_PERL\n+* CONDA_LUA\n+\n+CLI flags are also still available. These are sticking around for their\n+usefulness in one-off jobs.\n+\n+* --python\n+* --numpy\n+* --R\n+* --perl\n+* --lua\n+\n+In addition to these traditional options, there's one new flag to specify\n+variants: ``--variants``. This flag accepts a string of JSON-formatted text. For\n+example:\n+\n+\n+.. code-block:: shell\n+\n+    conda build recipe --variants \"{python: [2.7, 3.5], vc: [9, 14]}\"\n+\n+\n+Aggregation of multiple variants\n+--------------------------------\n+\n+The matrix of all variants is first consolidated from several dicts of lists\n+into a single dict of lists, and then transformed in a list of dicts (via the\n+Cartesian product of lists), where each value is a single string from the list\n+of potential values.\n+\n+For example, general input for ``variants`` could be something like:\n+\n+.. code-block:: python\n+\n+    a = {'python': ['2.7', '3.5'], 'numpy': ['1.10', '1.11']}\n+    # values can be strings or lists.  Strings are converted to one-element lists internally.\n+    b = {'python': ['3.4', '3.5'], 'numpy': '1.11'}\n+\n+\n+Here, let's say ``b`` is found after ``a``, and thus has priority over ``a``. Merging these\n+two variants yields:\n+\n+.. code-block:: python\n+\n+    merged = {'python': ['3.4', '3.5'], 'numpy': ['1.11']}\n+\n+\n+``b``'s values for ``python`` have clobbered ``a``'s. From here, we compute the\n+Cartesian product of all input variables. The end result is a collection of\n+dicts, each with a string for each value. Output would be something like:\n+\n+.. code-block:: python\n+\n+    variants = [{'python': '3.4', 'numpy': '1.11'}, {'python': '3.5', 'numpy': '1.11'}]\n+\n+\n+and conda-build would loop over these variants where appropriate (building,\n+outputting package output names, etc.)\n+\n+If ``numpy`` had had two values instead of one, we'd end up with *four* output\n+variants: 2 variants for ``python``, *times* two variants for ``numpy``:\n+\n+.. code-block:: python\n+\n+    variants = [{'python': '3.4', 'numpy': '1.11'}, {'python': '3.5', 'numpy': '1.11'},\n+                {'python': '3.4', 'numpy': '1.10'}, {'python': '3.5', 'numpy': '1.10'}]\n+\n+\n+Bootstrapping pins based on an existing environment\n+---------------------------------------------------\n+\n+\n+To establish your initial variant, you may point at an existing conda\n+environment. Conda-build will examine the contents of that environment and pin\n+to the exact requirements that make up that environment.\n+\n+.. code-block:: shell\n+\n+   conda build --bootstrap name_of_env\n+\n+\n+You may specify either environment name (and depend on conda's environment\n+lookup) or filesystem path to the environment.\n+\n+\n+Extended keys\n+-------------\n+\n+\n+These are not looped over to establish the build matrix. Rather, they are\n+aggregated from all input variants, and each derived variant shares the whole\n+set. These are used internally for tracking which requirements should be pinned,\n+for example, with the ``pin_run_as_build`` key. You can add your own extended\n+keys by passing in values for the ``extend_keys`` key for any variant.\n+\n+For example, if you wanted to collect some aggregate trait from multiple\n+conda_build_config.yaml files, you could do something like this:\n+\n+HOME/conda_build_config.yaml:\n+\n+.. code-block:: yaml\n+\n+   some_trait:\n+     - dog\n+   extend_keys:\n+     - some_trait\n+\n+\n+recipe/conda_build_config.yaml:\n+\n+.. code-block:: yaml\n+\n+   some_trait:\n+     - pony\n+   extend_keys:\n+     - some_trait\n+\n+Note that *both* of the conda_build_config.yaml files need to list the trait as\n+an ``extend_keys`` entry.  If you list it in only one of them, an error will be\n+raised, to avoid confusion with one conda_build_config.yaml file that would add\n+entries to the build matrix, and another which would not. For example, this\n+should raise an error:\n+\n+.. code-block:: yaml\n+\n+   some_trait:\n+     - dog\n+\n+\n+recipe/conda_build_config.yaml:\n+\n+.. code-block:: yaml\n+\n+   some_trait:\n+     - pony\n+   extend_keys:\n+     - some_trait\n+\n+\n+When our two proper yaml config files are combined, ordinarily the recipe-local\n+variant would clobber the user-wide variant, yielding ``{'some_trait':\n+'pony'}``. However, with the extend_keys entry, we end up with what we've always\n+wanted: a dog *and* pony show: ``{'some_trait': ['dog', 'pony'])}``\n+\n+Again, mostly an internal implementation detail - unless you find a use for it.\n+Internally, it is used to aggregate the ``pin_run_as_build`` and\n+``ignore_version`` entries from any of your conda_build_config.yaml\n+files.\n+\n+\n+Customizing compatibility\n+-------------------------\n+\n+.. _pinning_expressions:\n+\n+Pinning expressions\n+~~~~~~~~~~~~~~~~~~~\n+\n+\n+Pinning expressions are the syntax used to specify how many parts of the version\n+to pin. They are by convention strings containing ``x`` characters separated by\n+``.``. The number of version parts to pin is simply the number of things that\n+are separated by ``.``. For example, ``\"x.x\"`` pins major and minor version.\n+``\"x\"`` pins only major version.\n+\n+Wherever pinning expressions are accepted, you can customize both lower and\n+upper bounds.\n+\n+\n+.. code-block:: python\n+\n+    # produces pins like >=1.11.2,<1.12\n+    variants = [{'numpy': '1.11', 'pin_run_as_build': {'numpy': {'max_pin': 'x.x'}}}]\n+\n+\n+.. code-block:: python\n+\n+    # produces pins like >=1.11,<2\n+    variants = [{'numpy': '1.11', 'pin_run_as_build': {'numpy': {'min_pin': 'x.x', 'max_pin': 'x'}}}]\n+\n+\n+Pinning at the variant level\n+~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n+\n+Some packages, such as boost, *always* need to be pinned at runtime to the\n+version that was present at build time. For these cases where the need for\n+pinning is consistent, pinning at the variant level is a good option.\n+Conda-build will automatically pin run requirements to the versions present in\n+the build environment when the follow conditions are met:\n+\n+1. The dependency is listed in the requirements/build section. It can be pinned,\n+   but does not need to be.\n+2. The dependency is listed by name (no pinning) in the requirements/run section\n+3. The ``pin_run_as_build`` key in the variant has a value that is a dictionary,\n+   containing a key that matches the dependency name listed in the run\n+   requirements. The value should be a dictionary with up to 4 keys:\n+   ``min_pin``, ``max_pin``, ``lower_bound``, ``upper_bound``. The first two are\n+   pinning expressions. The latter two are version numbers, overriding detection\n+   of current version. (defaulting to None).","path":"docs/source/building/variants.rst","position":819,"original_position":819,"commit_id":"2fea343ea5ad50ede762bfa3ed583f93e5ebf53e","original_commit_id":"2fea343ea5ad50ede762bfa3ed583f93e5ebf53e","user":{"login":"electronwill","id":12059307,"avatar_url":"https://avatars0.githubusercontent.com/u/12059307?v=3","gravatar_id":"","url":"https://api.github.com/users/electronwill","html_url":"https://github.com/electronwill","followers_url":"https://api.github.com/users/electronwill/followers","following_url":"https://api.github.com/users/electronwill/following{/other_user}","gists_url":"https://api.github.com/users/electronwill/gists{/gist_id}","starred_url":"https://api.github.com/users/electronwill/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/electronwill/subscriptions","organizations_url":"https://api.github.com/users/electronwill/orgs","repos_url":"https://api.github.com/users/electronwill/repos","events_url":"https://api.github.com/users/electronwill/events{/privacy}","received_events_url":"https://api.github.com/users/electronwill/received_events","type":"User","site_admin":false},"body":"@msarahan what defaults to None? All four keys, the latter two, or the dictionary that contains the four keys?","created_at":"2017-06-22T20:22:11Z","updated_at":"2017-06-22T20:22:11Z","html_url":"https://github.com/conda/conda-docs/pull/414#discussion_r123612622","pull_request_url":"https://api.github.com/repos/conda/conda-docs/pulls/414","_links":{"self":{"href":"https://api.github.com/repos/conda/conda-docs/pulls/comments/123612622"},"html":{"href":"https://github.com/conda/conda-docs/pull/414#discussion_r123612622"},"pull_request":{"href":"https://api.github.com/repos/conda/conda-docs/pulls/414"}}},"pull_request":{"url":"https://api.github.com/repos/conda/conda-docs/pulls/414","id":103632036,"html_url":"https://github.com/conda/conda-docs/pull/414","diff_url":"https://github.com/conda/conda-docs/pull/414.diff","patch_url":"https://github.com/conda/conda-docs/pull/414.patch","issue_url":"https://api.github.com/repos/conda/conda-docs/issues/414","number":414,"state":"open","locked":false,"title":"first draft of conda-build variants docs","user":{"login":"msarahan","id":38393,"avatar_url":"https://avatars0.githubusercontent.com/u/38393?v=3","gravatar_id":"","url":"https://api.github.com/users/msarahan","html_url":"https://github.com/msarahan","followers_url":"https://api.github.com/users/msarahan/followers","following_url":"https://api.github.com/users/msarahan/following{/other_user}","gists_url":"https://api.github.com/users/msarahan/gists{/gist_id}","starred_url":"https://api.github.com/users/msarahan/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/msarahan/subscriptions","organizations_url":"https://api.github.com/users/msarahan/orgs","repos_url":"https://api.github.com/users/msarahan/repos","events_url":"https://api.github.com/users/msarahan/events{/privacy}","received_events_url":"https://api.github.com/users/msarahan/received_events","type":"User","site_admin":false},"body":"Proposed docs for https://github.com/conda/conda-build/pull/1585\r\n\r\n@cio-docs please ignore for now, but would appreciate copy editing soon, after this functionality has undergone more review and testing.","created_at":"2017-01-29T01:49:33Z","updated_at":"2017-06-22T20:22:11Z","closed_at":null,"merged_at":null,"merge_commit_sha":"f6811385dd1cea3d04ee90756c0458db1de3336b","assignee":null,"assignees":[],"requested_reviewers":[],"milestone":null,"commits_url":"https://api.github.com/repos/conda/conda-docs/pulls/414/commits","review_comments_url":"https://api.github.com/repos/conda/conda-docs/pulls/414/comments","review_comment_url":"https://api.github.com/repos/conda/conda-docs/pulls/comments{/number}","comments_url":"https://api.github.com/repos/conda/conda-docs/issues/414/comments","statuses_url":"https://api.github.com/repos/conda/conda-docs/statuses/2fea343ea5ad50ede762bfa3ed583f93e5ebf53e","head":{"label":"msarahan:document_conda_build_variants","ref":"document_conda_build_variants","sha":"2fea343ea5ad50ede762bfa3ed583f93e5ebf53e","user":{"login":"msarahan","id":38393,"avatar_url":"https://avatars0.githubusercontent.com/u/38393?v=3","gravatar_id":"","url":"https://api.github.com/users/msarahan","html_url":"https://github.com/msarahan","followers_url":"https://api.github.com/users/msarahan/followers","following_url":"https://api.github.com/users/msarahan/following{/other_user}","gists_url":"https://api.github.com/users/msarahan/gists{/gist_id}","starred_url":"https://api.github.com/users/msarahan/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/msarahan/subscriptions","organizations_url":"https://api.github.com/users/msarahan/orgs","repos_url":"https://api.github.com/users/msarahan/repos","events_url":"https://api.github.com/users/msarahan/events{/privacy}","received_events_url":"https://api.github.com/users/msarahan/received_events","type":"User","site_admin":false},"repo":{"id":58245278,"name":"conda-docs","full_name":"msarahan/conda-docs","owner":{"login":"msarahan","id":38393,"avatar_url":"https://avatars0.githubusercontent.com/u/38393?v=3","gravatar_id":"","url":"https://api.github.com/users/msarahan","html_url":"https://github.com/msarahan","followers_url":"https://api.github.com/users/msarahan/followers","following_url":"https://api.github.com/users/msarahan/following{/other_user}","gists_url":"https://api.github.com/users/msarahan/gists{/gist_id}","starred_url":"https://api.github.com/users/msarahan/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/msarahan/subscriptions","organizations_url":"https://api.github.com/users/msarahan/orgs","repos_url":"https://api.github.com/users/msarahan/repos","events_url":"https://api.github.com/users/msarahan/events{/privacy}","received_events_url":"https://api.github.com/users/msarahan/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/msarahan/conda-docs","description":"Conda documentation","fork":true,"url":"https://api.github.com/repos/msarahan/conda-docs","forks_url":"https://api.github.com/repos/msarahan/conda-docs/forks","keys_url":"https://api.github.com/repos/msarahan/conda-docs/keys{/key_id}","collaborators_url":"https://api.github.com/repos/msarahan/conda-docs/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/msarahan/conda-docs/teams","hooks_url":"https://api.github.com/repos/msarahan/conda-docs/hooks","issue_events_url":"https://api.github.com/repos/msarahan/conda-docs/issues/events{/number}","events_url":"https://api.github.com/repos/msarahan/conda-docs/events","assignees_url":"https://api.github.com/repos/msarahan/conda-docs/assignees{/user}","branches_url":"https://api.github.com/repos/msarahan/conda-docs/branches{/branch}","tags_url":"https://api.github.com/repos/msarahan/conda-docs/tags","blobs_url":"https://api.github.com/repos/msarahan/conda-docs/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/msarahan/conda-docs/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/msarahan/conda-docs/git/refs{/sha}","trees_url":"https://api.github.com/repos/msarahan/conda-docs/git/trees{/sha}","statuses_url":"https://api.github.com/repos/msarahan/conda-docs/statuses/{sha}","languages_url":"https://api.github.com/repos/msarahan/conda-docs/languages","stargazers_url":"https://api.github.com/repos/msarahan/conda-docs/stargazers","contributors_url":"https://api.github.com/repos/msarahan/conda-docs/contributors","subscribers_url":"https://api.github.com/repos/msarahan/conda-docs/subscribers","subscription_url":"https://api.github.com/repos/msarahan/conda-docs/subscription","commits_url":"https://api.github.com/repos/msarahan/conda-docs/commits{/sha}","git_commits_url":"https://api.github.com/repos/msarahan/conda-docs/git/commits{/sha}","comments_url":"https://api.github.com/repos/msarahan/conda-docs/comments{/number}","issue_comment_url":"https://api.github.com/repos/msarahan/conda-docs/issues/comments{/number}","contents_url":"https://api.github.com/repos/msarahan/conda-docs/contents/{+path}","compare_url":"https://api.github.com/repos/msarahan/conda-docs/compare/{base}...{head}","merges_url":"https://api.github.com/repos/msarahan/conda-docs/merges","archive_url":"https://api.github.com/repos/msarahan/conda-docs/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/msarahan/conda-docs/downloads","issues_url":"https://api.github.com/repos/msarahan/conda-docs/issues{/number}","pulls_url":"https://api.github.com/repos/msarahan/conda-docs/pulls{/number}","milestones_url":"https://api.github.com/repos/msarahan/conda-docs/milestones{/number}","notifications_url":"https://api.github.com/repos/msarahan/conda-docs/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/msarahan/conda-docs/labels{/name}","releases_url":"https://api.github.com/repos/msarahan/conda-docs/releases{/id}","deployments_url":"https://api.github.com/repos/msarahan/conda-docs/deployments","created_at":"2016-05-07T02:23:46Z","updated_at":"2016-05-07T02:23:50Z","pushed_at":"2017-06-22T18:55:02Z","git_url":"git://github.com/msarahan/conda-docs.git","ssh_url":"git@github.com:msarahan/conda-docs.git","clone_url":"https://github.com/msarahan/conda-docs.git","svn_url":"https://github.com/msarahan/conda-docs","homepage":null,"size":17766,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"conda:master","ref":"master","sha":"dea713626c8f6b3da05ebd2ad9c0163b058f21ac","user":{"login":"conda","id":6392739,"avatar_url":"https://avatars3.githubusercontent.com/u/6392739?v=3","gravatar_id":"","url":"https://api.github.com/users/conda","html_url":"https://github.com/conda","followers_url":"https://api.github.com/users/conda/followers","following_url":"https://api.github.com/users/conda/following{/other_user}","gists_url":"https://api.github.com/users/conda/gists{/gist_id}","starred_url":"https://api.github.com/users/conda/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/conda/subscriptions","organizations_url":"https://api.github.com/users/conda/orgs","repos_url":"https://api.github.com/users/conda/repos","events_url":"https://api.github.com/users/conda/events{/privacy}","received_events_url":"https://api.github.com/users/conda/received_events","type":"Organization","site_admin":false},"repo":{"id":16152807,"name":"conda-docs","full_name":"conda/conda-docs","owner":{"login":"conda","id":6392739,"avatar_url":"https://avatars3.githubusercontent.com/u/6392739?v=3","gravatar_id":"","url":"https://api.github.com/users/conda","html_url":"https://github.com/conda","followers_url":"https://api.github.com/users/conda/followers","following_url":"https://api.github.com/users/conda/following{/other_user}","gists_url":"https://api.github.com/users/conda/gists{/gist_id}","starred_url":"https://api.github.com/users/conda/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/conda/subscriptions","organizations_url":"https://api.github.com/users/conda/orgs","repos_url":"https://api.github.com/users/conda/repos","events_url":"https://api.github.com/users/conda/events{/privacy}","received_events_url":"https://api.github.com/users/conda/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/conda/conda-docs","description":"Conda documentation","fork":false,"url":"https://api.github.com/repos/conda/conda-docs","forks_url":"https://api.github.com/repos/conda/conda-docs/forks","keys_url":"https://api.github.com/repos/conda/conda-docs/keys{/key_id}","collaborators_url":"https://api.github.com/repos/conda/conda-docs/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/conda/conda-docs/teams","hooks_url":"https://api.github.com/repos/conda/conda-docs/hooks","issue_events_url":"https://api.github.com/repos/conda/conda-docs/issues/events{/number}","events_url":"https://api.github.com/repos/conda/conda-docs/events","assignees_url":"https://api.github.com/repos/conda/conda-docs/assignees{/user}","branches_url":"https://api.github.com/repos/conda/conda-docs/branches{/branch}","tags_url":"https://api.github.com/repos/conda/conda-docs/tags","blobs_url":"https://api.github.com/repos/conda/conda-docs/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/conda/conda-docs/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/conda/conda-docs/git/refs{/sha}","trees_url":"https://api.github.com/repos/conda/conda-docs/git/trees{/sha}","statuses_url":"https://api.github.com/repos/conda/conda-docs/statuses/{sha}","languages_url":"https://api.github.com/repos/conda/conda-docs/languages","stargazers_url":"https://api.github.com/repos/conda/conda-docs/stargazers","contributors_url":"https://api.github.com/repos/conda/conda-docs/contributors","subscribers_url":"https://api.github.com/repos/conda/conda-docs/subscribers","subscription_url":"https://api.github.com/repos/conda/conda-docs/subscription","commits_url":"https://api.github.com/repos/conda/conda-docs/commits{/sha}","git_commits_url":"https://api.github.com/repos/conda/conda-docs/git/commits{/sha}","comments_url":"https://api.github.com/repos/conda/conda-docs/comments{/number}","issue_comment_url":"https://api.github.com/repos/conda/conda-docs/issues/comments{/number}","contents_url":"https://api.github.com/repos/conda/conda-docs/contents/{+path}","compare_url":"https://api.github.com/repos/conda/conda-docs/compare/{base}...{head}","merges_url":"https://api.github.com/repos/conda/conda-docs/merges","archive_url":"https://api.github.com/repos/conda/conda-docs/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/conda/conda-docs/downloads","issues_url":"https://api.github.com/repos/conda/conda-docs/issues{/number}","pulls_url":"https://api.github.com/repos/conda/conda-docs/pulls{/number}","milestones_url":"https://api.github.com/repos/conda/conda-docs/milestones{/number}","notifications_url":"https://api.github.com/repos/conda/conda-docs/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/conda/conda-docs/labels{/name}","releases_url":"https://api.github.com/repos/conda/conda-docs/releases{/id}","deployments_url":"https://api.github.com/repos/conda/conda-docs/deployments","created_at":"2014-01-22T21:13:55Z","updated_at":"2017-06-14T12:37:27Z","pushed_at":"2017-06-22T18:55:02Z","git_url":"git://github.com/conda/conda-docs.git","ssh_url":"git@github.com:conda/conda-docs.git","clone_url":"https://github.com/conda/conda-docs.git","svn_url":"https://github.com/conda/conda-docs","homepage":null,"size":21938,"stargazers_count":68,"watchers_count":68,"language":"Python","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":173,"mirror_url":null,"open_issues_count":49,"forks":173,"open_issues":49,"watchers":68,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/conda/conda-docs/pulls/414"},"html":{"href":"https://github.com/conda/conda-docs/pull/414"},"issue":{"href":"https://api.github.com/repos/conda/conda-docs/issues/414"},"comments":{"href":"https://api.github.com/repos/conda/conda-docs/issues/414/comments"},"review_comments":{"href":"https://api.github.com/repos/conda/conda-docs/pulls/414/comments"},"review_comment":{"href":"https://api.github.com/repos/conda/conda-docs/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/conda/conda-docs/pulls/414/commits"},"statuses":{"href":"https://api.github.com/repos/conda/conda-docs/statuses/2fea343ea5ad50ede762bfa3ed583f93e5ebf53e"}}}}
{"actor":{"display_login":"electronwill"}}