commit b1cc8624a2ad8afdc04181ccf6ca42c37a9a701e Author: mulhern Date: Mon Feb 15 14:13:49 2016 -0500 Fixes for ID_PATH parsing. * Disable individual fields matching '-'. * Do not try to parse delimiter '-' between distinct ids. * Change format for a sas path. * Handle virtio-pci. Signed-off-by: mulhern diff --git a/src/pyudev/_parsing/_id_path.py b/src/pyudev/_parsing/_id_path.py index c94f332..0b65c43 100644 --- a/src/pyudev/_parsing/_id_path.py +++ b/src/pyudev/_parsing/_id_path.py @@ -35,6 +35,16 @@ from ._shared import Parser +class IdPathField(Field): + """ + Overrides default regular expression. + """ + # pylint: disable=too-few-public-methods + + def __init__(self, name, regexp=r'[^-]+', description=None): + super(IdPathField, self).__init__(name, regexp, description) + + class IdPathParsers(object): """ Aggregate parsers. @@ -42,70 +52,73 @@ class IdPathParsers(object): # pylint: disable=too-few-public-methods PARSERS = [ - Parser(r'acpi-%s', [Field('sys_name')]), - Parser(r'ap-%s', [Field('sys_name')]), - Parser(r'ata-%s', [Field('port_no')]), - Parser(r'bcma-%s', [Field('core')]), - Parser(r'cciss-disk%s', [Field('disk')]), - Parser(r'ccw-%s', [Field('sys_name')]), - Parser(r'ccwgroup-%s', [Field('sys_name')]), - Parser(r'fc-%s-%s', [Field('port_name'), Field('lun')]), + Parser(r'acpi-%s', [IdPathField('sys_name')]), + Parser(r'ap-%s', [IdPathField('sys_name')]), + Parser(r'ata-%s', [IdPathField('port_no')]), + Parser(r'bcma-%s', [IdPathField('core')]), + Parser(r'cciss-disk%s', [IdPathField('disk')]), + Parser(r'ccw-%s', [IdPathField('sys_name')]), + Parser(r'ccwgroup-%s', [IdPathField('sys_name')]), + Parser(r'fc-%s-%s', [IdPathField('port_name'), IdPathField('lun')]), Parser( r'ip-%s:%s-iscsi-%s-%s', [ - Field('persistent_address'), - Field('persistent_port'), - Field('target_name'), - Field('lun') + IdPathField('persistent_address'), + IdPathField('persistent_port'), + IdPathField('target_name'), + IdPathField('lun') ] ), - Parser(r'iucv-%s', [Field('sys_name')]), - Parser(r'nst%s', [Field('name')]), - Parser(r'pci-%s', [Field('sys_name')]), - Parser(r'platform-%s', [Field('sys_name')]), - Parser(r'sas-%s-%s', [Field('sas_address'), Field('lun')]), + Parser(r'iucv-%s', [IdPathField('sys_name')]), + Parser(r'nst%s', [IdPathField('name')]), + Parser(r'pci-%s', [IdPathField('sys_name')]), + Parser(r'platform-%s', [IdPathField('sys_name')]), + Parser(r'sas-%s-lun-%s', + [IdPathField('sas_address'), IdPathField('lun')] + ), Parser( r'sas-exp%s-phy%s-%s', [ - Field( + IdPathField( 'sas_address', r'.*', 'sysfs sas_address attribute of expander' ), - Field( + IdPathField( 'phy_identifier', r'.*', 'sysfs phy_identifier attribute of target sas device' ), - Field('lun', description='sysnum of device (0 if none)') + IdPathField('lun', description='sysnum of device (0 if none)') ] ), Parser( r'sas-phy%s-%s', [ - Field( + IdPathField( 'phy_identifier', r'.*', 'sysfs phy_identifier attribute of target sas device' ), - Field('lun', description='sysnum of device (0 if none)') + IdPathField('lun', description='sysnum of device (0 if none)') ] ), - Parser(r'scm-%s', [Field('sys_name')]), + Parser(r'scm-%s', [IdPathField('sys_name')]), Parser( r'scsi-%s:%s:%s:%s', [ - Field('host'), - Field('bus'), - Field('target'), - Field('lun') + IdPathField('host'), + IdPathField('bus'), + IdPathField('target'), + IdPathField('lun') ] ), - Parser('serio-%s', [Field('sysnum')]), - Parser('st%s', [Field('name')]), - Parser('usb-0:%s', [Field('port')]), - Parser('vmbus-%s-%s', [Field('guid'), Field('lun')]), - Parser('xen-%s', [Field('sys_name')]) + Parser('serio-%s', [IdPathField('sysnum')]), + Parser('st%s', [IdPathField('name')]), + Parser('usb-0:%s', [IdPathField('port')]), + Parser('virtio-pci-%s', [IdPathField('sys_name')]), + Parser('vmbus-%s-%s', [IdPathField('guid'), IdPathField('lun')]), + Parser('xen-%s', [IdPathField('sys_name')]) ] @@ -166,6 +179,6 @@ def parse(self, value): (parser, best_match) = max(matches, key=lambda x: len(x[0].prefix)) match_list.append((parser, best_match)) - value = value[len(best_match.group('total')):] + value = value[len(best_match.group('total')) + 1:] return match_list diff --git a/tests/test_parsing.py b/tests/test_parsing.py index 619fb01..fba5575 100644 --- a/tests/test_parsing.py +++ b/tests/test_parsing.py @@ -52,20 +52,27 @@ class TestIDPATH(object): Test parsing ID_PATH values. """ # pylint: disable=too-few-public-methods - - @given( - strategies.sampled_from(_DEVICES).filter( - lambda x: x.get('ID_PATH') is not None - ) + _devices = [d for d in _DEVICES if d.get('ID_PATH') is not None] + @pytest.mark.skipif( + len(_devices) == 0, + reason="no devices with ID_PATH property" ) + @given(strategies.sampled_from(_devices)) + @settings(min_satisfying_examples=1) def test_parsing(self, a_device): """ Test that parsing is satisfactory on all examples. """ + parsers = _parsing.IdPathParsers.PARSERS id_path = a_device.get('ID_PATH') - parser = _parsing.IdPathParse(_parsing.IdPathParsers.PARSERS) + parser = _parsing.IdPathParse(parsers) result = parser.parse(id_path) assert isinstance(result, list) and result != [] + assert all( + any(r[1].group('total').startswith(p.prefix) for p in parsers) \ + for r in result + ) + assert not any(r[1].group('total').startswith('-') for r in result) _devices = [d for d in _DEVICES if d.get('ID_SAS_PATH') is not None] @pytest.mark.skipif( @@ -78,10 +85,25 @@ def test_parsing_sas_path(self, a_device): """ Test that parsing is satisfactory on all examples. """ + parsers = _parsing.IdPathParsers.PARSERS id_path = a_device.get('ID_SAS_PATH') - parser = _parsing.IdPathParse(_parsing.IdPathParsers.PARSERS) + parser = _parsing.IdPathParse(parsers) result = parser.parse(id_path) assert isinstance(result, list) and result != [] + assert all( + any(r[1].group('total').startswith(p.prefix) for p in parsers) \ + for r in result + ) + assert not any(r[1].group('total').startswith('-') for r in result) + + def test_failure(self): + """ + Test at least one failure. + """ + id_path = 'pci-0000_09_00_0-sas0x5000155359566200-lun-0' + parser = _parsing.IdPathParse(_parsing.IdPathParsers.PARSERS) + result = parser.parse(id_path) + assert result == [] class TestDevlinks(object):