I think you're over-engineering it. Go for the simplest thing that works for 99% of cases, and leave the underlying API (__import__, etc.) sufficiently open that folk who want to be obtuse can code up custom importing behaviours themselves. Far as I can tell, the simplest thing that works is to have three version numbers:
- one supplied in your script's import statement:
import foo version 1.1.0
- one supplied in the module/package file/folder name:
- and one supplied in the module/package metadata:
__oldest_supported_version__ = 1.0.5
1. The 'import NAME version NUMBER' statement indicates the module version the script was authored against. (If the script author _knows_ their script will work with an older version of the same module, they may use the older version number instead.)
2. The version number in the module filename allows you to store multiple versions of the same module in the same directory. It is also the first number used when importing a module: the __import__ function should start with the newest module first.
3. When the __import__ function imports a module, it checks the module's __oldest_supported_version__ against the version supplied by the import statement. If the desired version is lower than __oldest_supported_version__, the __import__ function should load the next newest version of the module; and so on, until it finds one that is acceptable.
i. If no suitable versioned module is found, import a non-versioned module (if available).
ii. If no version is given in the import statement, import the newest module available.
iii. If a versioned module has no __oldest_supported_version__ attribute, it's backwards compatible with all previous releases.
It's loose, simple, can comfortably co-exist with non-versioned modules and involves no fancy comparison operators or other bloat. The various underlying operations (list filenames and versions of all modules of a given name, compare version numbers, etc.) can be exposed as magic functions for the benefit of those control freaks who simply _must_ bind against version 0.133.45a72r4 and nothing else, but for the vast majority of users the system has a dirt simple interface and in practice simply does 'the right thing'.
BTW, regarding metadata: Python's module system just plain sucks at it. As T E Whalen points out, you really don't want to have to import modules to get their metadata. Magic attributes are a Bad Thing and should be gotten rid of. While burying metadata in comments at the top of a module (where they can be retrieved by reading the module as a plain text file), that smells a bit hackish to me and a better option would be to use the package format for all modules and have a standard 'meta.txt' file included in the package folder that contains all metadata in RFC-822 or other human-readable/writable format. This would actually be a good foundation for a unified, decentralised, module metadata scheme: a single location within each package containing all information describing that package that can be accessed via a standard API, rather than having it spread all over module attributes, distutils scripts, pkginfo files, etc. where it's frequently duplicated and hard to access. This is getting off-topic though and would be better discussed in a separate thread, so I'll leave it there.