The emgapi_v2_client#

For developing or in case you want to work with the mgnipy.emgapi_v2_client sub-package directly.


What is it?#

mgnipy.emgapi_v2_client is a python sub-package in MGni.py that was created from the openapi.json spec using openapi-python-client .

It serves as the initial HTTP client to remove the complexity of direct HTTP requests to version 2 of the MGnify API while maintaining type safety through attrs-based models.

How was it created?#

This client library was automatically generated from the MGnify API v2 OpenAPI specification using openapi-python-client . This choice was made in the hopes that it would be easier for MGni.py to be updated with changes to the MGnify API endpoints and models.

See readme-openapi-python-client.md for more information on openapi-python-client

How does it work?#

Each MGnify API endpoint has its own module in emgapi_v2_client#

  • Every MGnify API v2 endpoint (e.g., list_all_biomes , get_mgnify_analysis ) has their own module in emgapi_v2_client (e.g., mgnipy.emgapi_v2_client.api.miscellaneous.list_mgnify_biomes, mgnipy.emgapi_v2_client.api.analyses.get_mgnify_analysis)

  • Within the emgapi_v2_client, the endpoint modules are in the api directory:

            emgapi_v2_client/
            β”œβ”€β”€ api/
            β”‚   β”œβ”€β”€ analyses/
            β”‚   β”‚   β”œβ”€β”€ get_mgnify_analysis.py
            β”‚   β”‚   └── ...
            β”‚   β”œβ”€β”€ assemblies/
            β”‚   β”‚   β”œβ”€β”€ get_assembly.py
            β”‚   β”‚   └── ...
            β”‚   β”œβ”€β”€ 'other-api-tag'/
            β”‚   β”‚   └── ...
            β”‚   β”œβ”€β”€ 'another-api-tag'/
            β”‚   β”‚   └── ...
            β”‚   └── ...
            β”œβ”€β”€ models/
            β”‚   β”œβ”€β”€ analysed_run.py
            β”‚   β”œβ”€β”€ biome.py
            β”‚   β”œβ”€β”€ 'some-other-attrs-data-model'.py
            β”‚   └── ...
            └── ...

   - each subdir in api/ corresponds to a tag in the MGnify API e.g., analyses, assemblies
   - the endpoints for that tag are in that tag's subdir (if multi tags, is in the first)
   - the `attrs` data models are in models/

Each API endpoint module exposes 4 functions:#

  1. sync: Blocking request that returns parsed data (if successful) or None

  2. sync_detailed: Blocking request that always returns a Request, optionally with parsed set if the request was successful.

  3. asyncio: async version of sync.

  4. asyncio_detailed: async version of sync_detailed.

Putting it altogether in a demo:#

Below we will have an example where we will find studies of the biome root:Host-associated:Plants


What to import#

At a minimum:

  1. We need to find and import the appropriate module for our endpoint: /Miscellaneous/list_mgnify_biomes

  2. Get and initiate the mgnipy.Client instance

  3. (Optional) add type annotations

# uncomment below if colab
#!pip install mgnipy
#!pip install asyncio
# at minimum need
# 1. the path
from mgnipy.emgapi_v2_client.api.miscellaneous import list_mgnify_biomes
# 2. the client
from mgnipy.emgapi_v2_client import Client

# extra nice to have annotations but not required for usage
# 3. the models
from mgnipy.emgapi_v2_client.models import NinjaPaginationResponseSchemaBiome
from mgnipy.emgapi_v2_client.types import UNSET, Response

Initiate the client#

To instantiate the python client we really only need the base_url. However there are options for loggiing and other httpx args.

mgnipy.emgapi_v2_client.Client/AuheticatedClient will take care of constructing and closing the httpx clients

example_client = Client(base_url="https://www.ebi.ac.uk")
# check it out
print(example_client)
Client(raise_on_unexpected_status=False, _base_url='https://www.ebi.ac.uk', _cookies={}, _headers={}, _timeout=None, _verify_ssl=True, _follow_redirects=False, _httpx_args={}, _client=None, _async_client=None)

Making the request to the API Endpoint#

The get request is made when running the .sync...() or .async...() functions. For example executing

            with example_client as client:
                response = list_mgnify_biomes.sync_detailed(
                    client=client, page_size=10
                )

the API will respond with the first page of 10 items from the list_mgnify_biomes endpoint.

πŸŽͺ A peak behind the curtain πŸŽͺ#

The order of the methods within list_mgnify_biomes.py when the above is executed would be:

  1. _get_kwargs to prepare the query params, ensuring that the kwarg exists e.g. that page_size is an acceptable kwarg

  2. the httpx request is made with the kwargs

  3. _build_response to prepare as Response type

  4. In the Response is attribute Response.parsed which uses _parse_response to get response as json / dict

Note: The difference between with and sans ..._detailed() is that with returns the whole response and sans only returns the parsed response.

# prep our search
params = {
    "biome_lineage": "root:Host-associated:Plants",
    "page_size": 25,#the default
    "max_depth": 6,
}

# make the sync call and store respone
with example_client as client:
    # adding type annotation for the response is optional 
    response: Response[NinjaPaginationResponseSchemaBiome] = list_mgnify_biomes.sync_detailed(client=client, **params)

# check
response.status_code
<HTTPStatus.OK: 200>

Parsing the response#

and if we take a look at the parsed content:

response.parsed.to_dict().keys()
dict_keys(['count', 'items'])
  • In items are records such as the biome_lineages

    • for the first page of results only

  • In count is the total number of records that matched our query. Note: you need to instantiate a new client object every call

Let’s take a closer look at the response

response.parsed.to_dict()
{'count': 15,
 'items': [{'biome_name': 'Plants', 'lineage': 'root:Host-associated:Plants'},
  {'biome_name': 'Phylloplane',
   'lineage': 'root:Host-associated:Plants:Phylloplane'},
  {'biome_name': 'Endophytes',
   'lineage': 'root:Host-associated:Plants:Phylloplane:Endophytes'},
  {'biome_name': 'Epiphytes',
   'lineage': 'root:Host-associated:Plants:Phylloplane:Epiphytes'},
  {'biome_name': 'Rhizome', 'lineage': 'root:Host-associated:Plants:Rhizome'},
  {'biome_name': 'Epiphytes',
   'lineage': 'root:Host-associated:Plants:Rhizome:Epiphytes'},
  {'biome_name': 'Rhizoplane',
   'lineage': 'root:Host-associated:Plants:Rhizoplane'},
  {'biome_name': 'Endophytes',
   'lineage': 'root:Host-associated:Plants:Rhizoplane:Endophytes'},
  {'biome_name': 'Epiphytes',
   'lineage': 'root:Host-associated:Plants:Rhizoplane:Epiphytes'},
  {'biome_name': 'Soil',
   'lineage': 'root:Host-associated:Plants:Rhizoplane:Soil'},
  {'biome_name': 'Rhizosphere',
   'lineage': 'root:Host-associated:Plants:Rhizosphere'},
  {'biome_name': 'Epiphytes',
   'lineage': 'root:Host-associated:Plants:Rhizosphere:Epiphytes'},
  {'biome_name': 'Forest soil',
   'lineage': 'root:Host-associated:Plants:Rhizosphere:Forest soil'},
  {'biome_name': 'Soil',
   'lineage': 'root:Host-associated:Plants:Rhizosphere:Soil'},
  {'biome_name': 'Root', 'lineage': 'root:Host-associated:Plants:Root'}]}

Async requests support#

import asyncio 

example_client = Client(base_url="https://www.ebi.ac.uk")

async with example_client as client: 
    parsed_response = await list_mgnify_biomes.asyncio(
        client=client, 
        biome_lineage="root:Host-associated",
        max_depth=6,
        page_size=5,
    )

parsed_response.to_dict()
{'count': 233,
 'items': [{'biome_name': 'Host-associated',
   'lineage': 'root:Host-associated'},
  {'biome_name': 'Algae', 'lineage': 'root:Host-associated:Algae'},
  {'biome_name': 'Brown Algae',
   'lineage': 'root:Host-associated:Algae:Brown Algae'},
  {'biome_name': 'Green algae',
   'lineage': 'root:Host-associated:Algae:Green algae'},
  {'biome_name': 'Ectosymbionts',
   'lineage': 'root:Host-associated:Algae:Green algae:Ectosymbionts'}]}