Compare commits

...

25 Commits

Author SHA1 Message Date
Lucidiot 1f7cac1d8c
Update pre-commit hooks
continuous-integration/drone/push Build is passing Details
2023-05-09 13:06:37 +02:00
Lucidiot ac6a1b3103
Add Python 3.11 in CI
continuous-integration/drone Build is failing Details
2023-05-09 12:48:18 +02:00
~lucidiot 04e3354394
Split PyPI secrets
continuous-integration/drone/push Build is passing Details
2022-08-09 14:19:14 +02:00
~lucidiot 91918e8d41
Bump to 0.4.3
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
continuous-integration/drone Build is passing Details
2022-08-05 01:53:28 +02:00
~lucidiot e3a89613e1
Updates due to Tildegit move 2022-08-05 01:53:08 +02:00
~lucidiot 4438f17e94
Bump to 0.4.2 2022-02-08 22:44:56 +01:00
~lucidiot 70b155cf04
Fix missing files in source packages 2022-02-08 22:43:02 +01:00
~lucidiot d6becffcc0
Bump to 0.4.1 2022-01-26 19:19:40 +01:00
~lucidiot 27cc5de1b9 Merge branch 'manifest' into 'master'
Add MANIFEST.in

Closes #21

See merge request Lucidiot/pylspci!19
2022-01-26 18:19:26 +00:00
~lucidiot 1936c58dec
Add MANIFEST.in 2022-01-26 19:17:26 +01:00
~lucidiot 544edd0b3d
Bump to 0.4.0 2021-09-21 20:12:18 +02:00
~lucidiot da39b09ef5 Merge branch 'bump-python' into 'master'
Bump CI image to Python 3.9

See merge request Lucidiot/pylspci!18
2021-09-21 18:09:03 +00:00
~lucidiot 149b3bde99
Bump CI image to Python 3.9 2021-09-21 20:06:55 +02:00
~lucidiot ad52e4c823 Merge branch 'docs-cleanup' into 'master'
Remove unnecessary types in Sphinx docstrings

See merge request Lucidiot/pylspci!17
2021-09-21 18:05:37 +00:00
~lucidiot 30e1ed5ec4
Remove unnecessary types in Sphinx docstrings 2021-09-21 20:03:21 +02:00
~lucidiot 7cebd6202d Merge branch 'as-dict' into 'master'
Add dict serialization methods

Closes #20

See merge request Lucidiot/pylspci!16
2021-09-21 18:02:32 +00:00
~lucidiot 57d96ab345
Add dict serialization methods 2021-09-21 19:51:28 +02:00
~lucidiot 386b7fc326 Merge branch 'bump-pre-commit' into 'master'
Bump pre-commit hooks

See merge request Lucidiot/pylspci!15
2021-09-21 17:48:51 +00:00
~lucidiot 587a55af73
Bump pre-commit hooks 2021-09-21 19:46:45 +02:00
~lucidiot 96cbe0e72c Merge branch 'fix-setup' into 'master'
Fix setup.py test for Alpine build

See merge request Lucidiot/pylspci!14
2021-09-21 17:03:26 +00:00
~lucidiot 09256806f1
Fix setup.py test for Alpine build
This removes some unnecessary dependencies installed by setup.py test,
fixing an issue found in Alpine's package building CI:

https://gitlab.alpinelinux.org/Lucidiot/aports/-/jobs/492430
2021-09-21 01:35:01 +02:00
Lucidiot 27695dd747 Bump to 0.3.4 2021-01-26 17:28:44 +00:00
Lucidiot 0b00a2e586 Update physical_slot docstring 2021-01-26 17:27:20 +00:00
Lucidiot 06906411a1 Merge branch 'change_phy_slot_to_str' into 'master'
Changed physical_slot to str, because linux adds '-#' if duplicate slot numbers are found

See merge request Lucidiot/pylspci!13
2021-01-26 17:21:41 +00:00
Jan Lützler 9f90cf8519 Changed physical_slot to str, because linux adds '-#' if duplicate slot numbers are found 2021-01-26 17:21:41 +00:00
19 changed files with 340 additions and 213 deletions

120
.drone.yml Normal file
View File

@ -0,0 +1,120 @@
---
kind: pipeline
type: docker
name: default
steps:
- name: pre-commit
image: python:3-alpine
commands:
- apk add --no-cache git gcc musl-dev
- pip install .[dev]
- pre-commit run -a
- name: test-py36
image: python:3.6-alpine
commands:
- pip install .[dev]
- coverage run setup.py test
- coverage report
- name: test-py37
image: python:3.7-alpine
commands:
- pip install .[dev]
- coverage run setup.py test
- coverage report
- name: test-py38
image: python:3.8-alpine
commands:
- pip install .[dev]
- coverage run setup.py test
- coverage report
- name: test-py39
image: python:3.9-alpine
commands:
- pip install .[dev]
- coverage run setup.py test
- coverage report
- name: test-py310
image: python:3.10-alpine
commands:
- pip install .[dev]
- coverage run setup.py test
- coverage report
- name: test-py311
image: python:3.11-alpine
commands:
- pip install .[dev]
- coverage run setup.py test
- coverage report
- name: testpypi
image: python:3.11-alpine
commands:
- pip install .[dev] twine setuptools wheel
- |
echo "[distutils]
index-servers = testpypi
[testpypi]
repository=https://test.pypi.org/legacy/
username=$$TESTPYPI_DEPLOY_USERNAME
password=$$TESTPYPI_DEPLOY_PASSWORD" > ~/.pypirc
- python setup.py sdist bdist_wheel
- twine upload dist/* -r testpypi
when:
event:
- promote
repo:
- lucidiot/pylspci
depends_on:
- pre-commit
- test-py36
- test-py37
- test-py38
- test-py39
- test-py310
- test-py311
environment:
TESTPYPI_DEPLOY_USERNAME:
from_secret: testpypi_username
TESTPYPI_DEPLOY_PASSWORD:
from_secret: testpypi_password
- name: pypi
image: python:3.11-alpine
commands:
- pip install .[dev] twine setuptools wheel
- |
echo "[distutils]
index-servers = pypi
[pypi]
repository=https://upload.pypi.org/legacy/
username=$$PYPI_DEPLOY_USERNAME
password=$$PYPI_DEPLOY_PASSWORD" > ~/.pypirc
- python setup.py sdist bdist_wheel
- twine upload dist/* -r pypi
when:
event:
- promote
repo:
- lucidiot/pylspci
branch:
- master
depends_on:
- testpypi
environment:
PYPI_DEPLOY_USERNAME:
from_secret: pypi_username
PYPI_DEPLOY_PASSWORD:
from_secret: pypi_password

View File

@ -1,90 +0,0 @@
image: python:3.7
stages:
- test
- deploy
variables:
PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip"
cache:
paths:
- .cache/pip
- venv/
before_script:
- pip install virtualenv
- virtualenv venv
- source venv/bin/activate
- pip install .[dev]
tests:
stage: test
coverage: '/TOTAL[\s\d]+\s(\d+%)/'
script:
- coverage run setup.py test
- coverage report
- codecov
pre-commit:
stage: test
script:
- pre-commit run -a
deploy-pypi:
stage: deploy
when: manual
only:
- master@Lucidiot/pylspci
environment:
name: pypi
url: https://pypi.org/project/pylspci
script:
- pip install twine setuptools wheel
- echo "[distutils]" > ~/.pypirc
- echo "index-servers =" >> ~/.pypirc
- echo " pypi" >> ~/.pypirc
- echo "[pypi]" >> ~/.pypirc
- echo "repository=https://upload.pypi.org/legacy/" >> ~/.pypirc
- echo "username=$PYPI_DEPLOY_USERNAME" >> ~/.pypirc
- echo "password=$PYPI_DEPLOY_PASSWORD" >> ~/.pypirc
- python setup.py sdist bdist_wheel
- twine upload dist/* -r pypi
deploy-testpypi:
stage: deploy
when: manual
only:
- branches@Lucidiot/pylspci
environment:
name: testpypi
url: https://test.pypi.org/project/pylspci
script:
- pip install twine setuptools wheel
- echo "[distutils]" > ~/.pypirc
- echo "index-servers =" >> ~/.pypirc
- echo " testpypi" >> ~/.pypirc
- echo "[testpypi]" >> ~/.pypirc
- echo "repository=https://test.pypi.org/legacy/" >> ~/.pypirc
- echo "username=$PYPI_DEPLOY_USERNAME" >> ~/.pypirc
- echo "password=$PYPI_DEPLOY_PASSWORD" >> ~/.pypirc
- python setup.py sdist bdist_wheel
- twine upload dist/* -r testpypi
pages:
stage: deploy
when: manual
needs:
- pre-commit
only:
- master@Lucidiot/pylspci
artifacts:
paths:
- public
script:
- cd docs
- make html
- mv _build/html ../public

View File

@ -2,7 +2,7 @@
# See https://pre-commit.com/hooks.html for more hooks
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v3.2.0
rev: v4.4.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
@ -11,12 +11,12 @@ repos:
- id: check-merge-conflict
- id: check-executables-have-shebangs
- id: check-symlinks
- repo: https://gitlab.com/PyCQA/flake8
rev: 3.8.4
- repo: https://github.com/PyCQA/flake8
rev: 6.0.0
hooks:
- id: flake8
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v0.790
rev: v1.2.0
hooks:
- id: mypy
args:
@ -26,10 +26,10 @@ repos:
- --check-untyped-defs
- --no-implicit-optional
- repo: https://github.com/PyCQA/doc8
rev: 0.8.1
rev: v1.1.1
hooks:
- id: doc8
- repo: https://github.com/PyCQA/isort
rev: 5.6.4
rev: 5.12.0
hooks:
- id: isort

6
MANIFEST.in Normal file
View File

@ -0,0 +1,6 @@
include requirements.txt
include requirements-dev.txt
include VERSION
include LICENSE
include README.rst
include pylspci/py.typed

View File

@ -5,4 +5,4 @@ A Python parser for the ``lspci`` command from the pciutils_ package.
`Browse documentation`_
.. _pciutils: http://mj.ucw.cz/sw/pciutils/
.. _Browse documentation: https://lucidiot.gitlab.io/pylspci/
.. _Browse documentation: https://lucidiot.tildepages.org/pylspci/

View File

@ -1 +1 @@
0.3.3
0.4.3

View File

@ -21,7 +21,7 @@ sys.path.insert(0, os.path.abspath('..'))
# -- Project information -----------------------------------------------------
project = 'pylspci'
copyright = '2019, Lucidiot and contributors'
copyright = '2022, Lucidiot and contributors'
author = 'Lucidiot and contributors'
# The short X.Y version
@ -62,7 +62,7 @@ master_doc = 'index'
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = None
language = 'en'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.

View File

@ -6,8 +6,8 @@ Contributions to the project are greatly appreciated.
Bugs and suggestions
--------------------
You may `submit an issue`_ to GitLab to warn of any bugs, ask for new features,
or ask any questions that are not answered in this documentation.
You may `submit an issue`_ to the Gitea repository to warn of any bugs, ask for
new features, or ask any questions that are not answered in this documentation.
When reporting a bug, do not forget to put in your version of Python and your
version of *pylspci*. This will greatly help when troubleshooting, as most
@ -22,7 +22,7 @@ Setup
You will need a virtual envionment to work properly. `virtualenvwrapper`_ is
recommended::
git clone https://gitlab.com/Lucidiot/pylspci
git clone https://tildegit.org/lucidiot/pylspci.git
cd pylspci
mkvirtualenv -a . pylspci
pip install -e .[dev]
@ -44,8 +44,8 @@ Tests coverage
I aim for 100% coverage on all of my Python packages whenever I add unit
tests to them; this package is no exception. CI checks use the `coverage`_
Python package and `codecov`_ to check for test coverage. To get test coverage
data locally, run::
Python package to get coverage statistics.
To get test coverage data locally, run::
coverage run setup.py test
@ -60,7 +60,7 @@ offline using your favorite web browser and shows line by line coverage::
If you are having issues reaching 100% coverage, try to still add some tests,
and mention your issues when creating a pull request to the
`GitLab repository`_.
`Gitea repository`_.
Linting
^^^^^^^
@ -82,13 +82,12 @@ Documentation
The documentation you are reading is generated by the `Sphinx`_ tool.
The text files that hold the documentation's contents are written in
`reStructuredText`_ and are available under the ``/docs`` folder of the
`GitLab repository`_.
`Gitea repository`_.
They are also subject to linting using the ``doc8`` tool.
.. _submit an issue: https://gitlab.com/Lucidiot/pylspci/issues/new
.. _submit an issue: https://tildegit.org/lucidiot/pylspci/issues/new
.. _virtualenvwrapper: https://virtualenvwrapper.readthedocs.io
.. _coverage: https://coverage.readthedocs.io/
.. _codecov: https://codecov.io/gl/Lucidiot/pylspci
.. _GitLab repository: https://gitlab.com/Lucidiot/pylspci
.. _Gitea repository: https://tildegit.org/lucidiot/pylspci
.. _Sphinx: http://www.sphinx-doc.org/
.. _reStructuredText: http://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html

View File

@ -18,14 +18,11 @@ Python lspci parser
.. image:: https://img.shields.io/pypi/status/pylspci.svg
:target: https://pypi.org/project/pylspci
.. image:: https://gitlab.com/Lucidiot/pylspci/badges/master/pipeline.svg
:target: https://gitlab.com/Lucidiot/pylspci/pipelines
.. image:: https://drone.tildegit.org/api/badges/lucidiot/pylspci/status.svg
:target: https://drone.tildegit.org/api/badges/lucidiot/pylspci/status.svg
.. image:: https://codecov.io/gl/Lucidiot/pylspci/branch/master/graph/badge.svg
:target: https://codecov.io/gl/Lucidiot/pylspci
.. image:: https://img.shields.io/badge/badge%20count-8-brightgreen.svg
:target: https://gitlab.com/Lucidiot/pylspci
.. image:: https://img.shields.io/badge/badge%20count-7-brightgreen.svg
:target: https://tildegit.org/lucidiot/pylspci
A Python parser for the ``lspci`` command from the pciutils_ package.

View File

@ -161,8 +161,7 @@ def main() -> None:
parser: argparse.ArgumentParser = get_parser()
args: Dict[str, Any] = vars(parser.parse_args())
# Specific parsing required
use_parser: bool = args.pop('json', True)
json_output: bool = args.pop('json', True)
kernel_modules: bool = args.pop('kernel_modules', False)
access_method: Optional[str] = args.pop('access_method', None)
pcilib_params = args.pop('pcilib_params', []) or []
@ -179,7 +178,7 @@ def main() -> None:
for param in pcilib_params:
if param.strip().lower() == 'help':
builder = builder.list_pcilib_params(raw=not use_parser)
builder = builder.list_pcilib_params(raw=not json_output)
break
if '=' not in param:
parser.error(
@ -187,24 +186,19 @@ def main() -> None:
key, value = map(str.strip, param.split('=', 2))
builder = builder.with_pcilib_params(**{key: value})
if use_parser:
if json_output:
builder = builder.with_default_parser()
result = list(builder)
if not use_parser: # Raw mode
if not json_output: # Raw mode
for item in result:
print(item)
return
def _item_handler(item: Any) -> Any:
if hasattr(item, '_asdict'):
return item._asdict()
return item
print(json.dumps(
list(map(_item_handler, result)),
default=vars,
))
print(json.dumps([
item if isinstance(item, str) else item.as_dict()
for item in result
]))
if __name__ == '__main__':

View File

@ -1,6 +1,15 @@
from typing import List, NamedTuple, Optional
from typing import Dict, List, NamedTuple, Optional, Union
from pylspci.fields import NameWithID, Slot
from pylspci.fields import NameWithID, NameWithIDDict, Slot, SlotDict
DeviceDict = Dict[str, Union[
int,
str,
SlotDict,
NameWithIDDict,
List[str],
None,
]]
class Device(NamedTuple):
@ -11,90 +20,92 @@ class Device(NamedTuple):
slot: Slot
"""
The device's slot (domain, bus, number and function).
:type: Slot
"""
cls: NameWithID
"""
The device's class, with a name and/or an ID.
:type: NameWithID
"""
vendor: NameWithID
"""
The device's vendor, with a name and/or an ID.
:type: NameWithID
"""
device: NameWithID
"""
The device's name and/or ID.
:type: NameWithID
"""
subsystem_vendor: Optional[NameWithID] = None
"""
The device's subsystem vendor, if found, with a name and/or an ID.
:type: NameWithID or None
"""
subsystem_device: Optional[NameWithID] = None
"""
The device's subsystem name and/or ID, if found.
:type: NameWithID or None
"""
revision: Optional[int] = None
"""
The device's revision number.
:type: int or None
"""
progif: Optional[int] = None
"""
The device's programming interface number.
:type: int or None
"""
driver: Optional[str] = None
"""
The device's driver (Linux only).
:type: str or None
"""
kernel_modules: List[str] = []
"""
One or more kernel modules that can handle this device (Linux only).
:type: List[str] or None
"""
numa_node: Optional[int] = None
"""
NUMA node this device is connected to (Linux only).
:type: int or None
"""
iommu_group: Optional[int] = None
"""
IOMMU group that this device is part of (optional, Linux only).
:type: int or None
"""
physical_slot: Optional[int] = None
physical_slot: Optional[str] = None
"""
The device's physical slot number (Linux only).
:type: int or None
"""
def as_dict(self) -> DeviceDict:
"""
Serialize this device as a JSON-serializable `dict`.
"""
return {
"slot": self.slot.as_dict(),
"cls": self.cls.as_dict(),
"vendor": self.vendor.as_dict(),
"device": self.device.as_dict(),
"subsystem_vendor": (
self.subsystem_vendor.as_dict()
if self.subsystem_vendor
else None
),
"subsystem_device": (
self.subsystem_device.as_dict()
if self.subsystem_device
else None
),
"revision": self.revision,
"progif": self.progif,
"driver": self.driver,
"kernel_modules": self.kernel_modules,
"numa_node": self.numa_node,
"iommu_group": self.iommu_group,
"physical_slot": self.physical_slot,
}

View File

@ -1,6 +1,11 @@
import re
from functools import partial
from typing import Any, Optional
from typing import Any, Dict, Optional, Union
# mypy does not support recursive type definitions
# SlotDict = Dict[str, Union[int, 'SlotDict', None]]
SlotDict = Dict[str, Union[int, Dict[str, Any], None]]
NameWithIDDict = Dict[str, Union[int, str, None]]
hexstring = partial(int, base=16)
@ -17,36 +22,26 @@ class Slot(object):
"""
The slot's domain, as a four-digit hexadecimal number.
When omitted, defaults to ``0x0000``.
:type: int
"""
bus: int
"""
The slot's bus, as a two-digit hexadecimal number.
:type: int
"""
device: int
"""
The slot's device, as a two-digit hexadecimal number, up to `0x1f`.
:type: int
"""
function: int
"""
The slot's function, as a single octal digit.
:type: int
"""
parent: Optional["Slot"] = None
"""
The slot's parent bridge, if present.
:type: Slot or None
"""
def __init__(self, value: str) -> None:
@ -75,6 +70,18 @@ class Slot(object):
def __repr__(self) -> str:
return '{}({!r})'.format(self.__class__.__name__, str(self))
def as_dict(self) -> SlotDict:
"""
Serialize this slot as a JSON-serializable `dict`.
"""
return {
"domain": self.domain,
"bus": self.bus,
"device": self.device,
"function": self.function,
"parent": self.parent.as_dict() if self.parent else None,
}
class NameWithID(object):
"""
@ -85,15 +92,11 @@ class NameWithID(object):
id: Optional[int]
"""
The PCI ID as a four-digit hexadecimal number.
:type: int or None
"""
name: Optional[str]
"""
The human-readable name associated with this ID.
:type: str or None
"""
_NAME_ID_REGEX = re.compile(r'^(?P<name>.+)\s\[(?P<id>[0-9a-fA-F]{4})\]$')
@ -131,6 +134,15 @@ class NameWithID(object):
def __repr__(self) -> str:
return '{}({!r})'.format(self.__class__.__name__, str(self))
def as_dict(self) -> NameWithIDDict:
"""
Serialize this name and ID as a JSON-serializable `dict`.
"""
return {
"id": self.id,
"name": self.name,
}
class PCIAccessParameter(object):
"""
@ -142,22 +154,16 @@ class PCIAccessParameter(object):
name: str
"""
The parameter's name.
:type: str
"""
description: str
"""
A short description of the parameter's use.
:type: str
"""
default: Optional[str]
"""
An optional default value for the parameter.
:type: str or None
"""
_PARAM_REGEX = re.compile(
@ -183,3 +189,13 @@ class PCIAccessParameter(object):
return isinstance(other, PCIAccessParameter) and \
(self.name, self.description, self.default) \
== (other.name, other.description, other.default)
def as_dict(self) -> Dict[str, Optional[str]]:
"""
Serialize this PCI access parameter as a JSON-serializable `dict`.
"""
return {
"name": self.name,
"description": self.description,
"default": self.default,
}

View File

@ -43,29 +43,21 @@ class SlotFilter(Filter):
domain: Optional[int] = None
"""
Device domain, as a four-digit hexadecimal number.
:type: int or None
"""
bus: Optional[int] = None
"""
Device bus, as a two-digit hexadecimal number.
:type: int or None
"""
device: Optional[int] = None
"""
Device number, as a two-digit hexadecimal number, up to `0x1f`.
:type: int or None
"""
function: Optional[int] = None
"""
The slot's function, as a single octal digit.
:type: int or None
"""
# [[domain:]bus:][device][.function]
@ -116,22 +108,16 @@ class DeviceFilter(Filter):
cls: Optional[int] = None
"""
Device class ID, as a four-digit hexadecimal number.
:type: int or None
"""
vendor: Optional[int] = None
"""
Device vendor ID, as a four-digit hexadecimal number.
:type: int or None
"""
device: Optional[int] = None
"""
Device ID, as a four-digit hexadecimal number.
:type: int or None
"""
# [vendor]:[device][:class]

View File

@ -8,7 +8,7 @@ from pylspci.parsers.base import Parser
UNKNOWN_FIELD_WARNING = (
'Unsupported device field {!r} with value {!r}\n'
'Please report this, along with the output of `lspci -mmnnvvvk`, at '
'https://gitlab.com/Lucidiot/pylspci/issues'
'https://tildegit.org/lucidiot/pylspci/issues/new'
)
@ -21,23 +21,17 @@ class FieldMapping(NamedTuple):
field_name: str
"""
Field name on the :class:`Device` named tuple.
:type: str
"""
field_type: Callable[[str], Any]
"""
Field type; a callable to use to parse the string value.
:type: Callable[[str], Any]
"""
many: bool = False
"""
Whether or not to use a List, if this field can be repeated multiple times
in the lspci output.
:type: bool
"""
@ -75,7 +69,7 @@ class VerboseParser(Parser):
),
'NUMANode': FieldMapping(field_name='numa_node', field_type=int),
'IOMMUGroup': FieldMapping(field_name='iommu_group', field_type=int),
'PhySlot': FieldMapping(field_name='physical_slot', field_type=int),
'PhySlot': FieldMapping(field_name='physical_slot', field_type=str),
}
def _parse_device(self, device_data: Union[str, Iterable[str]]) -> Device:

View File

@ -56,7 +56,7 @@ class TestVerboseParser(TestCase):
self.assertListEqual(dev.kernel_modules, ['nouveau', 'nvidia'])
self.assertEqual(dev.numa_node, 0)
self.assertEqual(dev.iommu_group, 1)
self.assertEqual(dev.physical_slot, 4)
self.assertEqual(dev.physical_slot, '4')
def test_parse_str(self) -> None:
devices: List[Device] = self.parser.parse(SAMPLE_DEVICE)
@ -87,7 +87,7 @@ class TestVerboseParser(TestCase):
msg="Unsupported device field 'NewField' with value 'Value'\n"
"Please report this, along with the output of"
"`lspci -mmnnvvvk`, at "
"https://gitlab.com/Lucidiot/pylspci/issues"):
"https://tildegit.org/lucidiot/pylspci/issues/new"):
devices: List[Device] = \
self.parser.parse(SAMPLE_DEVICE + 'NewField\tValue')

View File

@ -0,0 +1,60 @@
from unittest import TestCase
from pylspci.device import Device
from pylspci.fields import NameWithID, Slot
class TestDevice(TestCase):
def test_as_dict(self) -> None:
d = Device(
slot=Slot('cafe:13:07.2'),
cls=NameWithID('Something [caf3]'),
vendor=NameWithID('Something [caf3]'),
device=NameWithID('Something [caf3]'),
subsystem_vendor=NameWithID('Something [caf3]'),
subsystem_device=NameWithID('Something [caf3]'),
revision=20,
progif=1,
driver='self_driving',
kernel_modules=['snd-pcsp'],
numa_node=0,
iommu_group=1,
physical_slot='4-2',
)
self.assertDictEqual(d.as_dict(), {
'slot': {
'bus': 0x13,
'device': 0x07,
'domain': 0xcafe,
'function': 0x2,
'parent': None
},
'cls': {
'id': 0xcaf3,
'name': 'Something'
},
'vendor': {
'id': 0xcaf3,
'name': 'Something'
},
'device': {
'id': 0xcaf3,
'name': 'Something'
},
'subsystem_vendor': {
'id': 0xcaf3,
'name': 'Something'
},
'subsystem_device': {
'id': 0xcaf3,
'name': 'Something'
},
'revision': 20,
'progif': 1,
'driver': 'self_driving',
'kernel_modules': ['snd-pcsp'],
'numa_node': 0,
'iommu_group': 1,
'physical_slot': '4-2',
})

View File

@ -73,6 +73,16 @@ class TestSlot(TestCase):
self.assertEqual(s.parent.parent.device, 0x07)
self.assertEqual(s.parent.parent.function, 0x2)
def test_as_dict(self) -> None:
s = Slot('cafe:13:07.2')
self.assertDictEqual(s.as_dict(), {
"domain": 0xcafe,
"bus": 0x13,
"device": 0x07,
"function": 0x2,
"parent": None,
})
class TestNameWithID(TestCase):
@ -128,6 +138,13 @@ class TestNameWithID(TestCase):
self.assertIsNone(n.id)
self.assertEqual(n.name, 'Something [hexa]')
def test_as_dict(self) -> None:
n = NameWithID('Something [caf3]')
self.assertDictEqual(n.as_dict(), {
"id": 0xcaf3,
"name": "Something",
})
class TestPCIAccessParameter(TestCase):
@ -159,3 +176,11 @@ class TestPCIAccessParameter(TestCase):
p2 = PCIAccessParameter('param.name Some description ()')
self.assertEqual(p1, p1)
self.assertNotEqual(p1, p2)
def test_as_dict(self) -> None:
p = PCIAccessParameter('param.name Some description (default value)')
self.assertDictEqual(p.as_dict(), {
"name": "param.name",
"description": "Some description",
"default": "default value",
})

View File

@ -1,5 +1,4 @@
doc8>=0.8.0
Sphinx>=1.8.1
coverage>=4.5
codecov>=2.0
pre-commit>=2.9.2

View File

@ -22,22 +22,27 @@ setup(
'console_scripts': ['pylspci=pylspci.__main__:main'],
},
package_data={
'': ['VERSION', 'LICENSE', 'README.rst'],
'': [
'VERSION',
'LICENSE',
'README.rst',
'requirements.txt',
'requirements-dev.txt',
],
'pylspci': ['py.typed'],
},
python_requires='>=3.5',
python_requires='>=3.6',
install_requires=requirements,
extras_require={
'dev': dev_requirements,
},
tests_require=dev_requirements,
test_suite='pylspci.tests',
license='GNU General Public License 3',
description="Simple parser for lspci -mmnn.",
long_description=open('README.rst').read(),
long_description_content_type='text/x-rst',
keywords="lspci parser",
url="https://gitlab.com/Lucidiot/pylspci",
url="https://tildegit.org/lucidiot/pylspci",
classifiers=[
"Development Status :: 4 - Beta",
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
@ -45,16 +50,21 @@ setup(
"Intended Audience :: Developers",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.5",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Topic :: Software Development :: Libraries",
"Topic :: System :: Hardware",
"Topic :: Utilities",
"Typing :: Typed",
],
project_urls={
"Source Code": "https://gitlab.com/Lucidiot/pylspci",
"GitHub Mirror": "https://github.com/Lucidiot/pylspci",
"Homepage": "https://tildegit.org/lucidiot/pylspci",
"Changelog": "https://tildegit.org/lucidiot/pylspci/releases",
"Documentation": "https://lucidiot.tildepages.org/pylspci/",
"Issue tracker": "https://tildegit.org/lucidiot/pylspci/issues",
}
)