Commits

Daniel Holth committed 099352e

improve test_requires parsing, add entry_points.txt to json

Comments (0)

Files changed (4)

+0.22.0
+======
+- Include entry_points.txt, scripts a.k.a. commands, in experimental
+  pydist.json
+- Improved test_requires parsing
+- Python 2.6 fixes, "wheel version" command courtesy pombredanne
+
 0.21.0
 ======
 - Pregenerated scripts are the default again.

wheel/metadata.py

 from .pkginfo import read_pkg_info
 
 import re
-import os
+import os.path
 import textwrap
 import pkg_resources
 import email.parser
             package = value
         key = MayRequiresKey(condition, extra)
         may_requires[key].append(package)
-    
+
     if may_requires:
         metadata['run_requires'] = []
         for key, value in may_requires.items():
             if key.condition:
                 may_requirement['environment'] = key.condition
             metadata['run_requires'].append(may_requirement)
-        
+
         if not 'extras' in metadata:
             metadata['extras'] = []
         metadata['extras'].extend([key.extra for key in may_requires.keys() if key.extra])
         if low_key in PLURAL_FIELDS:
             metadata[PLURAL_FIELDS[low_key]] = pkg_info.get_all(key)
 
-        elif low_key == "requires_dist":            
+        elif low_key == "requires_dist":
             handle_requires(metadata, pkg_info, key)
 
         elif low_key == 'provides_extra':
         for requires, attr in (('test_requires', 'tests_require'),):
             try:
                 requirements = getattr(distribution, attr)
-                if requirements:
-                    metadata[requires] = [{'requires':requirements}]
+                if isinstance(requirements, list):
+                    new_requirements = list(convert_requirements(requirements))
+                    metadata[requires] = [{'requires':new_requirements}]
             except AttributeError:
                 pass
 
     if contacts:
         metadata['contacts'] = contacts
 
+    # convert entry points to exports
+    try:
+        with file(os.path.join(os.path.dirname(path), "entry_points.txt"), "r") as ep_file:
+            ep_map = pkg_resources.EntryPoint.parse_map(ep_file.read())
+        exports = {}
+        for group, items in ep_map.items():
+            exports[group] = {}
+            for item in items.values():
+                name, export = str(item).split(' = ', 1)
+                exports[group][name] = export
+        if exports:
+            metadata['exports'] = exports
+    except IOError:
+        pass
+
+    # copy console_scripts entry points to commands
+    if 'exports' in metadata:
+        for (ep_script, wrap_script) in (('console_scripts', 'wrap_console'),
+                                         ('gui_scripts', 'wrap_gui')):
+            if ep_script in metadata['exports']:
+                metadata['commands'] = metadata.get('commands', {})
+                metadata['commands'][wrap_script] = metadata['exports'][ep_script]
+
     return metadata
 
-
 def requires_to_requires_dist(requirement):
     """Compose the version predicates for requirement in PEP 345 fashion."""
     requires_dist = []
         return ''
     return " (%s)" % ','.join(requires_dist)
 
+def convert_requirements(requirements):
+    """Yield Requires-Dist: strings for parsed requirements strings."""
+    for req in requirements:
+        parsed_requirement = pkg_resources.Requirement.parse(req)
+        spec = requires_to_requires_dist(parsed_requirement)
+        extras = ",".join(parsed_requirement.extras)
+        if extras:
+            extras = "[%s]" % extras
+        yield (parsed_requirement.project_name + extras + spec)
 
 def pkginfo_to_metadata(egg_info_path, pkginfo_path):
     """
             if extra:
                 pkg_info['Provides-Extra'] = extra
                 condition = '; extra == %s' % repr(extra)
-            for req in reqs:
-                parsed_requirement = pkg_resources.Requirement.parse(req)
-                spec = requires_to_requires_dist(parsed_requirement)
-                extras = ",".join(parsed_requirement.extras)
-                if extras:
-                    extras = "[%s]" % extras
-                pkg_info['Requires-Dist'] = (parsed_requirement.project_name
-                                             + extras
-                                             + spec
-                                             + condition)
+            for new_req in convert_requirements(reqs):
+                pkg_info['Requires-Dist'] = new_req + condition
 
     description = pkg_info['Description']
     if description:

wheel/test/complex-dist/setup.py

       setup_requires=["wheel", "setuptools"],
       install_requires=["quux", "splort"],
       extras_require={'simple':['simple.dist']},
-      tests_require=["foo", "bar"],
+      tests_require=["foo", "bar>=10.0.0"],
       entry_points={'console_scripts':['complex-dist=complexdist:main']}
       )
 

wheel/test/pydist-schema.json

     "name": {
       "description": "The name of the distribution.",
       "type": "string",
-      "$ref": "#/definitions/valid_name"
+      "$ref": "#/definitions/distribution_name"
     },
     "version": {
       "description": "The distribution's public version identifier",
         "$ref": "#/definitions/provides_declaration"
       }
     },
+    "modules": {
+      "description": "A list of modules and/or packages available for import after installing this distribution.",
+      "type": "array",
+      "items": {
+        "type": "string",
+        "$ref": "#/definitions/qualified_name"
+      }
+    },
+    "namespaces": {
+      "description": "A list of namespace packages this distribution contributes to",
+      "type": "array",
+      "items": {
+        "type": "string",
+        "$ref": "#/definitions/qualified_name"
+      }
+    },
+    "commands": {
+      "description": "Command line interfaces provided by this distribution",
+      "type": "object",
+      "$ref": "#/definitions/commands"
+    },
+    "exports": {
+      "description": "Other exported interfaces provided by this distribution",
+      "type": "object",
+      "$ref": "#/definitions/exports"
+    },
     "obsoleted_by": {
       "description": "A string that indicates that this project is no longer being developed. The named project provides a substitute or replacement.",
       "type": "string",
       "properties": {
         "postinstall": {
           "type": "string",
-          "$ref": "#/definitions/entry_point"
+          "$ref": "#/definitions/export_specifier"
         },
         "preuninstall": {
           "type": "string",
-          "$ref": "#/definitions/entry_point"
+          "$ref": "#/definitions/export_specifier"
         }
       }
     },
     "extensions": {
       "description": "Extensions to the metadata may be present in a mapping under the 'extensions' key.",
-      "type": "object"
+      "type": "object",
+      "$ref": "#/definitions/extensions"
     }
   },
 
       "properties": {
         "extra": {
           "type": "string",
-          "$ref": "#/definitions/valid_name"
+          "$ref": "#/definitions/extra_name"
         },
         "environment": {
           "type": "string",
       "required": ["requires"],
       "additionalProperties": false
     },
-    "valid_name": {
+    "commands": {
+      "type": "object",
+      "properties": {
+        "wrap_console": {
+          "type": "object",
+          "$ref": "#/definitions/command_map"
+        },
+        "wrap_gui": {
+          "type": "object",
+          "$ref": "#/definitions/command_map"
+        },
+        "prebuilt": {
+          "type": "array",
+          "items": {
+            "type": "string",
+            "$ref": "#/definitions/relative_path"
+          }
+        }
+      },
+      "additionalProperties": false
+    },
+    "exports": {
+      "type": "object",
+      "patternProperties": {
+        "^[A-Za-z][0-9A-Za-z_]*([.][0-9A-Za-z_]*)*$": {
+          "type": "object",
+          "patternProperties": {
+            ".": {
+              "type": "string",
+              "$ref": "#/definitions/export_specifier"
+            }
+          },
+          "additionalProperties": false
+        }
+      },
+      "additionalProperties": false
+    },
+    "extensions": {
+      "type": "object",
+      "patternProperties": {
+        "^[A-Za-z][0-9A-Za-z_]*([.][0-9A-Za-z_]*)*$": {}
+      },
+      "additionalProperties": false
+    },
+    "command_map": {
+      "type": "object",
+      "patternProperties": {
+        "^[0-9A-Za-z]([0-9A-Za-z_.-]*[0-9A-Za-z])?$": {
+          "type": "string",
+          "$ref": "#/definitions/export_specifier"
+        }
+      },
+      "additionalProperties": false
+    },
+    "distribution_name": {
         "type": "string",
         "pattern": "^[0-9A-Za-z]([0-9A-Za-z_.-]*[0-9A-Za-z])?$"
     },
     "environment_marker": {
         "type": "string"
     },
-    "entry_point": {
-        "type": "string"
-    },
     "document_name": {
         "type": "string"
     },
     "extra_name" : {
+        "type": "string",
+        "pattern": "^[0-9A-Za-z]([0-9A-Za-z_.-]*[0-9A-Za-z])?$"
+    },
+    "relative_path" : {
         "type": "string"
+    },
+    "export_specifier": {
+      "type": "string",
+      "pattern": "^([A-Za-z_][A-Za-z_0-9]*([.][A-Za-z_][A-Za-z_0-9]*)*)(:[A-Za-z_][A-Za-z_0-9]*([.][A-Za-z_][A-Za-z_0-9]*)*)?(\\[[0-9A-Za-z]([0-9A-Za-z_.-]*[0-9A-Za-z])?\\])?$"
+    },
+    "qualified_name" : {
+        "type": "string",
+        "pattern": "^[A-Za-z_][A-Za-z_0-9]*([.][A-Za-z_][A-Za-z_0-9]*)*$"
+    },
+    "prefixed_name" : {
+        "type": "string",
+        "pattern": "^[A-Za-z_][A-Za-z_0-9]*([.][A-Za-z_0-9]*)*$"
     }
   }
 }