Introduction to eppoPynder
Overview
eppoPynder provides a Python interface to the public APIs of the European and Mediterranean Plant Protection Organization (EPPO) database. The package facilitates access to a wide range of pest-related information collected and maintained by EPPO, allowing users to query, retrieve, and process this data directly from Python.
The package is intended for researchers, analysts, and practitioners in plant protection who require convenient programmatic access to EPPO data.
Installation
From PyPI
$ pip install eppoPynder
Development version
To install the latest development version:
$ pip install git+https://github.com/openefsa/eppoPynder.git
Requirements
An active internet connection is required, as the package communicates with EPPO's online services to fetch and process data.
Working with API keys
The eppoPynder package requires your unique API token to function properly. You can provide this token in one of two ways:
- By setting it in a
.envfile. - By including it manually during the client initialization.
Setting the API key via .env
A .env file is used to define environment variables that Python can load at
runtime. This approach is particularly convenient for sensitive information
like API keys, as it allows you to use them in any Python script or function
without hardcoding them.
Place the .env file in the root directory of you project (for example,
C:/Users/username/Documents/myProject/.env on Windows or
~/Documents/myProject/.env on Unix-like systems). You can create or edit this
file with any plain text editor.
Add your EPPO API key in the following format:
EPPO_API_KEY=<your_eppo_api_key>
Once the file is saved, the variable will be correctly set for the library to use during execution.
Setting the API key manually during client initialization
Alternatively, you can provide the API key directly in the api_key argument
of client instantiation. This is useful if you prefer not to store the token
globally. For example:
from eppopynder import Client
client = Client(api_key="<your_eppo_api_key>")
Note that if an API key is explicitly provided, the API key set through the
.env file will be ignored, if any.
Basic usage
The main purpose of eppoPynder is to query the EPPO database for specific EPPO codes and retrieve relevant information across various endpoints. For each endpoint, you can either:
- Query all available services to obtain more comprehensive data.
- Query one or more services to obtain specific data.
For plant and pest species, the basic information returned includes scientific names, synonyms, common names in different languages, and taxonomic classification. For pests of regulatory interest, you can also retrieve more detailed information, such as host plants and quarantine categorization.
Below are examples demonstrating how to use the functions in this package. First, load the eppoPynder package:
from eppopynder import *
Then, initialize the client by specifying the API key you want to use:
client = Client() # Use the API key defined in .env file.
client = Client(api_key="<your_eppo_api_key>") # Manually define the API key.
To explore the arguments and usage of a specific function, you can run:
help(function_name)
This will show the full documentation for the function, including its arguments, return values, and usage examples.
For example, if you are working with the uniform_taxonomy() function,
you can check its documentation with:
help(uniform_taxonomy)
Again, if you want to check the documentation of a function that represents a category, you can run:
help(Client.taxon)
Note that the functions representing the categories are all defined inside the
Client class.
Querying a specific category
The eppoPynder package allows you to query all categories available in version 2.0 of the EPPO APIs: General, Taxons, Taxon, Country, RPPO, Tools, Reporting Service, and References.
Each category has a corresponding function in the package with the same name in snake_case format: general(), taxons(), taxon(), country(), rppo(), tools(), reporting_service(), and references(). By default, these functions return all data available under the selected category, but you can customize the query by specifying the desired services.
For example, to query all services of the Taxon category for the EPPO code "BEMITA", you can use the following code:
data = client.taxon(eppo_codes=["BEMITA"])
Some services require certain mandatory parameters, which must be provided when making the request. For example:
data = client.tools(
services=[ToolsService.NAME2CODES],
params={
ToolsService.NAME2CODES: {
"name": "Bemisia tabaci"
}
}
)
Each category comes with a set of service names that can be queried. These are
stored in an enumeration whose name follows the convention Category +
"Service". For example, for the Taxon category, the collection of queryable
services is named TaxonService, and its values are OVERVIEW, INFOS,
NAMES and so on, exactly matching the names of the available services.
Keep in mind that services can be provided to the corresponding functions only
through their dedicated enum.
You can import the enumeration associated with a specific category as shown below:
from eppopynder import TaxonService, ToolsService # And so on...
Alternatively, you can import all of them at once by importing everything from the library:
from eppopynder import *
Querying a specific service
To query a specific service within an endpoint, eppoPynder allows you to
specify it directly in the function call. For example, to access only the
/taxons/taxon/categorization service for the EPPO code "BEMITA", you can use
the Client.taxon() function as follows:
data = client.taxon(
eppo_codes=["BEMITA"],
services=[TaxonService.CATEGORIZATION]
)
Expected output
print(data)
{<TaxonService.CATEGORIZATION: 'categorization'>: queried_eppo_code continent_id continent_name country_iso country_name ... year_add year_delete year_transient queried_url queried_on
0 BEMITA 4 America CL Chile ... 2019 None None https://api.eppo.int/gd/v2/taxons/taxon/BEMITA... 2025-12-10 14:58:20.605414
1 BEMITA 2 Asia BH Bahrain ... 2003 None None https://api.eppo.int/gd/v2/taxons/taxon/BEMITA... 2025-12-10 14:58:20.605414
2 BEMITA 2 Asia KZ Kazakhstan ... 2017 None None https://api.eppo.int/gd/v2/taxons/taxon/BEMITA... 2025-12-10 14:58:20.605414
3 BEMITA 1 Europe AZ Azerbaijan ... 2024 None None https://api.eppo.int/gd/v2/taxons/taxon/BEMITA... 2025-12-10 14:58:20.605414
4 BEMITA 1 Europe BY Belarus ... 1994 None None https://api.eppo.int/gd/v2/taxons/taxon/BEMITA... 2025-12-10 14:58:20.605414
5 BEMITA 1 Europe GE Georgia ... 2018 None None https://api.eppo.int/gd/v2/taxons/taxon/BEMITA... 2025-12-10 14:58:20.605414
6 BEMITA 1 Europe MD Moldova, Republic of ... 2017 None None https://api.eppo.int/gd/v2/taxons/taxon/BEMITA... 2025-12-10 14:58:20.605414
7 BEMITA 1 Europe NO Norway ... 2012 None None https://api.eppo.int/gd/v2/taxons/taxon/BEMITA... 2025-12-10 14:58:20.605414
8 BEMITA 1 Europe RU Russian Federation (the) ... 2014 None None https://api.eppo.int/gd/v2/taxons/taxon/BEMITA... 2025-12-10 14:58:20.605414
9 BEMITA 1 Europe RS Serbia ... 2015 None None https://api.eppo.int/gd/v2/taxons/taxon/BEMITA... 2025-12-10 14:58:20.605414
10 BEMITA 1 Europe CH Switzerland ... 2019 None None https://api.eppo.int/gd/v2/taxons/taxon/BEMITA... 2025-12-10 14:58:20.605414
11 BEMITA 1 Europe TR Türkiye ... 2016 None None https://api.eppo.int/gd/v2/taxons/taxon/BEMITA... 2025-12-10 14:58:20.605414
12 BEMITA 1 Europe UA Ukraine ... 2019 None None https://api.eppo.int/gd/v2/taxons/taxon/BEMITA... 2025-12-10 14:58:20.605414
13 BEMITA 1 Europe GB United Kingdom ... 2020 None None https://api.eppo.int/gd/v2/taxons/taxon/BEMITA... 2025-12-10 14:58:20.605414
14 BEMITA 5 Oceania NZ New Zealand ... 2000 None None https://api.eppo.int/gd/v2/taxons/taxon/BEMITA... 2025-12-10 14:58:20.605414
15 BEMITA 6 RPPO/EU 9M EAEU ... 2016 None None https://api.eppo.int/gd/v2/taxons/taxon/BEMITA... 2025-12-10 14:58:20.605414
16 BEMITA 6 RPPO/EU 9A EPPO ... 1989 None None https://api.eppo.int/gd/v2/taxons/taxon/BEMITA... 2025-12-10 14:58:20.605414
17 BEMITA 6 RPPO/EU 9L EU ... 2019 None None https://api.eppo.int/gd/v2/taxons/taxon/BEMITA... 2025-12-10 14:58:20.605414
18 BEMITA 6 RPPO/EU 9L EU ... 2019 None None https://api.eppo.int/gd/v2/taxons/taxon/BEMITA... 2025-12-10 14:58:20.605414
19 BEMITA 6 RPPO/EU 9H OIRSA ... 1992 None None https://api.eppo.int/gd/v2/taxons/taxon/BEMITA... 2025-12-10 14:58:20.605414
[20 rows x 12 columns]}
All function calls return a dictionary of data frames, each containing the information from the requested services.
Querying all available services
To fetch data from all available services within a specific endpoint, simply
use the corresponding function without modifying the services parameter. Each
function will return a dictionary of data frames, with each data frame
containing information from one service.
data = client.taxon(eppo_codes=["BEMITA"])
Expected output
# Print the names of the services in the result.
print(data.keys())
dict_keys([<TaxonService.OVERVIEW: 'overview'>, <TaxonService.INFOS: 'infos'>, <TaxonService.NAMES: 'names'>, <TaxonService.TAXONOMY: 'taxonomy'>, <TaxonService.CATEGORIZATION: 'categorization'>, <TaxonService.KINGDOM: 'kingdom'>, <TaxonService.HOSTS: 'hosts'>, <TaxonService.PESTS: 'pests'>, <TaxonService.VECTORS: 'vectors'>, <TaxonService.VECTOR_OF: 'vectorof'>, <TaxonService.BCA: 'bca'>, <TaxonService.BCA_OF: 'bcaof'>, <TaxonService.PHOTOS: 'photos'>, <TaxonService.REPORTING_ARTICLES: 'reporting_articles'>, <TaxonService.DOCUMENTS: 'documents'>, <TaxonService.STANDARDS: 'standards'>, <TaxonService.DISTRIBUTION: 'distribution'>])
# Print the data from a specific service.
print(data[TaxonService.OVERVIEW])
queried_eppo_code eppocode datecreate lastupdate infos replacedby prefname is_active datatype queried_url queried_on
0 BEMITA BEMITA 2002-10-28 00:00:00 2002-10-28 00:00:00 None None Bemisia tabaci True GAI https://api.eppo.int/gd/v2/taxons/taxon/BEMITA... 2025-12-10 15:08:26.388685
Using data.keys() will display the names of the queried services. You can
then access a specific service to view the data associated with it.
Data wrangling
The eppoPynder package provides a convenient function, uniform_taxonomy(),
to create a complete and standardized taxonomy data frame. This function takes
the taxonomy data returned by the taxonomy service and ensures a uniform
structure, including all expected taxonomic ranks, even if some ranks are
missing in the original result.
For example, assume you have retrieved taxonomy data for the EPPO code "BEMITA"
using the Client.taxon() function:
data = client.taxon(eppo_codes=["BEMITA"], services=[TaxonService.TAXONOMY])
You can then generate a uniform taxonomy table with all ranks using:
taxonomy = uniform_taxonomy(data[TaxonService.TAXONOMY])
Expected output
print(taxonomy)
type queried_eppo_code eppocode prefname queried_url queried_on
0 Kingdom BEMITA 1ANIMK Animalia https://api.eppo.int/gd/v2/taxons/taxon/BEMITA... 2025-12-10 15:26:07.594529
1 Phylum BEMITA 1ARTHP Arthropoda https://api.eppo.int/gd/v2/taxons/taxon/BEMITA... 2025-12-10 15:26:07.594529
2 Subphylum BEMITA 1HEXAQ Hexapoda https://api.eppo.int/gd/v2/taxons/taxon/BEMITA... 2025-12-10 15:26:07.594529
3 Class BEMITA 1INSEC Insecta https://api.eppo.int/gd/v2/taxons/taxon/BEMITA... 2025-12-10 15:26:07.594529
4 Subclass NaN NaN NaN NaN NaT
5 Order BEMITA 1HEMIO Hemiptera https://api.eppo.int/gd/v2/taxons/taxon/BEMITA... 2025-12-10 15:26:07.594529
6 Suborder BEMITA 1STERR Sternorrhyncha https://api.eppo.int/gd/v2/taxons/taxon/BEMITA... 2025-12-10 15:26:07.594529
7 Family BEMITA 1ALEYF Aleyrodidae https://api.eppo.int/gd/v2/taxons/taxon/BEMITA... 2025-12-10 15:26:07.594529
8 Subfamily NaN NaN NaN NaN NaT
9 Genus BEMITA 1BEMIG Bemisia https://api.eppo.int/gd/v2/taxons/taxon/BEMITA... 2025-12-10 15:26:07.594529
10 Species BEMITA BEMITA Bemisia tabaci https://api.eppo.int/gd/v2/taxons/taxon/BEMITA... 2025-12-10 15:26:07.594529
Data retrieval for multiple EPPO or ISO codes
The Client.taxon() and Client.country() functions allow you to retrieve
also a complete data dump for multiple EPPO or ISO codes by querying all
available EPPO services for each of them.
Here is an example showing how to use the function to fetch all available information for the EPPO codes "BEMITA" and "GOSHI":
data = client.taxon(eppo_codes=["BEMITA", "GOSHI"])
Expected output
# Print the names of the services in the result.
print(data.keys())
dict_keys([<TaxonService.OVERVIEW: 'overview'>, <TaxonService.INFOS: 'infos'>, <TaxonService.NAMES: 'names'>, <TaxonService.TAXONOMY: 'taxonomy'>, <TaxonService.CATEGORIZATION: 'categorization'>, <TaxonService.KINGDOM: 'kingdom'>, <TaxonService.HOSTS: 'hosts'>, <TaxonService.PESTS: 'pests'>, <TaxonService.VECTORS: 'vectors'>, <TaxonService.VECTOR_OF: 'vectorof'>, <TaxonService.BCA: 'bca'>, <TaxonService.BCA_OF: 'bcaof'>, <TaxonService.PHOTOS: 'photos'>, <TaxonService.REPORTING_ARTICLES: 'reporting_articles'>, <TaxonService.DOCUMENTS: 'documents'>, <TaxonService.STANDARDS: 'standards'>, <TaxonService.DISTRIBUTION: 'distribution'>])
# Print the data from a specific service.
print(data[TaxonService.OVERVIEW])
queried_eppo_code eppocode datecreate lastupdate ... is_active datatype queried_url queried_on
0 BEMITA BEMITA 2002-10-28 00:00:00 2002-10-28 00:00:00 ... True GAI https://api.eppo.int/gd/v2/taxons/taxon/BEMITA... 2025-12-10 15:31:54.300453
1 GOSHI GOSHI 2004-04-21 00:00:00 2004-04-21 00:00:00 ... True PFL https://api.eppo.int/gd/v2/taxons/taxon/GOSHI/... 2025-12-10 15:31:54.864112
Using data.keys() will display the names of the queried services. You can
then access a specific service to view the data associated with it.