Skip to content

Commit 0e5d17e

Browse files
python3 -m pyupgrade --py39-plus on all python files. Removed six as a direct dependency.
1 parent 8f04ae3 commit 0e5d17e

26 files changed

+360
-363
lines changed

requirements.txt

-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ requests
1818
requests_cache
1919
requests_file
2020
simplejson >=2.6.2
21-
six>=1.11.0
2221
whoosh
2322
wsgi-intercept
2423
xmldiff

src/pyff/api.py

+18-17
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
import threading
33
from datetime import datetime, timedelta
44
from json import dumps
5-
from typing import Any, Dict, Generator, Iterable, List, Mapping, Optional, Tuple
5+
from typing import Any, Dict, List, Optional, Tuple
6+
from collections.abc import Generator, Iterable, Mapping
67

78
import pyramid.httpexceptions as exc
89
import pytz
@@ -15,7 +16,7 @@
1516
from pyramid.request import Request
1617
from pyramid.response import Response
1718
from six import b
18-
from six.moves.urllib_parse import quote_plus
19+
from urllib.parse import quote_plus
1920

2021
from pyff.constants import config
2122
from pyff.exceptions import ResourceException
@@ -30,7 +31,7 @@
3031
log = get_log(__name__)
3132

3233

33-
class NoCache(object):
34+
class NoCache:
3435
"""Dummy implementation for when caching isn't enabled"""
3536

3637
def __init__(self) -> None:
@@ -82,7 +83,7 @@ def status_handler(request: Request) -> Response:
8283
return response
8384

8485

85-
class MediaAccept(object):
86+
class MediaAccept:
8687
def __init__(self, accept: str):
8788
self._type = AcceptableType(accept)
8889

@@ -110,7 +111,7 @@ def _is_xml(data: Any) -> bool:
110111
return isinstance(data, (etree._Element, etree._ElementTree))
111112

112113

113-
def _fmt(data: Any, accepter: MediaAccept) -> Tuple[str, str]:
114+
def _fmt(data: Any, accepter: MediaAccept) -> tuple[str, str]:
114115
"""
115116
Format data according to the accepted content type of the requester.
116117
Return data as string (either XML or json) and a content-type.
@@ -162,7 +163,7 @@ def process_handler(request: Request) -> Response:
162163
"""
163164
_ctypes = {'xml': 'application/samlmetadata+xml;application/xml;text/xml', 'json': 'application/json'}
164165

165-
def _d(x: Optional[str], do_split: bool = True) -> Tuple[Optional[str], Optional[str]]:
166+
def _d(x: Optional[str], do_split: bool = True) -> tuple[Optional[str], Optional[str]]:
166167
"""Split a path into a base component and an extension."""
167168
if x is not None:
168169
x = x.strip()
@@ -195,7 +196,7 @@ def _d(x: Optional[str], do_split: bool = True) -> Tuple[Optional[str], Optional
195196

196197
# Enable matching on scope.
197198
match = match.split('@').pop() if match and not match.endswith('@') else match
198-
log.debug("match={}".format(match))
199+
log.debug(f"match={match}")
199200

200201
if not path_elem:
201202
path_elem = ['entities']
@@ -213,7 +214,7 @@ def _d(x: Optional[str], do_split: bool = True) -> Tuple[Optional[str], Optional
213214
if 'entities' not in alias:
214215
pfx = request.registry.aliases.get(alias, None)
215216
if pfx is None:
216-
log.debug("alias {} not found - passing to storage lookup".format(alias))
217+
log.debug(f"alias {alias} not found - passing to storage lookup")
217218
path = alias # treat as path
218219

219220
# content_negotiation_policy is one of three values:
@@ -353,11 +354,11 @@ def webfinger_handler(request: Request) -> Response:
353354
if resource is None:
354355
resource = request.host_url
355356

356-
jrd: Dict[str, Any] = dict()
357+
jrd: dict[str, Any] = dict()
357358
dt = datetime.now() + timedelta(hours=1)
358359
jrd['expires'] = dt.isoformat()
359360
jrd['subject'] = request.host_url
360-
links: List[Dict[str, Any]] = list()
361+
links: list[dict[str, Any]] = list()
361362
jrd['links'] = links
362363

363364
_dflt_rels = {
@@ -377,7 +378,7 @@ def _links(url: str, title: Any = None) -> None:
377378
suffix = ""
378379
if not url.endswith('/'):
379380
suffix = _dflt_rels[r][0]
380-
links.append(dict(rel=r, type=_dflt_rels[r][1], href='%s/%s%s' % (request.host_url, url, suffix)))
381+
links.append(dict(rel=r, type=_dflt_rels[r][1], href=f'{request.host_url}/{url}{suffix}'))
381382

382383
_links('/entities/')
383384
for a in request.registry.md.store.collections():
@@ -391,7 +392,7 @@ def _links(url: str, title: Any = None) -> None:
391392
aliases = request.registry.aliases
392393
for a in aliases.keys():
393394
for v in request.registry.md.store.attribute(aliases[a]):
394-
_links('%s/%s' % (a, quote_plus(v)))
395+
_links(f'{a}/{quote_plus(v)}')
395396

396397
response = Response(dumps(jrd, default=json_serializer))
397398
response.headers['Content-Type'] = 'application/json'
@@ -407,7 +408,7 @@ def resources_handler(request: Request) -> Response:
407408
:return: a JSON representation of the set of resources currently loaded by the server
408409
"""
409410

410-
def _infos(resources: Iterable[Resource]) -> List[Mapping[str, Any]]:
411+
def _infos(resources: Iterable[Resource]) -> list[Mapping[str, Any]]:
411412
return [_info(r) for r in resources if r.info.state is not None]
412413

413414
def _info(r: Resource) -> Mapping[str, Any]:
@@ -453,19 +454,19 @@ def search_handler(request: Request) -> Response:
453454
match = match.split('@').pop() if match and not match.endswith('@') else match
454455

455456
entity_filter = request.params.get('entity_filter', '{http://pyff.io/role}idp')
456-
log.debug("match={}".format(match))
457+
log.debug(f"match={match}")
457458
store = request.registry.md.store
458459

459460
def _response() -> Generator[bytes, bytes, None]:
460-
yield b('[')
461+
yield b'['
461462
in_loop = False
462463
entities = store.search(query=match.lower(), entity_filter=entity_filter)
463464
for e in entities:
464465
if in_loop:
465-
yield b(',')
466+
yield b','
466467
yield b(dumps(e))
467468
in_loop = True
468-
yield b(']')
469+
yield b']'
469470

470471
response = Response(content_type='application/json')
471472
response.app_iter = _response()

src/pyff/builtins.py

+28-29
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,10 @@
1717
from typing import Dict, Optional
1818

1919
import ipaddress
20-
import six
2120
import xmlsec
2221
from lxml import etree
2322
from lxml.etree import DocumentInvalid
24-
from six.moves.urllib_parse import quote_plus, urlparse
23+
from urllib.parse import quote_plus, urlparse
2524

2625
from pyff.constants import NS
2726
from pyff.decorators import deprecated
@@ -104,7 +103,7 @@ def _map(req: Plumbing.Request, *opts):
104103

105104
def _p(e):
106105
entity_id = e.get('entityID')
107-
ip = Plumbing(pipeline=req.args, pid="{}.each[{}]".format(req.plumbing.pid, entity_id))
106+
ip = Plumbing(pipeline=req.args, pid=f"{req.plumbing.pid}.each[{entity_id}]")
108107
ireq = Plumbing.Request(ip, req.md, t=e, scheduler=req.scheduler)
109108
ireq.set_id(entity_id)
110109
ireq.set_parent(req)
@@ -114,7 +113,7 @@ def _p(e):
114113

115114
pool = ThreadPool()
116115
result = pool.map(_p, iter_entities(req.t), chunksize=10)
117-
log.info("processed {} entities".format(len(result)))
116+
log.info(f"processed {len(result)} entities")
118117

119118

120119
@pipe(name="then")
@@ -461,7 +460,7 @@ def sort(req: Plumbing.Request, *opts):
461460
if req.t is None:
462461
raise PipeException("Unable to sort empty document.")
463462

464-
_opts: Dict[str, Optional[str]] = dict(list(zip(opts[0:1], [" ".join(opts[1:])])))
463+
_opts: dict[str, Optional[str]] = dict(list(zip(opts[0:1], [" ".join(opts[1:])])))
465464
if 'order_by' not in _opts:
466465
_opts['order_by'] = None
467466
sort_entities(req.t, _opts['order_by'])
@@ -837,7 +836,7 @@ def select(req: Plumbing.Request, *opts):
837836
if req.state.get('match', None): # TODO - allow this to be passed in via normal arguments
838837
match = req.state['match']
839838

840-
if isinstance(match, six.string_types):
839+
if isinstance(match, str):
841840
query = [match.lower()]
842841

843842
def _strings(elt):
@@ -870,22 +869,22 @@ def _match(q, elt):
870869

871870
if q is not None and len(q) > 0:
872871
tokens = _strings(elt)
873-
p = re.compile(r'\b{}'.format(q), re.IGNORECASE)
872+
p = re.compile(fr'\b{q}', re.IGNORECASE)
874873
for tstr in tokens:
875874
if p.search(tstr):
876875
return tstr
877876
return None
878877

879-
log.debug("matching {} in {} entities".format(match, len(entities)))
878+
log.debug(f"matching {match} in {len(entities)} entities")
880879
entities = list(filter(lambda e: _match(match, e) is not None, entities))
881-
log.debug("returning {} entities after match".format(len(entities)))
880+
log.debug(f"returning {len(entities)} entities after match")
882881

883882
ot = entitiesdescriptor(entities, name)
884883
if ot is None:
885884
raise PipeException("empty select - stop")
886885

887886
if req.plumbing.id != name:
888-
log.debug("storing synthetic collection {}".format(name))
887+
log.debug(f"storing synthetic collection {name}")
889888
req.store.update(ot, name)
890889

891890
return ot
@@ -1202,7 +1201,7 @@ def stats(req: Plumbing.Request, *opts):
12021201
raise PipeException("Your pipeline is missing a select statement.")
12031202

12041203
print("---")
1205-
print("total size: {:d}".format(req.store.size()))
1204+
print(f"total size: {req.store.size():d}")
12061205
if not hasattr(req.t, 'xpath'):
12071206
raise PipeException("Unable to call stats on non-XML")
12081207

@@ -1303,7 +1302,7 @@ def xslt(req: Plumbing.Request, *opts):
13031302
if stylesheet is None:
13041303
raise PipeException("xslt requires stylesheet")
13051304

1306-
params = dict((k, "'%s'" % v) for (k, v) in list(req.args.items()))
1305+
params = {k: "'%s'" % v for (k, v) in list(req.args.items())}
13071306
del params['stylesheet']
13081307
try:
13091308
return root(xslt_transform(req.t, stylesheet, params))
@@ -1429,13 +1428,13 @@ def check_xml_namespaces(req: Plumbing.Request, *opts):
14291428
raise PipeException("Your pipeline is missing a select statement.")
14301429

14311430
def _verify(elt):
1432-
if isinstance(elt.tag, six.string_types):
1431+
if isinstance(elt.tag, str):
14331432
for prefix, uri in list(elt.nsmap.items()):
14341433
if not uri.startswith('urn:'):
14351434
u = urlparse(uri)
14361435
if u.scheme not in ('http', 'https'):
14371436
raise MetadataException(
1438-
"Namespace URIs must be be http(s) URIs ('{}' declared on {})".format(uri, elt.tag)
1437+
f"Namespace URIs must be be http(s) URIs ('{uri}' declared on {elt.tag})"
14391438
)
14401439

14411440
with_tree(root(req.t), _verify)
@@ -1508,7 +1507,7 @@ def certreport(req: Plumbing.Request, *opts):
15081507
error_bits = int(req.args.get('error_bits', "1024"))
15091508
warning_bits = int(req.args.get('warning_bits', "2048"))
15101509

1511-
seen: Dict[str, bool] = {}
1510+
seen: dict[str, bool] = {}
15121511
for eid in req.t.xpath("//md:EntityDescriptor/@entityID", namespaces=NS, smart_strings=False):
15131512
for cd in req.t.xpath(
15141513
"md:EntityDescriptor[@entityID='%s']//ds:X509Certificate" % eid, namespaces=NS, smart_strings=False
@@ -1530,17 +1529,17 @@ def certreport(req: Plumbing.Request, *opts):
15301529
entity_elt,
15311530
"certificate-error",
15321531
"keysize too small",
1533-
"%s has keysize of %s bits (less than %s)" % (cert.getSubject(), keysize, error_bits),
1532+
"{} has keysize of {} bits (less than {})".format(cert.getSubject(), keysize, error_bits),
15341533
)
1535-
log.error("%s has keysize of %s" % (eid, keysize))
1534+
log.error("{} has keysize of {}".format(eid, keysize))
15361535
elif keysize < warning_bits:
15371536
annotate_entity(
15381537
entity_elt,
15391538
"certificate-warning",
15401539
"keysize small",
1541-
"%s has keysize of %s bits (less than %s)" % (cert.getSubject(), keysize, warning_bits),
1540+
"{} has keysize of {} bits (less than {})".format(cert.getSubject(), keysize, warning_bits),
15421541
)
1543-
log.warning("%s has keysize of %s" % (eid, keysize))
1542+
log.warning("{} has keysize of {}".format(eid, keysize))
15441543

15451544
notafter = cert.getNotAfter()
15461545
if notafter is None:
@@ -1560,23 +1559,23 @@ def certreport(req: Plumbing.Request, *opts):
15601559
entity_elt,
15611560
"certificate-error",
15621561
"certificate has expired",
1563-
"%s expired %s ago" % (cert.getSubject(), -dt),
1562+
"{} expired {} ago".format(cert.getSubject(), -dt),
15641563
)
1565-
log.error("%s expired %s ago" % (eid, -dt))
1564+
log.error("{} expired {} ago".format(eid, -dt))
15661565
elif total_seconds(dt) < warning_seconds:
15671566
annotate_entity(
15681567
entity_elt,
15691568
"certificate-warning",
15701569
"certificate about to expire",
1571-
"%s expires in %s" % (cert.getSubject(), dt),
1570+
"{} expires in {}".format(cert.getSubject(), dt),
15721571
)
1573-
log.warning("%s expires in %s" % (eid, dt))
1572+
log.warning("{} expires in {}".format(eid, dt))
15741573
except ValueError as ex:
15751574
annotate_entity(
15761575
entity_elt,
15771576
"certificate-error",
15781577
"certificate has unknown expiration time",
1579-
"%s unknown expiration time %s" % (cert.getSubject(), notafter),
1578+
"{} unknown expiration time {}".format(cert.getSubject(), notafter),
15801579
)
15811580

15821581
req.store.update(entity_elt)
@@ -1623,7 +1622,7 @@ def emit(req: Plumbing.Request, ctype="application/xml", *opts):
16231622

16241623
if d is not None:
16251624
m = hashlib.sha1()
1626-
if not isinstance(d, six.binary_type):
1625+
if not isinstance(d, bytes):
16271626
d = d.encode("utf-8")
16281627
m.update(d)
16291628
req.state['headers']['ETag'] = m.hexdigest()
@@ -1632,7 +1631,7 @@ def emit(req: Plumbing.Request, ctype="application/xml", *opts):
16321631

16331632
req.state['headers']['Content-Type'] = ctype
16341633
if six.PY2:
1635-
d = six.u(d)
1634+
d = d
16361635
return d
16371636

16381637

@@ -1664,7 +1663,7 @@ def signcerts(req: Plumbing.Request, *opts):
16641663

16651664
@pipe
16661665
def finalize(req: Plumbing.Request, *opts):
1667-
"""
1666+
r"""
16681667
Prepares the working document for publication/rendering.
16691668
16701669
:param req: The request
@@ -1716,7 +1715,7 @@ def finalize(req: Plumbing.Request, *opts):
17161715
# TODO: Investigate this error, which is probably correct:
17171716
# error: On Python 3 '{}'.format(b'abc') produces "b'abc'", not 'abc';
17181717
# use '{!r}'.format(b'abc') if this is desired behavior
1719-
name = "{}://{}{}".format(base_url.scheme, base_url.netloc, name_url.path) # type: ignore
1718+
name = f"{base_url.scheme}://{base_url.netloc}{name_url.path}" # type: ignore
17201719
log.debug("-------- using Name: %s" % name)
17211720
except ValueError as ex:
17221721
log.debug(f'Got an exception while finalizing: {ex}')
@@ -1752,7 +1751,7 @@ def finalize(req: Plumbing.Request, *opts):
17521751
offset = dt - now
17531752
e.set('validUntil', datetime2iso(dt))
17541753
except ValueError as ex:
1755-
log.error("Unable to parse validUntil: %s (%s)" % (valid_until, ex))
1754+
log.error("Unable to parse validUntil: {} ({})".format(valid_until, ex))
17561755

17571756
# set a reasonable default: 50% of the validity
17581757
# we replace this below if we have cacheDuration set

0 commit comments

Comments
 (0)