{"id":17327045,"url":"https://github.com/jaypipes/hwk","last_synced_at":"2026-02-25T19:33:51.676Z","repository":{"id":62569893,"uuid":"84237940","full_name":"jaypipes/hwk","owner":"jaypipes","description":"Simple library for common hardware-related discovery and manipulation routines","archived":false,"fork":false,"pushed_at":"2017-06-03T23:56:32.000Z","size":113,"stargazers_count":0,"open_issues_count":6,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-10-28T05:26:36.044Z","etag":null,"topics":["discovery","hardware","hardware-information","python"],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jaypipes.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-03-07T19:30:41.000Z","updated_at":"2017-06-02T22:38:25.000Z","dependencies_parsed_at":"2022-11-03T16:32:22.152Z","dependency_job_id":null,"html_url":"https://github.com/jaypipes/hwk","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/jaypipes/hwk","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jaypipes%2Fhwk","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jaypipes%2Fhwk/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jaypipes%2Fhwk/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jaypipes%2Fhwk/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jaypipes","download_url":"https://codeload.github.com/jaypipes/hwk/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jaypipes%2Fhwk/sbom","scorecard":{"id":509155,"data":{"date":"2025-08-11","repo":{"name":"github.com/jaypipes/hwk","commit":"b43be56fafc7e853614cafc7d02c734aadb72cbe"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3,"checks":[{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE.txt:0","Info: FSF or OSI recognized license: Apache License 2.0: LICENSE.txt:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}}]},"last_synced_at":"2025-08-20T00:05:01.819Z","repository_id":62569893,"created_at":"2025-08-20T00:05:01.819Z","updated_at":"2025-08-20T00:05:01.819Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29836310,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-25T19:08:47.527Z","status":"ssl_error","status_checked_at":"2026-02-25T18:59:04.705Z","response_time":61,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["discovery","hardware","hardware-information","python"],"created_at":"2024-10-15T14:18:27.416Z","updated_at":"2026-02-25T19:33:51.657Z","avatar_url":"https://github.com/jaypipes.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# hwk - The HardWare toolKit library [![PyPI version](https://badge.fury.io/py/hwk.svg)](https://badge.fury.io/py/hwk)[![Build Status](https://travis-ci.org/jaypipes/hwk.svg?branch=master)](https://travis-ci.org/jaypipes/hwk)\n\n`hwk` is a small Python library containing hardware discovery and configuration\ntools.\n\n## Design Principles\n\n### No root privileges needed for discovery\n\n`hwk` goes the extra mile to be useful without root priveleges. We query for\nhost hardware information as directly as possible without relying on shellouts\nto programs like `dmidecode` that require root privileges to execute.\n\nOf course, manipulating hardware often requires elevated privileges, and that\nis fine. However, when querying for device and host hardware information, we\nwill not use any method that requires elevating to root/superuser.\n\n### Well-documented code and inline help\n\nThe code itself should be well-documented, of course, but the objects that the\nlibrary exposes should themselves be self-describing. See below for the\n`describe()` methods that the Info objects all implement.\n\n### Interfaces should be consistent across modules\n\nEach module in the library is structured in a consistent fashion, and the\nobjects returned by various module functions should have consistent attribute\nand method names.\n\n## Usage\n\n### Discovery\n\nYou can use the functions in `hwk` to determine various\nhardware-related information about the host computer.\n\nEach module in `hwk` contains a single `info()` function that returns an object\ncontaining information about a particular subsystem or component. For example,\nto get information about the memory subsystem, you would use the\n`hwk.memory.info()` function. The `hwk.block.info()` method likewise returns an\nobject that describes the block devices of the host.\n\nThe objects returned by the `info()` functions all have a `describe()` method\nthat prints out helpful descriptions of the attributes of the object. For\nexample, from the `hwk.memory` module:\n\n```\n\u003e\u003e\u003e from hwk import memory\n\u003e\u003e\u003e i = memory.info()\n\u003e\u003e\u003e print i.describe()\nMemory subsystem\n===============================================================================\n`hwk.memory.Info` attributes:\n\ntotal_physical_bytes (int)\n\n  Number of bytes of physical RAM available to the system\n\ntotal_usable_bytes (int)\n\n  Number of bytes usable by the system (physical bytes minus a few bits\n  reserved for system and the resident kernel size)\n\nsupported_page_sizes (set of int)\n\n  A set of ints indicating memory page sizes the system can utilize, in bytes\n```\n\n#### Memory\n\n```\n\u003e\u003e\u003e from hwk import memory\n\u003e\u003e\u003e \n\u003e\u003e\u003e memory.info()\nmemory (24565.0 MB physical, 24099.0 MB usable)\n\u003e\u003e\u003e memory.supported_page_sizes()\nset([2048, 1048576])\n```\n\n#### Block devices\n\n```\n\u003e\u003e\u003e from hwk import block\n\u003e\u003e\u003e i = block.info()\n\u003e\u003e\u003e i\nblock (1 disk block devices, 1905440.0 MB total size)\n\u003e\u003e\u003e for d in i.disks:\n...     print \"disk: \" + str(d)\n...     for p in d.partitions:\n...             print \"  partition: \" + str(p)\n... \ndisk: /dev/sda (1905440 MB) [SCSI] LSI - SN #3600508e000000000f8253aac9a1abd0c\n  partition: /dev/sda6 (1699533 MB) [ext4] mounted@/\n  partition: /dev/sda1 (100 MB) [ntfs]\n  partition: /dev/sda3 (449 MB) [ntfs]\n  partition: /dev/sda2 (190881 MB) [ntfs]\n  partition: /dev/sda5 (14473 MB) [swap]\n  partition: /dev/sda4 (0 MB) [None]\n```\n\n#### CPU\n\n```\n\u003e\u003e\u003e import pprint\n\u003e\u003e\u003e from hwk import cpu\n\u003e\u003e\u003e i = cpu.info()\n\u003e\u003e\u003e i\ncpu (1 physical packages, 6 cores, 12 hardware threads)\n\u003e\u003e\u003e for c in i.cpus:\n...     print c\n... \nCPU 0 (6 cores, 12 threads)[Intel(R) Core(TM) i7 CPU         980  @ 3.33GHz]\n\u003e\u003e\u003e pmap = i.cpus[0].processor_map\n\u003e\u003e\u003e pprint.pprint(pmap)\n{0: set([0, 6]),\n 1: set([1, 7]),\n 2: set([2, 8]),\n 3: set([3, 9]),\n 4: set([4, 10]),\n 5: set([5, 11])}\n\u003e\u003e\u003e features = i.cpus[0].features\n\u003e\u003e\u003e pprint.pprint(features)\nset(['acpi',\n     'aes',\n     'aperfmperf',\n     'apic',\n     'arat',\n     \u003c ... \u003e\n     'vme',\n     'vmx',\n     'vnmi',\n     'vpid',\n     'xtopology',\n     'xtpr'])\n```\n\n#### Network\n\n```\n\u003e\u003e\u003e from hwk import net\n\u003e\u003e\u003e i = net.info()\n\u003e\u003e\u003e i\nnet (2 NICs)\n\u003e\u003e\u003e for nic in i.nics:\n...     print \"%8s %12s %s %s\" % (nic.name, nic.mac, nic.vendor_id, nic.vendor)\n... \n enp0s25 e06995034837 0x8086 Intel Corporation\n    wls1 1c7ee5299a06 0x168c Qualcomm Atheros\n\u003e\u003e\u003e\n\u003e\u003e\u003e for nic in i.nics:\n...     print \"%8s %12s %12s\" % (nic.name, nic.bus_type, nic.driver)\n...\n    wls1          pci        ath9k\n enp0s25          pci       e1000e\n\u003e\u003e\u003e\n\u003e\u003e\u003e for nic in i.nics:\n...     print \"NIC: \" + str(nic.name)\n...     print \"Enabled features: \"\n...     pprint.pprint(nic.enabled_features)\n... \nNIC: wls1\nEnabled features:\nset(['generic-receive-offload', 'netns-local'])\nNIC: enp0s25\nEnabled features:\nset(['generic-receive-offload',\n     'generic-segmentation-offload',\n     'highdma',\n     'receive-hashing',\n     'rx-checksumming',\n     'rx-vlan-offload',\n     'scatter-gather',\n     'tcp-segmentation-offload',\n     'tx-checksum-ip-generic',\n     'tx-checksumming',\n     'tx-scatter-gather',\n     'tx-tcp-segmentation',\n     'tx-tcp6-segmentation',\n     'tx-vlan-offload'])\n\u003e\u003e\u003e\n\u003e\u003e\u003e # The net.nic_features() function returns two sets, one of all features the\n\u003e\u003e\u003e # NIC supports and the other containing only the features that are\n\u003e\u003e\u003e # currently enabled on the NIC.\n\u003e\u003e\u003e\n\u003e\u003e\u003e pprint.pprint(net.nic_features('enp0s25'))\n(set(['busy-poll',\n     'fcoe-mtu',\n     'generic-receive-offload',\n     'generic-segmentation-offload',\n     'highdma',\n     'hw-tc-offload',\n     'l2-fwd-offload',\n     'large-receive-offload',\n     'loopback',\n     'netns-local',\n     'ntuple-filters',\n     'receive-hashing',\n     'rx-all',\n     'rx-checksumming',\n     'rx-fcs',\n     'rx-vlan-filter',\n     'rx-vlan-offload',\n     'rx-vlan-stag-filter',\n     'rx-vlan-stag-hw-parse',\n     'scatter-gather',\n     'tcp-segmentation-offload',\n     'tx-checksum-fcoe-crc',\n     'tx-checksum-ip-generic',\n     'tx-checksum-ipv4',\n     'tx-checksum-ipv6',\n     'tx-checksum-sctp',\n     'tx-checksumming',\n     'tx-fcoe-segmentation',\n     'tx-gre-csum-segmentation',\n     'tx-gre-segmentation',\n     'tx-gso-partial',\n     'tx-gso-robust',\n     'tx-ipxip4-segmentation',\n     'tx-ipxip6-segmentation',\n     'tx-lockless',\n     'tx-nocache-copy',\n     'tx-scatter-gather',\n     'tx-scatter-gather-fraglist',\n     'tx-sctp-segmentation',\n     'tx-tcp-ecn-segmentation',\n     'tx-tcp-mangleid-segmentation',\n     'tx-tcp-segmentation',\n     'tx-tcp6-segmentation',\n     'tx-udp_tnl-csum-segmentation',\n     'tx-udp_tnl-segmentation',\n     'tx-vlan-offload',\n     'tx-vlan-stag-hw-insert',\n     'udp-fragmentation-offload',\n     'vlan-challenged']),\nset(['generic-receive-offload',\n     'generic-segmentation-offload',\n     'highdma',\n     'receive-hashing',\n     'rx-checksumming',\n     'rx-vlan-offload',\n     'scatter-gather',\n     'tcp-segmentation-offload',\n     'tx-checksum-ip-generic',\n     'tx-checksumming',\n     'tx-scatter-gather',\n     'tx-tcp-segmentation',\n     'tx-tcp6-segmentation',\n     'tx-vlan-offload']))\n```\n\n#### GPU\n\n```\n\u003e\u003e\u003e from hwk import gpu\n\u003e\u003e\u003e i = gpu.info()\n\u003e\u003e\u003e i\ngpu (1 physical GPUs)\n\u003e\u003e\u003e i.gpus[0]\nGPU @pci:0000:03:00.0 [NVIDIA Corporation] (GF114 [GeForce GTX 560 Ti])\n\u003e\u003e\u003e print \"kernel driver: \" + i.gpus[0].driver\nkernel driver: nouveau\n```\n\n#### System Topology and NUMA\n\nFrom a single-processor Intel Core i7 6-core with 2 hardware threads per core:\n\n```\n\u003e\u003e\u003e from hwk import topology\n\u003e\u003e\u003e i = topology.info()\n\u003e\u003e\u003e i\ntopology SMP (1 nodes)\n\u003e\u003e\u003e n = i.nodes[0]\n\u003e\u003e\u003e n\nNode 0 (6 cores)\n\u003e\u003e\u003e n.processor_set\nset([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])\n\u003e\u003e\u003e c2 = n.cores[2]\n\u003e\u003e\u003e c2\nCore 2 (2 hardware threads)\n\u003e\u003e\u003e c2.processor_set\nset([10, 4])\n```\n\nFrom a NUMA system with 2 processors having 4 cores each with 2 hardware\nthreads per core::\n\n```\n\u003e\u003e\u003e from hwk import topology\n\u003e\u003e\u003e i = topology.info()\n\u003e\u003e\u003e i\ntopology NUMA (2 nodes)\n\u003e\u003e\u003e for node in i.nodes:\n...     print node.processor_set\n...\nset([0, 1, 2, 3, 8, 9, 10, 11])\nset([4, 5, 6, 7, 12, 13, 14, 15])\n```\n\nHere's topology information that shows the memory caches and their association\nwith cores and threads, along with their sizes, on a laptop running an Intel i5\nprocessor with 4 hardware threads:\n\n```\n\u003e\u003e\u003e import pprint\n\u003e\u003e\u003e from hwk import topology\n\u003e\u003e\u003e i = topology.info()\n\u003e\u003e\u003e i\ntopology SMP (1 nodes)\n\u003e\u003e\u003e n = i.nodes[0]\n\u003e\u003e\u003e n\nNode 0 (2 cores)\n\u003e\u003e\u003e for c in n.cores:\n...     print c\n...     print c.processor_set\n... \nCore 0 (2 hardware threads)\nset([0, 2])\nCore 1 (2 hardware threads)\nset([1, 3])\n\u003e\u003e\u003e caches = sorted(n.caches, key=lambda c: c.level)\n\u003e\u003e\u003e pprint.pprint(caches)\n[L1d cache (32 KB),\n L1i cache (32 KB),\n L1i cache (32 KB),\n L1d cache (32 KB),\n L2 cache (256 KB),\n L2 cache (256 KB),\n L3 cache (3072 KB)]\n\u003e\u003e\u003e for c in caches:\n...     print c, c.processor_set\n... \nL1d cache (32 KB) set([1, 3])\nL1i cache (32 KB) set([0, 2])\nL1i cache (32 KB) set([1, 3])\nL1d cache (32 KB) set([0, 2])\nL2 cache (256 KB) set([0, 2])\nL2 cache (256 KB) set([1, 3])\nL3 cache (3072 KB) set([0, 1, 2, 3])\n\u003e\u003e\u003e\n\u003e\u003e\u003e c0 = n.cores[0]\n\u003e\u003e\u003e for cache in sorted(c0.caches, key=lambda c: c.size_bytes):\n...     print cache\n...\nL1i cache (32 KB)\nL1d cache (32 KB)\nL2 cache (256 KB)\nL3 cache (3072 KB)\n\n```\n\n## Developers\n\nContributions to `hwk` are welcomed! Fork the repo on GitHub and submit a pull\nrequest with your proposed changes. Or, feel free to log an issue for a feature\nrequest or bug report.\n\n### Running tests\n\nYou can run unit tests easily using the `tox` command, like so:\n\n```bash\n$ tox\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjaypipes%2Fhwk","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjaypipes%2Fhwk","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjaypipes%2Fhwk/lists"}