Fix docstrings for core Spack libraries, fixes #1612

This commit is contained in:
Adam J. Stewart 2016-08-24 13:46:29 -05:00
parent 02239c094e
commit 69e50595bf
20 changed files with 199 additions and 195 deletions

View File

@ -476,14 +476,12 @@ def setup_package(pkg, dirty=False):
def fork(pkg, function, dirty=False):
"""Fork a child process to do part of a spack build.
Arguments:
:param pkg: pkg whose environemnt we should set up the forked process for.
:param function: arg-less function to run in the child process.
:param dirty: If True, do NOT clean the environment before building.
pkg -- pkg whose environemnt we should set up the
forked process for.
function -- arg-less function to run in the child process.
dirty -- If True, do NOT clean the environment before building.
Usage::
Usage:
def child_fun():
# do stuff
build_env.fork(pkg, child_fun)
@ -496,8 +494,8 @@ def child_fun():
If something goes wrong, the child process is expected to print
the error and the parent process will exit with error as
well. If things go well, the child exits and the parent
carries on.
"""
carries on."""
try:
pid = os.fork()
except OSError as e:

View File

@ -77,18 +77,17 @@ def cxx11_flag(self):
@classmethod
def default_version(cls, comp):
"""The '--version' option works for clang compilers.
On most platforms, output looks like this::
On most platforms, output looks like this::
clang version 3.1 (trunk 149096)
Target: x86_64-unknown-linux-gnu
Thread model: posix
clang version 3.1 (trunk 149096)
Target: x86_64-unknown-linux-gnu
Thread model: posix
On Mac OS X, it looks like this:
Apple LLVM version 7.0.2 (clang-700.1.81)
Target: x86_64-apple-darwin15.2.0
Thread model: posix
On Mac OS X, it looks like this::
Apple LLVM version 7.0.2 (clang-700.1.81)
Target: x86_64-apple-darwin15.2.0
Thread model: posix
"""
if comp not in cpr._version_cache:
compiler = Executable(comp)

View File

@ -68,15 +68,15 @@ def cxx11_flag(self):
@classmethod
def default_version(cls, comp):
"""The '--version' option seems to be the most consistent one
for intel compilers. Output looks like this::
for intel compilers. Output looks like this::
icpc (ICC) 12.1.5 20120612
Copyright (C) 1985-2012 Intel Corporation. All rights reserved.
icpc (ICC) 12.1.5 20120612
Copyright (C) 1985-2012 Intel Corporation. All rights reserved.
or::
or::
ifort (IFORT) 12.1.5 20120612
Copyright (C) 1985-2012 Intel Corporation. All rights reserved.
ifort (IFORT) 12.1.5 20120612
Copyright (C) 1985-2012 Intel Corporation. All rights reserved.
"""
return get_compiler_version(
comp, '--version', r'\((?:IFORT|ICC)\) ([^ ]+)')

View File

@ -70,10 +70,10 @@ def fc_rpath_arg(self):
@classmethod
def default_version(self, comp):
"""The '-V' option works for nag compilers.
Output looks like this::
Output looks like this::
NAG Fortran Compiler Release 6.0(Hibiya) Build 1037
Product NPL6A60NA for x86-64 Linux
NAG Fortran Compiler Release 6.0(Hibiya) Build 1037
Product NPL6A60NA for x86-64 Linux
"""
return get_compiler_version(
comp, '-V', r'NAG Fortran Compiler Release ([0-9.]+)')

View File

@ -58,11 +58,11 @@ def cxx11_flag(self):
@classmethod
def default_version(cls, comp):
"""The '-V' option works for all the PGI compilers.
Output looks like this::
Output looks like this::
pgcc 15.10-0 64-bit target on x86-64 Linux -tp sandybridge
The Portland Group - PGI Compilers and Tools
Copyright (c) 2015, NVIDIA CORPORATION. All rights reserved.
pgcc 15.10-0 64-bit target on x86-64 Linux -tp sandybridge
The Portland Group - PGI Compilers and Tools
Copyright (c) 2015, NVIDIA CORPORATION. All rights reserved.
"""
return get_compiler_version(
comp, '-V', r'pg[^ ]* ([^ ]+) \d\d\d?-bit target')

View File

@ -24,26 +24,28 @@
##############################################################################
"""This module implements Spack's configuration file handling.
=========================
Configuration file scopes
===============================
=========================
When Spack runs, it pulls configuration data from several config
directories, each of which contains configuration files. In Spack,
there are two configuration scopes:
1. ``site``: Spack loads site-wide configuration options from
1. ``site``: Spack loads site-wide configuration options from
``$(prefix)/etc/spack/``.
2. ``user``: Spack next loads per-user configuration options from
~/.spack/.
2. ``user``: Spack next loads per-user configuration options from
``~/.spack/``.
Spack may read configuration files from both of these locations. When
configurations conflict, the user config options take precedence over
the site configurations. Each configuration directory may contain
several configuration files, such as compilers.yaml or mirrors.yaml.
=========================
Configuration file format
===============================
=========================
Configuration files are formatted using YAML syntax. This format is
implemented by libyaml (included with Spack as an external module),
@ -63,13 +65,13 @@
cc: /usr/local/bin/mpixlc
...
In this example, entries like ''compilers'' and ''xlc@12.1'' are used to
In this example, entries like "compilers" and "xlc@12.1" are used to
categorize entries beneath them in the tree. At the root of the tree,
entries like ''cc'' and ''cxx'' are specified as name/value pairs.
entries like "cc" and "cxx" are specified as name/value pairs.
``config.get_config()`` returns these trees as nested dicts, but it
strips the first level off. So, ``config.get_config('compilers')``
would return something like this for the above example:
would return something like this for the above example::
{ 'chaos_5_x86_64_ib' :
{ 'gcc@4.4.7' :
@ -84,8 +86,9 @@
Likewise, the ``mirrors.yaml`` file's first line must be ``mirrors:``,
but ``get_config()`` strips that off too.
==========
Precedence
===============================
==========
``config.py`` routines attempt to recursively merge configuration
across scopes. So if there are ``compilers.py`` files in both the
@ -99,7 +102,7 @@
Sometimes, it is useful to *completely* override a site setting with a
user one. To accomplish this, you can use *two* colons at the end of
a key in a configuration file. For example, this:
a key in a configuration file. For example, this::
compilers::
chaos_5_x86_64_ib:
@ -114,9 +117,8 @@
...
Will make Spack take compilers *only* from the user configuration, and
the site configuration will be ignored.
the site configuration will be ignored."""
"""
import copy
import os
import re

View File

@ -288,8 +288,7 @@ def variant(pkg, name, default=False, description=""):
@directive('resources')
def resource(pkg, **kwargs):
"""
Define an external resource to be fetched and staged when building the
"""Define an external resource to be fetched and staged when building the
package. Based on the keywords present in the dictionary the appropriate
FetchStrategy will be used for the resource. Resources are fetched and
staged in their own folder inside spack stage area, and then moved into
@ -298,11 +297,11 @@ def resource(pkg, **kwargs):
List of recognized keywords:
* 'when' : (optional) represents the condition upon which the resource is
needed
needed
* 'destination' : (optional) path where to move the resource. This path
must be relative to the main package stage area.
must be relative to the main package stage area.
* 'placement' : (optional) gives the possibility to fine tune how the
resource is moved into the main package stage area.
resource is moved into the main package stage area.
"""
when = kwargs.get('when', pkg.name)
destination = kwargs.get('destination', "")

View File

@ -261,17 +261,13 @@ def apply_modifications(self):
@staticmethod
def from_sourcing_files(*args, **kwargs):
"""
Creates an instance of EnvironmentModifications that, if executed,
"""Creates an instance of EnvironmentModifications that, if executed,
has the same effect on the environment as sourcing the files passed as
parameters
Args:
*args: list of files to be sourced
:param \*args: list of files to be sourced
:rtype: instance of EnvironmentModifications"""
Returns:
instance of EnvironmentModifications
"""
env = EnvironmentModifications()
# Check if the files are actually there
if not all(os.path.isfile(file) for file in args):

View File

@ -120,28 +120,29 @@ def suggest_archive_basename(resource):
def create(path, specs, **kwargs):
"""Create a directory to be used as a spack mirror, and fill it with
package archives.
package archives.
Arguments:
path Path to create a mirror directory hierarchy in.
specs Any package versions matching these specs will be added
to the mirror.
Arguments:
path: Path to create a mirror directory hierarchy in.
specs: Any package versions matching these specs will be added \
to the mirror.
Keyword args:
no_checksum: If True, do not checkpoint when fetching (default False)
num_versions: Max number of versions to fetch per spec,
if spec is ambiguous (default is 0 for all of them)
Keyword args:
no_checksum: If True, do not checkpoint when fetching (default False)
num_versions: Max number of versions to fetch per spec, \
if spec is ambiguous (default is 0 for all of them)
Return Value:
Returns a tuple of lists: (present, mirrored, error)
* present: Package specs that were already present.
* mirrored: Package specs that were successfully mirrored.
* error: Package specs that failed to mirror due to some error.
Return Value:
Returns a tuple of lists: (present, mirrored, error)
* present: Package specs that were already present.
* mirrored: Package specs that were successfully mirrored.
* error: Package specs that failed to mirror due to some error.
This routine iterates through all known package versions, and
it creates specs for those versions. If the version satisfies any spec
in the specs list, it is downloaded and added to the mirror."""
This routine iterates through all known package versions, and
it creates specs for those versions. If the version satisfies any spec
in the specs list, it is downloaded and added to the mirror.
"""
# Make sure nothing is in the way.
if os.path.isfile(path):
raise MirrorError("%s already exists and is a file." % path)

View File

@ -84,9 +84,9 @@ class Package(object):
with the package itself. Packages are written in pure python.
Packages are all submodules of spack.packages. If spack is installed
in $prefix, all of its python files are in $prefix/lib/spack. Most
of them are in the spack module, so all the packages live in
$prefix/lib/spack/spack/packages.
in ``$prefix``, all of its python files are in ``$prefix/lib/spack``.
Most of them are in the spack module, so all the packages live in
``$prefix/lib/spack/spack/packages``.
All you have to do to create a package is make a new subclass of Package
in this directory. Spack automatically scans the python files there
@ -95,7 +95,7 @@ class Package(object):
**An example package**
Let's look at the cmake package to start with. This package lives in
$prefix/lib/spack/spack/packages/cmake.py:
``$prefix/var/spack/repos/builtin/packages/cmake/package.py``:
.. code-block:: python
@ -118,19 +118,21 @@ def install(self, spec, prefix):
1. The module name, ``cmake``.
* User will refers to this name, e.g. 'spack install cmake'.
* Corresponds to the name of the file, 'cmake.py', and it can
include ``_``, ``-``, and numbers (it can even start with a
* It can include ``_``, ``-``, and numbers (it can even start with a
number).
2. The class name, "Cmake". This is formed by converting `-` or
``_`` in the module name to camel case. If the name starts with
a number, we prefix the class name with ``_``. Examples:
Module Name Class Name
foo_bar FooBar
docbook-xml DocbookXml
FooBar Foobar
3proxy _3proxy
=========== ==========
Module Name Class Name
=========== ==========
foo_bar FooBar
docbook-xml DocbookXml
FooBar Foobar
3proxy _3proxy
=========== ==========
The class name is what spack looks for when it loads a package module.
@ -139,30 +141,30 @@ def install(self, spec, prefix):
Aside from proper naming, here is the bare minimum set of things you
need when you make a package:
homepage
informational URL, so that users know what they're
installing.
homepage:
informational URL, so that users know what they're
installing.
url or url_for_version(self, version)
url or url_for_version(self, version):
If url, then the URL of the source archive that spack will fetch.
If url_for_version(), then a method returning the URL required
to fetch a particular version.
install()
This function tells spack how to build and install the
software it downloaded.
install():
This function tells spack how to build and install the
software it downloaded.
**Optional Attributes**
You can also optionally add these attributes, if needed:
list_url
list_url:
Webpage to scrape for available version strings. Default is the
directory containing the tarball; use this if the default isn't
correct so that invoking 'spack versions' will work for this
package.
url_version(self, version)
url_version(self, version):
When spack downloads packages at particular versions, it just
converts version to string with str(version). Override this if
your package needs special version formatting in its URL. boost
@ -179,12 +181,15 @@ def install(self, spec, prefix):
**spack create**
Most software comes in nicely packaged tarballs, like this one:
http://www.cmake.org/files/v2.8/cmake-2.8.10.2.tar.gz
Most software comes in nicely packaged tarballs, like this one
http://www.cmake.org/files/v2.8/cmake-2.8.10.2.tar.gz
Taking a page from homebrew, spack deduces pretty much everything it
needs to know from the URL above. If you simply type this:
needs to know from the URL above. If you simply type this::
spack create http://www.cmake.org/files/v2.8/cmake-2.8.10.2.tar.gz
Spack will download the tarball, generate an md5 hash, figure out the
version and the name of the package from the URL, and create a new
package file for you with all the names and attributes set correctly.
@ -216,7 +221,6 @@ class Stackwalker(Package):
you can just run configure or cmake without any additional arguments and
it will find the dependencies automatically.
**The Install Function**
The install function is designed so that someone not too terribly familiar
@ -241,13 +245,12 @@ class Stackwalker(Package):
add_commands_to_module() function in this class. This is where most of
them are created and set on the module.
**Parallel Builds**
By default, Spack will run make in parallel when you run make() in your
install function. Spack figures out how many cores are available on
your system and runs make with -j<cores>. If you do not want this behavior,
you can explicitly mark a package not to use parallel make:
your system and runs make with -j<cores>. If you do not want this
behavior, you can explicitly mark a package not to use parallel make:
.. code-block:: python
@ -257,14 +260,15 @@ class SomePackage(Package):
...
This changes thd default behavior so that make is sequential. If you still
want to build some parts in parallel, you can do this in your install function:
want to build some parts in parallel, you can do this in your install
function:
.. code-block:: python
make(parallel=True)
Likewise, if you do not supply parallel = True in your Package, you can keep
the default parallel behavior and run make like this when you want a
Likewise, if you do not supply parallel = True in your Package, you can
keep the default parallel behavior and run make like this when you want a
sequential build:
.. code-block:: python
@ -295,14 +299,13 @@ class SomePackage(Package):
p.do_restage() # removes the build directory and
# re-expands the archive.
The convention used here is that a do_* function is intended to be called
internally by Spack commands (in spack.cmd). These aren't for package
writers to override, and doing so may break the functionality of the Package
class.
The convention used here is that a ``do_*`` function is intended to be
called internally by Spack commands (in spack.cmd). These aren't for
package writers to override, and doing so may break the functionality
of the Package class.
Package creators override functions like install() (all of them do this),
clean() (some of them do this), and others to provide custom behavior.
"""
#
# These are default values for instance variables.
@ -862,19 +865,21 @@ def do_install(self,
Package implementations should override install() to describe
their build process.
Args:
keep_prefix -- Keep install prefix on failure. By default, destroys it.
keep_stage -- By default, stage is destroyed only if there are no
exceptions during build. Set to True to keep the stage
even with exceptions.
ignore_deps -- Don't install dependencies before installing this
:param keep_prefix: Keep install prefix on failure. By default, \
destroys it.
:param keep_stage: By default, stage is destroyed only if there are \
no exceptions during build. Set to True to keep the stage
even with exceptions.
:param ignore_deps: Don't install dependencies before installing this \
package
fake -- Don't really build -- install fake stub files instead.
skip_patch -- Skip patch stage of build if True.
verbose -- Display verbose build output (by default, suppresses it)
dirty -- Don't clean the build environment before installing.
make_jobs -- Number of make jobs to use for install. Default is ncpus
run_tests -- Runn tests within the package's install()
:param fake: Don't really build; install fake stub files instead.
:param skip_patch: Skip patch stage of build if True.
:param verbose: Display verbose build output (by default, suppresses \
it)
:param dirty: Don't clean the build environment before installing.
:param make_jobs: Number of make jobs to use for install. Default is \
ncpus
:param run_tests: Run tests within the package's install()
"""
if not self.spec.concrete:
raise ValueError("Can only install concrete packages: %s."
@ -1110,20 +1115,20 @@ def setup_environment(self, spack_env, run_env):
def setup_dependent_environment(self, spack_env, run_env, dependent_spec):
"""Set up the environment of packages that depend on this one.
This is similar to `setup_environment`, but it is used to
This is similar to ``setup_environment``, but it is used to
modify the compile and runtime environments of packages that
*depend* on this one. This gives packages like Python and
others that follow the extension model a way to implement
common environment or compile-time settings for dependencies.
By default, this delegates to self.setup_environment()
By default, this delegates to ``self.setup_environment()``
Example :
Example:
1. Installing python modules generally requires
`PYTHONPATH` to point to the lib/pythonX.Y/site-packages
directory in the module's install prefix. This could
set that variable.
`PYTHONPATH` to point to the lib/pythonX.Y/site-packages
directory in the module's install prefix. This could
set that variable.
Args:
@ -1142,7 +1147,6 @@ def setup_dependent_environment(self, spack_env, run_env, dependent_spec):
This is useful if there are some common steps to installing
all extensions for a certain package.
"""
self.setup_environment(spack_env, run_env)

View File

@ -198,15 +198,19 @@ def remove(self, repo):
def get_repo(self, namespace, default=NOT_PROVIDED):
"""Get a repository by namespace.
Arguments
namespace
Look up this namespace in the RepoPath, and return
it if found.
Optional Arguments
default
If default is provided, return it when the namespace
isn't found. If not, raise an UnknownNamespaceError.
Arguments:
namespace:
Look up this namespace in the RepoPath, and return it if found.
Optional Arguments:
default:
If default is provided, return it when the namespace
isn't found. If not, raise an UnknownNamespaceError.
"""
fullspace = '%s.%s' % (self.super_namespace, namespace)
if fullspace not in self.by_namespace:

View File

@ -2085,7 +2085,7 @@ def format(self, format_string='$_$@$%@+$+$=', **kwargs):
$# 7-char prefix of DAG hash with '-' prefix
$$ $
You can also use full-string versions, which elide the prefixes:
You can also use full-string versions, which elide the prefixes::
${PACKAGE} Package name
${VERSION} Version
@ -2101,9 +2101,9 @@ def format(self, format_string='$_$@$%@+$+$=', **kwargs):
${SPACK_INSTALL} The default spack install directory,
${SPACK_PREFIX}/opt
Optionally you can provide a width, e.g. $20_ for a 20-wide name.
Optionally you can provide a width, e.g. ``$20_`` for a 20-wide name.
Like printf, you can provide '-' for left justification, e.g.
$-20_ for a left-justified name.
``$-20_`` for a left-justified name.
Anything else is copied verbatim into the output stream.

View File

@ -49,16 +49,14 @@ class Stage(object):
some source code is downloaded and built before being installed.
It handles fetching the source code, either as an archive to be
expanded or by checking it out of a repository. A stage's
lifecycle looks like this:
lifecycle looks like this::
```
with Stage() as stage: # Context manager creates and destroys the
# stage directory
stage.fetch() # Fetch a source archive into the stage.
stage.expand_archive() # Expand the source archive.
<install> # Build and install the archive. (handled by
# user of Stage)
```
with Stage() as stage: # Context manager creates and destroys the
# stage directory
stage.fetch() # Fetch a source archive into the stage.
stage.expand_archive() # Expand the source archive.
<install> # Build and install the archive.
# (handled by user of Stage)
When used as a context manager, the stage is automatically
destroyed if no exception is raised by the context. If an
@ -66,19 +64,17 @@ class Stage(object):
destroyed, for potential reuse later.
You can also use the stage's create/destroy functions manually,
like this:
like this::
```
stage = Stage()
try:
stage.create() # Explicitly create the stage directory.
stage.fetch() # Fetch a source archive into the stage.
stage.expand_archive() # Expand the source archive.
<install> # Build and install the archive. (handled by
# user of Stage)
finally:
stage.destroy() # Explicitly destroy the stage directory.
```
stage = Stage()
try:
stage.create() # Explicitly create the stage directory.
stage.fetch() # Fetch a source archive into the stage.
stage.expand_archive() # Expand the source archive.
<install> # Build and install the archive.
# (handled by user of Stage)
finally:
stage.destroy() # Explicitly destroy the stage directory.
If spack.use_tmp_stage is True, spack will attempt to create
stages in a tmp directory. Otherwise, stages are created directly

View File

@ -56,12 +56,13 @@ def assert_rev(self, rev):
def try_fetch(self, rev, test_file, args):
"""Tries to:
1. Fetch the repo using a fetch strategy constructed with
supplied args.
2. Check if the test_file is in the checked out repository.
3. Assert that the repository is at the revision supplied.
4. Add and remove some files, then reset the repo, and
ensure it's all there again.
1. Fetch the repo using a fetch strategy constructed with
supplied args.
2. Check if the test_file is in the checked out repository.
3. Assert that the repository is at the revision supplied.
4. Add and remove some files, then reset the repo, and
ensure it's all there again.
"""
self.pkg.versions[ver('git')] = args

View File

@ -52,12 +52,13 @@ def tearDown(self):
def try_fetch(self, rev, test_file, args):
"""Tries to:
1. Fetch the repo using a fetch strategy constructed with
supplied args.
2. Check if the test_file is in the checked out repository.
3. Assert that the repository is at the revision supplied.
4. Add and remove some files, then reset the repo, and
ensure it's all there again.
1. Fetch the repo using a fetch strategy constructed with
supplied args.
2. Check if the test_file is in the checked out repository.
3. Assert that the repository is at the revision supplied.
4. Add and remove some files, then reset the repo, and
ensure it's all there again.
"""
self.pkg.versions[ver('hg')] = args

View File

@ -52,9 +52,10 @@ def tearDown(self):
def set_up_package(self, name, MockRepoClass, url_attr):
"""Set up a mock package to be mirrored.
Each package needs us to:
1. Set up a mock repo/archive to fetch from.
2. Point the package's version args at that repo.
Each package needs us to:
1. Set up a mock repo/archive to fetch from.
2. Point the package's version args at that repo.
"""
# Set up packages to point at mock repos.
spec = Spec(name)

View File

@ -24,7 +24,7 @@
##############################################################################
"""Tests for provider index cache files.
Tests assume that mock packages provide this:
Tests assume that mock packages provide this::
{'blas': {
blas: set([netlib-blas, openblas, openblas-with-lapack])},

View File

@ -63,12 +63,13 @@ def get_rev():
def try_fetch(self, rev, test_file, args):
"""Tries to:
1. Fetch the repo using a fetch strategy constructed with
supplied args.
2. Check if the test_file is in the checked out repository.
3. Assert that the repository is at the revision supplied.
4. Add and remove some files, then reset the repo, and
ensure it's all there again.
1. Fetch the repo using a fetch strategy constructed with
supplied args.
2. Check if the test_file is in the checked out repository.
3. Assert that the repository is at the revision supplied.
4. Add and remove some files, then reset the repo, and
ensure it's all there again.
"""
self.pkg.versions[ver('svn')] = args

View File

@ -31,15 +31,15 @@ def composite(interface=None, method_list=None, container=list):
"""Returns a class decorator that patches a class adding all the methods
it needs to be a composite for a given interface.
:param interface: class exposing the interface to which the composite
object must conform. Only non-private and non-special methods will be
taken into account
:param interface: class exposing the interface to which the composite \
object must conform. Only non-private and non-special methods will \
be taken into account
:param method_list: names of methods that should be part of the composite
:param container: container for the composite object (default = list).
Must fulfill the MutableSequence contract. The composite class will expose
the container API to manage object composition
:param container: container for the composite object (default = list). \
Must fulfill the MutableSequence contract. The composite class will \
expose the container API to manage object composition
:return: class decorator
"""

View File

@ -155,11 +155,11 @@ def highest(self):
@coerced
def satisfies(self, other):
"""A Version 'satisfies' another if it is at least as specific and has a
common prefix. e.g., we want gcc@4.7.3 to satisfy a request for
gcc@4.7 so that when a user asks to build with gcc@4.7, we can find
a suitable compiler.
"""
"""A Version 'satisfies' another if it is at least as specific and has
a common prefix. e.g., we want gcc@4.7.3 to satisfy a request for
gcc@4.7 so that when a user asks to build with gcc@4.7, we can find
a suitable compiler."""
nself = len(self.version)
nother = len(other.version)
return nother <= nself and self.version[:nother] == other.version
@ -388,12 +388,12 @@ def __contains__(self, other):
@coerced
def satisfies(self, other):
"""
A VersionRange satisfies another if some version in this range
"""A VersionRange satisfies another if some version in this range
would satisfy some version in the other range. To do this it must
either:
a) Overlap with the other range
b) The start of this range satisfies the end of the other range.
a) Overlap with the other range
b) The start of this range satisfies the end of the other range.
This is essentially the same as overlaps(), but overlaps assumes
that its arguments are specific. That is, 4.7 is interpreted as
@ -401,6 +401,7 @@ def satisfies(self, other):
by 4.7.3.5, etc.
Rationale:
If a user asks for gcc@4.5:4.7, and a package is only compatible with
gcc@4.7.3:4.8, then that package should be able to build under the
constraints. Just using overlaps() would not work here.