There is no version attribute anywhere in zope.interface

Reported by Jean-Paul Calderone on 2010-03-03
20
This bug affects 4 people
Affects Status Importance Assigned to Milestone
zope.interface
Wishlist
Unassigned

Bug Description

It's very useful to be able to programmatically inspect the version of a package. There is apparently no version information anywhere in zope.interface, though. It would be nice if some were added.

Michael Haubenwallner (d2m) wrote :

try for a start:

import pkg_resources
version=pkg_resources.require('zope.interface')[0].version

Jean-Paul Calderone (exarkun) wrote :

This only works if pkg_resources is installed and Zope Interface was installed in a way agreeable to it. It's a start, certainly, but it doesn't completely resolve the issue.

On Thu, Mar 4, 2010 at 2:25 PM, Jean-Paul Calderone
<email address hidden> wrote:
> This only works if pkg_resources is installed and Zope Interface was
> installed in a way agreeable to it.  It's a start, certainly, but it
> doesn't completely resolve the issue.

Yup. I think we should take a stab at this. We (for some definition of we :)
should fix this in such a way that:

- The version isn't in more than one place

- setup.py doesn't have to import anything to get the version.

Jim

--
Jim Fulton

Tres Seaver (tseaver) wrote :

AFAIK, we have 3 places to put the version number without duplication:

 - in setup.py (where it has to be passed to setup(). pkg_resources consumes
   this value indirectly through the PKG-INFO file generated during installation.

 - in an attribute of a module (which one, please? Defend your choice. ;)

 - In a data file in the package (something like the Zope2 product convention of
   'version.txt').

Note that without setuptools / distribute installed, we are already running in degraded mode (hard wiring filename globs for package data, no C optimizations, no documentation generation, wonky namespace package support, etc.). Do we really expect to deliver this feature in that case?

The 'pkg_resources' solution is uniform across *all* installed packages (even stdlib modules in 2.7). I would vote for sticking with it as the blessed solution to this need.

On Tuesday 13 April 2010, Tres Seaver wrote:
> The 'pkg_resources' solution is uniform across all installed packages
> (even stdlib modules in 2.7). I would vote for sticking with it as the
> blessed solution to this need.

Could we expose the version number in an attribute:
zope.interface.__version__? This way it is easy to find while we still utilized
the most common version reference.

Regards,
Stephan
--
Entrepreneur and Software Geek
Google me. "Zope Stephan Richter"

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Stephan Richter wrote:
> On Tuesday 13 April 2010, Tres Seaver wrote:
>> The 'pkg_resources' solution is uniform across all installed packages
>> (even stdlib modules in 2.7). I would vote for sticking with it as the
>> blessed solution to this need.
>
> Could we expose the version number in an attribute:
> zope.interface.__version__? This way it is easy to find while we still utilized
> the most common version reference.

We don't want to have to import the package while building the
distribution, nor while installing it.

Tres.
- --
===================================================================
Tres Seaver +1 540-429-0999 <email address hidden>
Palladion Software "Excellence by Design" http://palladion.com
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iEYEARECAAYFAkvE5hkACgkQ+gerLs4ltQ5w0QCglnxV2nu8IYU7FFkyKBMnsv2+
hCUAoJCqnXpn7NtBY96mCFbq4cBHGXtp
=9r8l
-----END PGP SIGNATURE-----

On Tue, Apr 13, 2010 at 5:10 PM, Tres Seaver <email address hidden> wrote:
> AFAIK, we have 3 places to put the version number without duplication:
>
>  - in setup.py (where it has to be passed to setup().  pkg_resources consumes
>   this value indirectly through the PKG-INFO file generated during installation.
>
>  - in an attribute of a module (which one, please?  Defend your choice.
> ;)
>
>  - In a data file in the package (something like the Zope2 product convention of
>   'version.txt').

I would put it in a text file in the package. I would have the
__init__ of the package load this into the __version__ attribute for
instrospection by run-time code. (AFAIK, __version__ is still a Python
standard.)

I would have the setup.py read the file by constructing a relative
path. (I don't want setup.py to try importing the package.)

> Note that without setuptools / distribute installed, we are already
> running in degraded mode (hard wiring filename globs for package data,
> no C optimizations, no documentation generation, wonky namespace package
> support, etc.).  Do we really expect to deliver this feature in that
> case?
>
> The 'pkg_resources' solution is uniform across *all* installed packages
> (even stdlib modules in 2.7).  I would vote for sticking with it as the
> blessed solution to this need.

If Guido blesses it, I'll go along. :)

I don't like the idea of being dependent pn pkg_resoures for the
feature. My opinion would change if the API used to get the version
was part of the standard library.

I don't feel strongly about this, but would be inclined to try to do
something simple.

Jim

--
Jim Fulton

Download full text (3.7 KiB)

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Jim Fulton wrote:
> On Tue, Apr 13, 2010 at 5:10 PM, Tres Seaver <email address hidden> wrote:
>> AFAIK, we have 3 places to put the version number without duplication:
>>
>> - in setup.py (where it has to be passed to setup(). pkg_resources consumes
>> this value indirectly through the PKG-INFO file generated during installation.
>>
>> - in an attribute of a module (which one, please? Defend your choice.
>> ;)
>>
>> - In a data file in the package (something like the Zope2 product convention of
>> 'version.txt').
>
> I would put it in a text file in the package. I would have the
> __init__ of the package load this into the __version__ attribute for
> instrospection by run-time code.

I don't think there is any reliable way to read such a file at import
time that doesn't depend on pkg_resources (think zipped trees on GAI, or
zipped eggs, etc.).

> (AFAIK, __version__ is still a Python standard.)

Hmm, I wouldn't reead PEP8 that way:

  Version Bookkeeping

    If you have to have Subversion, CVS, or RCS crud in your source
    file, do it as follows.

        __version__ = "$Revision: 68852 $"
        # $Source$

    These lines should be included after the module's docstring,
    before any other code, separated by a blank line above and below.

That sounds pretty disparaging to me. Not only that, it says *nothing*
about a "release ID", which is wildly different from a VCS revision ID
for a specific file.

> I would have the setup.py read the file by constructing a relative
> path. (I don't want setup.py to try importing the package.)

setup.py at least has an unambiguous way to get to the file, unlike
import-time stuff.

>> Note that without setuptools / distribute installed, we are already
>> running in degraded mode (hard wiring filename globs for package data,
>> no C optimizations, no documentation generation, wonky namespace package
>> support, etc.). Do we really expect to deliver this feature in that
>> case?
>>
>> The 'pkg_resources' solution is uniform across *all* installed packages
>> (even stdlib modules in 2.7).

I'll have to retrac on this -- I can't find any evidence that recent
Pythons actually make PKG-INFO files for the stdlib. I thought that

>> I would vote for sticking with it as the
>> blessed solution to this need.
>
> If Guido blesses it, I'll go along. :)
>
> I don't like the idea of being dependent pn pkg_resoures for the
> feature. My opinion would change if the API used to get the version
> was part of the standard library.

I'm unhappy about coding up any non-standard support for such a feature.
 Given that pkg_resources works in nearly any environment where our
packages are used today, I can' t see any win for adding workaround
cruft to our packages just to avoid it. In other words, I would rather
not support the feature at all than add code which supports it badly,
and differently in each of the dozens of packages we already support.

> I don't feel strongly about this, but would be inclined to try to do
> something simple.

I guess I am -0 on doing anything at all, especially in the absence of
any concrete use cases for using such a feature in...

Read more...

On Tue, Apr 13, 2010 at 7:49 PM, Tres Seaver <email address hidden> wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> Jim Fulton wrote:
>> On Tue, Apr 13, 2010 at 5:10 PM, Tres Seaver <email address hidden> wrote:
>>> AFAIK, we have 3 places to put the version number without duplication:
>>>
>>>  - in setup.py (where it has to be passed to setup().  pkg_resources consumes
>>>   this value indirectly through the PKG-INFO file generated during installation.
>>>
>>>  - in an attribute of a module (which one, please?  Defend your choice.
>>> ;)
>>>
>>>  - In a data file in the package (something like the Zope2 product convention of
>>>   'version.txt').
>>
>> I would put it in a text file in the package.  I would have the
>> __init__ of the package load this into the __version__ attribute for
>> instrospection by run-time code.
>
> I don't think there is any reliable way to read such a file at import
> time that doesn't depend on pkg_resources (think zipped trees on GAI, or
> zipped eggs, etc.).

Good point.

Hm, so you zip your packages to make them fit on GAI,
now you have 2 problems. :)

I guess the file could be a .py file, which would rather suck.

>
>> (AFAIK, __version__ is still a Python standard.)
>
> Hmm, I wouldn't reead PEP8 that way:
>
>  Version Bookkeeping
>
>    If you have to have Subversion, CVS, or RCS crud in your source
>    file, do it as follows.
>
>        __version__ = "$Revision: 68852 $"
>        # $Source$
>
>    These lines should be included after the module's docstring,
>    before any other code, separated by a blank line above and below.
>
> That sounds pretty disparaging to me.  Not only that, it says *nothing*
> about a "release ID", which is wildly different from a VCS revision ID
> for a specific file.

Well, I was in the room at SPAM I when the feature was proposed and
the intent was to capture the "module" version. This wasn't ties to
source control. Source control provides
a convenient mechanism for individual files.

...

> I'm unhappy about coding up any non-standard support for such a feature.

Me neither.

>  Given that pkg_resources works in nearly any environment where our
> packages are used today, I can' t see any win for adding workaround
> cruft to our packages just to avoid it.  In other words, I would rather
> not support the feature at all than add code which supports it badly,
> and differently in each of the dozens of packages we already support.

I really really really wish distribute or setuptools or something suitably
like them would become truly standard. Until that day, life will suck. :)

>> I don't feel strongly about this, but would be inclined to try to do
>> something simple.
>
> I guess I am -0 on doing anything at all, especially in the absence of
> any concrete use cases for using such a feature in environments where
> setuptools / pkg_resources is not already ubiquitous.

That's fine. I may try something anyway, if only because this
keeps coming up and I find the answer of requiring setuptools
to be pretty unsatisfying. Yeah -- I realize that most of our packages
require setuptools to be installed ....

Jim

--
Jim Fulton

Jim Fulton (jim-zope) wrote :

On Thu, Mar 4, 2010 at 3:25 PM, Jean-Paul Calderone
<email address hidden> wrote:
> This only works if pkg_resources is installed and Zope Interface was
> installed in a way agreeable to it.  It's a start, certainly, but it
> doesn't completely resolve the issue.

Can you think of real situations in which someone would have
zope.interface but not the pkg_resources?

Jim

--
Jim Fulton

Jean-Paul Calderone (exarkun) wrote :

> Can you think of real situations in which someone would have zope.interface but not the pkg_resources?

Yep. This came up for real on one of Twisted's buildslaves, which is what prompted me to file the ticket. I don't know the particulars of how it was installed, but I suppose it was either built from source or, perhaps, installed with a .exe installer (I seem to recall older versions of zope.interface were sometimes distributed that way). I can't tell you which version of zope.interface is installed, though. ;)

Tres Seaver (tseaver) wrote :

> I can't tell you which version of zope.interface is installed, though. ;)

Seriously: If you can't recreate your build environment from some
manifest or other, naming the distributions used for each component,
you have problems beyond our ability to help..

Querying installed versions at runtime is a subtly different problem, with
the same underling cause: using bare distutils sucks. It sucks so much
that I would personally rather rip out the fallback code currently in the
setup.py for zope.interface, than try to enable further workarounds.

Changed in zope.interface:
importance: Undecided → Wishlist
status: New → Triaged
Jean-Paul Calderone (exarkun) wrote :

> Seriously: If you can't recreate your build environment from some
> manifest or other, naming the distributions used for each component,
> you have problems beyond our ability to help..

And I'm not asking you to solve those problems. I'm only asking for zope.interface to identify its version number.

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Jean-Paul Calderone wrote:
>> Seriously: If you can't recreate your build environment from some
>> manifest or other, naming the distributions used for each component,
>> you have problems beyond our ability to help..
>
> And I'm not asking you to solve those problems. I'm only asking for
> zope.interface to identify its version number.

You are asking for us to do so outside the "standard" metadata which all
installable packages are supposed to provide, and which any recent
Python (>= 2.5) captures to the filesystem at install time. Older
Python's also do fine with capturing the data if they use setuptools.

Satisfying your request to be able to query this information on an old
python without setuptools requires introducing cruft into the software,
for very little benefit to the vast majority of its users, who use the
software in a way which makes querying the version via its packaging
metadata simple and straightforward.

Tres.
- --
===================================================================
Tres Seaver +1 540-429-0999 <email address hidden>
Palladion Software "Excellence by Design" http://palladion.com
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iEYEARECAAYFAkvoercACgkQ+gerLs4ltQ7djgCfRCweFGXzeQdwPFO1JKSt0QYN
0YQAn3mfR6ieMfjikehLV/ClKlezHpop
=cOnD
-----END PGP SIGNATURE-----

Glyph Lefkowitz (glyph) wrote :

pkg_resources is not a good way to get access to this information programmatically because it's decoupled from the mechanism used to actually load the code (i.e. importing). So there's the opportunity for desynchronization.

For example (Jim asked for an example where you might have zope.interface but not the pkg_resources) let's say I put an svn checkout on sys.path programmatically because I'm using some deployment tool which sets up the environment in Python rather than environment variables, for portability. But my system has an earlier version of zope.interface installed.

I'll see the system version of the package information, despite importing the packaged version. So, if my code is trying to interrogate the system environment to see what version of zope I'm really using in order to tell if I can safely access a particular feature, it'll blow up. Worse yet, If I happened to import pkg_resources before zope, I won't even see a warning that indicates my environment isn't set up correctly, since pkg_resources performs this check at import time rather than when you make various API calls.

As it happens, this is actually how my development environment is often set up, and it is a constant annoyance that I have to run 'setup.py egg_info' in a bunch of different places to either get rid of warnings or get package metadata to line up correctly.

Zooko Wilcox-O'Hearn (zooko) wrote :

Here is how I do this. Advantages of the following method:

1. It provides a __version__ attribute, satisfying the request in this ticket.

2. It provides the standard egg-info formatted version.

3. It doesn't import zope.interface (or anything else) when building zope.interface, which can cause problems in some situations.

4. There is only one place that the version number is written down, so there is only one place to change it when the version number changes, and there is less chance of inconsistent versions.

Here is an example of this technique that I've been using for years: http://tahoe-lafs.org/trac/zfec/browser/trunk/zfec/setup.py?annotate=blame&rev=390

(The code in my zfec package is a bit more complicated, but the simplified example that I wrote into this comment should be a complete implementation.)

Here is how it works: the "one canonical place" to store the version number is a .py file, named "_version.py" which is in your Python package, for example in zope/interface/_version.py. This file is a Python module, but your setup.py doesn't import it! (That would defeat feature 3.) Instead your setup.py knows that the contents of this file is very simple, something like:

__version__ = "3.6.5"

And so your setup.py opens the file and parses it, with code like:

verstrline = open(VERSIONFILE, "rt").read()
VSRE = r"^__version__ = ['\"]([^'\"]*)['\"]"
mo = re.search(VSRE, verstrline, re.M)
if mo:
    verstr = mo.group(1)
else:
    raise RuntimeError("Unable to find version string in %s." % (VERSIONFILE,))

Then your setup.py passes that string as the value of "version" to setup(), thus satisfying feature 2.

To satisfy feature 1, you can have your package (at run-time, not at setup time!) import the _version file from zope/interface/__init__.py like this:

from _version import __version__

example: http://tahoe-lafs.org/trac/zfec/browser/trunk/zfec/zfec/__init__.py?annotate=blame&rev=363

Regards,

Zooko

Daira Hopwood (daira) wrote :

Glyph Lefkowitz wrote:
> pkg_resources is not a good way to get access to this information programmatically because it's decoupled from the mechanism used to actually load the code (i.e. importing). So there's the opportunity for desynchronization.

+1. In Tahoe-LAFS we consider pkg_resources to be an unreliable method of getting version numbers, having been bitten by cases where the returned version was simply wrong (http://tahoe-lafs.org/trac/tahoe-lafs/ticket/1258#comment:8).

Zooko Wilcox-O'Hearn (zooko) wrote :

Note that the scheme in https://bugs.launchpad.net/zope.interface/+bug/531662/comments/16 works equally well for users who use pkg_resources to learn version numbers and for users who import your module and inspect its "__version__" attribute to learn version numbers. It also works correctly for users who inspect the standard metadata and parse the version numbers therein.

To post a comment you must log in.
This report contains Public information  Edit
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.