Skip to content

Commit 7025368

Browse files
rakesh balusapombredanne
authored andcommitted
#253 Recognize Python packages using setup.py files
Signed-off-by: Philippe Ombredanne <[email protected]>
1 parent 4574f3b commit 7025368

File tree

4 files changed

+384
-0
lines changed

4 files changed

+384
-0
lines changed

src/packagedcode/pypi.py

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
#
2+
# Copyright (c) 2015 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 logging
29+
import re
30+
31+
from packagedcode.models import AssertedLicense
32+
from packagedcode.models import PythonPackage
33+
34+
"""
35+
Handle Python PyPi packages
36+
"""
37+
38+
39+
logger = logging.getLogger(__name__)
40+
# import sys
41+
# logging.basicConfig(level=logging.DEBUG, stream=sys.stdout)
42+
# logger.setLevel(logging.DEBUG)
43+
44+
45+
def get_attribute(setup_location, attribute):
46+
"""
47+
Return the value specified for a given 'attribute' mentioned in a 'setup.py'
48+
file.
49+
Example :
50+
setup(
51+
name='requests',
52+
version='1.0',
53+
)
54+
'requests' is returned for the attribute 'name'
55+
"""
56+
setup_text = open(setup_location, 'rb').read()
57+
setup_text = setup_text.replace('\n', '')
58+
# FIXME Use a valid parser for parsing 'setup.py'
59+
values = re.findall('setup\(.*?'+attribute+'=[\"\']{1}.*?\',', setup_text)
60+
if len(values) > 1:
61+
return
62+
else:
63+
values = ''.join(values)
64+
output = re.sub('setup\(.*?'+attribute+'=[\"\']{1}', '', values)
65+
if output.endswith('\','):
66+
return output.replace('\',', '')
67+
else:
68+
return output
69+
70+
71+
def parse(location):
72+
"""
73+
Parse a 'setup.py' and return a PythonPackage object.
74+
"""
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
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
#!/usr/bin/env python
2+
# -*- encoding: utf-8 -*-
3+
from __future__ import absolute_import, print_function
4+
5+
import io
6+
import os
7+
import re
8+
from glob import glob
9+
from os.path import basename
10+
from os.path import dirname
11+
from os.path import join
12+
from os.path import splitext
13+
14+
from setuptools import find_packages
15+
from setuptools import setup
16+
17+
18+
def read(*names, **kwargs):
19+
return io.open(
20+
join(dirname(__file__), *names),
21+
encoding=kwargs.get('encoding', 'utf8')
22+
).read()
23+
24+
25+
long_description = '%s\n%s' % (
26+
read('README.rst'),
27+
re.sub(':obj:`~?(.*?)`', r'``\1``', read('CHANGELOG.rst'))
28+
)
29+
30+
setup(
31+
name='scancode-toolkit',
32+
version='1.5.0',
33+
license='Apache-2.0 with ScanCode acknowledgment and CC0-1.0 and others',
34+
description='ScanCode is a tool to scan code for license, copyright and other interesting facts.',
35+
long_description=long_description,
36+
author='ScanCode',
37+
author_email='[email protected]',
38+
url='https://github.com/nexB/scancode-toolkit',
39+
packages=find_packages('src'),
40+
package_dir={'': 'src'},
41+
py_modules=[splitext(basename(path))[0] for path in glob('src/*.py')],
42+
include_package_data=True,
43+
zip_safe=False,
44+
classifiers=[
45+
# complete classifier list: http://pypi.python.org/pypi?%3Aaction=list_classifiers
46+
'Development Status :: 4 - Beta',
47+
'Intended Audience :: Developers',
48+
'License :: OSI Approved :: Apache Software License',
49+
'License :: OSI Approved :: CC0',
50+
'Programming Language :: Python',
51+
'Programming Language :: Python :: 2.7',
52+
'Topic :: Utilities',
53+
],
54+
keywords=[
55+
'license', 'filetype', 'urn', 'date', 'codec',
56+
],
57+
install_requires=[
58+
# cluecode
59+
'py2-ipaddress >= 2.0, <3.0',
60+
'url >= 0.1.4',
61+
'publicsuffix2',
62+
# TODO: upgrade to nltk==3.0.1
63+
'nltk >= 2.0b4, <3.0.0',
64+
65+
# extractcode
66+
'patch >= 1.14.2, < 1.15 ',
67+
# to work around bug http://bugs.python.org/issue19839
68+
# on multistream bzip2 files
69+
'bz2file >= 0.98',
70+
71+
# licensedcode
72+
'PyYAML >= 3.0, <4.0',
73+
74+
# textcode
75+
'Beautifulsoup >= 3.2.0, <4.0.0',
76+
'Beautifulsoup4 >= 4.3.0, <5.0.0',
77+
'html5lib',
78+
'six',
79+
80+
# typecode and textcode
81+
'pygments >= 2.0.0, <3.0.0',
82+
'pdfminer >= 20140328',
83+
84+
# typecode
85+
'chardet >= 2.1.1, <3.0.0',
86+
'binaryornot >= 0.4.0',
87+
88+
# scancode and AboutCode
89+
'click >= 4.0.0, < 5.0.0',
90+
'jinja2 >= 2.7.0, < 3.0.0',
91+
'MarkupSafe >= 0.23',
92+
'colorama',
93+
94+
# AboutCode
95+
'about-code-tool >= 0.9.0',
96+
97+
# packagedcode
98+
'requests >= 2.7.0, < 3.0.0',
99+
],
100+
101+
extras_require={
102+
'base': [
103+
'certifi',
104+
'setuptools',
105+
'wheel',
106+
'pip',
107+
'wincertstore',
108+
],
109+
'dev': [
110+
'pytest',
111+
'execnet',
112+
'py',
113+
'pytest-xdist',
114+
'bumpversion',
115+
],
116+
117+
},
118+
entry_points={
119+
'console_scripts': [
120+
'scancode = scancode.cli:scancode',
121+
'extractcode = scancode.extract_cli:extractcode',
122+
],
123+
},
124+
)
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
#!/usr/bin/env python
2+
# -*- encoding: utf-8 -*-
3+
from __future__ import absolute_import, print_function
4+
5+
import io
6+
import os
7+
import re
8+
from glob import glob
9+
from os.path import basename
10+
from os.path import dirname
11+
from os.path import join
12+
from os.path import splitext
13+
14+
from setuptools import find_packages
15+
from setuptools import setup
16+
17+
18+
def read(*names, **kwargs):
19+
return io.open(
20+
join(dirname(__file__), *names),
21+
encoding=kwargs.get('encoding', 'utf8')
22+
).read()
23+
24+
25+
long_description = '%s\n%s' % (
26+
read('README.rst'),
27+
re.sub(':obj:`~?(.*?)`', r'``\1``', read('CHANGELOG.rst'))
28+
)
29+
30+
setup(
31+
name='scancode-toolkit',
32+
version='1.5.0',
33+
license='Apache-2.0 with ScanCode acknowledgment and CC0-1.0 and others',
34+
description='ScanCode is a tool to scan code for license, copyright and other interesting facts.',
35+
long_description=long_description,
36+
author='ScanCode',
37+
author_email='[email protected]',
38+
url='https://github.com/nexB/scancode-toolkit',
39+
packages=find_packages('src'),
40+
package_dir={'': 'src'},
41+
py_modules=[splitext(basename(path))[0] for path in glob('src/*.py')],
42+
include_package_data=True,
43+
zip_safe=False,
44+
classifiers=[
45+
# complete classifier list: http://pypi.python.org/pypi?%3Aaction=list_classifiers
46+
'Development Status :: 4 - Beta',
47+
'Intended Audience :: Developers',
48+
'License :: OSI Approved :: Apache Software License',
49+
'License :: OSI Approved :: CC0',
50+
'Programming Language :: Python',
51+
'Programming Language :: Python :: 2.7',
52+
'Topic :: Utilities',
53+
],
54+
keywords=[
55+
'license', 'filetype', 'urn', 'date', 'codec',
56+
],
57+
install_requires=[
58+
# cluecode
59+
'py2-ipaddress >= 2.0, <3.0',
60+
'url >= 0.1.4',
61+
'publicsuffix2',
62+
# TODO: upgrade to nltk==3.0.1
63+
'nltk >= 2.0b4, <3.0.0',
64+
65+
# extractcode
66+
'patch >= 1.14.2, < 1.15 ',
67+
# to work around bug http://bugs.python.org/issue19839
68+
# on multistream bzip2 files
69+
'bz2file >= 0.98',
70+
71+
# licensedcode
72+
'PyYAML >= 3.0, <4.0',
73+
74+
# textcode
75+
'Beautifulsoup >= 3.2.0, <4.0.0',
76+
'Beautifulsoup4 >= 4.3.0, <5.0.0',
77+
'html5lib',
78+
'six',
79+
80+
# typecode and textcode
81+
'pygments >= 2.0.0, <3.0.0',
82+
'pdfminer >= 20140328',
83+
84+
# typecode
85+
'chardet >= 2.1.1, <3.0.0',
86+
'binaryornot >= 0.4.0',
87+
88+
# scancode and AboutCode
89+
'click >= 4.0.0, < 5.0.0',
90+
'jinja2 >= 2.7.0, < 3.0.0',
91+
'MarkupSafe >= 0.23',
92+
'colorama',
93+
94+
# AboutCode
95+
'about-code-tool >= 0.9.0',
96+
97+
# packagedcode
98+
'requests >= 2.7.0, < 3.0.0',
99+
],
100+
101+
extras_require={
102+
'base': [
103+
'certifi',
104+
'setuptools',
105+
'wheel',
106+
'pip',
107+
'wincertstore',
108+
],
109+
'dev': [
110+
'pytest',
111+
'execnet',
112+
'py',
113+
'pytest-xdist',
114+
'bumpversion',
115+
],
116+
117+
},
118+
entry_points={
119+
'console_scripts': [
120+
'scancode = scancode.cli:scancode',
121+
'extractcode = scancode.extract_cli:extractcode',
122+
],
123+
},
124+
)

tests/packagedcode/test_pypi.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
#
2+
# Copyright (c) 2015 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 os.path
29+
30+
from commoncode.testcase import FileBasedTesting
31+
32+
from packagedcode import pypi
33+
34+
35+
class TestPyPi(FileBasedTesting):
36+
test_data_dir = os.path.join(os.path.dirname(__file__), 'data')
37+
38+
def test_parse(self):
39+
test_file = self.get_test_loc('pypi/setup.py')
40+
package = pypi.parse(test_file)
41+
assert 'scancode-toolkit' == package.name
42+
assert '1.5.0' == package.version
43+
assert 'ScanCode' == package.authors[0]
44+
assert 'ScanCode is a tool to scan code for license, copyright and other interesting facts.' == package.description
45+
assert 'https://github.com/nexB/scancode-toolkit' == package.homepage_url
46+
47+
def test_get_attribute(self):
48+
test_file = self.get_test_loc('pypi/setup2.py')
49+
assert 'scancode-toolkit' == pypi.get_attribute(test_file, 'name')
50+
assert '1.5.0' == pypi.get_attribute(test_file, 'version')
51+
assert 'ScanCode' == pypi.get_attribute(test_file, 'author')

0 commit comments

Comments
 (0)