Options for lspci
This commit is contained in:
parent
7bda6b9ac7
commit
7a4e85830c
65
pylspci/command.py
Normal file
65
pylspci/command.py
Normal file
|
@ -0,0 +1,65 @@
|
|||
from enum import Enum
|
||||
from typing import Optional, Union, List, Mapping, Any
|
||||
from pathlib import Path
|
||||
import subprocess
|
||||
|
||||
OptionalPath = Optional[Union[str, Path]]
|
||||
|
||||
|
||||
class IDResolveOption(Enum):
|
||||
NameOnly = ''
|
||||
IDOnly = '-n'
|
||||
Both = '-nn'
|
||||
|
||||
|
||||
def lspci(
|
||||
pciids: OptionalPath = None,
|
||||
pcimap: OptionalPath = None,
|
||||
access_method: Optional[str] = None,
|
||||
pcilib_params: Mapping[str, Any] = {},
|
||||
file: OptionalPath = None,
|
||||
verbose: bool = False,
|
||||
kernel_drivers: bool = False,
|
||||
hide_single_domain: bool = True,
|
||||
id_resolve_option: IDResolveOption = IDResolveOption.Both,
|
||||
) -> str:
|
||||
args: List[str] = ['lspci', '-mm']
|
||||
if verbose:
|
||||
args.append('-vvv')
|
||||
if kernel_drivers:
|
||||
args.append('-k')
|
||||
if not hide_single_domain:
|
||||
args.append('-D')
|
||||
if access_method:
|
||||
args.append('-A{}'.format(access_method))
|
||||
if id_resolve_option != IDResolveOption.NameOnly:
|
||||
args.append(id_resolve_option.value)
|
||||
|
||||
if pciids:
|
||||
args.append('-i')
|
||||
if not isinstance(pciids, Path):
|
||||
pciids = Path(pciids)
|
||||
assert pciids.is_file(), 'ID database file not found'
|
||||
args.append(str(pciids.absolute()))
|
||||
|
||||
if pcimap:
|
||||
args.append('-p')
|
||||
if not isinstance(pcimap, Path):
|
||||
pcimap = Path(pcimap)
|
||||
assert pcimap.is_file(), 'Kernel module mapping file not found'
|
||||
args.append(str(pcimap.absolute()))
|
||||
|
||||
if file:
|
||||
args.append('-F')
|
||||
if not isinstance(file, Path):
|
||||
file = Path(file)
|
||||
assert file.is_file(), 'Hex dump file not found'
|
||||
args.append(str(file.absolute()))
|
||||
|
||||
for key, value in pcilib_params.items():
|
||||
args.append('-O{}={}'.format(key, value))
|
||||
|
||||
return subprocess.check_output(
|
||||
args,
|
||||
universal_newlines=True,
|
||||
)
|
|
@ -1,10 +1,10 @@
|
|||
from typing import Union, List
|
||||
from cached_property import cached_property
|
||||
from pylspci.command import lspci
|
||||
from pylspci.fields import hexstring, Slot, NameWithID
|
||||
from pylspci.device import Device
|
||||
import argparse
|
||||
import shlex
|
||||
import subprocess
|
||||
|
||||
|
||||
class SimpleFormatParser(object):
|
||||
|
@ -58,8 +58,5 @@ class SimpleFormatParser(object):
|
|||
def from_lspci(self) -> List[Device]:
|
||||
return list(map(
|
||||
self.parse,
|
||||
subprocess.check_output(
|
||||
['lspci', '-nnmm'],
|
||||
universal_newlines=True,
|
||||
).splitlines(),
|
||||
lspci().splitlines(),
|
||||
))
|
||||
|
|
186
pylspci/tests/test_command.py
Normal file
186
pylspci/tests/test_command.py
Normal file
|
@ -0,0 +1,186 @@
|
|||
from unittest import TestCase
|
||||
from unittest.mock import patch, call, MagicMock
|
||||
from pylspci.command import lspci, IDResolveOption
|
||||
|
||||
|
||||
class TestCommand(TestCase):
|
||||
|
||||
@patch('pylspci.command.subprocess.check_output')
|
||||
def test_default(self, cmd_mock: MagicMock) -> None:
|
||||
cmd_mock.return_value = 'something'
|
||||
self.assertEqual(lspci(), 'something')
|
||||
self.assertEqual(cmd_mock.call_count, 1)
|
||||
self.assertEqual(cmd_mock.call_args, call(
|
||||
['lspci', '-mm', '-nn'], universal_newlines=True,
|
||||
))
|
||||
|
||||
@patch('pylspci.command.Path.is_file')
|
||||
@patch('pylspci.command.subprocess.check_output')
|
||||
def test_pciids(self, cmd_mock: MagicMock, is_file_mock: MagicMock):
|
||||
cmd_mock.return_value = 'something'
|
||||
is_file_mock.return_value = True
|
||||
self.assertEqual(lspci(pciids='/somewhere'), 'something')
|
||||
self.assertEqual(cmd_mock.call_count, 1)
|
||||
self.assertEqual(cmd_mock.call_args, call(
|
||||
['lspci', '-mm', '-nn', '-i', '/somewhere'],
|
||||
universal_newlines=True,
|
||||
))
|
||||
self.assertEqual(is_file_mock.call_count, 1)
|
||||
|
||||
@patch('pylspci.command.Path.is_file')
|
||||
def test_pciids_missing(self, is_file_mock: MagicMock):
|
||||
is_file_mock.return_value = False
|
||||
with self.assertRaises(AssertionError):
|
||||
lspci(pciids='/nowhere')
|
||||
self.assertEqual(is_file_mock.call_count, 1)
|
||||
|
||||
@patch('pylspci.command.Path.is_file')
|
||||
@patch('pylspci.command.subprocess.check_output')
|
||||
def test_pcimap(self, cmd_mock: MagicMock, is_file_mock: MagicMock):
|
||||
cmd_mock.return_value = 'something'
|
||||
is_file_mock.return_value = True
|
||||
self.assertEqual(lspci(pcimap='/somewhere'), 'something')
|
||||
self.assertEqual(cmd_mock.call_count, 1)
|
||||
self.assertEqual(cmd_mock.call_args, call(
|
||||
['lspci', '-mm', '-nn', '-p', '/somewhere'],
|
||||
universal_newlines=True,
|
||||
))
|
||||
self.assertEqual(is_file_mock.call_count, 1)
|
||||
|
||||
@patch('pylspci.command.Path.is_file')
|
||||
def test_pcimap_missing(self, is_file_mock: MagicMock):
|
||||
is_file_mock.return_value = False
|
||||
with self.assertRaises(AssertionError):
|
||||
lspci(pcimap='/nowhere')
|
||||
self.assertEqual(is_file_mock.call_count, 1)
|
||||
|
||||
@patch('pylspci.command.subprocess.check_output')
|
||||
def test_access_method(self, cmd_mock: MagicMock) -> None:
|
||||
cmd_mock.return_value = 'something'
|
||||
self.assertEqual(lspci(access_method='somemethod'), 'something')
|
||||
self.assertEqual(cmd_mock.call_count, 1)
|
||||
self.assertEqual(cmd_mock.call_args, call(
|
||||
['lspci', '-mm', '-Asomemethod', '-nn'], universal_newlines=True,
|
||||
))
|
||||
|
||||
@patch('pylspci.command.subprocess.check_output')
|
||||
def test_pcilib_params(self, cmd_mock: MagicMock) -> None:
|
||||
cmd_mock.return_value = 'something'
|
||||
self.assertEqual(lspci(pcilib_params={'a': 'b', 'c': 2}), 'something')
|
||||
self.assertEqual(cmd_mock.call_count, 1)
|
||||
self.assertEqual(cmd_mock.call_args, call(
|
||||
['lspci', '-mm', '-nn', '-Oa=b', '-Oc=2'],
|
||||
universal_newlines=True,
|
||||
))
|
||||
|
||||
@patch('pylspci.command.Path.is_file')
|
||||
@patch('pylspci.command.subprocess.check_output')
|
||||
def test_file(self, cmd_mock: MagicMock, is_file_mock: MagicMock):
|
||||
cmd_mock.return_value = 'something'
|
||||
is_file_mock.return_value = True
|
||||
self.assertEqual(lspci(file='/somewhere'), 'something')
|
||||
self.assertEqual(cmd_mock.call_count, 1)
|
||||
self.assertEqual(cmd_mock.call_args, call(
|
||||
['lspci', '-mm', '-nn', '-F', '/somewhere'],
|
||||
universal_newlines=True,
|
||||
))
|
||||
self.assertEqual(is_file_mock.call_count, 1)
|
||||
|
||||
@patch('pylspci.command.Path.is_file')
|
||||
def test_file_missing(self, is_file_mock: MagicMock):
|
||||
is_file_mock.return_value = False
|
||||
with self.assertRaises(AssertionError):
|
||||
lspci(file='/nowhere')
|
||||
self.assertEqual(is_file_mock.call_count, 1)
|
||||
|
||||
@patch('pylspci.command.subprocess.check_output')
|
||||
def test_verbose(self, cmd_mock: MagicMock) -> None:
|
||||
cmd_mock.return_value = 'something'
|
||||
self.assertEqual(lspci(verbose=True), 'something')
|
||||
self.assertEqual(cmd_mock.call_count, 1)
|
||||
self.assertEqual(cmd_mock.call_args, call(
|
||||
['lspci', '-mm', '-vvv', '-nn'],
|
||||
universal_newlines=True,
|
||||
))
|
||||
|
||||
@patch('pylspci.command.subprocess.check_output')
|
||||
def test_kernel_drivers(self, cmd_mock: MagicMock) -> None:
|
||||
cmd_mock.return_value = 'something'
|
||||
self.assertEqual(lspci(kernel_drivers=True), 'something')
|
||||
self.assertEqual(cmd_mock.call_count, 1)
|
||||
self.assertEqual(cmd_mock.call_args, call(
|
||||
['lspci', '-mm', '-k', '-nn'],
|
||||
universal_newlines=True,
|
||||
))
|
||||
|
||||
@patch('pylspci.command.subprocess.check_output')
|
||||
def test_hide_single_domain(self, cmd_mock: MagicMock) -> None:
|
||||
cmd_mock.return_value = 'something'
|
||||
self.assertEqual(lspci(hide_single_domain=False), 'something')
|
||||
self.assertEqual(cmd_mock.call_count, 1)
|
||||
self.assertEqual(cmd_mock.call_args, call(
|
||||
['lspci', '-mm', '-D', '-nn'],
|
||||
universal_newlines=True,
|
||||
))
|
||||
|
||||
@patch('pylspci.command.subprocess.check_output')
|
||||
def test_id_resolve_option_id_only(self, cmd_mock: MagicMock) -> None:
|
||||
cmd_mock.return_value = 'something'
|
||||
self.assertEqual(
|
||||
lspci(id_resolve_option=IDResolveOption.IDOnly),
|
||||
'something',
|
||||
)
|
||||
self.assertEqual(cmd_mock.call_count, 1)
|
||||
self.assertEqual(cmd_mock.call_args, call(
|
||||
['lspci', '-mm', '-n'],
|
||||
universal_newlines=True,
|
||||
))
|
||||
|
||||
@patch('pylspci.command.subprocess.check_output')
|
||||
def test_id_resolve_option_name_only(self, cmd_mock: MagicMock) -> None:
|
||||
cmd_mock.return_value = 'something'
|
||||
self.assertEqual(
|
||||
lspci(id_resolve_option=IDResolveOption.NameOnly),
|
||||
'something',
|
||||
)
|
||||
self.assertEqual(cmd_mock.call_count, 1)
|
||||
self.assertEqual(cmd_mock.call_args, call(
|
||||
['lspci', '-mm'],
|
||||
universal_newlines=True,
|
||||
))
|
||||
|
||||
@patch('pylspci.command.Path.is_file')
|
||||
@patch('pylspci.command.subprocess.check_output')
|
||||
def test_everything(self, cmd_mock: MagicMock, is_file_mock: MagicMock):
|
||||
cmd_mock.return_value = 'something'
|
||||
is_file_mock.return_value = True
|
||||
|
||||
self.assertEqual(lspci(
|
||||
pciids='/pciids',
|
||||
pcimap='/pcimap',
|
||||
access_method='somemethod',
|
||||
pcilib_params={'a': 'b', 'c': 42},
|
||||
file='/file',
|
||||
verbose=True,
|
||||
kernel_drivers=True,
|
||||
hide_single_domain=False,
|
||||
id_resolve_option=IDResolveOption.IDOnly,
|
||||
), 'something')
|
||||
|
||||
self.assertEqual(cmd_mock.call_count, 1)
|
||||
self.assertEqual(cmd_mock.call_args, call(
|
||||
['lspci',
|
||||
'-mm',
|
||||
'-vvv',
|
||||
'-k',
|
||||
'-D',
|
||||
'-Asomemethod',
|
||||
'-n',
|
||||
'-i', '/pciids',
|
||||
'-p', '/pcimap',
|
||||
'-F', '/file',
|
||||
'-Oa=b',
|
||||
'-Oc=42'],
|
||||
universal_newlines=True,
|
||||
))
|
||||
self.assertEqual(is_file_mock.call_count, 3)
|
|
@ -74,7 +74,7 @@ class TestSimpleFormatParser(TestCase):
|
|||
self.assertIsNone(dev.revision)
|
||||
self.assertIsNone(dev.progif)
|
||||
|
||||
@patch('pylspci.simple_parser.subprocess.check_output')
|
||||
@patch('pylspci.simple_parser.lspci')
|
||||
def test_command(self, cmd_mock: MagicMock) -> None:
|
||||
cmd_mock.return_value = \
|
||||
'00:1c.3 "PCI bridge [0604]" "Intel Corporation [8086]" ' \
|
||||
|
@ -87,7 +87,4 @@ class TestSimpleFormatParser(TestCase):
|
|||
self._check_device(devices[1])
|
||||
|
||||
self.assertEqual(cmd_mock.call_count, 1)
|
||||
self.assertEqual(cmd_mock.call_args, call(
|
||||
['lspci', '-nnmm'],
|
||||
universal_newlines=True,
|
||||
))
|
||||
self.assertEqual(cmd_mock.call_args, call())
|
||||
|
|
Loading…
Reference in New Issue
Block a user