# Timenet connectors.discovery

## timenet\_connectors.discovery

Discover connectors lazily by convention.

Each connector lives in its own folder at `datasets/<org>/<name>/`, or `datasets/<name>/` for a
flat id. The package's `__init__.py` exposes a `CONNECTOR` class. A `dataset.yaml` card sits
beside it. A dataset id maps to that package by convention, so there is no central registry. Discovery
imports only the requested connector. Each connector declares its own id through `metadata()`.

### available

```
available() -> list[str]
```

List the dataset ids of every discoverable connector.

This imports each connector module. Use it for listings and error messages, not the build hot path.

Returns:

| Type | Description |
| --- | --- |
| `list[str]` | The declared dataset ids, sorted. |

### connector\_dir

```
connector_dir(dataset_id: str) -> Path
```

Return the directory of a dataset id's connector package.

Deliberately import-free. This runs before the connector's environment
exists, so importing the connector module (which is what :func:`resolve`
does) would fail on the very dependencies its `requirements.txt`
declares. `find_spec` imports the parent packages only, never the leaf.

A connector directory holds a `dataset.yaml` card. An org namespace package
(`physionet`) also has `submodule_search_locations` but no card, so it is
not a connector and is rejected like any unknown id.

Parameters:

| Name | Type | Description | Default |
| --- | --- | --- | --- |
| `dataset_id` | `str` | A flat (`hello_world`) or `org/name` id. | *required* |

Returns:

| Type | Description |
| --- | --- |
| `Path` | The connector package's directory. |

Raises:

| Type | Description |
| --- | --- |
| `LookupError` | If no connector with a `dataset.yaml` card exists for the id. |

### known\_ids

```
known_ids() -> list[str]
```

List dataset IDs from connector cards without importing connectors.

A card that cannot be read, is not a YAML mapping, or lacks `dataset_id` is skipped with a
:class:`~timenet.errors.ConnectorCardWarning`, so it fails only its own dataset.

Returns:

| Type | Description |
| --- | --- |
| `list[str]` | The sorted dataset IDs, with duplicates removed. |

### requirements\_for

```
requirements_for(dataset_id: str) -> Path | None
```

Find a connector's requirements file.

Parameters:

| Name | Type | Description | Default |
| --- | --- | --- | --- |
| `dataset_id` | `str` | The dataset ID, as `org/name`. | *required* |

Returns:

| Type | Description |
| --- | --- |
| `Path | None` | The path to `requirements.txt`, or `None` if the file is absent. |

Raises:

| Type | Description |
| --- | --- |
| `LookupError` | If no connector with a `dataset.yaml` card exists for the ID. |

### resolve

```
resolve(dataset_id: str) -> type[BaseConnector]
```

Return the connector class for a dataset id and import only its module.

Parameters:

| Name | Type | Description | Default |
| --- | --- | --- | --- |
| `dataset_id` | `str` | A flat (`hello_world`) or `org/name` (`chengsenwang/tsqa`) id. | *required* |

Returns:

| Type | Description |
| --- | --- |
| `type[BaseConnector]` | The connector class. |

Raises:

| Type | Description |
| --- | --- |
| `LookupError` | If no module exists for the id, or it exposes no `CONNECTOR`. |
| `ModuleNotFoundError` | If a connector module for the id exists but fails to import one of its own dependencies. This surfaces the real error instead of masking it as an unknown id. |
