Commits

Anonymous committed 0430fd0

initial commit

  • Participants

Comments (0)

Files changed (11)

+=============================
+pkgutil extension for PEP 376
+=============================
+
+
+
+PEP: 376
+Title: Changing the .egg-info structure
+Version: $Revision: 72780 $
+Last-Modified: $Date: 2009-05-19 14:43:34 +0200 (Mar, 19 mai 2009) $
+Author: Tarek Ziadé <tarek@ziade.org>
+Status: Draft
+Type: Standards Track
+Content-Type: text/x-rst
+Created: 22-Feb-2009
+Python-Version: 2.7, 3.2
+Post-History:
+
+
+Abstract
+========
+
+This PEP proposes various enhancements for Distutils:
+
+- A new format for the .egg-info structure.
+- Some APIs to read the meta-data of a project
+
+Definitions
+===========
+
+A **project** is a Python application composed of one or several files, which can
+be Python modules, extensions or data. It is distributed using a `setup.py` script 
+with Distutils and/or Setuptools. The `setup.py` script indicates where each 
+elements should be installed.
+
+Once installed, the elements are located in various places in the system, like:
+
+- in Python's site-packages (Python modules, Python modules organized into packages, 
+  Extensions, etc.)
+- in Python's `include` directory.
+- in Python's `bin` or `Script` directory.
+- etc.
+
+Rationale
+=========
+
+There are two problems right now in the way projects are installed in Python:
+
+- There are too many ways to do it.
+- There is no API to get the metadata of installed projects.
+
+How projects are installed
+--------------------------
+
+Right now, when a project is installed in Python, every elements its contains 
+is installed in various directories. 
+
+The pure Python code for instance is  installed in the `purelib` directory,
+which is located in the Python  installation in `lib\python2.6\site-packages`
+for example under unix-like systems or Mac OS X, and in `Lib/site-packages` 
+under Windows. This is done with the Distutils `install` command, which calls
+various subcommands.
+
+The `install_egg_info` subcommand is called during this process, in order to 
+create an `.egg-info` file in the `purelib` directory.
+
+For example, if the `zlib` project (which contains one package) is installed,
+two elements will be installed in `site-packages`::
+
+ - zlib
+ - zlib-2.5.2-py2.4.egg-info
+
+Where `zlib` is a Python package, and `zlib-2.5.2-py2.4.egg-info` is
+a file containing the project metadata as described in PEP 314 [#pep314]_.
+
+This file corresponds to the file called `PKG-INFO`, built by 
+the `sdist` command.
+
+The problem is that many people use `easy_install` (setuptools [#setuptools]_) 
+or `pip` [#pip]_ to install their packages, and these third-party tools do not 
+install packages in the same way that Distutils does:
+
+- `easy_install` creates an `EGG-INFO` directory inside an `.egg` directory, 
+  and adds a `PKG-INFO` file inside this directory. The `.egg` directory 
+  contains in that case all the elements of the project that are supposed to
+  be installed in `site-packages`, and is placed in the `site-packages` 
+  directory.
+
+- `pip` creates an `.egg-info` directory inside the `site-packages` directory
+  and adds a `PKG-INFO` file inside it. Elements of the project are then
+  installed in various places like Distutils does.
+
+They both add other files in the `EGG-INFO` or `.egg-info` directory, and
+create or modify `.pth` files.
+
+Uninstall information
+---------------------
+
+Distutils doesn't provide any `uninstall` command. If you want to uninstall
+a project, you have to be a power user and remove the various elements that
+were installed. Then look over the `.pth` file to clean them if necessary.
+
+And the process differs, depending on the tools you have used to install the
+project, and if the project's `setup.py` uses Distutils or Setuptools.
+
+Under some circumstances, you might not be able to know for sure that you 
+have removed everything, or that you didn't break another project by
+removing a file that was shared among the two projects.
+
+But there's common behavior: when you install a project, files are copied 
+in your system. And there's a way to keep track of theses files, so to remove 
+them.
+
+What this PEP proposes
+----------------------
+
+To address those issues, this PEP proposes a few changes:
+
+- a new `.egg-info` structure using a directory;
+- a list of elements this directory holds;
+- new functions in `pkgutil` to be able to query the information
+  of installed projects.
+
+.egg-info becomes a directory
+=============================
+
+The first change would be to make `.egg-info` a directory and let it
+hold the `PKG-INFO` file built by the `write_pkg_file` method of 
+the `Distribution` class in Distutils.
+
+This change will not impact Python itself, because `egg-info` files are not
+used anywhere yet in the standard library besides Distutils. 
+
+Although it will impact the `setuptools` and `pip` projects, but given 
+the fact that they already work with a directory that contains a `PKG-INFO` 
+file, the change will have no deep consequences.
+
+For example, if the `zlib` package is installed, the elements that
+will be installed in `site-packages` will become::
+
+    - zlib
+    - zlib-2.5.2.egg-info/
+        PKG-INFO
+
+The Python version will also be removed from the `.egg-info` directory
+name.
+
+Adding a RECORD in the .egg-info directory
+==========================================
+
+A `RECORD` file will be added inside the `.egg-info` directory at installation
+time. The `RECORD` file will hold the list of installed files. These correspond 
+to the files listed by the `record` option of the `install` command, and will 
+always be generated. This will allow uninstallation, as explained later in this 
+PEP. This RECORD file is inspired from PEP 262 FILES [#pep262]_.
+
+The RECORD format
+-----------------
+
+The `RECORD` file is composed of records, one line per installed file.
+Each record is composed of three elements separated by a <tab> character:
+
+- the file's full **path**
+
+ - if the installed file is located in the directory where the .egg-info
+   directory of the package is located, it will be a '/'-separated relative 
+   path, no matter what is the target system. This makes this information 
+   cross-compatible and allows simple installation to be relocatable.
+
+ - if the installed file is located elsewhere in the system, a 
+   '/'-separated absolute path is used.
+
+- the **MD5** hash of the file, encoded in hex. Notice that `pyc` and `pyo`
+  generated files will not have a hash.
+
+- the file's size in bytes
+
+Example
+-------
+
+Back to our `zlib` example, we will have::
+
+    - zlib
+    - zlib-2.5.2.egg-info/
+        PKG-INFO
+        RECORD
+
+And the RECORD file will contain::
+
+    zlib/include/zconf.h    b690274f621402dda63bf11ba5373bf2    9544
+    zlib/include/zlib.h 9c4b84aff68aa55f2e9bf70481b94333    66188
+    zlib/lib/libz.a e6d43fb94292411909404b07d0692d46    91128
+    zlib/share/man/man3/zlib.3  785dc03452f0508ff0678fba2457e0ba    4486
+    zlib-2.5.2.egg-info/PKG-INFO    6fe57de576d749536082d8e205b77748    195
+    zlib-2.5.2.egg-info/RECORD
+
+Notice that:
+
+- the `RECORD` file can't contain a hash of itself and is just mentioned here
+- `zlib` and `zlib-2.5.2.egg-info` are located in `site-packages` so the file 
+  paths are relative to it.
+
+New functions in pkgutil
+========================
+
+To use the `.egg-info` directory content, we need to add in the standard 
+library a set of APIs. The best place to put these APIs seems to be `pkgutil`.
+
+The new functions added in the package are :
+
+- get_projects() -> iterator
+
+  Provides an iterator that will return (name, path) tuples, where `name`
+  is the name of a registered project and `path` the path to its `egg-info`
+  directory.
+
+- get_egg_info(project_name) -> path or None
+
+  Scans all elements in `sys.path` and looks for all directories ending with
+  `.egg-info`. Returns the directory path that contains a PKG-INFO that matches
+  `project_name` for the `name` metadata. Notice that there should be at most 
+  one result. The first result founded will be returned.
+
+  If the directory is not found, returns None.
+
+  XXX The implementation of `get_egg_info` will focus on minimizing the I/O 
+  accesses.
+
+- get_metadata(project_name) -> DistributionMetadata or None
+
+  Uses `get_egg_info` to get the `PKG-INFO` file, and returns a 
+  `DistributionMetadata` instance that contains the metadata.
+
+- get_files(project_name, local=False) -> iterator of (path, hash, size, 
+                                                       other_projects)
+
+  Uses `get_egg_info` to get the `RECORD` file, and returns an iterator.
+
+  Each returned element is a tuple `(path, hash, size, other_projects)` where
+  ``path``, ``hash``, ``size`` are the values found in the RECORD file.
+
+  `path` is the raw value founded in the RECORD file. If `local` is 
+  set to True, `path` will be translated to its real absolute path, using
+  the local path separator.
+
+  `other_projects` is a tuple containing the name of the projects that are 
+  also referring to this file in their own RECORD file (same path).
+
+  If `other_projects` is empty, it means that the file is only referred by the
+  current project. In other words, it can be removed if the project is removed.
+
+- get_egg_info_file(project_name, path, binary=False) -> file object or None
+
+  Uses `get_egg_info` and gets any element inside the directory,
+  pointed by its relative path. `get_egg_info_file` will perform
+  an `os.path.join` on `get_egg_info(project_name)` and `path` to build the 
+  whole path. 
+
+  `path` can be a '/'-separated path or can use the local separator. 
+  `get_egg_info_file` will automatically convert it using the platform path 
+  separator, to look for the file.
+
+  If `binary` is set True, the file will be opened using the binary mode.
+
+Let's use it with our `zlib` example::
+
+    >>> from pkgutil import (get_egg_info, get_metadata, get_egg_info_file, 
+    ...                      get_files)
+    >>> get_egg_info('zlib')
+    '/opt/local/lib/python2.6/site-packages/zlib-2.5.2.egg-info'
+    >>> metadata = get_metadata('zlib')
+    >>> metadata.version
+    '2.5.2'
+    >>> get_egg_info_file('zlib', 'PKG-INFO').read()
+    some
+    ...
+    files
+    >>> for path, hash, size, other_projects in get_files('zlib'):
+    ...     print '%s %s %d %s' % (path, hash, size, ','.join(other_projects))
+    ...
+    zlib/include/zconf.h b690274f621402dda63bf11ba5373bf2 9544
+    zlib/include/zlib.h 9c4b84aff68aa55f2e9bf70481b94333 66188
+    zlib/lib/libz.a e6d43fb94292411909404b07d0692d46 91128 
+    zlib/share/man/man3/zlib.3 785dc03452f0508ff0678fba2457e0ba 4486 
+    zlib-2.5.2.egg-info/PKG-INFO 6fe57de576d749536082d8e205b77748 195 
+    zlib-2.5.2.egg-info/RECORD None None 
+
+
+Adding an Uninstall function
+============================
+
+Distutils provides a very basic way to install a project, which is running
+the `install` command over the `setup.py` script of the distribution.
+
+Distutils will provide a very basic ``uninstall`` function, that will be added 
+in ``distutils.util`` and will take the name of the project to uninstall as 
+its argument. ``uninstall`` will use ``pkgutil.get_files`` and remove all 
+unique files, as long as their hash didn't change. Then it will remove
+directories where it removed the last elements.
+
+``uninstall`` will return a list of uninstalled files::
+
+    >>> from distutils.util import uninstall
+    >>> uninstall('zlib')
+    ['/opt/local/lib/python2.6/site-packages/zlib/file1',
+     '/opt/local/lib/python2.6/site-packages/zlib/file2']
+
+If the project is not found, a ``DistutilsUninstallError`` will be raised.
+
+To make it a reference API for third-party projects that wish to control 
+how `uninstall` works, a second callable argument can be used. It will be 
+called for each file that is removed. If the callable returns `True`, the 
+file will be removed. If it returns False, it will be left alone.
+
+Examples::
+
+    >>> def _remove_and_log(path):
+    ...     logging.info('Removing %s' % path)
+    ...     return True
+    ...
+    >>> uninstall('zlib', _remove_and_log)
+
+    >>> def _dry_run(path):
+    ...     logging.info('Removing %s (dry run)' % path)
+    ...     return False
+    ...
+    >>> uninstall('zlib', _dry_run)
+
+Of course, a third-party tool can use ``pkgutil.get_files``, to implement 
+its own uninstall feature.
+
+Backward compatibility and roadmap
+==================================
+
+These changes will not introduce any compatibility problems with the previous
+version of Distutils, and will also work with existing third-party tools.
+
+Although, a backport of the new Distutils for 2.5, 2.6, 3.0 and 3.1 will be
+provided so people can benefit from these new features.
+
+The plan is to integrate them for Python 2.7 and Python 3.2
+
+References
+==========
+
+.. [#pep262]
+   http://www.python.org/dev/peps/pep-0262
+
+.. [#pep314]
+   http://www.python.org/dev/peps/pep-0314
+
+.. [#setuptools]
+   http://peak.telecommunity.com/DevCenter/setuptools
+
+.. [#pip]
+   http://pypi.python.org/pypi/pip
+
+Aknowledgments
+==============
+
+Jim Fulton, Ian Bicking, Phillip Eby, and many people at Pycon and Distutils-SIG.
+
+Copyright
+=========
+
+This document has been placed in the public domain.
+
+
+
+..
+   Local Variables:
+   mode: indented-text
+   indent-tabs-mode: nil
+   sentence-end-double-space: t
+   fill-column: 70
+   coding: utf-8
+   End:
+# -*- coding: utf8 -*-
+""" PEP 376
+"""
+import os
+from os.path import join, splitext, isdir
+from os import listdir
+from string import maketrans
+import csv
+import sys
+import re
+
+from distutils.dist  import  DistributionMetadata
+
+#
+# distutils.dist.DistributionMetadata new version
+#
+class _DistributionMetadata(DistributionMetadata):
+    """distutils.dist.DistributionMetadata new version
+
+    That can load an existing PKG-INFO file
+    """
+    def __init__ (self, file=None):
+        if file is not None:
+            self.read_pkg_file(file)
+        else:
+            self.name = None
+            self.version = None
+            self.author = None
+            self.author_email = None
+            self.maintainer = None
+            self.maintainer_email = None
+            self.url = None
+            self.license = None
+            self.description = None
+            self.long_description = None
+            self.keywords = None
+            self.platforms = None
+            self.classifiers = None
+            self.download_url = None
+            # PEP 314
+            self.provides = None
+            self.requires = None
+            self.obsoletes = None
+
+    def read_pkg_file(self, file):
+        """Reads from a PKG-INFO file object and initialize the instance.
+        """
+        if isinstance(file, str):
+            file = open(file, 'rU')
+
+        pkg_info = file.read()
+        re_options = re.I|re.DOTALL|re.M
+
+        def _extract(fieldname):
+            if fieldname == 'Description':
+                # crappy, need to be reworked
+                pattern = r'^Description: (.*)'
+                res = re.findall(pattern, pkg_info , re_options)
+                if len(res) == 0:
+                    return 'UNKNOWN'
+                else:
+                    res = res[0].split('\n' + 8*' ')
+                    res = [r for r in res if not r.startswith('\n')]
+                    return '\n'.join(res) + '\n'
+
+            pattern = r'^%s: (.*?)$' % fieldname
+            res = re.findall(pattern, pkg_info , re_options)
+            if fieldname in ('Classifier', 'Requires', 'Provides',
+                             'Obsolete'):
+                return res
+            if len(res) == 0:
+                return 'UNKNOWN'
+            return res[0]
+
+        version = _extract('Metadata-Version')
+        self.name = _extract('Name')
+        self.version = _extract('Version')
+        self.summary = _extract('Summary')
+        self.url = _extract('Home-page')
+        self.author = _extract('Author')
+        self.author_email = _extract('Author-email')
+        self.license = _extract('License')
+        self.download_url = _extract('Download-URL')
+        self.long_description = _extract('Description')
+        self.keywords = _extract('Keywords').split(',')
+        self.classifiers = _extract('Classifier')
+        self.platform = _extract('Platform')
+
+        # PEP 314
+        if version == '1.1':
+            self.requires = _extract('Requires')
+            self.provides = _extract('Provides')
+            self.obsoletes = _extract('Obsoletes')
+        else:
+            self.requires = None
+            self.provides = None
+            self.obsoletes = None
+
+
+SEP_TRANS = maketrans('/', os.path.sep)
+
+#
+# EggInfo class (with DistributionMetadata in it)
+#
+class EggInfo(object):
+
+    def __init__(self, path):
+        self.info_path = path
+        self.pkg_info_path = join(path, 'PKG-INFO')
+        self.record_path = join(path, 'RECORD')
+        self.metadata = _DistributionMetadata(self.pkg_info_path)
+        self.name = self.metadata.name
+        self._files = None
+
+    def __str__(self):
+        return "EggInfo('%s')" % self.name
+
+    def _read_record(self):
+        """Reads RECORD."""
+        files = []
+        for row in csv.reader(open(self.record_path)):
+            if row == []:
+                continue
+            location = row[0]
+            md5 = len(row) > 1 and row[1] or None
+            size = len(row) > 2 and row[2] or None
+            files.append((location, md5, size ))
+        return files
+
+    def get_installed_files(self, local=False):
+        """Iterates over the RECORD entries."""
+        # the file is open once and kept in the object memory
+        # to avoid spurious I/O accesses
+        if self._files is None:
+            self._files = self._read_record()
+
+        # returning cross-platform *or* local paths
+        for location, md5, size  in self._files:
+            if local:
+                location = location.translate(SEP_TRANS)
+                location = join(self.info_path, location)
+            yield location, md5, size
+
+    def uses(self, path, local=False):
+        """Returns True is the path is listed in the RECORD file.
+
+        e.g. if the project uses this file.
+        """
+        for location, md5, size in self.get_installed_files(local):
+            if location == path:
+                return True
+        return False
+
+    def owns(self, path, local=False):
+        """Returns True is the path is listed in the RECORD file and nowhere
+        else.
+
+        e.g. if the project uses this file.
+        """
+        if not self.uses(path):
+            return False
+
+        for egg_info in get_egg_infos():
+            if egg_info is not self and egg_info.uses(path, local):
+                return False
+
+        return True
+
+    def get_file(self, path, binary=False):
+        """Returns a file instance on the path.
+
+        If binary is True, opens the file in binary mode.
+        """
+        if os.path.sep != '/':
+            path = path.translate(SEP_TRANS)
+        fullpath = join(self.info_path, path)
+        return open(fullpath, binary and 'rb' or 'r')
+
+#
+# cache managment
+#
+
+_EGG_INFO_CACHE = {}
+_CACHE_ENABLED = True
+
+def purge_cache():
+    global _EGG_INFO_CACHE
+    _EGG_INFO_CACHE = {}
+
+def enable_cache():
+    global _CACHE_ENABLED
+    _CACHE_ENABLED = True
+
+def disable_cache():
+    global _CACHE_ENABLED
+    _CACHE_ENABLED = True
+
+#
+# .egg-info finders
+#
+
+def _is_egg_info(path):
+    """Returns True if `path` is an egg-info directory.
+
+    Also makes sure it doesn't pick older versions by checking
+    the presence of `RECORD` and `PKG-INFO`.
+    """
+    if not (splitext(path)[-1].lower() == '.egg-info' and isdir(path)):
+        return False
+    content = os.listdir(path)
+    return 'PKG-INFO' in content and 'RECORD' in content
+
+def _egg_info_dirs(path):
+    """Returns the EGG-INFO directories found in `path`."""
+    if _is_egg_info(path):
+        yield path
+    elif isdir(path):
+        for element in os.listdir(path):
+            fullpath = join(path, element)
+            if _is_egg_info(fullpath):
+                yield fullpath
+
+def get_egg_infos():
+    """Iterates on all .egg-info directories founded in sys.path.
+
+    Each returned element is an EggInfo instance.
+    Uses a memory cache to minimize I/O access.
+    """
+    for path in sys.path:
+        if _CACHE_ENABLED and path in _EGG_INFO_CACHE:
+            for egg_info in _EGG_INFO_CACHE[path]:
+                yield egg_info
+        else:
+            egg_infos = []
+            for egg_info_dir in _egg_info_dirs(path):
+                egg_info = EggInfo(egg_info_dir)
+                if _CACHE_ENABLED:
+                    egg_infos.append(egg_info)
+                yield egg_info
+            # the cache is created only if all elements have been
+            # iterated through
+            if _CACHE_ENABLED:
+                _EGG_INFO_CACHE[path] = egg_infos
+
+def get_egg_info(project_name):
+    """Returns an EggInfo instance for the given project name.
+
+    If not found, returns None.
+    """
+    for project in get_egg_infos():
+        if project.name == project_name:
+            return project
+
+#
+# helper for the uninstall feature
+#
+
+def get_file_users(path, local=False):
+    """Iterates over all projects to find out which project uses the file.
+
+    Return EggInfo instances.
+    """
+    for egg_info in get_egg_infos():
+        if egg_info.uses(path, local):
+            yield egg_info
+

site-packages/mercurial-1.0.1.egg-info/PKG-INFO

+Metadata-Version: 1.0
+Name: mercurial
+Version: 1.0.1
+Summary: Scalable distributed SCM
+Home-page: http://selenic.com/mercurial
+Author: Matt Mackall
+Author-email: mpm@selenic.com
+License: GNU GPL
+Description: UNKNOWN
+Platform: UNKNOWN

site-packages/mercurial-1.0.1.egg-info/RECORD

+mercurial/filelog.py,98676876876876,12
+mercurial/filelog.pyc,98676876876876,1
+mercurial-1.0.1.egg-info/PKG_INFO,98676876876876,12
+mercurial-1.0.1.egg-info/RECORD

site-packages/mercurial/filelog.py

+# filelog.py - file history class for mercurial
+#
+# Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
+#
+# This software may be used and distributed according to the terms
+# of the GNU General Public License, incorporated herein by reference.
+
+from node import bin, nullid
+from revlog import revlog
+
+class filelog(revlog):
+    def __init__(self, opener, path):
+        revlog.__init__(self, opener,
+                        "/".join(("data", self.encodedir(path + ".i"))))
+
+    # This avoids a collision between a file named foo and a dir named
+    # foo.i or foo.d
+    def encodedir(self, path):
+        return (path
+                .replace(".hg/", ".hg.hg/")
+                .replace(".i/", ".i.hg/")
+                .replace(".d/", ".d.hg/"))
+
+    def decodedir(self, path):
+        return (path
+                .replace(".d.hg/", ".d/")
+                .replace(".i.hg/", ".i/")
+                .replace(".hg.hg/", ".hg/"))
+
+    def read(self, node):
+        t = self.revision(node)
+        if not t.startswith('\1\n'):
+            return t
+        s = t.index('\1\n', 2)
+        return t[s+2:]
+
+    def _readmeta(self, node):
+        t = self.revision(node)
+        if not t.startswith('\1\n'):
+            return {}
+        s = t.index('\1\n', 2)
+        mt = t[2:s]
+        m = {}
+        for l in mt.splitlines():
+            k, v = l.split(": ", 1)
+            m[k] = v
+        return m
+
+    def add(self, text, meta, transaction, link, p1=None, p2=None):
+        if meta or text.startswith('\1\n'):
+            mt = ""
+            if meta:
+                mt = [ "%s: %s\n" % (k, v) for k,v in meta.items() ]
+            text = "\1\n%s\1\n%s" % ("".join(mt), text)
+        return self.addrevision(text, transaction, link, p1, p2)
+
+    def renamed(self, node):
+        if self.parents(node)[0] != nullid:
+            return False
+        m = self._readmeta(node)
+        if m and "copy" in m:
+            return (m["copy"], bin(m["copyrev"]))
+        return False
+
+    def size(self, rev):
+        """return the size of a given revision"""
+
+        # for revisions with renames, we have to go the slow way
+        node = self.node(rev)
+        if self.renamed(node):
+            return len(self.read(node))
+
+        return revlog.size(self, rev)
+
+    def cmp(self, node, text):
+        """compare text with a given file revision"""
+
+        # for renames, we have to go the slow way
+        if self.renamed(node):
+            t2 = self.read(node)
+            return t2 != text
+
+        return revlog.cmp(self, node, text)

site-packages/mercurial/filelog.pyc

Binary file added.

site-packages/processing-0.52.egg-info/PKG-INFO

+Metadata-Version: 1.0
+Name: processing
+Version: 0.52
+Summary: Package for using processes which mimics the threading module
+Home-page: http://developer.berlios.de/projects/pyprocessing
+Author: R Oudkerk
+Author-email: roudkerk at users.berlios.de
+License: BSD Licence
+Description: `processing` is a package for the Python language which supports the
+        spawning of processes using the API of the standard library's
+        `threading` module.  It runs on both Unix and Windows.
+        
+        Features:
+        
+        * Objects can be transferred between processes using pipes or
+        multi-producer/multi-consumer queues.
+        
+        * Objects can be shared between processes using a server process or
+        (for simple data) shared memory.
+        
+        * Equivalents of all the synchronization primitives in `threading`
+        are available.
+        
+        * A `Pool` class makes it easy to submit tasks to a pool of worker
+        processes.
+        
+        
+        Links
+        =====
+        
+        * `Documentation <http://pyprocessing.berlios.de/doc/index.html>`_
+        * `Installation instructions <http://pyprocessing.berlios.de/doc/INSTALL.html>`_
+        * `Changelog <http://pyprocessing.berlios.de/doc/CHANGES.html>`_
+        * `Acknowledgments <http://pyprocessing.berlios.de/doc/THANKS.html>`_
+        * `BSD Licence <http://pyprocessing.berlios.de/doc/COPYING.html>`_
+        
+        The project is hosted at
+        
+        *    http://developer.berlios.de/projects/pyprocessing
+        
+        The package can be downloaded from
+        
+        *    http://developer.berlios.de/project/filelist.php?group_id=9001 or
+        *    http://pypi.python.org/pypi/processing
+        
+        
+        Examples
+        ========
+        
+        The `processing.Process` class follows the API of `threading.Thread`.
+        For example ::
+        
+        from processing import Process, Queue
+        
+        def f(q):
+        q.put('hello world')
+        
+        if __name__ == '__main__':
+        q = Queue()
+        p = Process(target=f, args=[q])
+        p.start()
+        print q.get()
+        p.join()
+        
+        Synchronization primitives like locks, semaphores and conditions are
+        available, for example ::
+        
+        >>> from processing import Condition
+        >>> c = Condition()
+        >>> print c
+        <Condition(<RLock(None, 0)>), 0>
+        >>> c.acquire()
+        True
+        >>> print c
+        <Condition(<RLock(MainProcess, 1)>), 0>
+        
+        One can also use a manager to create shared objects either in shared
+        memory or in a server process, for example ::
+        
+        >>> from processing import Manager
+        >>> manager = Manager()
+        >>> l = manager.list(range(10))
+        >>> l.reverse()
+        >>> print l
+        [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
+        >>> print repr(l)
+        <Proxy[list] object at 0x00E1B3B0>
+        
+        Tasks can be offloaded to a pool of worker processes in various ways,
+        for example ::
+        
+        >>> from processing import Pool
+        >>> def f(x): return x*x
+        ...
+        >>> p = Pool(4)
+        >>> result = p.mapAsync(f, range(10))
+        >>> print result.get(timeout=1)
+        [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
+        
+        
+        
+Platform: Unix and Windows
+Classifier: Development Status :: 4 - Beta
+Classifier: Intended Audience :: Developers
+Classifier: Programming Language :: Python

site-packages/processing-0.52.egg-info/RECORD

+processing/__init__.py,98676876876876,12
+processing-0.52.egg-info/PKG_INFO,98676876876876,12
+processing-0.52.egg-info/RECORD
+mercurial/filelog.py,98676876876876,12
+

site-packages/processing/__init__.py

Empty file added.
+from nose.tools import *
+from pkgutil import *
+import sys
+import os
+
+SITE_PKG = os.path.join(os.path.dirname(__file__), 'site-packages')
+
+def setup():
+    sys.old = sys.path
+    sys.path = [SITE_PKG]
+
+def teardown():
+    sys.path = sys.old
+    del sys.old
+
+def test_get_egg_infos():
+    projects = list(get_egg_infos())
+    assert_equals(len(projects), 2)
+
+def test_get_egg_info():
+    assert_equals(get_egg_info('xxx'), None)
+
+    project = get_egg_info('mercurial')
+    assert_equals(project.name, 'mercurial')
+
+    project = get_egg_info('processing')
+    assert_equals(project.name, 'processing')
+
+def test_egg_info():
+
+    egg_info = get_egg_info('mercurial')
+    assert_equals(str(egg_info), "EggInfo('mercurial')")
+
+    files = list(egg_info.get_installed_files())
+    assert_equals(len(files), 4)
+    assert_equals(files[0], ('mercurial/filelog.py', '98676876876876', '12'))
+
+    files = list(egg_info.get_installed_files(local=True))
+    location = os.path.join(egg_info.info_path, 'mercurial', 'filelog.py')
+    assert_equals(files[0], (location, '98676876876876', '12'))
+
+    f = egg_info.get_file('RECORD')
+    record = os.path.join(SITE_PKG, 'mercurial-1.0.1.egg-info', 'RECORD')
+    assert_equals(open(record).read(), f.read())
+
+    assert egg_info.uses('mercurial/filelog.py')
+    assert not egg_info.uses('mercurial/filelog.sasasasa')
+    assert egg_info.owns('mercurial/filelog.pyc')
+    assert not egg_info.owns('mercurial/filelog.py')
+
+def test_get_file_users():
+
+    users = list(get_file_users('mercurial/filelog.py'))
+    assert_equals(len(users), 2)
+