Skip to content

Commit

Permalink
Update ready for ontology changes
Browse files Browse the repository at this point in the history
  • Loading branch information
ieuans committed Dec 20, 2024
1 parent 9fb2115 commit fbd86fc
Show file tree
Hide file tree
Showing 11 changed files with 269 additions and 34 deletions.
88 changes: 85 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ client = Client(public=True)
client = Client(public=False)

# Authenticated API (user providing credentials)
client = Client(username='my-username', password='password)
client = Client(username='my-username', password='password')
```

The `url` parameter can be used to specify a different version of the ConceptLibrary API
Expand Down Expand Up @@ -100,12 +100,31 @@ template_list = client.templates.get_detail(1, version_id=1)

#### Querying
``` python
# Search phenotypes
# Search phenotypes (defaults to paginated)
search_results = client.phenotypes.get(
search='asthma',
collections=19
)

page = search_results.get('page')
page_size = search_results.get('page_size')
total_pages = search_results.get('total_pages')
search_data = search_results.get('data')

# Iterate over search result pages
next_page = client.phenotypes.get(
page=page + 1,
search='asthma',
collections=19
)

# [NOTE: not recommended!] Search unpaginated list of phenotypes
search_results = client.phenotypes.get(
search='asthma',
collections=19,
no_pagination=True
)

# Search phenotypes
phenotype_versions = client.phenotypes.get_versions('PH1')

Expand Down Expand Up @@ -142,12 +161,31 @@ client.phenotypes.update('./path/to/file.yaml')

### Concepts
``` python
# Search concepts
# Search concepts (defaults to paginated)
search_results = client.concepts.get(
search='asthma',
collections=19
)

page = search_results.get('page')
page_size = search_results.get('page_size')
total_pages = search_results.get('total_pages')
search_data = search_results.get('data')

# Iterate over search result pages
next_page = client.concepts.get(
page=page + 1,
search='asthma',
collections=19
)

# [NOTE: not recommended!] Search unpaginated list of concepts
search_results = client.concepts.get(
search='asthma',
collections=19,
no_pagination=True
)

# Search concepts
concept_versions = client.concepts.get_versions('C714')

Expand Down Expand Up @@ -190,3 +228,47 @@ datasource_list = client.datasources.get()
# Get the datasource detail
datasource_detail = client.datasources.get_detail(1)
```

### Ontology
``` python
# Get paginated list of ontological term(s) (nodes; paginated by default)
search_results = client.ontology.get()

page = search_results.get('page')
page_size = search_results.get('page_size')
total_pages = search_results.get('total_pages')
search_data = search_results.get('data')

# Iterate over search result pages
next_page = client.ontology.get(
page=page + 1,
search='asthma',
collections=19
)

# [NOTE: not recommended!] Get unpaginated list of ontological term(s)
search_results = client.ontology.get(no_pagination=TRUE)

# Search ontological term(s) (paginated by default, apply `no_pagination=T` if required)
# [!] See the following for more information on parameters:
# https://conceptlibrary.saildatabank.com/api/v1/#operations-tag-ontology
#
search_results = client.ontology.get(
# Searches across names, descriptions & synonyms
search='dementia',

# Search by snomed codes (or ICD9/10, OPSC4, ReadCode2/3 etc)
# - Note: this will fuzzy match across all code mappings;
# apply the `exact_codes=T` parameter if you want exact matches
codes='281004'
)

# Get a specific ontology node by ID
ontology_node = client.ontology.get_detail(1)

# Get all ontology groups available
ontology_groups = client.ontology.get_groups()

# Get the ontology group's detail
clin_speciality_list = client.ontology.get_group_detail(1)
```
40 changes: 22 additions & 18 deletions assets/definition_file_create.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,33 @@ name: COVID-19 infection
author: BHF CVD COVID UK Consortium
type: '2'
data_sources:
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
sex: '3'
coding_system:
- 9
- 4
- 9
- 4
collections:
- 20
- 18
- 20
- 18
ontology:
- 50323
- 'icd9:569.82'
- 'snomed:420764009'
definition: "ABCDEFGHIJKLMNOPQRSTUVXYZ"
concept_information:
- name: COVID-19 infection - Primary Care
type: existing_concept
concept_id: 714
concept_version_id: 2567
- name: COVID-19 infection - Hospitalizations
type: csv
coding_system: 4
code_column: Code
description_column: Description
filepath: "./path/to/file.csv"
- name: COVID-19 infection - Primary Care
type: existing_concept
concept_id: 714
concept_version_id: 2567
- name: COVID-19 infection - Hospitalizations
type: csv
coding_system: 4
code_column: Code
description_column: Description
filepath: "./path/to/file.csv"
world_access: 1
group_access: 1
template:
Expand Down
4 changes: 4 additions & 0 deletions assets/definition_file_update.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ concept_information:
type: existing_concept
concept_id: 715
concept_history_id: 2569
ontology:
- 50323
- 'icd9:569.82'
- 'snomed:420764009'
world_access: 1
group_access: 1
template:
Expand Down
3 changes: 3 additions & 0 deletions docs/ontology.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Ontology

::: pyconceptlibraryclient.ontology.Ontology
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ nav:
- "Collections": collections.md
- "Tags": tags.md
- "DataSources": datasources.md
- "Ontology": ontology.md

markdown_extensions:
- pymdownx.highlight:
Expand Down
10 changes: 10 additions & 0 deletions pyconceptlibraryclient/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from pyconceptlibraryclient.collections import Collections
from pyconceptlibraryclient.tags import Tags
from pyconceptlibraryclient.datasources import Datasources
from pyconceptlibraryclient.ontology import Ontology
import pyconceptlibraryclient.constants as constants

class Client():
Expand Down Expand Up @@ -125,3 +126,12 @@ def datasources(self) -> Datasources:
if not getattr(self, '__datasources', None):
setattr(self, '__datasources', Datasources(self.url, self.__auth))
return getattr(self, '__datasources')

@property
def ontology(self) -> Ontology:
'''
Entrypoint for ontology through the client instance
'''
if not getattr(self, '__ontology', None):
setattr(self, '__ontology', Ontology(self.url, self.__auth))
return getattr(self, '__ontology')
19 changes: 13 additions & 6 deletions pyconceptlibraryclient/concepts.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,33 @@ class Concepts(Endpoint):
def __init__(self, *args, **kwargs) -> None:
super(Concepts, self).__init__(*args, **kwargs)

def get(self, **kwargs) -> list | None:
def get(self, **kwargs) -> dict | list | None:
'''
Queries concepts/, with optional query parameters
NOTE:
- See the following URL for more information on query parameters: https://conceptlibrary.saildatabank.com/api/v1/#operations-tag-concepts
Keyword Args:
search (string): Keyword search
collections (list): IDs of collections
tags (list): IDs of tags
datasources (list): IDs of datasources
Returns:
Response (list): List of concepts matching query parameters
Response (dict|list):
- If paginated: a dict of concepts matching query parameters
- If unpaginated: a list of concepts matching query parameters
Examples:
>>> from pyconceptlibraryclient import Client
>>> client = Client(public=False)
>>> # Get all concepts
>>> # Get all concepts (defaults to paginated)
>>> client.concepts.get()
>>> # [NOTE: not recommended!] Get unpaginated list of concepts
>>> client.concepts.get(no_pagination=True)
>>> # Search concepts
>>> client.concepts.get(search='asthma', collections=19)
'''
Expand All @@ -46,7 +53,7 @@ def get_versions(self, id: str) -> list | None:
Returns:
Response (list): Version list of queried concept
Examples:
>>> from pyconceptlibraryclient import Client
>>> client = Client(public=False)
Expand Down
6 changes: 6 additions & 0 deletions pyconceptlibraryclient/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@ class PATH(str, Enum):
GET_ALL_DATASOURCES = 'data-sources'
GET_DATASOURCE_BY_ID = 'data-sources/{id}/detail'

# Ontology
GET_ONTOLOGY_GROUPS = 'ontology/'
GET_ONTOLOGY_TYPE = 'ontology/type/{id}/'
GET_ONTOLOGY_SEARCH = 'ontology/node/'
GET_ONTOLOGY_DETAIL = 'ontology/node/{id}/'

class DOMAINS(str, Enum):
'''
List of common ConceptLibrary domains:
Expand Down
110 changes: 110 additions & 0 deletions pyconceptlibraryclient/ontology.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
from pyconceptlibraryclient.endpoint import Endpoint
from pyconceptlibraryclient.constants import PATH

class Ontology(Endpoint):
'''
Queries ontology/ endpoints
'''

def __init__(self, *args, **kwargs) -> None:
super(Ontology, self).__init__(*args, **kwargs)

def get(self, **kwargs) -> list | dict | None:
'''
Queries ontology/node/, with optional query parameters
NOTE:
- See the following URL for more information on query parameters: https://conceptlibrary.saildatabank.com/api/v1/#operations-tag-ontology
- Adding the `?exact_codes` will match the exact SNOMED code instead of fuzzy matching
the given `codes` across all related mappings (ICD-9/10, MeSH, OPSC4, ReadCodes etc)
Keyword Args:
| Param | Type | Default | Desc |
|---------------|----------|--------------------|------------------------------------------------------------------|
| search | `string` | `NULL` | Full-text search |
| codes | `list` | `NULL` | Either (a) SNOMED code (see below); or (b) Code ID |
| exact_codes | `empty` | `NULL` | apply this parameter if you would like to search for exact codes |
| type_ids | `list` | `NULL` | Filter ontology type by ID |
| reference_ids | `list` | `NULL` | Filter ontology by Atlas reference |
| page | `number` | `1` | Page cursor |
| page_size | `enum` | `1` (_20_ results) | Page size enum, where: `1` = 20, `2` = 50 & `3` = 100 rows |
Returns:
Response (dict|list):
- If paginated: a dict of ontological nodes matching query parameters
- If unpaginated: a list of ontological nodes matching query parameters
Examples:
>>> from pyconceptlibraryclient import Client
>>> client = Client(public=False)
>>> # Get all ontological term(s) (nodes; defaults to paginated)
>>> client.ontology.get()
>>> # Search ontological terms (apply '?exact_codes' parameter to search only SNOMED codes)
>>> client.ontology.get(search='dementia', codes='281004,569.82')
'''
url = self._build_url(PATH.GET_ONTOLOGY_SEARCH)

response = self._get(url, params=kwargs)
return response

def get_detail(self, id: int) -> dict | None:
'''
Queries ontology/node/{id}/
Parameters:
id (int): Ontology node ID
Returns:
Response (dict): Details of queried ontology
Examples:
>>> import pyconceptlibraryclient
>>> client = Client(public=False)
>>> client.ontology.get_detail(1)
'''
url = self._build_url(PATH.GET_ONTOLOGY_DETAIL, id=id)

response = self._get(url)
return response

def get_groups(self) -> list | None:
'''
Queries ontology/; gets list of all ontological groups (types)
Returns:
Response (list): Details of the ontology groups
Examples:
>>> import pyconceptlibraryclient
>>> client = Client(public=False)
>>> client.ontology.get_detail(1)
'''
url = self._build_url(PATH.GET_ONTOLOGY_GROUPS)

response = self._get(url)
return response

def get_group_detail(self, id: int) -> list | None:
'''
Queries ontology/type/{id}/; gets an ontology group's detail
Parameters:
id (int): Ontological ID
Returns:
Response (dict): Details of the queried ontology group
Examples:
>>> import pyconceptlibraryclient
>>> client = Client(public=False)
>>> client.ontology.get_group_detail(1)
'''
url = self._build_url(PATH.GET_ONTOLOGY_TYPE, id=id)

response = self._get(url)
return response

Loading

0 comments on commit fbd86fc

Please sign in to comment.