implement '--range' with Python ranges
This commit is contained in:
@@ -714,29 +714,33 @@ def chain_predicates(predicates, url, kwdict):
|
|||||||
|
|
||||||
|
|
||||||
class RangePredicate():
|
class RangePredicate():
|
||||||
"""Predicate; True if the current index is in the given range"""
|
"""Predicate; True if the current index is in the given range(s)"""
|
||||||
|
|
||||||
def __init__(self, rangespec):
|
def __init__(self, rangespec):
|
||||||
self.ranges = self.optimize_range(self.parse_range(rangespec))
|
self.ranges = ranges = self._parse(rangespec)
|
||||||
self.index = 0
|
self.index = 0
|
||||||
|
|
||||||
if self.ranges:
|
if ranges:
|
||||||
self.lower, self.upper = self.ranges[0][0], self.ranges[-1][1]
|
# technically wrong, but good enough for now
|
||||||
|
# and evaluating min/max for a öarge range is slow
|
||||||
|
self.lower = min(r.start for r in ranges)
|
||||||
|
self.upper = max(r.stop for r in ranges) - 1
|
||||||
else:
|
else:
|
||||||
self.lower, self.upper = 0, 0
|
self.lower = self.upper = 0
|
||||||
|
|
||||||
def __call__(self, url, _):
|
def __call__(self, _url, _kwdict):
|
||||||
self.index += 1
|
self.index = index = self.index + 1
|
||||||
|
|
||||||
if self.index > self.upper:
|
if index > self.upper:
|
||||||
raise exception.StopExtraction()
|
raise exception.StopExtraction()
|
||||||
|
|
||||||
for lower, upper in self.ranges:
|
for range in self.ranges:
|
||||||
if lower <= self.index <= upper:
|
if index in range:
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def parse_range(rangespec):
|
def _parse(rangespec):
|
||||||
"""Parse an integer range string and return the resulting ranges
|
"""Parse an integer range string and return the resulting ranges
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
@@ -744,22 +748,29 @@ class RangePredicate():
|
|||||||
parse_range(" - 3 , 4- 4, 2-6") -> [(1,3), (4,4), (2,6)]
|
parse_range(" - 3 , 4- 4, 2-6") -> [(1,3), (4,4), (2,6)]
|
||||||
"""
|
"""
|
||||||
ranges = []
|
ranges = []
|
||||||
|
append = ranges.append
|
||||||
|
|
||||||
for group in rangespec.split(","):
|
if isinstance(rangespec, str):
|
||||||
|
rangespec = rangespec.split(",")
|
||||||
|
|
||||||
|
for group in rangespec:
|
||||||
if not group:
|
if not group:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
first, sep, last = group.partition("-")
|
first, sep, last = group.partition("-")
|
||||||
if not sep:
|
if sep:
|
||||||
beg = end = int(first)
|
append(range(
|
||||||
|
int(first) if first.strip() else 1,
|
||||||
|
int(last) + 1 if last.strip() else sys.maxsize,
|
||||||
|
))
|
||||||
else:
|
else:
|
||||||
beg = int(first) if first.strip() else 1
|
v = int(first)
|
||||||
end = int(last) if last.strip() else sys.maxsize
|
append(range(v, v+1))
|
||||||
ranges.append((beg, end) if beg <= end else (end, beg))
|
|
||||||
|
|
||||||
return ranges
|
return ranges
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def optimize_range(ranges):
|
def _optimize(ranges):
|
||||||
"""Simplify/Combine a parsed list of ranges
|
"""Simplify/Combine a parsed list of ranges
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
|
|||||||
@@ -24,39 +24,32 @@ from gallery_dl import util, text, exception # noqa E402
|
|||||||
|
|
||||||
class TestRange(unittest.TestCase):
|
class TestRange(unittest.TestCase):
|
||||||
|
|
||||||
def test_parse_range(self, f=util.RangePredicate.parse_range):
|
def test_parse_range(self, f=util.RangePredicate._parse):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
f(""),
|
f(""),
|
||||||
[])
|
[],
|
||||||
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
f("1-2"),
|
f("1-2"),
|
||||||
[(1, 2)])
|
[range(1, 3)],
|
||||||
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
f("-"),
|
f("-"),
|
||||||
[(1, sys.maxsize)])
|
[range(1, sys.maxsize)],
|
||||||
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
f("-2,4,6-8,10-"),
|
f("-2,4,6-8,10-"),
|
||||||
[(1, 2), (4, 4), (6, 8), (10, sys.maxsize)])
|
[range(1, 3),
|
||||||
|
range(4, 5),
|
||||||
|
range(6, 9),
|
||||||
|
range(10, sys.maxsize)],
|
||||||
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
f(" - 3 , 4- 4, 2-6"),
|
f(" - 3 , 4- 4, 2-6"),
|
||||||
[(1, 3), (4, 4), (2, 6)])
|
[range(1, 4),
|
||||||
|
range(4, 5),
|
||||||
def test_optimize_range(self, f=util.RangePredicate.optimize_range):
|
range(2, 7)],
|
||||||
self.assertEqual(
|
)
|
||||||
f([]),
|
|
||||||
[])
|
|
||||||
self.assertEqual(
|
|
||||||
f([(2, 4)]),
|
|
||||||
[(2, 4)])
|
|
||||||
self.assertEqual(
|
|
||||||
f([(2, 4), (6, 8), (10, 12)]),
|
|
||||||
[(2, 4), (6, 8), (10, 12)])
|
|
||||||
self.assertEqual(
|
|
||||||
f([(2, 4), (4, 6), (5, 8)]),
|
|
||||||
[(2, 8)])
|
|
||||||
self.assertEqual(
|
|
||||||
f([(1, 1), (2, 2), (3, 6), (8, 9)]),
|
|
||||||
[(1, 6), (8, 9)])
|
|
||||||
|
|
||||||
|
|
||||||
class TestPredicate(unittest.TestCase):
|
class TestPredicate(unittest.TestCase):
|
||||||
@@ -68,7 +61,7 @@ class TestPredicate(unittest.TestCase):
|
|||||||
for i in range(6):
|
for i in range(6):
|
||||||
self.assertTrue(pred(dummy, dummy))
|
self.assertTrue(pred(dummy, dummy))
|
||||||
with self.assertRaises(exception.StopExtraction):
|
with self.assertRaises(exception.StopExtraction):
|
||||||
bool(pred(dummy, dummy))
|
pred(dummy, dummy)
|
||||||
|
|
||||||
pred = util.RangePredicate("1, 3, 5")
|
pred = util.RangePredicate("1, 3, 5")
|
||||||
self.assertTrue(pred(dummy, dummy))
|
self.assertTrue(pred(dummy, dummy))
|
||||||
@@ -77,11 +70,11 @@ class TestPredicate(unittest.TestCase):
|
|||||||
self.assertFalse(pred(dummy, dummy))
|
self.assertFalse(pred(dummy, dummy))
|
||||||
self.assertTrue(pred(dummy, dummy))
|
self.assertTrue(pred(dummy, dummy))
|
||||||
with self.assertRaises(exception.StopExtraction):
|
with self.assertRaises(exception.StopExtraction):
|
||||||
bool(pred(dummy, dummy))
|
pred(dummy, dummy)
|
||||||
|
|
||||||
pred = util.RangePredicate("")
|
pred = util.RangePredicate("")
|
||||||
with self.assertRaises(exception.StopExtraction):
|
with self.assertRaises(exception.StopExtraction):
|
||||||
bool(pred(dummy, dummy))
|
pred(dummy, dummy)
|
||||||
|
|
||||||
def test_unique_predicate(self):
|
def test_unique_predicate(self):
|
||||||
dummy = None
|
dummy = None
|
||||||
|
|||||||
Reference in New Issue
Block a user