The package meta-info patch I sent out a while ago includes some immature facilities for tracking project dependencies and project compatibilities, two ideas that I'm very interested in which I'd like to seed some discussion on in the hopes that they will be integrated in some form or another into distutils.
Definition of terms:
_Dependencies_ are versions of external packages that a given package is dependent upon.
A version of A a package is _Compatible_ with version B of the same package iff A provides the same _Public Interface_ as B - A may extend B's interface, but it may not omit any portion of it. The _Public Interface_ of a package includes all methods and attributes that are available and not designated as private, either explicitly in the documentation of the package, or implicitly through the use of standard naming conventions (i.e. names preceeded by an underscore). It also includes the documented behavior of methods, particularly with respect to parameter types and return values. This subject is worthy of a much longer document, but I want to keep this brief.
_Compatible Versions_ are versions of a package that are Compatible with a given version of the package.
I define the _Compatibility Set_ as the inverse form of Compatible Versions: it is the set of all versions that a package is compatible with. If p-v1 is compatible with p-v0, p-v0 is in p-v1's compatibility set, and p-v1 is in p-v0's compatible versions.
If we track the dependencies and the compatibility sets of each package, it should be possible to provide a fairly flexible system to determine whether or not all of the required dependencies for a particular package are present, and at least advise the user if they are not, perhaps allowing them to download the required packages at the time of installation.
The problem is, a dependent may be compatible with many versions of a particular dependency. Rather than enumerating every compatibility, it would seem desirable to define a regular-expression like syntax for describing sets of versions, for example:
1.20-? matches all versions with a major number of 1 and a minor number > 20 1 matches all versions with a major number of 1 1.3-4 matches 1.3.6, 1.4.1, and 1.4, but not 1.5, or 1.40
Here's an example of how such a system might function in a particular case:
Package A version 1.2 is installed on a system and has a compatibility set = [ '1.0.5-?', '1.1*' ] (i.e. 1.2 is compatible with all 1.0.n versions after 1.0.5, and all 1.1 versions).
Package B version 2.0 has a dependency on package A version '1.0.9'.
In this case, the dependency is satisfied by the installed version.
This model is pretty straight-forward, however, it gets worse. Sometimes a compatibility break in a service package doesn't affect a particular dependent: it doesn't matter to my package if you remove method foo() if I don't use method foo(). For this reason, each dependency should be described as a /set/ of compatible versions of a package, rather than a single compatible version.
Let's consider another example:
Package A versions 1.0.8 is installed on a system and has a compatibility set = [ '1.0.5-7' ]
Package A version 1.0.4 (which is not installed) has a compatibility set = [ '1.0.1-3' ]
Package B version 2.0 (which is not affected by the interface change between 1.0.4 and 1.0.5) has a dependency on package A versions 1.0.1 _or_ 1.0.5.
Again, the dependency is satisfied.
There is no concept that is more demeaning to the human spirit than the notion that our freedom must be limited in the interests of our own