diff --git a/docs/source/index.md b/docs/source/index.md index b857b62..0029419 100644 --- a/docs/source/index.md +++ b/docs/source/index.md @@ -23,6 +23,8 @@ workflow-guides/index development-guides/index apidocs/index +Releases +PyPI GitHub ``` diff --git a/docs/source/usage-guides/insights-api.md b/docs/source/usage-guides/insights-api.md index 840f848..3b4f3bf 100644 --- a/docs/source/usage-guides/insights-api.md +++ b/docs/source/usage-guides/insights-api.md @@ -4,7 +4,7 @@ This guide provides detailed instructions on how to use the [gfw-api-python-client](https://github.com/GlobalFishingWatch/gfw-api-python-client) to access aggregated insights about vessel activities. Currently, the [Insights API](https://globalfishingwatch.org/our-apis/documentation#insights-api) focuses on providing summaries related to specific vessels over a defined time range. Here is a [Jupyter Notebook](https://github.com/GlobalFishingWatch/gfw-api-python-client/blob/develop/notebooks/usage-guides/insights-api.ipynb) version of this guide with more usage examples. -> **Note:** See the [Insights Data Caveats](https://globalfishingwatch.org/our-apis/documentation#insights-api-fishing-detected-in-no-take-mpas)—it is critical to avoid misinterpreting the insights. You can find the [Datasets](https://globalfishingwatch.org/our-apis/documentation#api-dataset), and [Terms of Use](https://globalfishingwatch.org/our-apis/documentation#terms-of-use) pages in the [GFW API documentation](https://globalfishingwatch.org/our-apis/documentation#introduction) for details on GFW data, API licenses, and rate limits. +> **Note:** See the [Apparent fishing detected in no-take MPAs](https://globalfishingwatch.org/our-apis/documentation#insights-api-fishing-detected-in-no-take-mpas), [Apparent fishing event detected outside known authorized areas](https://globalfishingwatch.org/our-apis/documentation#insights-api-fishing-event-detected-outside-known-authorized-areas), [Coverage](https://globalfishingwatch.org/our-apis/documentation#insights-api-coverage), [AIS off event (aka GAP)](https://globalfishingwatch.org/our-apis/documentation#insights-api-ais-off-event-aka-gap), and [RFMO IUU vessel list](https://globalfishingwatch.org/our-apis/documentation#insights-api-rfmo-iuu-vessel-list) Data Caveats — it is critical to avoid misinterpreting the insights. You can find the [Datasets](https://globalfishingwatch.org/our-apis/documentation#api-dataset), and [Terms of Use](https://globalfishingwatch.org/our-apis/documentation#terms-of-use) pages in the [GFW API documentation](https://globalfishingwatch.org/our-apis/documentation#introduction) for details on GFW data, API licenses, and rate limits. ## Prerequisites @@ -40,16 +40,15 @@ The `gfw_client.insights` object provides methods for retrieving insights data f The `get_vessel_insights()` method allows you to retrieve aggregated insights for a specific vessel within a given time range. +**Important:** `start_date` must be on or after `January 1, 2020` + ```python insights_result = await gfw_client.insights.get_vessel_insights( includes=["FISHING"], start_date="2020-01-01", end_date="2025-03-03", vessels=[ - { - "dataset_id": "public-global-vessel-identity:latest", - "vessel_id": "785101812-2127-e5d2-e8bf-7152c5259f5f", - } + "785101812-2127-e5d2-e8bf-7152c5259f5f", ], ) ``` @@ -100,6 +99,277 @@ dtypes: object(6) memory usage: 180.0+ bytes ``` +## Getting Apparent Fishing-related Insights (`FISHING`) + +```python +fishing_insights_result = await gfw_client.insights.get_vessel_insights( + includes=["FISHING"], + start_date="2020-01-01", + end_date="2025-03-03", + vessels=[ + "785101812-2127-e5d2-e8bf-7152c5259f5f", + "2339c52c3-3a84-1603-f968-d8890f23e1ed", + "2d26aa452-2d4f-4cae-2ec4-377f85e88dcb", + ], +) +``` + +```python +fishing_insights_df = fishing_insights_result.df() +print(fishing_insights_df) +``` + +**Output:** + +``` + +RangeIndex: 1 entries, 0 to 0 +Data columns (total 6 columns): + # Column Non-Null Count Dtype +--- ------ -------------- ----- + 0 period 1 non-null object + 1 vessel_ids_without_identity 0 non-null object + 2 gap 0 non-null object + 3 coverage 0 non-null object + 4 apparent_fishing 1 non-null object + 5 vessel_identity 0 non-null object +dtypes: object(6) +memory usage: 180.0+ bytes +``` + +## Getting AIS off/disabling Insights (`GAP`) + +```python +gap_insights_result = await gfw_client.insights.get_vessel_insights( + includes=["GAP"], + start_date="2020-01-01", + end_date="2025-03-03", + vessels=[ + "785101812-2127-e5d2-e8bf-7152c5259f5f", + "2339c52c3-3a84-1603-f968-d8890f23e1ed", + "2d26aa452-2d4f-4cae-2ec4-377f85e88dcb", + ], +) +``` + +```python +gap_insights_df = gap_insights_result.df() +print(gap_insights_df) +``` + +**Output:** + +``` + +RangeIndex: 1 entries, 0 to 0 +Data columns (total 6 columns): + # Column Non-Null Count Dtype +--- ------ -------------- ----- + 0 period 1 non-null object + 1 vessel_ids_without_identity 0 non-null object + 2 gap 1 non-null object + 3 coverage 0 non-null object + 4 apparent_fishing 0 non-null object + 5 vessel_identity 0 non-null object +dtypes: object(6) +memory usage: 180.0+ bytes +``` + +## Getting AIS Coverage Metrics Insights (`COVERAGE`) + +```python +coverage_insights_result = await gfw_client.insights.get_vessel_insights( + includes=["COVERAGE"], + start_date="2020-01-01", + end_date="2025-03-03", + vessels=[ + "2339c52c3-3a84-1603-f968-d8890f23e1ed", + ], +) +``` + +```python +coverage_insights_df = coverage_insights_result.df() +print(coverage_insights_df) +``` + +**Output:** + +``` + +RangeIndex: 1 entries, 0 to 0 +Data columns (total 6 columns): + # Column Non-Null Count Dtype +--- ------ -------------- ----- + 0 period 1 non-null object + 1 vessel_ids_without_identity 0 non-null object + 2 gap 0 non-null object + 3 coverage 1 non-null object + 4 apparent_fishing 0 non-null object + 5 vessel_identity 0 non-null object +dtypes: object(6) +memory usage: 180.0+ bytes +``` + +## Getting Being Listed in IUU (Illegal,Unreported, and Unregulated) Insights (`VESSEL-IDENTITY-IUU-VESSEL-LIST`) + +```python +iuu_insights_result = await gfw_client.insights.get_vessel_insights( + includes=["VESSEL-IDENTITY-IUU-VESSEL-LIST"], + start_date="2020-01-01", + end_date="2025-03-03", + vessels=[ + "2d26aa452-2d4f-4cae-2ec4-377f85e88dcb", + ], +) +``` + +```python +iuu_insights_df = iuu_insights_result.df() +print(iuu_insights_df) +``` + +**Output:** + +``` + +RangeIndex: 1 entries, 0 to 0 +Data columns (total 6 columns): + # Column Non-Null Count Dtype +--- ------ -------------- ----- + 0 period 1 non-null object + 1 vessel_ids_without_identity 0 non-null object + 2 gap 0 non-null object + 3 coverage 0 non-null object + 4 apparent_fishing 0 non-null object + 5 vessel_identity 1 non-null object +dtypes: object(6) +memory usage: 180.0+ bytes +``` + +## Getting Flag Changes Insights (`VESSEL-IDENTITY-FLAG-CHANGES`) + +> **Note:** In order to enable this insight for your API access token (`GFW_API_ACCESS_TOKEN`), please contact apis@globalfishingwatch.org. In your message, please specify the email address used to generate the [API tokens](https://globalfishingwatch.org/our-apis/tokens) (i.e., the email address associated with your [Global Fishing Watch account](https://globalfishingwatch.org/our-apis/tokens/signup)). + +```python +flag_changes_insights_result = await gfw_client.insights.get_vessel_insights( + includes=["VESSEL-IDENTITY-FLAG-CHANGES"], + start_date="2020-01-01", + end_date="2025-03-03", + vessels=[ + "2d26aa452-2d4f-4cae-2ec4-377f85e88dcb", + ], +) +``` + +```python +flag_changes_insights_df = flag_changes_insights_result.df() +print(flag_changes_insights_df.info()) +``` + +**Output:** + +``` + +RangeIndex: 1 entries, 0 to 0 +Data columns (total 6 columns): + # Column Non-Null Count Dtype +--- ------ -------------- ----- + 0 period 1 non-null object + 1 vessel_ids_without_identity 0 non-null object + 2 gap 0 non-null object + 3 coverage 0 non-null object + 4 apparent_fishing 0 non-null object + 5 vessel_identity 1 non-null object +dtypes: object(6) +memory usage: 180.0+ bytes +``` + +## Getting Flag State Presence under Tokyo/Paris MOU black or grey Lists Insights (`VESSEL-IDENTITY-MOU-LIST`) + +> **Note:** In order to enable this insight for your API access token (`GFW_API_ACCESS_TOKEN`), please contact apis@globalfishingwatch.org. In your message, please specify the email address used to generate the [API tokens](https://globalfishingwatch.org/our-apis/tokens) (i.e., the email address associated with your [Global Fishing Watch account](https://globalfishingwatch.org/our-apis/tokens/signup)). + +```python +mou_insights_result = await gfw_client.insights.get_vessel_insights( + includes=["VESSEL-IDENTITY-MOU-LIST"], + start_date="2020-01-01", + end_date="2025-03-03", + vessels=[ + "785101812-2127-e5d2-e8bf-7152c5259f5f", + ], +) +``` + +```python +mou_insights_df = mou_insights_result.df() +print(mou_insights_df.info()) +``` + +**Output:** + +``` + +RangeIndex: 1 entries, 0 to 0 +Data columns (total 6 columns): + # Column Non-Null Count Dtype +--- ------ -------------- ----- + 0 period 1 non-null object + 1 vessel_ids_without_identity 0 non-null object + 2 gap 0 non-null object + 3 coverage 0 non-null object + 4 apparent_fishing 0 non-null object + 5 vessel_identity 1 non-null object +dtypes: object(6) +memory usage: 180.0+ bytes +``` + +## Getting Multiple Insights for Multiple Vessels + +> **Note:** In order to enable `VESSEL-IDENTITY-FLAG-CHANGES` and `VESSEL-IDENTITY-MOU-LIST` insights for your API access token (`GFW_API_ACCESS_TOKEN`), please contact apis@globalfishingwatch.org. In your message, please specify the email address used to generate the [API tokens](https://globalfishingwatch.org/our-apis/tokens) (i.e., the email address associated with your [Global Fishing Watch account](https://globalfishingwatch.org/our-apis/tokens/signup)). + +```python +all_insights_result = await gfw_client.insights.get_vessel_insights( + includes=[ + "FISHING", + "GAP", + "VESSEL-IDENTITY-IUU-VESSEL-LIST", + "COVERAGE", + "VESSEL-IDENTITY-FLAG-CHANGES", + "VESSEL-IDENTITY-MOU-LIST", + ], + start_date="2020-01-01", + end_date="2025-03-03", + vessels=[ + "785101812-2127-e5d2-e8bf-7152c5259f5f", + "2339c52c3-3a84-1603-f968-d8890f23e1ed", + "2d26aa452-2d4f-4cae-2ec4-377f85e88dcb", + ], +) +``` + +```python +all_insights_df = all_insights_result.df() +print(all_insights_df.info()) +``` + +**Output:** + +``` + +RangeIndex: 1 entries, 0 to 0 +Data columns (total 6 columns): + # Column Non-Null Count Dtype +--- ------ -------------- ----- + 0 period 1 non-null object + 1 vessel_ids_without_identity 0 non-null object + 2 gap 1 non-null object + 3 coverage 1 non-null object + 4 apparent_fishing 1 non-null object + 5 vessel_identity 1 non-null object +dtypes: object(6) +memory usage: 180.0+ bytes +``` + ## Next Steps Explore the [Usage Guides](index) and [Workflow Guides](../workflow-guides/index) for other API resources to understand how you can combine vessel insights with event data, vessel details, and more. Check out the following resources: diff --git a/notebooks/usage-guides/insights-api.ipynb b/notebooks/usage-guides/insights-api.ipynb index 5b7c2ad..be1aeaf 100644 --- a/notebooks/usage-guides/insights-api.ipynb +++ b/notebooks/usage-guides/insights-api.ipynb @@ -36,7 +36,7 @@ "id": "d1d62e3b-fc42-422a-bb7d-2ccc927ba494", "metadata": {}, "source": [ - "**Note:** See the [Insights Data Caveats](https://globalfishingwatch.org/our-apis/documentation#insights-api-fishing-detected-in-no-take-mpas)—it is critical to avoid misinterpreting the insights. You can find the [Datasets](https://globalfishingwatch.org/our-apis/documentation#api-dataset), and [Terms of Use](https://globalfishingwatch.org/our-apis/documentation#terms-of-use) pages in the [GFW API documentation](https://globalfishingwatch.org/our-apis/documentation#introduction) for details on GFW data, API licenses, and rate limits." + "**Note:** See the [Apparent fishing detected in no-take MPAs](https://globalfishingwatch.org/our-apis/documentation#insights-api-fishing-detected-in-no-take-mpas), [Apparent fishing event detected outside known authorized areas](https://globalfishingwatch.org/our-apis/documentation#insights-api-fishing-event-detected-outside-known-authorized-areas), [Coverage](https://globalfishingwatch.org/our-apis/documentation#insights-api-coverage), [AIS off event (aka GAP)](https://globalfishingwatch.org/our-apis/documentation#insights-api-ais-off-event-aka-gap), and [RFMO IUU vessel list](https://globalfishingwatch.org/our-apis/documentation#insights-api-rfmo-iuu-vessel-list) Data Caveats — it is critical to avoid misinterpreting the insights. You can find the [Datasets](https://globalfishingwatch.org/our-apis/documentation#api-dataset), and [Terms of Use](https://globalfishingwatch.org/our-apis/documentation#terms-of-use) pages in the [GFW API documentation](https://globalfishingwatch.org/our-apis/documentation#introduction) for details on GFW data, API licenses, and rate limits." ] }, { @@ -188,10 +188,7 @@ " start_date=\"2020-01-01\",\n", " end_date=\"2025-03-03\",\n", " vessels=[\n", - " {\n", - " \"dataset_id\": \"public-global-vessel-identity:latest\",\n", - " \"vessel_id\": \"785101812-2127-e5d2-e8bf-7152c5259f5f\",\n", - " }\n", + " \"785101812-2127-e5d2-e8bf-7152c5259f5f\",\n", " ],\n", ")" ] @@ -281,7 +278,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "\n", + "\n", "RangeIndex: 1 entries, 0 to 0\n", "Data columns (total 6 columns):\n", " # Column Non-Null Count Dtype \n", @@ -350,7 +347,7 @@ " None\n", " None\n", " None\n", - " {'datasets': ['public-global-fishing-events:v3...\n", + " {'datasets': ['public-global-fishing-events:v4...\n", " None\n", " \n", " \n", @@ -365,7 +362,7 @@ "0 None None None \n", "\n", " apparent_fishing vessel_identity \n", - "0 {'datasets': ['public-global-fishing-events:v3... None " + "0 {'datasets': ['public-global-fishing-events:v4... None " ] }, "execution_count": 10, @@ -376,6 +373,996 @@ "source": [ "insights_df.head()" ] + }, + { + "cell_type": "markdown", + "id": "49e9dbd4-b022-4247-a6d5-fe7c6dcb4b3b", + "metadata": {}, + "source": [ + "## Getting Apparent Fishing-related Insights (`FISHING`)" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "262203ed-2597-4074-96b6-b31c3aa74e2c", + "metadata": {}, + "outputs": [], + "source": [ + "fishing_insights_result = await gfw_client.insights.get_vessel_insights(\n", + " includes=[\"FISHING\"],\n", + " start_date=\"2020-01-01\",\n", + " end_date=\"2025-03-03\",\n", + " vessels=[\n", + " \"785101812-2127-e5d2-e8bf-7152c5259f5f\",\n", + " \"2339c52c3-3a84-1603-f968-d8890f23e1ed\",\n", + " \"2d26aa452-2d4f-4cae-2ec4-377f85e88dcb\",\n", + " ],\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "5304c902-bbbb-4869-ab05-6d61a4869936", + "metadata": {}, + "outputs": [], + "source": [ + "fishing_insights_df = fishing_insights_result.df()" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "83a14697-b13b-4ff0-b9ff-182e6f2ac1b7", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "RangeIndex: 1 entries, 0 to 0\n", + "Data columns (total 6 columns):\n", + " # Column Non-Null Count Dtype \n", + "--- ------ -------------- ----- \n", + " 0 period 1 non-null object\n", + " 1 vessel_ids_without_identity 0 non-null object\n", + " 2 gap 0 non-null object\n", + " 3 coverage 0 non-null object\n", + " 4 apparent_fishing 1 non-null object\n", + " 5 vessel_identity 0 non-null object\n", + "dtypes: object(6)\n", + "memory usage: 180.0+ bytes\n" + ] + } + ], + "source": [ + "fishing_insights_df.info()" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "df330962-c019-4f7b-b9e9-bddcd79fd1f2", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
periodvessel_ids_without_identitygapcoverageapparent_fishingvessel_identity
0{'start_date': 2020-01-01, 'end_date': 2025-03...NoneNoneNone{'datasets': ['public-global-fishing-events:v4...None
\n", + "
" + ], + "text/plain": [ + " period \\\n", + "0 {'start_date': 2020-01-01, 'end_date': 2025-03... \n", + "\n", + " vessel_ids_without_identity gap coverage \\\n", + "0 None None None \n", + "\n", + " apparent_fishing vessel_identity \n", + "0 {'datasets': ['public-global-fishing-events:v4... None " + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fishing_insights_df.head()" + ] + }, + { + "cell_type": "markdown", + "id": "f4dc3e37-ad7f-44d9-929c-4eb83678a9a7", + "metadata": {}, + "source": [ + "## Getting AIS off/disabling Insights (`GAP`)" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "c18aba46-d1bd-4375-bf15-97afac3b5f3e", + "metadata": {}, + "outputs": [], + "source": [ + "gap_insights_result = await gfw_client.insights.get_vessel_insights(\n", + " includes=[\"GAP\"],\n", + " start_date=\"2020-01-01\",\n", + " end_date=\"2025-03-03\",\n", + " vessels=[\n", + " \"785101812-2127-e5d2-e8bf-7152c5259f5f\",\n", + " \"2339c52c3-3a84-1603-f968-d8890f23e1ed\",\n", + " \"2d26aa452-2d4f-4cae-2ec4-377f85e88dcb\",\n", + " ],\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "d9285f1c-db40-4215-9358-1a07473de2e2", + "metadata": {}, + "outputs": [], + "source": [ + "gap_insights_df = gap_insights_result.df()" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "c9cb34a3-dcdc-4f2e-b772-ff67e812e511", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "RangeIndex: 1 entries, 0 to 0\n", + "Data columns (total 6 columns):\n", + " # Column Non-Null Count Dtype \n", + "--- ------ -------------- ----- \n", + " 0 period 1 non-null object\n", + " 1 vessel_ids_without_identity 0 non-null object\n", + " 2 gap 1 non-null object\n", + " 3 coverage 0 non-null object\n", + " 4 apparent_fishing 0 non-null object\n", + " 5 vessel_identity 0 non-null object\n", + "dtypes: object(6)\n", + "memory usage: 180.0+ bytes\n" + ] + } + ], + "source": [ + "gap_insights_df.info()" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "99a2d935-e3c5-49df-bead-d8bc1986abbd", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
periodvessel_ids_without_identitygapcoverageapparent_fishingvessel_identity
0{'start_date': 2020-01-01, 'end_date': 2025-03...None{'datasets': ['public-global-gaps-events:v4.0'...NoneNoneNone
\n", + "
" + ], + "text/plain": [ + " period \\\n", + "0 {'start_date': 2020-01-01, 'end_date': 2025-03... \n", + "\n", + " vessel_ids_without_identity \\\n", + "0 None \n", + "\n", + " gap coverage \\\n", + "0 {'datasets': ['public-global-gaps-events:v4.0'... None \n", + "\n", + " apparent_fishing vessel_identity \n", + "0 None None " + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "gap_insights_df.head()" + ] + }, + { + "cell_type": "markdown", + "id": "669396bc-6a19-493a-a1a9-d7840aad51aa", + "metadata": {}, + "source": [ + "## Getting AIS Coverage Metrics Insights (`COVERAGE`)" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "0e991053-9015-4724-b7d6-ac1f0f77a880", + "metadata": {}, + "outputs": [], + "source": [ + "coverage_insights_result = await gfw_client.insights.get_vessel_insights(\n", + " includes=[\"COVERAGE\"],\n", + " start_date=\"2020-01-01\",\n", + " end_date=\"2025-03-03\",\n", + " vessels=[\n", + " \"2339c52c3-3a84-1603-f968-d8890f23e1ed\",\n", + " ],\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "e7470865-9c6a-4e99-a1e8-10bfb760a723", + "metadata": {}, + "outputs": [], + "source": [ + "coverage_insights_df = coverage_insights_result.df()" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "14d88f0d-f779-4ad8-b565-37857be65067", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "RangeIndex: 1 entries, 0 to 0\n", + "Data columns (total 6 columns):\n", + " # Column Non-Null Count Dtype \n", + "--- ------ -------------- ----- \n", + " 0 period 1 non-null object\n", + " 1 vessel_ids_without_identity 0 non-null object\n", + " 2 gap 0 non-null object\n", + " 3 coverage 1 non-null object\n", + " 4 apparent_fishing 0 non-null object\n", + " 5 vessel_identity 0 non-null object\n", + "dtypes: object(6)\n", + "memory usage: 180.0+ bytes\n" + ] + } + ], + "source": [ + "coverage_insights_df.info()" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "615025e8-5ee6-4562-b92f-b52030cf24d9", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
periodvessel_ids_without_identitygapcoverageapparent_fishingvessel_identity
0{'start_date': 2020-01-01, 'end_date': 2025-03...NoneNone{'blocks': '8917', 'blocks_with_positions': '7...NoneNone
\n", + "
" + ], + "text/plain": [ + " period \\\n", + "0 {'start_date': 2020-01-01, 'end_date': 2025-03... \n", + "\n", + " vessel_ids_without_identity gap \\\n", + "0 None None \n", + "\n", + " coverage apparent_fishing \\\n", + "0 {'blocks': '8917', 'blocks_with_positions': '7... None \n", + "\n", + " vessel_identity \n", + "0 None " + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "coverage_insights_df.head()" + ] + }, + { + "cell_type": "markdown", + "id": "a72eebf7-e389-4ef4-8a0e-b97e11769292", + "metadata": {}, + "source": [ + "## Getting Being Listed in IUU (Illegal,Unreported, and Unregulated) Insights (`VESSEL-IDENTITY-IUU-VESSEL-LIST`)" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "8d865858-c2dd-4561-9331-8a8e0e3134ef", + "metadata": {}, + "outputs": [], + "source": [ + "iuu_insights_result = await gfw_client.insights.get_vessel_insights(\n", + " includes=[\"VESSEL-IDENTITY-IUU-VESSEL-LIST\"],\n", + " start_date=\"2020-01-01\",\n", + " end_date=\"2025-03-03\",\n", + " vessels=[\n", + " \"2d26aa452-2d4f-4cae-2ec4-377f85e88dcb\",\n", + " ],\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "2bbe1f16-4a8f-43dd-b8c4-8f077e8ac754", + "metadata": {}, + "outputs": [], + "source": [ + "iuu_insights_df = iuu_insights_result.df()" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "5bb6f05c-1582-4d26-ab75-d39fa0f0e1f2", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "RangeIndex: 1 entries, 0 to 0\n", + "Data columns (total 6 columns):\n", + " # Column Non-Null Count Dtype \n", + "--- ------ -------------- ----- \n", + " 0 period 1 non-null object\n", + " 1 vessel_ids_without_identity 0 non-null object\n", + " 2 gap 0 non-null object\n", + " 3 coverage 0 non-null object\n", + " 4 apparent_fishing 0 non-null object\n", + " 5 vessel_identity 1 non-null object\n", + "dtypes: object(6)\n", + "memory usage: 180.0+ bytes\n" + ] + } + ], + "source": [ + "iuu_insights_df.info()" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "id": "e12ef530-72f3-4309-baa6-7c7a158c7db4", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
periodvessel_ids_without_identitygapcoverageapparent_fishingvessel_identity
0{'start_date': 2020-01-01, 'end_date': 2025-03...NoneNoneNoneNone{'datasets': ['public-global-vessel-identity:v...
\n", + "
" + ], + "text/plain": [ + " period \\\n", + "0 {'start_date': 2020-01-01, 'end_date': 2025-03... \n", + "\n", + " vessel_ids_without_identity gap coverage apparent_fishing \\\n", + "0 None None None None \n", + "\n", + " vessel_identity \n", + "0 {'datasets': ['public-global-vessel-identity:v... " + ] + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "iuu_insights_df.head()" + ] + }, + { + "cell_type": "markdown", + "id": "da557346-5d3a-4ef4-9b3f-7e3aac3ae0c8", + "metadata": {}, + "source": [ + "## Getting Flag Changes Insights (`VESSEL-IDENTITY-FLAG-CHANGES`)" + ] + }, + { + "cell_type": "markdown", + "id": "1f3e5772-993e-4a96-a179-fa2d28430be4", + "metadata": {}, + "source": [ + "**Note:** In order to enable this insight for your API access token (`GFW_API_ACCESS_TOKEN`), please contact apis@globalfishingwatch.org. In your message, please specify the email address used to generate the [API tokens](https://globalfishingwatch.org/our-apis/tokens) (i.e., the email address associated with your [Global Fishing Watch account](https://globalfishingwatch.org/our-apis/tokens/signup))." + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "c034210b-29f3-496d-b07e-f2c2700e191e", + "metadata": {}, + "outputs": [], + "source": [ + "flag_changes_insights_result = await gfw_client.insights.get_vessel_insights(\n", + " includes=[\"VESSEL-IDENTITY-FLAG-CHANGES\"],\n", + " start_date=\"2020-01-01\",\n", + " end_date=\"2025-03-03\",\n", + " vessels=[\n", + " \"2d26aa452-2d4f-4cae-2ec4-377f85e88dcb\",\n", + " ],\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "id": "884088b9-7c37-491f-87fd-2005925942cb", + "metadata": {}, + "outputs": [], + "source": [ + "flag_changes_insights_df = flag_changes_insights_result.df()" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "id": "71b633c9-328c-40f7-8707-871ec79beb0a", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "RangeIndex: 1 entries, 0 to 0\n", + "Data columns (total 6 columns):\n", + " # Column Non-Null Count Dtype \n", + "--- ------ -------------- ----- \n", + " 0 period 1 non-null object\n", + " 1 vessel_ids_without_identity 0 non-null object\n", + " 2 gap 0 non-null object\n", + " 3 coverage 0 non-null object\n", + " 4 apparent_fishing 0 non-null object\n", + " 5 vessel_identity 1 non-null object\n", + "dtypes: object(6)\n", + "memory usage: 180.0+ bytes\n" + ] + } + ], + "source": [ + "flag_changes_insights_df.info()" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "id": "c25b642a-fe12-4d77-8684-3c54b8f8bfd4", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
periodvessel_ids_without_identitygapcoverageapparent_fishingvessel_identity
0{'start_date': 2020-01-01, 'end_date': 2025-03...NoneNoneNoneNone{'datasets': ['public-global-vessel-identity:v...
\n", + "
" + ], + "text/plain": [ + " period \\\n", + "0 {'start_date': 2020-01-01, 'end_date': 2025-03... \n", + "\n", + " vessel_ids_without_identity gap coverage apparent_fishing \\\n", + "0 None None None None \n", + "\n", + " vessel_identity \n", + "0 {'datasets': ['public-global-vessel-identity:v... " + ] + }, + "execution_count": 30, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "flag_changes_insights_df.head()" + ] + }, + { + "cell_type": "markdown", + "id": "7037a8e7-a66c-4ee5-a08a-0f924ef14360", + "metadata": {}, + "source": [ + "## Getting Flag State Presence under Tokyo/Paris MOU black or grey Lists Insights (`VESSEL-IDENTITY-MOU-LIST`)" + ] + }, + { + "cell_type": "markdown", + "id": "a36813b7-b2c5-4ea8-a55a-c1a923f9237d", + "metadata": {}, + "source": [ + "**Note:** In order to enable this insight for your API access token (`GFW_API_ACCESS_TOKEN`), please contact apis@globalfishingwatch.org. In your message, please specify the email address used to generate the [API tokens](https://globalfishingwatch.org/our-apis/tokens) (i.e., the email address associated with your [Global Fishing Watch account](https://globalfishingwatch.org/our-apis/tokens/signup))." + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "id": "2fcda356-43db-4060-9e17-678e349b5ee7", + "metadata": {}, + "outputs": [], + "source": [ + "mou_insights_result = await gfw_client.insights.get_vessel_insights(\n", + " includes=[\"VESSEL-IDENTITY-MOU-LIST\"],\n", + " start_date=\"2020-01-01\",\n", + " end_date=\"2025-03-03\",\n", + " vessels=[\n", + " \"785101812-2127-e5d2-e8bf-7152c5259f5f\",\n", + " ],\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "id": "950f328b-4b16-493f-af98-73f5ba8be300", + "metadata": {}, + "outputs": [], + "source": [ + "mou_insights_df = mou_insights_result.df()" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "id": "c9ae5cad-01d0-4d97-bc5c-6d18cc7052df", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "RangeIndex: 1 entries, 0 to 0\n", + "Data columns (total 6 columns):\n", + " # Column Non-Null Count Dtype \n", + "--- ------ -------------- ----- \n", + " 0 period 1 non-null object\n", + " 1 vessel_ids_without_identity 0 non-null object\n", + " 2 gap 0 non-null object\n", + " 3 coverage 0 non-null object\n", + " 4 apparent_fishing 0 non-null object\n", + " 5 vessel_identity 1 non-null object\n", + "dtypes: object(6)\n", + "memory usage: 180.0+ bytes\n" + ] + } + ], + "source": [ + "mou_insights_df.info()" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "id": "65ea0ba4-b9bd-4157-b488-e6a7f50a9778", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
periodvessel_ids_without_identitygapcoverageapparent_fishingvessel_identity
0{'start_date': 2020-01-01, 'end_date': 2025-03...NoneNoneNoneNone{'datasets': ['public-global-vessel-identity:v...
\n", + "
" + ], + "text/plain": [ + " period \\\n", + "0 {'start_date': 2020-01-01, 'end_date': 2025-03... \n", + "\n", + " vessel_ids_without_identity gap coverage apparent_fishing \\\n", + "0 None None None None \n", + "\n", + " vessel_identity \n", + "0 {'datasets': ['public-global-vessel-identity:v... " + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "mou_insights_df.head()" + ] + }, + { + "cell_type": "markdown", + "id": "a70de4c2-1922-4ed1-84b7-de438103654a", + "metadata": {}, + "source": [ + "## Getting Multiple Insights for Multiple Vessels" + ] + }, + { + "cell_type": "markdown", + "id": "2899f3be-a582-47c2-9fa2-98bd2002c7fc", + "metadata": {}, + "source": [ + "**Note:** In order to enable `VESSEL-IDENTITY-FLAG-CHANGES` and `VESSEL-IDENTITY-MOU-LIST` insights for your API access token (`GFW_API_ACCESS_TOKEN`), please contact apis@globalfishingwatch.org. In your message, please specify the email address used to generate the [API tokens](https://globalfishingwatch.org/our-apis/tokens) (i.e., the email address associated with your [Global Fishing Watch account](https://globalfishingwatch.org/our-apis/tokens/signup))." + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "id": "6561627c-b472-401d-8ec6-befca13a41d6", + "metadata": {}, + "outputs": [], + "source": [ + "all_insights_result = await gfw_client.insights.get_vessel_insights(\n", + " includes=[\n", + " \"FISHING\",\n", + " \"GAP\",\n", + " \"VESSEL-IDENTITY-IUU-VESSEL-LIST\",\n", + " \"COVERAGE\",\n", + " \"VESSEL-IDENTITY-FLAG-CHANGES\",\n", + " \"VESSEL-IDENTITY-MOU-LIST\",\n", + " ],\n", + " start_date=\"2020-01-01\",\n", + " end_date=\"2025-03-03\",\n", + " vessels=[\n", + " \"785101812-2127-e5d2-e8bf-7152c5259f5f\",\n", + " \"2339c52c3-3a84-1603-f968-d8890f23e1ed\",\n", + " \"2d26aa452-2d4f-4cae-2ec4-377f85e88dcb\",\n", + " ],\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "id": "09af2c8f-ee6c-4d6d-8372-092c4bef2051", + "metadata": {}, + "outputs": [], + "source": [ + "all_insights_df = all_insights_result.df()" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "id": "cf48b48e-b6ee-4ef8-8db8-1f265cbe29e8", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "RangeIndex: 1 entries, 0 to 0\n", + "Data columns (total 6 columns):\n", + " # Column Non-Null Count Dtype \n", + "--- ------ -------------- ----- \n", + " 0 period 1 non-null object\n", + " 1 vessel_ids_without_identity 0 non-null object\n", + " 2 gap 1 non-null object\n", + " 3 coverage 1 non-null object\n", + " 4 apparent_fishing 1 non-null object\n", + " 5 vessel_identity 1 non-null object\n", + "dtypes: object(6)\n", + "memory usage: 180.0+ bytes\n" + ] + } + ], + "source": [ + "all_insights_df.info()" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "id": "73316b77-f4f8-4eca-8c0d-be0d0561f8f6", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
periodvessel_ids_without_identitygapcoverageapparent_fishingvessel_identity
0{'start_date': 2020-01-01, 'end_date': 2025-03...None{'datasets': ['public-global-gaps-events:v4.0'...{'blocks': '53447', 'blocks_with_positions': '...{'datasets': ['public-global-fishing-events:v4...{'datasets': ['public-global-vessel-identity:v...
\n", + "
" + ], + "text/plain": [ + " period \\\n", + "0 {'start_date': 2020-01-01, 'end_date': 2025-03... \n", + "\n", + " vessel_ids_without_identity \\\n", + "0 None \n", + "\n", + " gap \\\n", + "0 {'datasets': ['public-global-gaps-events:v4.0'... \n", + "\n", + " coverage \\\n", + "0 {'blocks': '53447', 'blocks_with_positions': '... \n", + "\n", + " apparent_fishing \\\n", + "0 {'datasets': ['public-global-fishing-events:v4... \n", + "\n", + " vessel_identity \n", + "0 {'datasets': ['public-global-vessel-identity:v... " + ] + }, + "execution_count": 38, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "all_insights_df.head()" + ] } ], "metadata": { diff --git a/src/gfwapiclient/client/client.py b/src/gfwapiclient/client/client.py index 1474534..d7b0e98 100644 --- a/src/gfwapiclient/client/client.py +++ b/src/gfwapiclient/client/client.py @@ -53,7 +53,7 @@ class Client: Access to the Events data API resources. insights (InsightResource): - Access to the vessel insights data resources. + Access to the Insights API resources. datasets (DatasetResource): Access to the datasets data resources. diff --git a/src/gfwapiclient/resources/bulk_downloads/resources.py b/src/gfwapiclient/resources/bulk_downloads/resources.py index cde500c..249a4d9 100644 --- a/src/gfwapiclient/resources/bulk_downloads/resources.py +++ b/src/gfwapiclient/resources/bulk_downloads/resources.py @@ -119,7 +119,7 @@ async def create_bulk_report( long date range etc), generating the bulk report can take several minutes to several hours. - Attributes: + Args: name (str): Human-readable name of the bulk report. Example: `"sar-fixed-infrastructure-data-20240903"`. diff --git a/src/gfwapiclient/resources/insights/__init__.py b/src/gfwapiclient/resources/insights/__init__.py index 9f108dc..cca8d3c 100644 --- a/src/gfwapiclient/resources/insights/__init__.py +++ b/src/gfwapiclient/resources/insights/__init__.py @@ -1,11 +1,25 @@ -"""Global Fishing Watch (GFW) API Python Client - Vessels Insights API Resource. +"""Global Fishing Watch (GFW) API Python Client - Insights API Resource. -This module provides the `InsightResource` class, which allows you to interact with the -Global Fishing Watch Vessels Insights API. It provides methods for retrieving -insights data for specified vessels. +This module provides the `InsightResource` class, which allows to interact with the +Insights API. It provides methods for retrieving insights data for specified vessels. -For more details, please refer to the official -`Global Fishing Watch Insights API Documentation `_. +For detailed information about the Insights API, please refer to the official +Global Fishing Watch API documentation: + +See: https://globalfishingwatch.org/our-apis/documentation#insights-api + +For more details on the Insights data caveats, please refer to the official +Global Fishing Watch API documentation: + +See: https://globalfishingwatch.org/our-apis/documentation#insights-api-fishing-detected-in-no-take-mpas + +See: https://globalfishingwatch.org/our-apis/documentation#insights-api-fishing-event-detected-outside-known-authorized-areas + +See: https://globalfishingwatch.org/our-apis/documentation#insights-api-coverage + +See: https://globalfishingwatch.org/our-apis/documentation#insights-api-ais-off-event-aka-gap + +See: https://globalfishingwatch.org/our-apis/documentation#insights-api-rfmo-iuu-vessel-list """ from gfwapiclient.resources.insights.resources import InsightResource diff --git a/src/gfwapiclient/resources/insights/endpoints.py b/src/gfwapiclient/resources/insights/endpoints.py index b3176e0..52c0304 100644 --- a/src/gfwapiclient/resources/insights/endpoints.py +++ b/src/gfwapiclient/resources/insights/endpoints.py @@ -1,4 +1,4 @@ -"""Global Fishing Watch (GFW) API Python Client - Vessels Insights API EndPoints.""" +"""Global Fishing Watch (GFW) API Python Client - Get Vessels Insights API Endpoint.""" from gfwapiclient.http.client import HTTPClient from gfwapiclient.http.endpoints import PostEndPoint @@ -21,6 +21,26 @@ class VesselInsightEndPoint( This endpoint retrieves insights for specified vessels based on the provided request parameters. + + For detailed information about the Get Vessels Insights API endpoint, please + refer to the official Global Fishing Watch API documentation: + + See: https://globalfishingwatch.org/our-apis/documentation#insights-by-vessels + + See: https://globalfishingwatch.org/our-apis/documentation#insights-by-vessels-body + + For more details on the Get Vessels Insights data caveats, please refer to the + official Global Fishing Watch API documentation: + + See: https://globalfishingwatch.org/our-apis/documentation#insights-api-fishing-detected-in-no-take-mpas + + See: https://globalfishingwatch.org/our-apis/documentation#insights-api-fishing-event-detected-outside-known-authorized-areas + + See: https://globalfishingwatch.org/our-apis/documentation#insights-api-coverage + + See: https://globalfishingwatch.org/our-apis/documentation#insights-api-ais-off-event-aka-gap + + See: https://globalfishingwatch.org/our-apis/documentation#insights-api-rfmo-iuu-vessel-list """ def __init__( diff --git a/src/gfwapiclient/resources/insights/models/__init__.py b/src/gfwapiclient/resources/insights/models/__init__.py index 271d250..9aa519f 100644 --- a/src/gfwapiclient/resources/insights/models/__init__.py +++ b/src/gfwapiclient/resources/insights/models/__init__.py @@ -1,18 +1,26 @@ -"""Global Fishing Watch (GFW) API Python Client - Vessels Insights API Models. +"""Global Fishing Watch (GFW) API Python Client - Get Vessels Insights API Models. -This module contains the Pydantic models used for interacting with the Global Fishing Watch -Vessels Insights API. These models define the structure of the request and response data -for the API endpoints, ensuring type safety and data validation. +This module defines Pydantic data models used for interacting with the +Vessels Insights API endpoint. These models are used to represent request bodies +and response data when retrieving insights data for specified vessels. -For more information on the Vessels Insights API, please refer to the -`Global Fishing Watch API documentation `_. -""" +For detailed information about the Get Vessels Insights API endpoint, please +refer to the official Global Fishing Watch API documentation: + +See: https://globalfishingwatch.org/our-apis/documentation#insights-by-vessels + +See: https://globalfishingwatch.org/our-apis/documentation#insights-by-vessels-body + +For more details on the Get Vessels Insights data caveats, please refer to the +official Global Fishing Watch API documentation: -from gfwapiclient.resources.insights.models.request import VesselInsightBody -from gfwapiclient.resources.insights.models.response import ( - VesselInsightItem, - VesselInsightResult, -) +See: https://globalfishingwatch.org/our-apis/documentation#insights-api-fishing-detected-in-no-take-mpas +See: https://globalfishingwatch.org/our-apis/documentation#insights-api-fishing-event-detected-outside-known-authorized-areas -__all__ = ["VesselInsightBody", "VesselInsightItem", "VesselInsightResult"] +See: https://globalfishingwatch.org/our-apis/documentation#insights-api-coverage + +See: https://globalfishingwatch.org/our-apis/documentation#insights-api-ais-off-event-aka-gap + +See: https://globalfishingwatch.org/our-apis/documentation#insights-api-rfmo-iuu-vessel-list +""" diff --git a/src/gfwapiclient/resources/insights/models/request.py b/src/gfwapiclient/resources/insights/models/request.py index 6a87a69..b049085 100644 --- a/src/gfwapiclient/resources/insights/models/request.py +++ b/src/gfwapiclient/resources/insights/models/request.py @@ -1,4 +1,4 @@ -"""Global Fishing Watch (GFW) API Python Client - Vessels Insights API Request Models.""" +"""Global Fishing Watch (GFW) API Python Client - Get Vessels Insights API Request Models.""" import datetime @@ -9,6 +9,7 @@ from gfwapiclient.base.models import BaseModel from gfwapiclient.http.models import RequestBody +from gfwapiclient.resources.vessels.base.models.request import VesselDataset __all__ = ["VesselInsightBody", "VesselInsightDatasetVessel", "VesselInsightInclude"] @@ -26,23 +27,31 @@ class VesselInsightInclude(str, Enum): vessel insights request, specifying the types of insights to retrieve. Attributes: + COVERAGE (str): + Insights related to AIS coverage. + FISHING (str): Insights related to fishing activity. GAP (str): Insights related to AIS gaps. - COVERAGE (str): - Insights related to AIS coverage. + VESSEL_IDENTITY_FLAG_CHANGES (str): + Insights related to vessels flag changes. VESSEL_IDENTITY_IUU_VESSEL_LIST (str): Insights related to vessels listed in IUU lists. + + VESSEL_IDENTITY_MOU_LIST (str): + Insights related to vessels listed in MOU lists. """ + COVERAGE = "COVERAGE" FISHING = "FISHING" GAP = "GAP" - COVERAGE = "COVERAGE" + VESSEL_IDENTITY_FLAG_CHANGES = "VESSEL-IDENTITY-FLAG-CHANGES" VESSEL_IDENTITY_IUU_VESSEL_LIST = "VESSEL-IDENTITY-IUU-VESSEL-LIST" + VESSEL_IDENTITY_MOU_LIST = "VESSEL-IDENTITY-MOU-LIST" class VesselInsightDatasetVessel(BaseModel): @@ -52,21 +61,29 @@ class VesselInsightDatasetVessel(BaseModel): vessel insights request. Attributes: - dataset_id (str): - The dataset identifier. Default to `"public-global-vessel-identity:latest"`. + dataset_id (VesselDataset): + The dataset identifier. Default to `VesselDataset.VESSEL_IDENTITY_LATEST`. - vessel_id: + vessel_id (str): The vessel identifier. """ - dataset_id: str = Field(...) - vessel_id: str = Field(...) + dataset_id: VesselDataset = Field( + VesselDataset.VESSEL_IDENTITY_LATEST, alias="datasetId" + ) + vessel_id: str = Field(..., alias="vesselId") class VesselInsightBody(RequestBody): """Vessel insight request body. - This model represents the request body for retrieving vessel insights. + Represents includes, start_date, end_date, vessels etc. parameters + for retrieving vessel insights. + + For more details on the Get Vessels Insights API endpoint supported request body, + please refer to the official Global Fishing Watch API documentation: + + See: https://globalfishingwatch.org/our-apis/documentation#insights-by-vessels-body Attributes: includes (List[VesselInsightInclude]): @@ -78,11 +95,13 @@ class VesselInsightBody(RequestBody): end_date (datetime.date): End date of the request. - vessels List[VesselInsightIdBody]: + vessels (List[VesselInsightDatasetVessel]): List of Dataset and Vessel ID to use to get vessel insights. """ - includes: List[VesselInsightInclude] = Field([VesselInsightInclude.FISHING]) - start_date: datetime.date = Field(...) - end_date: datetime.date = Field(...) - vessels: List[VesselInsightDatasetVessel] = Field(...) + includes: List[VesselInsightInclude] = Field( + [VesselInsightInclude.FISHING], alias="includes" + ) + start_date: datetime.date = Field(..., alias="startDate") + end_date: datetime.date = Field(..., alias="endDate") + vessels: List[VesselInsightDatasetVessel] = Field(..., alias="vessels") diff --git a/src/gfwapiclient/resources/insights/models/response.py b/src/gfwapiclient/resources/insights/models/response.py index dbd749c..d183a75 100644 --- a/src/gfwapiclient/resources/insights/models/response.py +++ b/src/gfwapiclient/resources/insights/models/response.py @@ -1,8 +1,8 @@ -"""Global Fishing Watch (GFW) API Python Client - Vessels Insights API Response Models.""" +"""Global Fishing Watch (GFW) API Python Client - Get Vessels Insights API Response Models.""" import datetime -from typing import List, Optional, Type +from typing import Any, Dict, List, Optional, Type from pydantic import Field @@ -57,7 +57,7 @@ class Gap(BaseModel): """AIS off insights. Attributes: - datasets ( Optional[List[str]], default=None): + datasets (Optional[List[str]], default=None): The datasets used for AIS off insights. historical_counters (Optional[PeriodicCounters], default=None): @@ -134,8 +134,8 @@ class ApparentFishing(BaseModel): ) -class IuuListPeriod(BaseModel): - """IUU list period. +class PeriodicValue(BaseModel): + """Periodic vessel value (i.e., `FLAG CHANGE`, `IUU`, `MOU` etc.). Attributes: from_ (Optional[datetime.datetime], default=None): @@ -143,17 +143,21 @@ class IuuListPeriod(BaseModel): to (Optional[datetime.datetime], default=None): The end date of the period. + + value (Optional[Any], default=None): + The value of the period. """ from_: Optional[datetime.datetime] = Field(None, alias="from") to: Optional[datetime.datetime] = Field(None, alias="to") + value: Optional[Any] = Field(None, alias="value") -class IuuVesselList(BaseModel): - """IUU vessel list. +class PeriodicValueList(BaseModel): + """Periodic vessel value (i.e., `FLAG CHANGE`, `IUU`, `MOU` etc.) list. Attributes: - values_in_the_period (Optional[List[IuuListPeriod]], default=None): + values_in_the_period (Optional[List[PeriodicValue]], default=None): The values in the period. total_times_listed (Optional[int], default=None): @@ -163,7 +167,7 @@ class IuuVesselList(BaseModel): The total times listed in the period. """ - values_in_the_period: Optional[List[IuuListPeriod]] = Field( + values_in_the_period: Optional[List[PeriodicValue]] = Field( None, alias="valuesInThePeriod" ) total_times_listed: Optional[int] = Field(None, alias="totalTimesListed") @@ -172,24 +176,56 @@ class IuuVesselList(BaseModel): ) +class FlagsChanges(PeriodicValueList): + """Periodic FLAG CHANGES list.""" + + pass + + +class IuuVesselList(PeriodicValueList): + """Periodic IUU vessel list.""" + + pass + + +class MouList(PeriodicValueList): + """Periodic MOU vessel list.""" + + pass + + class VesselIdentity(BaseModel): - """IUU (Illegal, Unreported, or Unregulated) insights. + """FLAG CHANGES, IUU (Illegal, Unreported, or Unregulated), and MOU insights. Attributes: datasets (Optional[List[str]], default=None): The datasets used for IUU insights. + flag_changes (Optional[FlagsChanges], default=None): + The FLAG CHANGES list. + iuu_vessel_list (Optional[IuuVesselList], default=None): The IUU vessel list. + + mou_list (Optional[Optional[Dict[str, MouList]]], default=None): + The MOU vessel list. """ datasets: Optional[List[str]] = Field(None, alias="datasets") + flag_changes: Optional[FlagsChanges] = Field(None, alias="flagsChanges") iuu_vessel_list: Optional[IuuVesselList] = Field(None, alias="iuuVesselList") + mou_list: Optional[Optional[Dict[str, MouList]]] = Field(None, alias="mouList") class VesselInsightItem(ResultItem): """Vessel insight item. + For more details on the Get Vessels Insights API endpoint supported + response bodies, please refer to the official Global Fishing Watch API + documentation: + + See: https://globalfishingwatch.org/our-apis/documentation#insights-by-vessels + Attributes: period (Optional[Period], default=None): The period of the insights. @@ -197,7 +233,8 @@ class VesselInsightItem(ResultItem): vessel_ids_without_identity (Optional[List[str]], default=None): The list of vessel IDs without identity. - gap (Optional[Gap], default=None): The AIS off insights. + gap (Optional[Gap], default=None): + The AIS off insights. coverage (Optional[Coverage], default=None): The coverage insights. @@ -206,7 +243,7 @@ class VesselInsightItem(ResultItem): The apparent fishing insights. vessel_identity (Optional[VesselIdentity], default=None): - The IUU insights. + The FLAG CHANGES, IUU, and MOU insights. """ period: Optional[Period] = Field(None, alias="period") @@ -220,7 +257,21 @@ class VesselInsightItem(ResultItem): class VesselInsightResult(Result[VesselInsightItem]): - """Result for Vessel Insights API endpoint.""" + """Result for Vessel Insights API endpoint. + + For more details on the Get Vessels Insights API endpoint supported + response bodies, please refer to the official Global Fishing Watch API + documentation: + + See: https://globalfishingwatch.org/our-apis/documentation#insights-by-vessels + + Attributes: + _result_item_class (Type[VesselInsightItem]): + The model used for individual result items. + + _data (VesselInsightItem): + The vessel insight item returned in the response. + """ _result_item_class: Type[VesselInsightItem] _data: VesselInsightItem @@ -230,6 +281,6 @@ def __init__(self, data: VesselInsightItem) -> None: Args: data (VesselInsightItem): - The vessel insight item data. + The vessel insight data. """ super().__init__(data=data) diff --git a/src/gfwapiclient/resources/insights/resources.py b/src/gfwapiclient/resources/insights/resources.py index 5008741..6193afa 100644 --- a/src/gfwapiclient/resources/insights/resources.py +++ b/src/gfwapiclient/resources/insights/resources.py @@ -1,4 +1,4 @@ -"""Global Fishing Watch (GFW) API Python Client - Vessels Insights API Resource.""" +"""Global Fishing Watch (GFW) API Python Client - Insights API Resource.""" import datetime @@ -24,7 +24,26 @@ class InsightResource(BaseResource): """Insights data API resource. - This resource provides methods to interact with the insights data API endpoints. + This resource provides methods to interact with the Insights API, specifically + for retrieving insights data for specified vessels. + + For detailed information about the Insights API, please refer to the official + Global Fishing Watch API documentation: + + See: https://globalfishingwatch.org/our-apis/documentation#insights-api + + For more details on the Insights data caveats, please refer to the official + Global Fishing Watch API documentation: + + See: https://globalfishingwatch.org/our-apis/documentation#insights-api-fishing-detected-in-no-take-mpas + + See: https://globalfishingwatch.org/our-apis/documentation#what-does-it-mean-that-an-api-dataset-is-in-prototype-stage + + See: https://globalfishingwatch.org/our-apis/documentation#insights-api-fishing-event-detected-outside-known-authorized-areas + + See: https://globalfishingwatch.org/our-apis/documentation#insights-api-coverage + + See: https://globalfishingwatch.org/our-apis/documentation#insights-api-rfmo-iuu-vessel-list """ async def get_vessel_insights( @@ -33,33 +52,77 @@ async def get_vessel_insights( includes: Union[List[VesselInsightInclude], List[str]], start_date: Union[datetime.date, str], end_date: Union[datetime.date, str], - vessels: Union[List[VesselInsightDatasetVessel], List[Dict[str, Any]]], + vessels: Union[ + List[VesselInsightDatasetVessel], List[Dict[str, Any]], List[str] + ], **kwargs: Dict[str, Any], ) -> VesselInsightResult: - """Get vessels insights data. + """Get insights for one or several vessels. Retrieves insights data for specified vessels based on the provided request parameters. + The following insight types are supported: + + - Any apparent fishing events in no-take MPAs (`"FISHING"`) + - Any apparent fishing events detected in areas with no known RFMO authorization (`"FISHING"`) + - The vessel's AIS coverage metric (`"COVERAGE"`) + - Any AIS off/disabling events (`"GAP"`) + - If the vessel is present on an RFMO IUU vessel list (`"VESSEL-IDENTITY-IUU-VESSEL-LIST"`) + - The vessel's flag changes (`"VESSEL-IDENTITY-FLAG-CHANGES"`) + - The vessel's flag state presence under the Tokyo/Paris MOU black or grey lists (`"VESSEL-IDENTITY-MOU-LIST"`) + + For detailed information about the Get Vessels Insights API endpoint, please + refer to the official Global Fishing Watch API documentation: + + See: https://globalfishingwatch.org/our-apis/documentation#insights-by-vessels + + For more details on the Get Vessels Insights data caveats, please refer to the + official Global Fishing Watch API documentation: + + See: https://globalfishingwatch.org/our-apis/documentation#insights-api-fishing-detected-in-no-take-mpas + + See: https://globalfishingwatch.org/our-apis/documentation#insights-api-fishing-event-detected-outside-known-authorized-areas + + See: https://globalfishingwatch.org/our-apis/documentation#insights-api-coverage + + See: https://globalfishingwatch.org/our-apis/documentation#insights-api-ais-off-event-aka-gap + + See: https://globalfishingwatch.org/our-apis/documentation#insights-api-rfmo-iuu-vessel-list + + **Important:** + + `start_date` must be on or after `January 1, 2020` + + **Note:** + + In order to enable `"VESSEL-IDENTITY-FLAG-CHANGES"` and `"VESSEL-IDENTITY-MOU-LIST"` + insights for your API access token (`GFW_API_ACCESS_TOKEN`), please contact + apis@globalfishingwatch.org. In your message, please specify the email address + used to generate the [API tokens](https://globalfishingwatch.org/our-apis/tokens) + (i.e., the email address associated with your [Global Fishing Watch account](https://globalfishingwatch.org/our-apis/tokens/signup)). + Args: - includes (Union[List[VesselInsightInclude], List[str]]): + includes (Union[List[VesselInsightInclude], List[str]], default=["FISHING"]): List of insight types to include in the response. - Allowed values are `"FISHING"`, `"GAP"`, `"COVERAGE"`, `"VESSEL-IDENTITY-IUU-VESSEL-LIST"`. + Allowed values are `"COVERAGE"`, `"FISHING"`, `"GAP"`, `"VESSEL-IDENTITY-FLAG-CHANGES"`, + `"VESSEL-IDENTITY-IUU-VESSEL-LIST"`, `"VESSEL-IDENTITY-MOU-LIST"`. Example: `["FISHING", "GAP"]`. - start_date (Union[datetime.date, str]): + start_date (Union[datetime.date, str], default=None): The start date for the insights period. Allowed values: A string in `ISO 8601 format` or `datetime.date` instance. Example: "2020-01-01" or `datetime.date(2020, 1, 1)`. - end_date (Union[datetime.date, str]): + end_date (Union[datetime.date, str], default=None): The end date for the insights period. Allowed values: A string in `ISO 8601 format` or `datetime.date` instance. Example: `"2025-03-03"` or `datetime.date(2025, 3, 3)`. - vessels (Union[List[VesselInsightDatasetVessel], List[Dict[str, Any]]]): + vessels (Union[List[VesselInsightDatasetVessel], List[Dict[str, Any]], List[str]], default=None): List of vessel identifiers to retrieve insights for. - Example: `[{"vessel_id": "785101812-2127-e5d2-e8bf-7152c5259f5f", "dataset_id": "public-global-vessel-identity:latest",}]`. + Example: `[{"vessel_id": "785101812-2127-e5d2-e8bf-7152c5259f5f", "dataset_id": "public-global-vessel-identity:latest"}]` + or `["785101812-2127-e5d2-e8bf-7152c5259f5f"]`. **kwargs (Dict[str, Any]): Additional keyword arguments. @@ -97,16 +160,22 @@ def _prepare_get_vessel_insights_request_body( includes: Union[List[VesselInsightInclude], List[str]], start_date: Union[datetime.date, str], end_date: Union[datetime.date, str], - vessels: Union[List[VesselInsightDatasetVessel], List[Dict[str, Any]]], + vessels: Union[ + List[VesselInsightDatasetVessel], List[Dict[str, Any]], List[str] + ], **kwargs: Dict[str, Any], ) -> VesselInsightBody: """Prepare and returns get vessel insights request body.""" try: + _vessels: List[Union[VesselInsightDatasetVessel, Dict[str, Any]]] = [ + {"vessel_id": vessel} if isinstance(vessel, str) else vessel + for vessel in vessels + ] _request_body: Dict[str, Any] = { "includes": includes, "start_date": start_date, "end_date": end_date, - "vessels": vessels, + "vessels": _vessels, } request_body: VesselInsightBody = VesselInsightBody(**_request_body) except pydantic.ValidationError as exc: diff --git a/src/gfwapiclient/resources/vessels/__init__.py b/src/gfwapiclient/resources/vessels/__init__.py index 392b8ed..a84a3bb 100644 --- a/src/gfwapiclient/resources/vessels/__init__.py +++ b/src/gfwapiclient/resources/vessels/__init__.py @@ -6,8 +6,14 @@ details by ID or IDs, and provides a convenient way to access vessel data. For detailed information about the Vessels API, please refer to the official -`Global Fishing Watch Vessels API Documentation -`_. +Global Fishing Watch API documentation: + +See: https://globalfishingwatch.org/our-apis/documentation#vessels-api + +For more details on the Vessels data caveats, please refer to the official +Global Fishing Watch API documentation: + +See: https://globalfishingwatch.org/our-apis/documentation#vessel-api-vessel-identity-information """ from gfwapiclient.resources.vessels.resources import VesselResource diff --git a/src/gfwapiclient/resources/vessels/base/models/request.py b/src/gfwapiclient/resources/vessels/base/models/request.py index dd96979..3de847f 100644 --- a/src/gfwapiclient/resources/vessels/base/models/request.py +++ b/src/gfwapiclient/resources/vessels/base/models/request.py @@ -57,7 +57,19 @@ class VesselInclude(str, Enum): Attributes: POTENTIAL_RELATED_SELF_REPORTED_INFO (str): - Include potential related self-reported information. + Include potential related self-reported vessel information. + + This include provides related `vessel ids` identified through + matching with vessel registry records. It represents Global Fishing Watch's + best estimate for linking AIS (self-reported) vessel positions to Vessel + Identity information derived from public registries. + + See how the Vessel API is used in the Vessel Viewer + here: https://globalfishingwatch.org/our-apis/assets/2024_Vessel_Viewer_and_APIs_behind_It.pdf + + For more details on the Vessels API data caveats, please refer to the + official Global Fishing Watch API documentation + here: https://globalfishingwatch.org/our-apis/documentation#vessel-api-vessel-identity-information """ POTENTIAL_RELATED_SELF_REPORTED_INFO = "POTENTIAL_RELATED_SELF_REPORTED_INFO" diff --git a/src/gfwapiclient/resources/vessels/detail/__init__.py b/src/gfwapiclient/resources/vessels/detail/__init__.py index 699e798..4857a4e 100644 --- a/src/gfwapiclient/resources/vessels/detail/__init__.py +++ b/src/gfwapiclient/resources/vessels/detail/__init__.py @@ -5,7 +5,13 @@ It defines the `VesselDetailEndPoint` class, which handles the construction of API requests and the parsing of API responses for vessel details. -For detailed information about the Get Vessel by ID API, please refer to the -official `Global Fishing Watch Vessels API Documentation -`_. +For detailed information about the Get Vessel by ID API endpoint, please refer to +the official Global Fishing Watch API documentation: + +See: https://globalfishingwatch.org/our-apis/documentation#get-vessel-by-id + +For more details on the Get Vessel by ID data caveats, please refer to the +official Global Fishing Watch API documentation: + +See: https://globalfishingwatch.org/our-apis/documentation#vessel-api-vessel-identity-information """ diff --git a/src/gfwapiclient/resources/vessels/detail/endpoints.py b/src/gfwapiclient/resources/vessels/detail/endpoints.py index 76e7cab..34e6442 100644 --- a/src/gfwapiclient/resources/vessels/detail/endpoints.py +++ b/src/gfwapiclient/resources/vessels/detail/endpoints.py @@ -23,6 +23,11 @@ class VesselDetailEndPoint( This endpoint retrieves vessel details by ID and other provided request parameters. + + For more details on the Get Vessel by ID API endpoint, please refer to the + official Global Fishing Watch API documentation: + + See: https://globalfishingwatch.org/our-apis/documentation#get-vessel-by-id """ def __init__( diff --git a/src/gfwapiclient/resources/vessels/list/__init__.py b/src/gfwapiclient/resources/vessels/list/__init__.py index 3de3c55..3772ff5 100644 --- a/src/gfwapiclient/resources/vessels/list/__init__.py +++ b/src/gfwapiclient/resources/vessels/list/__init__.py @@ -5,7 +5,13 @@ It defines the `VesselListEndPoint` class, which handles the construction of API requests and the parsing of API responses for vessel lists. -For detailed information about the Get Vessels by IDs API, please refer to the -official `Global Fishing Watch Vessels API Documentation -`_. +For detailed information about the Get Vessels by IDs API endpoint, please refer to +the official Global Fishing Watch API documentation: + +See: https://globalfishingwatch.org/our-apis/documentation#get-list-of-vessels-filtered-by-ids + +For more details on the Get Vessels by IDs data caveats, please refer to the +official Global Fishing Watch API documentation: + +See: https://globalfishingwatch.org/our-apis/documentation#vessel-api-vessel-identity-information """ diff --git a/src/gfwapiclient/resources/vessels/list/endpoints.py b/src/gfwapiclient/resources/vessels/list/endpoints.py index f0333a8..4095290 100644 --- a/src/gfwapiclient/resources/vessels/list/endpoints.py +++ b/src/gfwapiclient/resources/vessels/list/endpoints.py @@ -28,6 +28,11 @@ class VesselListEndPoint( This endpoint retrieves a list of vessels based on the provided IDs and other request parameters. + + For more details on the Get Vessels by IDs API endpoint, please refer to the + official Global Fishing Watch API documentation: + + See: https://globalfishingwatch.org/our-apis/documentation#get-list-of-vessels-filtered-by-ids """ def __init__( diff --git a/src/gfwapiclient/resources/vessels/resources.py b/src/gfwapiclient/resources/vessels/resources.py index 0d4c0aa..7d50cd0 100644 --- a/src/gfwapiclient/resources/vessels/resources.py +++ b/src/gfwapiclient/resources/vessels/resources.py @@ -48,6 +48,16 @@ class VesselResource(BaseResource): This resource provides methods to interact with the Vessels API, allowing retrieval of vessel information including search, list by IDs, and retrieval by ID. + + For detailed information about the Vessels API, please refer to the official + Global Fishing Watch API documentation: + + See: https://globalfishingwatch.org/our-apis/documentation#vessels-api + + For more details on the Vessels API data caveats, please refer to the + official Global Fishing Watch API documentation: + + See: https://globalfishingwatch.org/our-apis/documentation#vessel-api-vessel-identity-information """ async def search_vessels( @@ -64,6 +74,16 @@ async def search_vessels( ) -> VesselSearchResult: """Search vessels based on provided parameters. + For detailed information about the Vessels Search API endpoint, please + refer to the official Global Fishing Watch API documentation: + + See: https://globalfishingwatch.org/our-apis/documentation#search + + For more details on the Vessels Search data caveats, please refer to the + official Global Fishing Watch API documentation: + + See: https://globalfishingwatch.org/our-apis/documentation#vessel-api-vessel-identity-information + Args: since (Optional[str], default=None): The token to send to get more results. @@ -147,6 +167,16 @@ async def get_vessels_by_ids( ) -> VesselListResult: """Get a list of vessels by their IDs. + For detailed information about the Get Vessels by IDs API endpoint, please + refer to the official Global Fishing Watch API documentation: + + See: https://globalfishingwatch.org/our-apis/documentation#get-list-of-vessels-filtered-by-ids + + For more details on the Get Vessels by IDs data caveats, please refer to the + official Global Fishing Watch API documentation: + + See: https://globalfishingwatch.org/our-apis/documentation#vessel-api-vessel-identity-information + Args: ids (List[str]): List of vessel IDs to retrieve. @@ -171,6 +201,14 @@ async def get_vessels_by_ids( Allowed values: `"POTENTIAL_RELATED_SELF_REPORTED_INFO"`. Example: `["POTENTIAL_RELATED_SELF_REPORTED_INFO"]`. + This include provides related `vessel ids` identified through + matching with vessel registry records. It represents Global Fishing Watch's + best estimate for linking AIS (self-reported) vessel positions to Vessel + Identity information derived from public registries. + + See how the Vessel API is used in the Vessel Viewer + here: https://globalfishingwatch.org/our-apis/assets/2024_Vessel_Viewer_and_APIs_behind_It.pdf + match_fields (Optional[Union[List[VesselMatchField], List[str]]], default=None): This query param allows to filter by matchFields levels. Defaults to `None`. Allowed values: `"SEVERAL_FIELDS"`, `"NO_MATCH"`, `"ALL"`. @@ -224,6 +262,16 @@ async def get_vessel_by_id( ) -> VesselDetailResult: """Get vessel details by ID. + For detailed information about the Get Vessel by ID API endpoint, please + refer to the official Global Fishing Watch API documentation: + + See: https://globalfishingwatch.org/our-apis/documentation#get-vessel-by-id + + For more details on the Get Vessel by ID data caveats, please refer to the + official Global Fishing Watch API documentation: + + See: https://globalfishingwatch.org/our-apis/documentation#vessel-api-vessel-identity-information + Args: id (str): The ID of the vessel to retrieve. @@ -247,6 +295,14 @@ async def get_vessel_by_id( Allowed values: `"POTENTIAL_RELATED_SELF_REPORTED_INFO"`. Example: `["POTENTIAL_RELATED_SELF_REPORTED_INFO"]`. + This include provides related `vessel ids` identified through + matching with vessel registry records. It represents Global Fishing Watch's + best estimate for linking AIS (self-reported) vessel positions to Vessel + Identity information derived from public registries. + + See how the Vessel API is used in the Vessel Viewer + here: https://globalfishingwatch.org/our-apis/assets/2024_Vessel_Viewer_and_APIs_behind_It.pdf + match_fields (Optional[Union[List[VesselMatchField], List[str]]], default=None): This query param allows to filter by matchFields levels. Defaults to `None`. Allowed values: `"SEVERAL_FIELDS"`, `"NO_MATCH"`, `"ALL"`. diff --git a/src/gfwapiclient/resources/vessels/search/__init__.py b/src/gfwapiclient/resources/vessels/search/__init__.py index 7a6a453..4179298 100644 --- a/src/gfwapiclient/resources/vessels/search/__init__.py +++ b/src/gfwapiclient/resources/vessels/search/__init__.py @@ -9,8 +9,13 @@ filters, and other parameters. This module provides the necessary tools for interacting with the API's endpoint. -For detailed information about the Vessels Search API, please refer to the -official `Global Fishing Watch Vessels API Documentation -`_. +For detailed information about the Vessels Search API endpoint, please refer to +the official Global Fishing Watch API documentation: +See: https://globalfishingwatch.org/our-apis/documentation#search + +For more details on the Vessels Search data caveats, please refer to the +official Global Fishing Watch API documentation: + +See: https://globalfishingwatch.org/our-apis/documentation#vessel-api-vessel-identity-information """ diff --git a/src/gfwapiclient/resources/vessels/search/endpoints.py b/src/gfwapiclient/resources/vessels/search/endpoints.py index a607e0b..4213d35 100644 --- a/src/gfwapiclient/resources/vessels/search/endpoints.py +++ b/src/gfwapiclient/resources/vessels/search/endpoints.py @@ -1,4 +1,4 @@ -"""Global Fishing Watch (GFW) API Python Client - Vessels Search API EndPoint. +"""Global Fishing Watch (GFW) API Python Client - Vessels Search API endpoint. This module defines the endpoint for searching vessels. """ @@ -27,6 +27,11 @@ class VesselSearchEndPoint( """Search vessels API endpoint. This endpoint searches for vessels based on the provided search request parameters. + + For more details on the Vessels Search API endpoint, please refer to the + official Global Fishing Watch API documentation: + + See: https://globalfishingwatch.org/our-apis/documentation#search """ def __init__( diff --git a/tests/fixtures/insights/vessel_insight_item.json b/tests/fixtures/insights/vessel_insight_item.json index dcd444b..960f418 100644 --- a/tests/fixtures/insights/vessel_insight_item.json +++ b/tests/fixtures/insights/vessel_insight_item.json @@ -5,11 +5,15 @@ "datasets": ["public-global-gaps-events:v3.0"], "historicalCounters": { "events": 1, - "eventsGapOff": 1 + "eventsGapOff": 1, + "eventsInNoTakeMPAs": 5, + "eventsInRFMOWithoutKnownAuthorization": 10 }, "periodSelectedCounters": { "events": 4, - "eventsGapOff": 4 + "eventsGapOff": 4, + "eventsInNoTakeMPAs": 5, + "eventsInRFMOWithoutKnownAuthorization": 10 }, "aisOff": [ "5c08c6e146315b98d8569dd253681ace", @@ -43,6 +47,17 @@ }, "vesselIdentity": { "datasets": ["public-global-vessel-identity:v3.0"], + "flagsChanges": { + "totalTimesListed": 10, + "totalTimesListedInThePeriod": 1, + "valuesInThePeriod": [ + { + "from": "2012-01-19T14:24:39Z", + "to": "2024-03-04T23:59:41Z", + "value": "CHL" + } + ] + }, "iuuVesselList": { "valuesInThePeriod": [ { @@ -52,6 +67,30 @@ ], "totalTimesListed": 1, "totalTimesListedInThePeriod": 0 + }, + "mouList": { + "paris": { + "totalTimesListed": 3, + "totalTimesListedInThePeriod": 3, + "valuesInThePeriod": [ + { + "from": "2022-12-08T13:38:20.000Z", + "to": "2023-11-30T22:27:07.000Z", + "value": "grey" + } + ] + }, + "tokyo": { + "totalTimesListed": 3, + "totalTimesListedInThePeriod": 3, + "valuesInThePeriod": [ + { + "from": "2022-12-08T13:38:20.000Z", + "to": "2023-11-30T22:27:07.000Z", + "value": "black" + } + ] + } } } } diff --git a/tests/fixtures/insights/vessel_insight_request_body.json b/tests/fixtures/insights/vessel_insight_request_body.json index 9ba7b08..4bc4211 100644 --- a/tests/fixtures/insights/vessel_insight_request_body.json +++ b/tests/fixtures/insights/vessel_insight_request_body.json @@ -1,9 +1,11 @@ { "includes": [ + "COVERAGE", "FISHING", "GAP", + "VESSEL-IDENTITY-FLAG-CHANGES", "VESSEL-IDENTITY-IUU-VESSEL-LIST", - "COVERAGE" + "VESSEL-IDENTITY-MOU-LIST" ], "startDate": "2020-01-01", "endDate": "2025-03-03", diff --git a/tests/integration/test_insights_api.py b/tests/integration/test_insights_api.py index 4bc2b81..7790811 100644 --- a/tests/integration/test_insights_api.py +++ b/tests/integration/test_insights_api.py @@ -25,10 +25,10 @@ async def test_insights_get_vessel_insights_get_insights_for_fishing_events( gfw_client: gfw.Client, ) -> None: - """Test getting vessel insights related to fishing events. + """Test getting vessel insights related to apparent fishing events. This test verifies that the `get_vessel_insights` method correctly retrieves - insights for a specific vessel related to fishing activity within a given + insights for a specific vessel related to apparent fishing activity within a given date range. It checks the structure and content of the returned data, ensuring it's a valid `VesselInsightResult` and that the data can be converted to a pandas DataFrame. @@ -38,10 +38,7 @@ async def test_insights_get_vessel_insights_get_insights_for_fishing_events( start_date="2020-01-01", end_date="2025-03-03", vessels=[ - { - "dataset_id": "public-global-vessel-identity:latest", - "vessel_id": "785101812-2127-e5d2-e8bf-7152c5259f5f", - } + "785101812-2127-e5d2-e8bf-7152c5259f5f", ], ) data: VesselInsightItem = cast(VesselInsightItem, result.data()) @@ -59,10 +56,10 @@ async def test_insights_get_vessel_insights_get_insights_for_fishing_events( async def test_insights_get_vessel_insights_get_insights_for_ais_off_events( gfw_client: gfw.Client, ) -> None: - """Test getting vessel insights related to AIS off events (gaps). + """Test getting vessel insights related to AIS off/disabling events (gaps). This test verifies that the `get_vessel_insights` method correctly retrieves - insights for a specific vessel related to AIS off events (gaps) within a + insights for a specific vessel related to AIS off/disabling events (gaps) within a given date range. It checks the structure and content of the returned data, ensuring it's a valid `VesselInsightResult` and that the data can be converted to a pandas DataFrame. @@ -72,10 +69,7 @@ async def test_insights_get_vessel_insights_get_insights_for_ais_off_events( start_date="2020-01-01", end_date="2025-03-03", vessels=[ - { - "dataset_id": "public-global-vessel-identity:latest", - "vessel_id": "2339c52c3-3a84-1603-f968-d8890f23e1ed", - } + "2339c52c3-3a84-1603-f968-d8890f23e1ed", ], ) data: VesselInsightItem = cast(VesselInsightItem, result.data()) @@ -106,10 +100,7 @@ async def test_insights_get_vessel_insights_get_insights_for_ais_coverage_events start_date="2020-01-01", end_date="2025-03-03", vessels=[ - { - "dataset_id": "public-global-vessel-identity:latest", - "vessel_id": "2339c52c3-3a84-1603-f968-d8890f23e1ed", - } + "2339c52c3-3a84-1603-f968-d8890f23e1ed", ], ) data: VesselInsightItem = cast(VesselInsightItem, result.data()) @@ -141,10 +132,70 @@ async def test_insights_get_vessel_insights_get_insights_for_iuu_list( start_date="2020-01-01", end_date="2025-03-03", vessels=[ - { - "dataset_id": "public-global-vessel-identity:latest", - "vessel_id": "2d26aa452-2d4f-4cae-2ec4-377f85e88dcb", - } + "2d26aa452-2d4f-4cae-2ec4-377f85e88dcb", + ], + ) + data: VesselInsightItem = cast(VesselInsightItem, result.data()) + assert isinstance(result, VesselInsightResult) + assert isinstance(data, VesselInsightItem) + + df: pd.DataFrame = cast(pd.DataFrame, result.df()) + assert isinstance(df, pd.DataFrame) + assert len(df) >= 1, "Expected at least one row in the DataFrame." + assert list(df.columns) == list(dict(data).keys()) + + +@pytest.mark.integration +@pytest.mark.asyncio +async def test_insights_get_vessel_insights_get_insights_for_flag_changes( + gfw_client: gfw.Client, +) -> None: + """Test getting vessel insights related to flag changes. + + This test verifies that the `get_vessel_insights` method correctly retrieves + insights for a specific vessel related to its flag changes within a given date range. + It checks the structure and content of the returned data, ensuring it's a + valid `VesselInsightResult` and that the data can be converted to a + pandas DataFrame. + """ + result: VesselInsightResult = await gfw_client.insights.get_vessel_insights( + includes=["VESSEL-IDENTITY-FLAG-CHANGES"], + start_date="2020-01-01", + end_date="2025-03-03", + vessels=[ + "2d26aa452-2d4f-4cae-2ec4-377f85e88dcb", + ], + ) + data: VesselInsightItem = cast(VesselInsightItem, result.data()) + assert isinstance(result, VesselInsightResult) + assert isinstance(data, VesselInsightItem) + + df: pd.DataFrame = cast(pd.DataFrame, result.df()) + assert isinstance(df, pd.DataFrame) + assert len(df) >= 1, "Expected at least one row in the DataFrame." + assert list(df.columns) == list(dict(data).keys()) + + +@pytest.mark.integration +@pytest.mark.asyncio +async def test_insights_get_vessel_insights_get_insights_for_mou_list( + gfw_client: gfw.Client, +) -> None: + """Test getting vessel insights related to to being listed in the MOU list. + + This test verifies that the `get_vessel_insights` method correctly retrieves + insights for a specific vessel related to its flag state presence under the + Tokyo/Paris MOU black or grey lists within a given date range. + It checks the structure and content of the returned data, ensuring it's a + valid `VesselInsightResult` and that the data can be converted to a + pandas DataFrame. + """ + result: VesselInsightResult = await gfw_client.insights.get_vessel_insights( + includes=["VESSEL-IDENTITY-MOU-LIST"], + start_date="2020-01-01", + end_date="2025-03-03", + vessels=[ + "785101812-2127-e5d2-e8bf-7152c5259f5f", ], ) data: VesselInsightItem = cast(VesselInsightItem, result.data()) @@ -171,22 +222,20 @@ async def test_insights_get_vessel_insights_get_insights_for_multiple_insight_ty converted to a pandas DataFrame. """ result: VesselInsightResult = await gfw_client.insights.get_vessel_insights( - includes=["FISHING", "GAP", "VESSEL-IDENTITY-IUU-VESSEL-LIST", "COVERAGE"], + includes=[ + "FISHING", + "GAP", + "VESSEL-IDENTITY-IUU-VESSEL-LIST", + "COVERAGE", + "VESSEL-IDENTITY-FLAG-CHANGES", + "VESSEL-IDENTITY-MOU-LIST", + ], start_date="2020-01-01", end_date="2025-03-03", vessels=[ - { - "dataset_id": "public-global-vessel-identity:latest", - "vessel_id": "785101812-2127-e5d2-e8bf-7152c5259f5f", - }, - { - "dataset_id": "public-global-vessel-identity:latest", - "vessel_id": "2339c52c3-3a84-1603-f968-d8890f23e1ed", - }, - { - "dataset_id": "public-global-vessel-identity:latest", - "vessel_id": "2d26aa452-2d4f-4cae-2ec4-377f85e88dcb", - }, + "785101812-2127-e5d2-e8bf-7152c5259f5f", + "2339c52c3-3a84-1603-f968-d8890f23e1ed", + "2d26aa452-2d4f-4cae-2ec4-377f85e88dcb", ], ) data: VesselInsightItem = cast(VesselInsightItem, result.data()) diff --git a/tests/resources/insights/models/test_request_models.py b/tests/resources/insights/models/test_request_models.py index b6e3669..06c8513 100644 --- a/tests/resources/insights/models/test_request_models.py +++ b/tests/resources/insights/models/test_request_models.py @@ -3,6 +3,7 @@ from typing import Any, Dict from gfwapiclient.resources.insights.models.request import VesselInsightBody +from gfwapiclient.resources.vessels.base.models.request import VesselDataset def test_vessel_insight_request_body_serializes_all_fields( @@ -16,4 +17,35 @@ def test_vessel_insight_request_body_serializes_all_fields( assert vessel_insight_body.start_date is not None assert vessel_insight_body.end_date is not None assert vessel_insight_body.vessels is not None + + for vessel in vessel_insight_body.vessels: + assert vessel.dataset_id is not None + + assert vessel_insight_body.to_json_body() == mock_raw_vessel_insight_request_body + + +def test_vessel_insight_request_body_serializes_none_vessels_dataset_id_with_default( + mock_raw_vessel_insight_request_body: Dict[str, Any], +) -> None: + """Test that `VesselInsightBody` serializes vessels with no dataset id using default dataset id.""" + raw_vessel_insight_request_body: Dict[str, Any] = { + **mock_raw_vessel_insight_request_body + } + raw_vessel_insight_request_body["vessels"] = [ + {**vessel, "dataset_id": None} + for vessel in raw_vessel_insight_request_body["vessels"] + ] + + vessel_insight_body: VesselInsightBody = VesselInsightBody( + **raw_vessel_insight_request_body + ) + assert vessel_insight_body.includes is not None + assert vessel_insight_body.start_date is not None + assert vessel_insight_body.end_date is not None + assert vessel_insight_body.vessels is not None + + for vessel in vessel_insight_body.vessels: + assert vessel.dataset_id is not None + assert vessel.dataset_id == VesselDataset.VESSEL_IDENTITY_LATEST + assert vessel_insight_body.to_json_body() == mock_raw_vessel_insight_request_body diff --git a/tests/resources/insights/models/test_response_models.py b/tests/resources/insights/models/test_response_models.py index b810d1a..6623fa1 100644 --- a/tests/resources/insights/models/test_response_models.py +++ b/tests/resources/insights/models/test_response_models.py @@ -16,10 +16,33 @@ def test_vessel_insight_item_derializes_all_fields( **mock_raw_vessel_insight_item ) assert vessel_insight_item.period is not None + assert vessel_insight_item.gap is not None + assert vessel_insight_item.gap.datasets is not None + assert vessel_insight_item.gap.historical_counters is not None + assert vessel_insight_item.gap.period_selected_counters is not None + assert vessel_insight_item.gap.ais_off is not None + assert vessel_insight_item.coverage is not None + assert vessel_insight_item.coverage.blocks is not None + assert vessel_insight_item.coverage.blocks_with_positions is not None + assert vessel_insight_item.coverage.percentage is not None + assert vessel_insight_item.apparent_fishing is not None + assert vessel_insight_item.apparent_fishing.datasets is not None + assert vessel_insight_item.apparent_fishing.historical_counters is not None + assert vessel_insight_item.apparent_fishing.period_selected_counters is not None + assert ( + vessel_insight_item.apparent_fishing.events_in_rfmo_without_known_authorization + is not None + ) + assert vessel_insight_item.apparent_fishing.events_in_no_take_mpas is not None + assert vessel_insight_item.vessel_identity is not None + assert vessel_insight_item.vessel_identity.datasets is not None + assert vessel_insight_item.vessel_identity.flag_changes is not None + assert vessel_insight_item.vessel_identity.iuu_vessel_list is not None + assert vessel_insight_item.vessel_identity.mou_list is not None def test_vessel_insight_result_deserializes_all_fields( diff --git a/tests/resources/insights/test_resources.py b/tests/resources/insights/test_resources.py index c1902cc..d85a9f4 100644 --- a/tests/resources/insights/test_resources.py +++ b/tests/resources/insights/test_resources.py @@ -5,6 +5,8 @@ import pytest import respx +from pydantic.alias_generators import to_snake + from gfwapiclient.exceptions.validation import RequestBodyValidationError from gfwapiclient.http.client import HTTPClient from gfwapiclient.resources.insights.models.request import ( @@ -41,10 +43,48 @@ async def test_insight_resource_get_vessel_insights( assert isinstance(data, VesselInsightItem) +@pytest.mark.asyncio +@pytest.mark.respx +async def test_insight_resource_get_vessel_insights_by_vessels_ids( + mock_http_client: HTTPClient, + mock_raw_vessel_insight_request_body: Dict[str, Any], + mock_raw_vessel_insight_item: Dict[str, Any], + mock_responsex: respx.MockRouter, +) -> None: + """Test `InsightResource` get vessel insights with list of vessels ids succeeds with valid response.""" + mock_responsex.post("/insights/vessels").respond( + 200, json=mock_raw_vessel_insight_item + ) + resource = InsightResource(http_client=mock_http_client) + result = await resource.get_vessel_insights( + includes=mock_raw_vessel_insight_request_body["includes"], + start_date=mock_raw_vessel_insight_request_body["startDate"], + end_date=mock_raw_vessel_insight_request_body["endDate"], + vessels=[ + v["vesselId"] for v in mock_raw_vessel_insight_request_body["vessels"] + ], + ) + data = cast(VesselInsightItem, result.data()) + assert isinstance(result, VesselInsightResult) + assert isinstance(data, VesselInsightItem) + + +@pytest.mark.parametrize( + "invalid_vessel_insight_request_body", + [ + {"includes": ["INVALID_INCLUDE"]}, + {"start_date": "INVALID_START_DATE"}, + {"end_date": "INVALID_END_DATE"}, + {"vessels": [None]}, + {"vessels": [{"vessel_id": None}]}, + {"vessels": [{"vessel_id": None, "dataset_id": "INVALID_DATASET_ID"}]}, + ], +) @pytest.mark.asyncio async def test_insight_resource_get_vessel_insights_validation_error_raises( mock_http_client: HTTPClient, mock_raw_vessel_insight_request_body: Dict[str, Any], + invalid_vessel_insight_request_body: Dict[str, Any], ) -> None: """Test `InsightResource` get vessel insights raises `RequestBodyValidationError` with invalid parameters.""" resource = InsightResource(http_client=mock_http_client) @@ -53,9 +93,8 @@ async def test_insight_resource_get_vessel_insights_validation_error_raises( RequestBodyValidationError, match=VESSEL_INSIGHT_REQUEST_BODY_VALIDATION_ERROR_MESSAGE, ): - await resource.get_vessel_insights( - includes=["INVALID_INCLUDE"], - start_date=mock_raw_vessel_insight_request_body["startDate"], - end_date=mock_raw_vessel_insight_request_body["endDate"], - vessels=mock_raw_vessel_insight_request_body["vessels"], - ) + raw_vessel_insight_request_body: Dict[str, Any] = { + **{to_snake(k): v for k, v in mock_raw_vessel_insight_request_body.items()}, + **invalid_vessel_insight_request_body, + } + await resource.get_vessel_insights(**raw_vessel_insight_request_body)