Prep for type annotations

- Remove unused pyver var
- Fix ret_string type for ECStripingDriver
- Clean up ECDriver signature
- Fix AttributeError in ECDriver repr when no ec_type specified
- Fix typo in verify_stripe_metadata docstring
- Ensure positive_int_value works properly regardless of optimization level

Change-Id: If20196d067ff42a1179923b422a6f0bed9917d45
This commit is contained in:
Tim Burke
2025-08-05 14:31:30 -07:00
parent d876bef65f
commit d10ec59e70
5 changed files with 78 additions and 74 deletions

View File

@@ -28,9 +28,6 @@ from .ec_iface import PyECLib_FRAGHDRCHKSUM_Types
import math
import pyeclib_c
import sys
pyver = float('%s.%s' % sys.version_info[:2])
class ECPyECLibDriver(object):
@@ -254,7 +251,7 @@ class ECStripingDriver(object):
"Decode requires %d fragments, %d fragments were given" %
(len(fragment_payloads), self.k))
ret_string = ''
ret_string = b''
for fragment in fragment_payloads:
ret_string += fragment

View File

@@ -93,7 +93,15 @@ class PyECLib_FRAGHDRCHKSUM_Types(Enum):
class ECDriver(object):
'''A driver to encode, decode, and reconstruct erasure-coded data.'''
def __init__(self, **kwargs):
def __init__(
self, *,
ec_type=None,
library_import_str='pyeclib.core.ECPyECLibDriver',
k,
m,
chksum_type='none',
validate=False,
):
'''
:param ec_type: the erasure coding type to use for this driver.
:param k: number of data fragments to use. Required.
@@ -112,68 +120,63 @@ class ECDriver(object):
self.hd = -1
self.ec_type = None
self.chksum_type = None
self.validate = False
for required in ('k', 'm'):
if required not in kwargs:
raise ECDriverError(
"Invalid Argument: %s is required" % required)
if 'ec_type' not in kwargs and 'library_import_str' not in kwargs:
if (
ec_type is None and
library_import_str == 'pyeclib.core.ECPyECLibDriver'
):
raise ECDriverError(
"Invalid Argument: either ec_type or library_import_str "
"must be provided")
for (key, value) in kwargs.items():
if key == "k":
try:
self.k = positive_int_value(value)
except ValueError:
raise ECDriverError(
"Invalid number of data fragments (k)")
elif key == "m":
try:
self.m = positive_int_value(value)
except ValueError:
raise ECDriverError(
"Invalid number of parity fragments (m)")
elif key == "ec_type":
if value in ["flat_xor_hd", "flat_xor_hd_3", "flat_xor_hd_4"]:
if value == "flat_xor_hd" or value == "flat_xor_hd_3":
self.hd = 3
elif value == "flat_xor_hd_4":
self.hd = 4
value = "flat_xor_hd"
elif value == "libphazr":
self.hd = 1
try:
self.k = positive_int_value(k)
except ValueError:
raise ECDriverError(
"Invalid number of data fragments (k)")
if value in PyECLib_EC_Types.__members__:
self.ec_type = PyECLib_EC_Types[value]
if self.ec_type in (PyECLib_EC_Types.jerasure_rs_vand,
PyECLib_EC_Types.jerasure_rs_cauchy):
warnings.warn('Jerasure support is deprecated and '
'may be removed in a future release',
FutureWarning, stacklevel=2)
try:
self.m = positive_int_value(m)
except ValueError:
raise ECDriverError(
"Invalid number of parity fragments (m)")
else:
raise ECBackendNotSupported(
"%s is not a valid EC type for PyECLib!" % value)
elif key == "chksum_type":
if value in PyECLib_FRAGHDRCHKSUM_Types.__members__:
self.chksum_type = \
PyECLib_FRAGHDRCHKSUM_Types[value]
else:
raise ECDriverError(
"%s is not a valid checksum type for PyECLib!" % value)
elif key == "validate":
# validate if the ec type is available (runtime check)
self.validate = value
if ec_type:
if ec_type in ["flat_xor_hd", "flat_xor_hd_3", "flat_xor_hd_4"]:
if ec_type == "flat_xor_hd" or ec_type == "flat_xor_hd_3":
self.hd = 3
elif ec_type == "flat_xor_hd_4":
self.hd = 4
ec_type = "flat_xor_hd"
elif ec_type == "libphazr":
self.hd = 1
if ec_type in PyECLib_EC_Types.__members__:
self.ec_type = PyECLib_EC_Types[ec_type]
if self.ec_type in (PyECLib_EC_Types.jerasure_rs_vand,
PyECLib_EC_Types.jerasure_rs_cauchy):
warnings.warn('Jerasure support is deprecated and '
'may be removed in a future release',
FutureWarning, stacklevel=2)
else:
raise ECBackendNotSupported(
"%s is not a valid EC type for PyECLib!" % ec_type)
if chksum_type in PyECLib_FRAGHDRCHKSUM_Types.__members__:
self.chksum_type = \
PyECLib_FRAGHDRCHKSUM_Types[chksum_type]
else:
raise ECDriverError(
"%s is not a valid checksum type for PyECLib!"
% chksum_type)
self.validate = validate
if self.hd == -1:
self.hd = self.m
self.library_import_str = kwargs.pop('library_import_str',
'pyeclib.core.ECPyECLibDriver')
self.library_import_str = library_import_str
#
# Instantiate EC backend driver
#
@@ -211,12 +214,15 @@ class ECDriver(object):
"in %s: %s" % (self.library_import_str, missing_methods))
def __repr__(self):
return '%s(ec_type=%r, k=%r, m=%r)' % (
type(self).__name__,
'flat_xor_hd_%s' % self.hd if self.ec_type.name == 'flat_xor_hd'
else self.ec_type.name,
self.k,
self.m)
if self.ec_type is None:
ec_type = 'None'
elif self.ec_type.name == 'flat_xor_hd':
ec_type = f'flat_xor_hd_{self.hd}'
else:
ec_type = self.ec_type.name
return (f'{type(self).__name__}('
f'ec_type={ec_type!r}, k={self.k}, m={self.m})')
def close(self):
self.ec_lib_reference.close()
@@ -313,7 +319,7 @@ class ECDriver(object):
Verify a subset of fragments generated by encode()
:param fragment_metadata_list: a list of buffers representing the
metadata from a subset of the framgments
metadata from a subset of the fragments
generated by encode().
:returns: 'None' if the metadata is consistent.
a list of fragment indexes corresponding to inconsistent

View File

@@ -30,10 +30,11 @@ def positive_int_value(param):
# Returns value as a positive int or raises ValueError otherwise
try:
value = int(param)
assert value > 0
except (TypeError, ValueError, AssertionError):
if value <= 0:
raise ValueError
except (TypeError, ValueError):
# Handle: TypeError for 'None', ValueError for non-int strings
# and AssertionError for values <= 0
# and values <= 0
raise ValueError('Must be an integer > 0, not "%s".' % param)
return value

View File

@@ -124,16 +124,16 @@ class TestPyECLibDriver(unittest.TestCase):
for ec_type in VALID_EC_TYPES:
# missing k
with self.assertRaises(ECDriverError) as err_context:
with self.assertRaises(TypeError) as err_context:
ECDriver(ec_type=ec_type, m=1)
self.assertEqual(str(err_context.exception),
"Invalid Argument: k is required")
self.assertIn("missing 1 required keyword-only argument: 'k'",
str(err_context.exception))
# missing m
with self.assertRaises(ECDriverError) as err_context:
with self.assertRaises(TypeError) as err_context:
ECDriver(ec_type=ec_type, k=1)
self.assertEqual(str(err_context.exception),
"Invalid Argument: m is required")
self.assertIn("missing 1 required keyword-only argument: 'm'",
str(err_context.exception))
def test_invalid_km_args(self):
for ec_type in VALID_EC_TYPES:

View File

@@ -38,8 +38,8 @@ from pyeclib.ec_iface import VALID_EC_TYPES
class Timer:
def __init__(self):
self.start_time = 0
self.end_time = 0
self.start_time = 0.0
self.end_time = 0.0
def start(self):
self.start_time = time.time()