Skip to content

Commit 088e86a

Browse files
authored
Merge pull request #421 from nexB/253-python-packages
#253 python packages
2 parents 43773a0 + deda5e0 commit 088e86a

File tree

8 files changed

+597
-0
lines changed

8 files changed

+597
-0
lines changed

src/packagedcode/pypi.py

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
#
2+
# Copyright (c) 2016 nexB Inc. and others. All rights reserved.
3+
# http://nexb.com and https://github.com/nexB/scancode-toolkit/
4+
# The ScanCode software is licensed under the Apache License version 2.0.
5+
# Data generated with ScanCode require an acknowledgment.
6+
# ScanCode is a trademark of nexB Inc.
7+
#
8+
# You may not use this software except in compliance with the License.
9+
# You may obtain a copy of the License at: http://apache.org/licenses/LICENSE-2.0
10+
# Unless required by applicable law or agreed to in writing, software distributed
11+
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
12+
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
13+
# specific language governing permissions and limitations under the License.
14+
#
15+
# When you publish or redistribute any data created with ScanCode or any ScanCode
16+
# derivative work, you must accompany this data with the following acknowledgment:
17+
#
18+
# Generated with ScanCode and provided on an "AS IS" BASIS, WITHOUT WARRANTIES
19+
# OR CONDITIONS OF ANY KIND, either express or implied. No content created from
20+
# ScanCode should be considered or used as legal advice. Consult an Attorney
21+
# for any legal advice.
22+
# ScanCode is a free software code scanning tool from nexB Inc. and others.
23+
# Visit https://github.com/nexB/scancode-toolkit/ for support and download.
24+
25+
from __future__ import absolute_import
26+
from __future__ import print_function
27+
28+
import json
29+
import os
30+
import re
31+
32+
from commoncode import fileutils
33+
from packagedcode.models import AssertedLicense
34+
from packagedcode.models import PythonPackage
35+
from packagedcode import models
36+
37+
38+
"""
39+
Detect and collect Python packages information.
40+
"""
41+
42+
43+
PKG_INFO_ATTRIBUTES = [
44+
'Name',
45+
'Version',
46+
'Author',
47+
'Author-email',
48+
'License',
49+
'Description',
50+
'Platform',
51+
'Home-page',
52+
'Summary'
53+
]
54+
55+
56+
def parse_pkg_info(location):
57+
"""
58+
Return a Package from a a 'PKG-INFO' file at 'location' or None.
59+
"""
60+
if not location or not location.endswith('PKG-INFO'):
61+
return
62+
infos = {}
63+
# FIXME: wrap in a with statement
64+
pkg_info = open(location, 'rb').read()
65+
for attribute in PKG_INFO_ATTRIBUTES:
66+
# FIXME: what is this code doing? this is cryptic
67+
infos[attribute] = re.findall('^' + attribute + '[\s:]*.*', pkg_info, flags=re.MULTILINE)[0]
68+
infos[attribute] = re.sub('^' + attribute + '[\s:]*', '', infos[attribute], flags=re.MULTILINE)
69+
if infos[attribute] == 'UNKNOWN':
70+
infos[attribute] = None
71+
72+
package = PythonPackage(
73+
name=infos.get('Name'),
74+
version=infos.get('Version'),
75+
summary=infos.get('Summary'),
76+
homepage_url=infos.get('Home-page'),
77+
asserted_licenses=[AssertedLicense(license=infos.get('License'))],
78+
# FIXME: what about Party objects and email?
79+
# FIXME: what about maintainers?
80+
authors=[models.Party(type=models.party_person, name=infos.get('Author'))],
81+
)
82+
return package
83+
84+
85+
def get_attribute(location, attribute):
86+
"""
87+
Return the the value for an `attribute` if found in the 'setup.py' file at
88+
`location` or None.
89+
90+
For example with this setup.py file:
91+
setup(
92+
name='requests',
93+
version='1.0',
94+
)
95+
the value 'request' is returned for the attribute 'name'
96+
"""
97+
if not location or not location.endswith('setup.py'):
98+
return
99+
# FIXME: what if this is unicode text?
100+
# FIXME: wrap in a with statement
101+
setup_text = open(location, 'rb').read()
102+
# FIXME Use a valid parser for parsing 'setup.py'
103+
# FIXME: it does not make sense to reread a setup.py once for each attribute
104+
105+
# FIXME: what are these regex doing?
106+
values = re.findall('setup\(.*?' + attribute + '=[\"\']{1}.*?\',', setup_text.replace('\n', ''))
107+
if len(values) > 1 or len(values) == 0:
108+
return
109+
else:
110+
values = ''.join(values)
111+
output = re.sub('setup\(.*?' + attribute + '=[\"\']{1}', '', values)
112+
if output.endswith('\','):
113+
return output.replace('\',', '')
114+
else:
115+
return output
116+
117+
118+
def parse_metadata(location):
119+
"""
120+
Return a Package object from the Python wheel 'metadata.json' file at 'location'
121+
or None. Check if the parent directory of 'location' contains both a 'METADATA'
122+
and a 'DESCRIPTION.rst' file.
123+
"""
124+
if not location or not location.endswith('metadata.json'):
125+
return
126+
parent_dir = fileutils.parent_directory(location)
127+
# FIXME: is the absence of these two files a show stopper?
128+
if not all(os.path.exists(os.path.join(parent_dir, fname))
129+
for fname in ('METADATA', 'DESCRIPTION.rst')):
130+
return
131+
# FIXME: wrap in a with statement
132+
infos = json.loads(open(location, 'rb').read())
133+
print(infos)
134+
homepage_url = None
135+
authors = []
136+
if infos['extensions']:
137+
try:
138+
homepage_url = infos['extensions']['python.details']['project_urls']['Home']
139+
except:
140+
# FIXME: why catch all expections?
141+
pass
142+
try:
143+
for contact in infos['extensions']['python.details']['contacts']:
144+
authors.append(models.Party(type=models.party_person, name=contact['name'],))
145+
except:
146+
# FIXME: why catch all expections?
147+
pass
148+
149+
package = PythonPackage(
150+
name=infos.get('name'),
151+
version=infos.get('version'),
152+
summary=infos.get('summary'),
153+
asserted_licenses=[AssertedLicense(license=infos.get('license'))],
154+
homepage_url=homepage_url,
155+
authors=authors,
156+
)
157+
return package
158+
159+
160+
def parse(location):
161+
"""
162+
Return a Package built from parsing a file at 'location'
163+
The file name can be either a 'setup.py', 'metadata.json' or 'PKG-INFO' file.
164+
"""
165+
file_name = fileutils.file_name(location)
166+
if file_name == 'setup.py':
167+
package = PythonPackage(
168+
name=get_attribute(location, 'name'),
169+
homepage_url=get_attribute(location, 'url'),
170+
description=get_attribute(location, 'description'),
171+
version=get_attribute(location, 'version'),
172+
authors=[models.Party(type=models.party_person, name=get_attribute(location, 'author'))],
173+
asserted_licenses=[AssertedLicense(license=get_attribute(location, 'license'))],
174+
)
175+
return package
176+
if file_name == 'metadata.json':
177+
parse_metadata(location)
178+
if file_name == 'PKG-INFO':
179+
parse_pkg_info(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: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
Metadata-Version: 1.0
2+
Name: TicketImport
3+
Version: 0.7a
4+
Summary: Import CSV and Excel files
5+
Home-page: http://nexb.com
6+
Author: Francois Granade
7+
Author-email: [email protected]
8+
License: BSD
9+
Description: UNKNOWN
10+
Platform: UNKNOWN
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+
}

0 commit comments

Comments
 (0)