API reference
The top-level package keeps common imports short
from hostlens import (
DeviceProfile,
HostLens,
ScanMode,
discover,
discover_async,
identify,
identify_async,
)
Models, scan events, collectors, parsers, and exceptions remain available from their own modules
HostLens
HostLens(
*,
interface: str | None = None,
timeout: float = 3.0,
concurrency: int = 64,
cloud: bool = False,
fingerbank_api_key: str | None = None,
collectors: Sequence[Collector] | None = None,
)
Constructor arguments
interface
: System adapter name or friendly name used for automatic subnet detection and ARP discovery
timeout
: Maximum collector timeout in seconds, must be greater than zero
concurrency
: Maximum number of hosts enriched at once, must be at least one
cloud
: Enables Fingerbank enrichment when true
fingerbank_api_key
: Fingerbank key required when cloud enrichment is enabled
collectors
: Optional sequence replacing all built-in collectors, mainly useful for tests and custom integrations
Each instance owns its configuration, collectors, Fingerbank client, and in-memory profile cache
identify
Alias for scan_host with the same behavior
scan_host
Validates one address, checks the cache, looks for its MAC in the neighbor table, collects evidence, and returns a profile
scan_hosts
await intel.scan_hosts(
targets: Sequence[str],
*,
mode: ScanMode | str = ScanMode.NORMAL,
) -> list[DeviceProfile]
Scans several addresses with bounded concurrency
The returned list follows the input order
scan_network
await intel.scan_network(
subnet: str | None = None,
*,
mode: ScanMode | str = ScanMode.NORMAL,
return_result: bool = False,
) -> list[DeviceProfile] | ScanResult
Discovers devices and enriches them
If subnet is absent, the local subnet is detected from the preferred or selected interface
The common return value is a device list
Set return_result=True to receive a ScanResult with a ScanSummary
discover
Runs scan_network in fast mode
scan
Streams a normal scan
This is the short form of scan_stream(subnet, mode="normal")
scan_stream
intel.scan_stream(
subnet: str | None = None,
*,
mode: ScanMode | str = ScanMode.NORMAL,
) -> AsyncIterator[ScanEvent]
Yields DeviceFound for initial discovery, followed by DeviceUpdated and DeviceIdentified after enrichment
The final event is ScanCompleted
Passive mode is rejected here because it has no natural completion point
watch_network
intel.watch_network(
subnet: str | None = None,
*,
mode: ScanMode | str = ScanMode.PASSIVE,
interval: float = 2.0,
) -> AsyncIterator[ScanEvent]
Reads the neighbor table repeatedly and yields each newly observed device once
The iterator runs until it is cancelled or closed
Only passive mode is accepted
preview_cloud_payload
Returns the values that the configured Fingerbank client would receive
Returns an empty dictionary when cloud enrichment is disabled
Module-level helpers
identify
Synchronous helper that creates a default client and calls asyncio.run()
identify_async
Async helper that creates a default client and identifies one address
discover
Synchronous fast discovery helper
discover_async
Async fast discovery helper
ScanMode
ScanMode is a string enum
Methods also accept the lowercase strings fast, normal, deep, and passive
Unknown values raise ConfigurationError
Models
Import public models from hostlens.models
DeviceProfile
See device profiles for field details, evidence, confidence, and serialization
Evidence
Evidence(
source: str,
field: str,
value: str | int | float | bool | list[str],
confidence: float,
observed_at: datetime,
description: str | None = None,
metadata: dict[str, str] = {},
)
Confidence is validated from 0 through 1
Evidence models are frozen after construction
FieldValue
Records the selected value and the evidence sources that supported it
Service
Service(
name: str,
protocol: Literal["tcp", "udp"] | None = None,
port: int | None = None,
service_type: str | None = None,
metadata: dict[str, str] = {},
)
Ports are validated from 1 through 65535
Target
Internal collectors receive a Target
It is public so custom collectors can use the same input model
ScanSummary and ScanResult
ScanSummary(
duration: float,
targets_checked: int,
devices_found: int,
mode: str,
)
ScanResult(
devices: list[DeviceProfile],
summary: ScanSummary,
)
Events
All events are Pydantic models with a literal type field
| Event | Type value | Payload |
|---|---|---|
DeviceFound |
device_found |
Baseline device profile |
DeviceUpdated |
device_updated |
Enriched device profile |
DeviceIdentified |
device_identified |
Completed identity for one target |
ScanCompleted |
scan_completed |
Scan summary |
ScanEvent is the union of these four models
Exceptions
Import exceptions from hostlens.exceptions
HostLensError
├── ConfigurationError
├── DiscoveryError
│ ├── PermissionDenied
│ └── InterfaceNotFound
├── TargetUnreachable
├── CollectorError
└── ResolverError
└── CloudResolverError
ConfigurationError
: Invalid timeout, concurrency, mode, or cloud configuration
DiscoveryError
: Invalid subnet or failure to determine the local interface or subnet
InterfaceNotFound
: Selected interface is missing or has no usable IPv4 address
CloudResolverError
: Direct Fingerbank client request failed
Individual collector failures are normally isolated and returned as missing evidence rather than raised through HostLens
Custom collectors
A collector needs a name and one async method
from hostlens.models import Evidence, Target
class CameraCollector:
name = "camera"
async def collect(self, target: Target, timeout: float) -> list[Evidence]:
return []
Pass the complete collector list to the client
Supplying collectors replaces the built-in list rather than extending it
See collectors and parsers before adding a collector to the project