Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use Pydantic in Search #50

Merged
merged 1 commit into from
Jun 27, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions pygleif/api/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
"""Pydantic Representation of models."""
from typing import List

from pydantic import BaseModel, Field

from .data import Data
Expand All @@ -10,3 +12,10 @@ class GLEIFResponse(BaseModel):

meta: Meta = Field(alias="meta")
data: Data = Field(alias="data")


class SearchResponse(BaseModel):
"""Represent search result response."""

meta: Meta = Field(alias="meta")
data: List[Data] = Field(alias="data")
14 changes: 14 additions & 0 deletions pygleif/api/meta.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""Meta data."""
from datetime import datetime
from typing import Optional

from pydantic import BaseModel, Field

Expand All @@ -10,7 +11,20 @@ class GoldenCopy(BaseModel):
publish_date: datetime = Field(alias="publishDate")


class Pagination(BaseModel):
"""Represent response pagination."""

current_page: int = Field(alias="currentPage")
per_page: int = Field(alias="perPage")
_from: int = Field(alias="from")
to: int = Field(alias="to")
total: int = Field(alias="total")
last_page: int = Field(alias="lastPage")


class Meta(BaseModel):
"""Represent meta information."""

golden_copy: GoldenCopy = Field(alias="goldenCopy")
# Pagination is part of the search response
pagination: Optional[Pagination] = Field(alias="pagination")
8 changes: 0 additions & 8 deletions pygleif/const.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,8 @@
"""Constants."""
URL_API = "https://api.gleif.org/api/v1/lei-records/"
URL_SEARCH = "https://api.gleif.org/api/v1/lei-records?filter%5Bfulltext%5D="
URL_DIRECT_CHILD = (
"https://api.gleif.org/api/v1/lei-records/{}/direct-child-relationships"
)


ATTR_REGISTRATION = "registration"

# Allowed attributes for a record
ALLOW_ATTR_REGISTRATION_STATUS = ["ISSUED", "LAPSED"]

# The ELF codes are unique per country, not globally.
# Hence the nested dict.
LEGAL_FORMS = {
Expand Down
3 changes: 2 additions & 1 deletion pygleif/gleif.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""GLEIF API."""
from .api import GLEIFResponse
from .const import URL_API
from .utils import load_json


Expand All @@ -8,5 +9,5 @@ class PyGleif:

def __init__(self, lei_code: str) -> None:
"""Init class."""
json_data = load_json(lei_code)
json_data = load_json(search_url=URL_API, search_string=lei_code)
self.response = GLEIFResponse(**json_data)
45 changes: 8 additions & 37 deletions pygleif/search.py
Original file line number Diff line number Diff line change
@@ -1,45 +1,16 @@
"""Search."""
import json
from urllib import request as url

from pygleif.const import ALLOW_ATTR_REGISTRATION_STATUS, URL_SEARCH

from pygleif.api import SearchResponse
from pygleif.const import URL_SEARCH

from .utils import load_json


class Search:
"""Class to use the search form of the GLEIF web site."""

def __init__(self, orgnr=None):
def __init__(self, orgnr: str) -> None:
"""Init class."""
# Allow searching using organisation number
self.orgnr = orgnr

@property
def json_data(self):
"""Get raw data from the service."""
return url.urlopen(URL_SEARCH + url.quote(self.orgnr))

@property
def raw(self):
"""Return parsed json."""
return json.loads(self.json_data.read().decode("UTF-8"))

@property
def valid_record(self):
"""Loop through data to find a valid record. Return first valid."""
for d in self.raw["data"]:

# We're not very greedy here, but it seems some records have
# lapsed even through the issuer is active
if (
d["attributes"]["registration"]["status"]
in ALLOW_ATTR_REGISTRATION_STATUS
):
return d["attributes"]

@property
def lei(self):
"""Return the LEI code."""
try:
return self.valid_record["lei"]
except (IndexError, TypeError):
return None
json_data = load_json(search_url=URL_SEARCH, search_string=orgnr)
self.response = SearchResponse(**json_data)
8 changes: 3 additions & 5 deletions pygleif/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,10 @@

import json
from typing import Any, Dict, List, Union, cast
import urllib.request as url
from urllib import request

from .const import URL_API


def load_json(lei_code: str) -> list[Any] | dict[Any, Any]:
def load_json(search_url: str, search_string: str) -> list[Any] | dict[Any, Any]:
"""Download data as JSON."""
with url.urlopen(f"{URL_API}{lei_code}") as fdesc:
with request.urlopen(f"{search_url}{request.quote(search_string)}") as fdesc:
return cast(Union[Dict[Any, Any], List[Any]], json.loads(fdesc.read()))
18 changes: 17 additions & 1 deletion tests/test_gleif.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""Tests."""
import pytest

from pygleif import PyGleif
from pygleif import PyGleif, Search


@pytest.fixture(scope="module")
Expand All @@ -10,6 +10,12 @@ def gleif_fixture_1() -> PyGleif:
return PyGleif("549300MLUDYVRQOOXS22")


@pytest.fixture(scope="module")
def gleif_search_fixture() -> Search:
"""Fixture."""
return Search("917685991")


def test_lei(gleif_fixture_1: PyGleif):
"""Test LEI attribute."""
assert gleif_fixture_1.response.data.attributes.lei, "549300MLUDYVRQOOXS22"
Expand All @@ -18,3 +24,13 @@ def test_lei(gleif_fixture_1: PyGleif):
def test_id(gleif_fixture_1: PyGleif):
"""Test ID attribute."""
assert gleif_fixture_1.response.data.id, "549300MLUDYVRQOOXS22"


def test_search_lei(gleif_search_fixture: Search):
"""Test LEI attribute."""
assert gleif_search_fixture.response.data[0].attributes.lei, "549300MLUDYVRQOOXS22"


def test_search_id(gleif_search_fixture: Search):
"""Test ID attribute."""
assert gleif_search_fixture.response.data[0].id, "549300MLUDYVRQOOXS22"