Skip to content

Commit d147fea

Browse files
committed
Add --insecure option #62
Reference: #62 Signed-off-by: Tushar Goel <tushar.goel.dav@gmail.com>
1 parent 5b1d45c commit d147fea

File tree

9 files changed

+471
-5
lines changed

9 files changed

+471
-5
lines changed

CHANGELOG.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
Changelog
22
=========
33

4+
v0.6.6
5+
------
6+
- Add --insecure option to compute arguments.
7+
48
v0.6.5
59
------
610

src/python_inspector/resolution.py

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
from packaging.version import LegacyVersion
2727
from packaging.version import Version
2828
from packaging.version import parse as parse_version
29+
from requirements_builder.requirements_builder import iter_requirements
2930
from resolvelib import AbstractProvider
3031
from resolvelib import Resolver
3132
from resolvelib.reporters import BaseReporter
@@ -134,6 +135,17 @@ def is_requirements_file_in_setup_files(setup_files: List[str]) -> bool:
134135
return False
135136

136137

138+
def parse_setup_py_insecurely(setup_py):
139+
"""
140+
Yield requirements from the setup.py file at ``setup_py``.
141+
"""
142+
if not os.path.exists(setup_py):
143+
return []
144+
unparsed_requirements = iter_requirements(level="", extras=[], setup_file=setup_py)
145+
for requirement in unparsed_requirements:
146+
yield get_requirements_from_string(requirement)
147+
148+
137149
def is_valid_version(
138150
parsed_version: Union[LegacyVersion, Version],
139151
requirements: Dict,
@@ -222,7 +234,14 @@ def get_requirements_from_dependencies(
222234
# and other pip options for now
223235
# https://github.com/nexB/python-inspector/issues/41
224236
if can_process_dependent_package(dep):
225-
yield Requirement(str(dep.extracted_requirement))
237+
yield get_requirements_from_string(str(dep.extracted_requirement))
238+
239+
240+
def get_requirements_from_string(string: str) -> List[Requirement]:
241+
"""
242+
Generate parsed requirements for the given ``string``.
243+
"""
244+
return Requirement(string)
226245

227246

228247
def remove_extras(identifier: str) -> str:
@@ -235,13 +254,14 @@ def remove_extras(identifier: str) -> str:
235254

236255

237256
class PythonInputProvider(AbstractProvider):
238-
def __init__(self, environment=None, repos=tuple()):
257+
def __init__(self, environment=None, repos=tuple(), insecure=False):
239258
self.environment = environment
240259
self.environment_marker = get_environment_marker_from_environment(environment)
241260
self.repos = repos or []
242261
self.versions_by_package = {}
243262
self.dependencies_by_purl = {}
244263
self.wheel_or_sdist_by_package = {}
264+
self.insecure = insecure
245265

246266
def identify(self, requirement_or_candidate: Union[Candidate, Requirement]) -> str:
247267
"""Given a requirement, return an identifier for it. Overridden."""
@@ -357,12 +377,10 @@ def get_requirements_for_package_from_pypi_simple(
357377
if deps:
358378
has_wheels = True
359379
yield from deps
360-
361380
if not has_wheels:
362381
sdist_location = fetch_and_extract_sdist(
363382
repos=self.repos, candidate=candidate, python_version=python_version
364383
)
365-
366384
if sdist_location:
367385
setup_py_location = os.path.join(
368386
sdist_location,
@@ -393,6 +411,8 @@ def get_requirements_for_package_from_pypi_simple(
393411
sdist_location,
394412
"requirements.txt",
395413
)
414+
415+
has_deps_yielded = False
396416
if not deps_in_setup and is_requirements_file_in_setup_files(
397417
setup_files=[setup_py_location, setup_cfg_location]
398418
):
@@ -401,8 +421,12 @@ def get_requirements_for_package_from_pypi_simple(
401421
location=requirement_location,
402422
)
403423
if deps:
424+
has_deps_yielded = True
404425
yield from deps
405426

427+
if not has_deps_yielded and self.insecure:
428+
yield from parse_setup_py_insecurely(setup_py=setup_py_location)
429+
406430
def get_requirements_for_package_from_pypi_json_api(
407431
self, purl: PackageURL
408432
) -> List[Requirement]:
@@ -686,6 +710,7 @@ def get_resolved_dependencies(
686710
max_rounds: int = 200000,
687711
verbose: bool = False,
688712
pdt_output: bool = False,
713+
insecure: bool = False,
689714
):
690715
"""
691716
Return resolved dependencies of a ``requirements`` list of Requirement for
@@ -697,7 +722,7 @@ def get_resolved_dependencies(
697722
"""
698723
try:
699724
resolver = Resolver(
700-
provider=PythonInputProvider(environment=environment, repos=repos),
725+
provider=PythonInputProvider(environment=environment, repos=repos, insecure=insecure),
701726
reporter=BaseReporter(),
702727
)
703728
resolver_results = resolver.resolve(requirements=requirements, max_rounds=max_rounds)

src/python_inspector/resolve_cli.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,11 @@ def print_version(ctx, param, value):
156156
help="Use PyPI JSON API to fetch dependency data. Faster but not always correct. "
157157
"--index-url are ignored when this option is active.",
158158
)
159+
@click.option(
160+
"--insecure",
161+
is_flag=True,
162+
help="Resolve insecurely",
163+
)
159164
@click.option(
160165
"--verbose",
161166
is_flag=True,
@@ -186,6 +191,7 @@ def resolve_dependencies(
186191
max_rounds,
187192
use_cached_index=False,
188193
use_pypi_json_api=False,
194+
insecure=False,
189195
verbose=TRACE,
190196
):
191197
"""
@@ -329,6 +335,7 @@ def resolve_dependencies(
329335
max_rounds=max_rounds,
330336
verbose=verbose,
331337
pdt_output=pdt_output,
338+
insecure=insecure,
332339
)
333340

334341
cli_options = [f"--requirement {rf}" for rf in requirement_files]
@@ -383,6 +390,7 @@ def resolve(
383390
max_rounds=200000,
384391
verbose=False,
385392
pdt_output=False,
393+
insecure=False,
386394
):
387395
"""
388396
Resolve dependencies given a ``direct_dependencies`` list of
@@ -408,6 +416,7 @@ def resolve(
408416
max_rounds=max_rounds,
409417
verbose=verbose,
410418
pdt_output=pdt_output,
419+
insecure=insecure,
411420
)
412421

413422
initial_requirements = [d.to_dict() for d in direct_dependencies]
Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
import logging
2+
import sys
3+
4+
import six
5+
from rdflib import plugin
6+
from rdflib import query
7+
from rdflib import util
8+
from rdflib.graph import ConjunctiveGraph
9+
from rdflib.graph import Dataset
10+
from rdflib.graph import Graph
11+
from rdflib.namespace import CSVW
12+
from rdflib.namespace import DC
13+
from rdflib.namespace import DCAT
14+
from rdflib.namespace import DCTERMS
15+
from rdflib.namespace import DOAP
16+
from rdflib.namespace import FOAF
17+
from rdflib.namespace import ODRL2
18+
from rdflib.namespace import ORG
19+
from rdflib.namespace import OWL
20+
from rdflib.namespace import PROF
21+
from rdflib.namespace import PROV
22+
from rdflib.namespace import RDF
23+
from rdflib.namespace import RDFS
24+
from rdflib.namespace import SDO
25+
from rdflib.namespace import SH
26+
from rdflib.namespace import SKOS
27+
from rdflib.namespace import SOSA
28+
from rdflib.namespace import SSN
29+
from rdflib.namespace import TIME
30+
from rdflib.namespace import VOID
31+
from rdflib.namespace import XMLNS
32+
from rdflib.namespace import XSD
33+
from rdflib.namespace import Namespace
34+
from rdflib.term import BNode
35+
from rdflib.term import Literal
36+
from rdflib.term import URIRef
37+
from rdflib.term import Variable
38+
39+
# tedious sop to flake8
40+
assert plugin
41+
assert query
42+
43+
44+
"""A pure Python package providing the core RDF constructs.
45+
46+
The packages is intended to provide the core RDF types and interfaces
47+
for working with RDF. The package defines a plugin interface for
48+
parsers, stores, and serializers that other packages can use to
49+
implement parsers, stores, and serializers that will plug into the
50+
rdflib package.
51+
52+
The primary interface `rdflib` exposes to work with RDF is
53+
`rdflib.graph.Graph`.
54+
55+
A tiny example:
56+
57+
>>> from rdflib import Graph, URIRef, Literal
58+
59+
>>> g = Graph()
60+
>>> result = g.parse("http://www.w3.org/2000/10/swap/test/meet/blue.rdf")
61+
62+
>>> print("graph has %s statements." % len(g))
63+
graph has 4 statements.
64+
>>>
65+
>>> for s, p, o in g:
66+
... if (s, p, o) not in g:
67+
... raise Exception("It better be!")
68+
69+
>>> s = g.serialize(format='nt')
70+
>>>
71+
>>> sorted(g) == [
72+
... (URIRef(u'http://meetings.example.com/cal#m1'),
73+
... URIRef(u'http://www.example.org/meeting_organization#homePage'),
74+
... URIRef(u'http://meetings.example.com/m1/hp')),
75+
... (URIRef(u'http://www.example.org/people#fred'),
76+
... URIRef(u'http://www.example.org/meeting_organization#attending'),
77+
... URIRef(u'http://meetings.example.com/cal#m1')),
78+
... (URIRef(u'http://www.example.org/people#fred'),
79+
... URIRef(u'http://www.example.org/personal_details#GivenName'),
80+
... Literal(u'Fred')),
81+
... (URIRef(u'http://www.example.org/people#fred'),
82+
... URIRef(u'http://www.example.org/personal_details#hasEmail'),
83+
... URIRef(u'mailto:fred@example.com'))
84+
... ]
85+
True
86+
87+
"""
88+
__docformat__ = "restructuredtext en"
89+
90+
# The format of the __version__ line is matched by a regex in setup.py
91+
__version__ = "5.0.0"
92+
__date__ = "2020-04-18"
93+
94+
__all__ = [
95+
"URIRef",
96+
"BNode",
97+
"Literal",
98+
"Variable",
99+
"Namespace",
100+
"Dataset",
101+
"Graph",
102+
"ConjunctiveGraph",
103+
"CSVW",
104+
"DC",
105+
"DCAT",
106+
"DCTERMS",
107+
"DOAP",
108+
"FOAF",
109+
"ODRL2",
110+
"ORG",
111+
"OWL",
112+
"PROF",
113+
"PROV",
114+
"RDF",
115+
"RDFS",
116+
"SDO",
117+
"SH",
118+
"SKOS",
119+
"SOSA",
120+
"SSN",
121+
"TIME",
122+
"VOID",
123+
"XMLNS",
124+
"XSD",
125+
"util",
126+
]
127+
128+
129+
assert sys.version_info >= (2, 7, 0), "rdflib requires Python 2.7 or higher"
130+
131+
logger = logging.getLogger(__name__)
132+
_interactive_mode = False
133+
try:
134+
import __main__
135+
136+
if not hasattr(__main__, "__file__") and sys.stdout is not None and sys.stderr.isatty():
137+
# show log messages in interactive mode
138+
_interactive_mode = True
139+
logger.setLevel(logging.INFO)
140+
logger.addHandler(logging.StreamHandler())
141+
del __main__
142+
except ImportError:
143+
# Main already imported from elsewhere
144+
import warnings
145+
146+
warnings.warn("__main__ already imported", ImportWarning)
147+
del warnings
148+
149+
if _interactive_mode:
150+
logger.info("RDFLib Version: %s" % __version__)
151+
else:
152+
logger.debug("RDFLib Version: %s" % __version__)
153+
del _interactive_mode
154+
del sys
155+
156+
try:
157+
six.unichr(0x10FFFF)
158+
except ValueError:
159+
import warnings
160+
161+
warnings.warn(
162+
"You are using a narrow Python build!\n"
163+
"This means that your Python does not properly support chars > 16bit.\n"
164+
'On your system chars like c=u"\\U0010FFFF" will have a len(c)==2.\n'
165+
"As this can cause hard to debug problems with string processing\n"
166+
"(slicing, regexp, ...) later on, we strongly advise to use a wide\n"
167+
"Python build in production systems.",
168+
ImportWarning,
169+
)
170+
del warnings
171+
del six
172+
173+
174+
NORMALIZE_LITERALS = True
175+
"""
176+
If True - Literals lexical forms are normalized when created.
177+
I.e. the lexical forms is parsed according to data-type, then the
178+
stored lexical form is the re-serialized value that was parsed.
179+
180+
Illegal values for a datatype are simply kept. The normalized keyword
181+
for Literal.__new__ can override this.
182+
183+
For example:
184+
185+
>>> from rdflib import Literal,XSD
186+
>>> Literal("01", datatype=XSD.int)
187+
rdflib.term.Literal(u'1', datatype=rdflib.term.URIRef(u'http://www.w3.org/2001/XMLSchema#integer'))
188+
189+
This flag may be changed at any time, but will only affect literals
190+
created after that time, previously created literals will remain
191+
(un)normalized.
192+
193+
"""
194+
195+
196+
DAWG_LITERAL_COLLATION = False
197+
"""
198+
DAWG_LITERAL_COLLATION determines how literals are ordered or compared
199+
to each other.
200+
201+
In SPARQL, applying the >,<,>=,<= operators to literals of
202+
incompatible data-types is an error, i.e:
203+
204+
Literal(2)>Literal('cake') is neither true nor false, but an error.
205+
206+
This is a problem in PY3, where lists of Literals of incompatible
207+
types can no longer be sorted.
208+
209+
Setting this flag to True gives you strict DAWG/SPARQL compliance,
210+
setting it to False will order Literals with incompatible datatypes by
211+
datatype URI
212+
213+
In particular, this determines how the rich comparison operators for
214+
Literal work, eq, __neq__, __lt__, etc.
215+
"""

0 commit comments

Comments
 (0)