33
44We use [ SWIG] ( http://www.swig.org/ ) to generate Python bindings for libnvme.
55
6+ ## Classes
7+
8+ Five classes are exposed, matching the NVMe topology:
9+
10+ | Class | Description |
11+ | ---| ---|
12+ | ` nvme.GlobalCtx ` | Root context. Manages the NVMe device tree and logging. Create one instance per process. |
13+ | ` nvme.Host ` | Represents the local host: NQN, host ID, optional symbolic name (symname). |
14+ | ` nvme.Subsystem ` | An NVMe subsystem discovered under a host. |
15+ | ` nvme.Ctrl ` | An NVMe controller (physical or fabrics). Constructed from a configuration dict. |
16+ | ` nvme.Namespace ` | A namespace under a controller. |
17+
18+ All five classes support the context manager protocol (` with ` statement) for automatic cleanup.
19+
20+ Topology can be traversed with iterators: ` ctx.hosts() ` , ` host.subsystems() ` ,
21+ ` subsystem.controllers() ` , ` ctrl.namespaces() ` .
22+
23+ ### Ctrl configuration dict
24+
25+ ` nvme.Ctrl(ctx, cfg) ` accepts a flat dict. Common keys:
26+
27+ | Key | Description |
28+ | ---| ---|
29+ | ` subsysnqn ` | Subsystem NQN (required) |
30+ | ` transport ` | Transport type: ` pcie ` , ` tcp ` , ` rdma ` , ` fc ` , ` loop ` , ` apple-nvme ` (required) |
31+ | ` traddr ` | Target address |
32+ | ` trsvcid ` | Target service ID (port) |
33+ | ` host_iface ` | Local network interface to use |
34+ | ` hostnqn ` | Override the host NQN |
35+ | ` hostid ` | Override the host ID |
36+ | ` hdr_digest ` | Enable header digests (` bool ` ) |
37+ | ` data_digest ` | Enable data digests (` bool ` ) |
38+ | ` persistent ` | Keep the connection alive after the object is released (` bool ` ) |
39+
40+ ### Key Ctrl methods and properties
41+
42+ | Name | Type | Description |
43+ | ---| ---| ---|
44+ | ` connected ` | property | ` True ` if the controller is currently connected |
45+ | ` registration_supported ` | property | ` True ` if the target supports explicit host registration |
46+ | ` name ` | property | Kernel device name (e.g. ` nvme0 ` ), or ` None ` if not connected |
47+ | ` transport ` , ` traddr ` , ` trsvcid ` | properties | Connection parameters |
48+ | ` connect(host) ` | method | Establish the kernel connection |
49+ | ` disconnect() ` | method | Tear down the connection |
50+ | ` discover() ` | method | Retrieve the discovery log page (discovery controllers only) |
51+ | ` get_supported_log_pages() ` | method | Fetch the Supported Log Pages log |
52+ | ` rescan() ` | method | Rescan the controller and refresh its namespace list |
53+ | ` registration_control(tas) ` | method | Register / deregister / update with the DIM service |
54+
55+ ## Exceptions
56+
57+ All libnvme errors are reported through a small exception hierarchy:
58+
59+ ```
60+ NvmeError base class — carries .errno (int) and .message (str)
61+ ├── ConnectError raised by ctrl.connect()
62+ ├── DisconnectError raised by ctrl.disconnect()
63+ ├── DiscoverError raised by ctrl.discover()
64+ └── NotConnectedError raised when an operation requires a connected controller
65+ (.errno is always 0)
66+ ```
67+
68+ Import them directly from the ` nvme ` module:
69+
70+ ``` python
71+ from libnvme import nvme
72+
73+ try :
74+ ctrl.connect(host)
75+ except nvme.ConnectError as e:
76+ print (f " errno= { e.errno} , message= { e.message} " )
77+ except nvme.NotConnectedError:
78+ print (" not connected" )
79+ ```
80+
81+ ` NvmeError ` is also raised by ` get_supported_log_pages() ` and
82+ ` registration_control() ` on failure.
83+
684## How to use
785
886``` python
@@ -19,59 +97,75 @@ def disc_supp_str(dlp_supp_opts):
1997 }
2098 return [txt for msk, txt in bitmap.items() if dlp_supp_opts & msk]
2199
22- ctx = nvme.global_ctx() # This is a singleton
23- ctx.log_level(' debug' ) # Optional: extra debug info
100+ ctx = nvme.GlobalCtx()
101+ ctx.log_level(' debug' ) # Optional: extra debug info
24102
25- host = nvme.host(ctx) # This "may be" a singleton.
26- subsysnqn = [string] # e.g. nvme.NVME_DISC_SUBSYS_NAME, ...
27- transport = [string] # One of: 'tcp', 'rdma', 'fc', 'loop'.
28- traddr = [IPv4 or IPv6] # e.g. '192.168.10.10', 'fd2e:853b:3cad:e135:506a:65ee:29f2:1b18', ...
29- trsvcid = [string] # e.g. '8009', '4420', ...
30- host_iface = [interface] # e.g. 'eth1', ens256', ...
31- ctrl = nvme.ctrl(ctx, subsysnqn = subsysnqn, transport = transport, traddr = traddr, trsvcid = trsvcid, host_iface = host_iface)
103+ host = nvme.Host(ctx)
104+
105+ ctrl = nvme.Ctrl(ctx, {
106+ ' subsysnqn' : ' ...' , # e.g. nvme.NVME_DISC_SUBSYS_NAME
107+ ' transport' : ' ...' , # One of: 'tcp', 'rdma', 'fc', 'loop'
108+ ' traddr' : ' ...' , # e.g. '192.168.10.10'
109+ ' trsvcid' : ' ...' , # e.g. '8009', '4420'
110+ ' host_iface' : ' ...' , # e.g. 'eth1', 'ens256'
111+ ' hdr_digest' : True , # Enable header digests
112+ ' data_digest' : False , # Disable data digests
113+ })
32114
33115try :
34- cfg = {
35- ' hdr_digest' : True , # Enable header digests
36- ' data_digest' : False , # Disable data digests
37- }
38- ctrl.connect(host, cfg)
116+ ctrl.connect(host)
39117 print (f " connected to { ctrl.name} subsys { ctrl.subsystem.name} " )
40- except Exception as e:
118+ except nvme.ConnectError as e:
41119 sys.exit(f ' Failed to connect: { e} ' )
42120
43- supported_log_pages = ctrl.supported_log_pages()
44121try :
45- # Get the supported options for the Get Discovery Log Page command
46- dlp_supp_opts = supported_log_pages [nvme.NVME_LOG_LID_DISCOVERY ] >> 16
47- except (TypeError , IndexError ):
122+ slp = ctrl.get_supported_log_pages()
123+ dlp_supp_opts = slp [nvme.NVME_LOG_LID_DISCOVERY ] >> 16
124+ except (nvme.NvmeError , IndexError , TypeError ):
48125 dlp_supp_opts = 0
49126
50127print (f " LID { nvme.NVME_LOG_LID_DISCOVERY :02x } h (Discovery), supports: { disc_supp_str(dlp_supp_opts)} " )
128+
51129try :
52130 lsp = nvme.NVMF_LOG_DISC_LSP_PLEO if dlp_supp_opts & nvme.NVMF_LOG_DISC_LID_PLEOS else 0
53131 log_pages = ctrl.discover(lsp = lsp)
54132 print (pprint.pformat(log_pages))
55- except Exception as e:
133+ except nvme.DiscoverError as e:
56134 sys.exit(f ' Failed to retrieve log pages: { e} ' )
57135
58136try :
59137 ctrl.disconnect()
60- except Exception as e:
138+ except nvme.DisconnectError as e:
61139 sys.exit(f ' Failed to disconnect: { e} ' )
62-
63- ctrl = None
64- host = None
65- ctx = None
66140```
67141
68- ## Testing PyPI package
142+ ## Installation
69143
70- Use the following command to test installing the package from TestPyPI before publishing to the official PyPI registry.
144+ The package is available from most Linux distribution repositories and on PyPI.
145+
146+ ** From your distribution (recommended):**
71147
72148``` bash
73- pip install \
74- --index-url https://test.pypi.org/simple/ \
75- --extra-index-url https://pypi.org/simple/ \
76- libnvme==[libnvme-version]
149+ # Debian / Ubuntu
150+ apt-get install python3-libnvme
151+
152+ # Fedora
153+ dnf install python3-libnvme
154+
155+ # openSUSE
156+ zypper install python3-libnvme
77157```
158+
159+ ** From PyPI:**
160+
161+ ``` bash
162+ pip install libnvme
163+ ```
164+
165+ > ** Note:** The PyPI package is a source distribution — it builds libnvme and
166+ > the Python bindings directly on your machine. Build dependencies (a C
167+ > compiler, Meson, Ninja, SWIG, and the libnvme C dependencies) must be
168+ > present. If any are missing, ` pip install ` will fail. Installing from your
169+ > distribution package manager is generally easier and avoids this requirement.
170+
171+ See [ PUBLISHING.md] ( PUBLISHING.md ) for instructions on testing and publishing new releases.
0 commit comments