Skip to content

Commit bd70867

Browse files
rakesh balusapombredanne
authored andcommitted
#253 Recognize python wheels as packages
Signed-off-by: Philippe Ombredanne <[email protected]>
1 parent 7025368 commit bd70867

File tree

5 files changed

+141
-14
lines changed

5 files changed

+141
-14
lines changed

src/packagedcode/pypi.py

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#
2-
# Copyright (c) 2015 nexB Inc. and others. All rights reserved.
2+
# Copyright (c) 2016 nexB Inc. and others. All rights reserved.
33
# http://nexb.com and https://github.com/nexB/scancode-toolkit/
44
# The ScanCode software is licensed under the Apache License version 2.0.
55
# Data generated with ScanCode require an acknowledgment.
@@ -25,12 +25,16 @@
2525
from __future__ import absolute_import
2626
from __future__ import print_function
2727

28+
import json
2829
import logging
30+
import os
2931
import re
3032

33+
from commoncode import fileutils
3134
from packagedcode.models import AssertedLicense
3235
from packagedcode.models import PythonPackage
3336

37+
3438
"""
3539
Handle Python PyPi packages
3640
"""
@@ -54,9 +58,8 @@ def get_attribute(setup_location, attribute):
5458
'requests' is returned for the attribute 'name'
5559
"""
5660
setup_text = open(setup_location, 'rb').read()
57-
setup_text = setup_text.replace('\n', '')
5861
# FIXME Use a valid parser for parsing 'setup.py'
59-
values = re.findall('setup\(.*?'+attribute+'=[\"\']{1}.*?\',', setup_text)
62+
values = re.findall('setup\(.*?'+attribute+'=[\"\']{1}.*?\',', setup_text.replace('\n', ''))
6063
if len(values) > 1:
6164
return
6265
else:
@@ -68,18 +71,47 @@ def get_attribute(setup_location, attribute):
6871
return output
6972

7073

74+
def parse_metadata(location):
75+
parent_dir = fileutils.parent_directory(location)
76+
if os.path.exists(os.path.join(parent_dir, 'METADATA')) and os.path.exists(os.path.join(parent_dir, 'DESCRIPTION.rst')):
77+
infos = json.loads(open(location, 'rb').read())
78+
homepage_url = None
79+
authors = []
80+
if infos['extensions']:
81+
try:
82+
homepage_url = infos['extensions']['python.details']['project_urls']['Home']
83+
except:
84+
pass
85+
try:
86+
for contact in infos['extensions']['python.details']['contacts']:
87+
authors.append(contact['name'])
88+
except:
89+
pass
90+
package = PythonPackage(
91+
name=infos.get('name'),
92+
version=infos.get('version'),
93+
summary=infos.get('summary'),
94+
asserted_licenses=[AssertedLicense(license=infos.get('license'))],
95+
homepage_url=homepage_url,
96+
authors=authors,
97+
)
98+
return package
99+
100+
71101
def parse(location):
72102
"""
73103
Parse a 'setup.py' and return a PythonPackage object.
74104
"""
75-
if not location.endswith('setup.py'):
76-
return
77-
package = PythonPackage(
78-
name=get_attribute(location, 'name'),
79-
homepage_url=get_attribute(location, 'url'),
80-
description=get_attribute(location, 'description'),
81-
version=get_attribute(location, 'version'),
82-
authors=[get_attribute(location, 'author')],
83-
asserted_licenses=[AssertedLicense(license=get_attribute(location, 'license'))],
84-
)
85-
return package
105+
file_name = fileutils.file_name(location)
106+
if file_name == 'setup.py':
107+
package = PythonPackage(
108+
name=get_attribute(location, 'name'),
109+
homepage_url=get_attribute(location, 'url'),
110+
description=get_attribute(location, 'description'),
111+
version=get_attribute(location, 'version'),
112+
authors=[get_attribute(location, 'author')],
113+
asserted_licenses=[AssertedLicense(license=get_attribute(location, 'license'))],
114+
)
115+
return package
116+
if file_name == 'metadata.json':
117+
parse_metadata(location)
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
Six is a Python 2 and 3 compatibility library. It provides utility functions
2+
for smoothing over the differences between the Python versions with the goal of
3+
writing Python code that is compatible on both Python versions. See the
4+
documentation for more information on what is provided.
5+
6+
Six supports every Python version since 2.6. It is contained in only one Python
7+
file, so it can be easily copied into your project. (The copyright and license
8+
notice must be retained.)
9+
10+
Online documentation is at https://pythonhosted.org/six/.
11+
12+
Bugs can be reported to https://bitbucket.org/gutworth/six. The code can also
13+
be found there.
14+
15+
For questions about six or porting in general, email the python-porting mailing
16+
list: https://mail.python.org/mailman/listinfo/python-porting
17+
18+
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
Metadata-Version: 2.0
2+
Name: six
3+
Version: 1.10.0
4+
Summary: Python 2 and 3 compatibility utilities
5+
Home-page: http://pypi.python.org/pypi/six/
6+
Author: Benjamin Peterson
7+
Author-email: [email protected]
8+
License: MIT
9+
Platform: UNKNOWN
10+
Classifier: Programming Language :: Python :: 2
11+
Classifier: Programming Language :: Python :: 3
12+
Classifier: Intended Audience :: Developers
13+
Classifier: License :: OSI Approved :: MIT License
14+
Classifier: Topic :: Software Development :: Libraries
15+
Classifier: Topic :: Utilities
16+
17+
Six is a Python 2 and 3 compatibility library. It provides utility functions
18+
for smoothing over the differences between the Python versions with the goal of
19+
writing Python code that is compatible on both Python versions. See the
20+
documentation for more information on what is provided.
21+
22+
Six supports every Python version since 2.6. It is contained in only one Python
23+
file, so it can be easily copied into your project. (The copyright and license
24+
notice must be retained.)
25+
26+
Online documentation is at https://pythonhosted.org/six/.
27+
28+
Bugs can be reported to https://bitbucket.org/gutworth/six. The code can also
29+
be found there.
30+
31+
For questions about six or porting in general, email the python-porting mailing
32+
list: https://mail.python.org/mailman/listinfo/python-porting
33+
34+
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
{
2+
"generator": "bdist_wheel (0.26.0)",
3+
"summary": "Python 2 and 3 compatibility utilities",
4+
"classifiers": [
5+
"Programming Language :: Python :: 2",
6+
"Programming Language :: Python :: 3",
7+
"Intended Audience :: Developers",
8+
"License :: OSI Approved :: MIT License",
9+
"Topic :: Software Development :: Libraries",
10+
"Topic :: Utilities"
11+
],
12+
"extensions": {
13+
"python.details": {
14+
"project_urls": {
15+
"Home": "http://pypi.python.org/pypi/six/"
16+
},
17+
"contacts": [
18+
{
19+
"email": "[email protected]",
20+
"name": "Benjamin Peterson",
21+
"role": "author"
22+
}
23+
],
24+
"document_names": {
25+
"description": "DESCRIPTION.rst"
26+
}
27+
}
28+
},
29+
"license": "MIT",
30+
"metadata_version": "2.0",
31+
"name": "six",
32+
"version": "1.10.0"
33+
}

tests/packagedcode/test_pypi.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,13 @@ def test_get_attribute(self):
4949
assert 'scancode-toolkit' == pypi.get_attribute(test_file, 'name')
5050
assert '1.5.0' == pypi.get_attribute(test_file, 'version')
5151
assert 'ScanCode' == pypi.get_attribute(test_file, 'author')
52+
53+
def test_parse_metadata(self):
54+
test_file = self.get_test_loc('pypi/metadata.json')
55+
package = pypi.parse_metadata(test_file)
56+
assert 'six' == package.name
57+
assert '1.10.0' == package.version
58+
assert 'Python 2 and 3 compatibility utilities' == package.summary
59+
assert 'MIT' == package.asserted_licenses[0].license
60+
assert ['Benjamin Peterson'] == package.authors
61+
assert 'http://pypi.python.org/pypi/six/' == package.homepage_url

0 commit comments

Comments
 (0)