Skip to content

Research Products

Models

Pydantic models for representing OpenAIRE Research Product entities.

This module defines the Pydantic model for an OpenAIRE Research Product, which can be a publication, dataset, software, or other research output. It includes various nested models to represent complex fields like authors, persistent identifiers (PIDs), access rights, citation impacts, instances, etc., based on the OpenAIRE data model documentation. Reference: https://graph.openaire.eu/docs/data-model/entities/research-product

OpenAccessRouteType = Literal['gold', 'green', 'hybrid', 'bronze'] module-attribute

Type alias for allowed Open Access routes (e.g., gold, green).

RefereedType = Literal['peerReviewed', 'nonPeerReviewed', 'UNKNOWN'] module-attribute

Type alias for refereed status (e.g., peerReviewed, nonPeerReviewed).

ResearchProductResponse = ApiResponse[ResearchProduct] module-attribute

Type alias for an API response containing a list of ResearchProduct entities.

ResearchProductType = Literal['publication', 'dataset', 'software', 'other'] module-attribute

Type alias for the type of research product (e.g., publication, dataset).

AccessRight

Bases: BaseModel

Represents the access rights associated with an instance of a research product.

Attributes:

Name Type Description
code str | None

A code representing the access right (e.g., "OPEN", "RESTRICTED").

label str | None

A human-readable label for the access right.

openAccessRoute OpenAccessRouteType | None

The Open Access route, if applicable (e.g., "gold", "green").

scheme str | None

The scheme defining the access right codes.

Source code in src/aireloom/models/research_product.py
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
class AccessRight(BaseModel):
    """Represents the access rights associated with an instance of a research product.

    Attributes:
        code: A code representing the access right (e.g., "OPEN", "RESTRICTED").
        label: A human-readable label for the access right.
        openAccessRoute: The Open Access route, if applicable (e.g., "gold", "green").
        scheme: The scheme defining the access right codes.
    """

    code: str | None = None
    label: str | None = None
    openAccessRoute: OpenAccessRouteType | None = None
    scheme: str | None = None

    model_config = ConfigDict(extra="allow")

ArticleProcessingCharge

Bases: BaseModel

Represents Article Processing Charge (APC) information.

Attributes:

Name Type Description
amount str | None

The amount of the APC, typically as a string to accommodate various formats.

currency str | None

The currency code for the APC amount (e.g., "EUR", "USD").

Source code in src/aireloom/models/research_product.py
208
209
210
211
212
213
214
215
216
217
218
219
class ArticleProcessingCharge(BaseModel):
    """Represents Article Processing Charge (APC) information.

    Attributes:
        amount: The amount of the APC, typically as a string to accommodate various formats.
        currency: The currency code for the APC amount (e.g., "EUR", "USD").
    """

    amount: str | None = None
    currency: str | None = None

    model_config = ConfigDict(extra="allow")

Author

Bases: BaseModel

Represents an author of a research product.

Attributes:

Name Type Description
fullName str | None

The full name of the author.

rank int | None

The rank or order of the author in an author list.

name str | None

The given name(s) of the author.

surname str | None

The surname or family name of the author.

pid Pid | None

A Pid object representing a persistent identifier for the author (e.g., ORCID).

Source code in src/aireloom/models/research_product.py
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
class Author(BaseModel):
    """Represents an author of a research product.

    Attributes:
        fullName: The full name of the author.
        rank: The rank or order of the author in an author list.
        name: The given name(s) of the author.
        surname: The surname or family name of the author.
        pid: A `Pid` object representing a persistent identifier for the author (e.g., ORCID).
    """

    fullName: str | None = None
    rank: int | None = None
    name: str | None = None
    surname: str | None = None
    pid: Pid | None = None

    model_config = ConfigDict(extra="allow")

BestAccessRight

Bases: BaseModel

Represents the best determined access right for a research product.

Attributes:

Name Type Description
code str | None

The code representing the access right (e.g., "OPEN").

label str | None

A human-readable label for the access right (e.g., "Open Access").

scheme str | None

The scheme or vocabulary defining the access right code.

Source code in src/aireloom/models/research_product.py
80
81
82
83
84
85
86
87
88
89
90
91
92
93
class BestAccessRight(BaseModel):
    """Represents the best determined access right for a research product.

    Attributes:
        code: The code representing the access right (e.g., "OPEN").
        label: A human-readable label for the access right (e.g., "Open Access").
        scheme: The scheme or vocabulary defining the access right code.
    """

    code: str | None = None
    label: str | None = None
    scheme: str | None = None

    model_config = ConfigDict(extra="allow")

CitationImpact

Bases: BaseModel

Captures various citation-based impact metrics for a research product.

Attributes:

Name Type Description
influence float | None

A numerical score representing influence (meaning may vary).

influenceClass Literal['C1', 'C2', 'C3', 'C4', 'C5'] | None

A categorical classification of influence (e.g., C1-C5).

citationCount int | None

The total number of citations received.

citationClass Literal['C1', 'C2', 'C3', 'C4', 'C5'] | None

A categorical classification based on citation count.

popularity float | None

A numerical score representing popularity.

popularityClass Literal['C1', 'C2', 'C3', 'C4', 'C5'] | None

A categorical classification of popularity.

impulse float | None

A numerical score representing research impulse or momentum.

impulseClass Literal['C1', 'C2', 'C3', 'C4', 'C5'] | None

A categorical classification of impulse.

Source code in src/aireloom/models/research_product.py
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
class CitationImpact(BaseModel):
    """Captures various citation-based impact metrics for a research product.

    Attributes:
        influence: A numerical score representing influence (meaning may vary).
        influenceClass: A categorical classification of influence (e.g., C1-C5).
        citationCount: The total number of citations received.
        citationClass: A categorical classification based on citation count.
        popularity: A numerical score representing popularity.
        popularityClass: A categorical classification of popularity.
        impulse: A numerical score representing research impulse or momentum.
        impulseClass: A categorical classification of impulse.
    """

    influence: float | None = None
    influenceClass: Literal["C1", "C2", "C3", "C4", "C5"] | None = None
    citationCount: int | None = None
    citationClass: Literal["C1", "C2", "C3", "C4", "C5"] | None = None
    popularity: float | None = None
    popularityClass: Literal["C1", "C2", "C3", "C4", "C5"] | None = None
    impulse: float | None = None
    impulseClass: Literal["C1", "C2", "C3", "C4", "C5"] | None = None

    model_config = ConfigDict(extra="allow")

Container

Bases: BaseModel

Represents the container of a publication (e.g., journal, book series).

Attributes:

Name Type Description
edition str | None

The edition of the container.

iss str | None

The issue number of the container.

issnLinking str | None

The linking ISSN for a serial publication.

issnOnline str | None

The ISSN for the online version of a serial.

issnPrinted str | None

The ISSN for the printed version of a serial.

name str | None

The name of the container (e.g., journal title).

sp str | None

Start page of the item within the container.

ep str | None

End page of the item within the container.

vol str | None

Volume number of the container.

Source code in src/aireloom/models/research_product.py
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
class Container(BaseModel):
    """Represents the container of a publication (e.g., journal, book series).

    Attributes:
        edition: The edition of the container.
        iss: The issue number of the container.
        issnLinking: The linking ISSN for a serial publication.
        issnOnline: The ISSN for the online version of a serial.
        issnPrinted: The ISSN for the printed version of a serial.
        name: The name of the container (e.g., journal title).
        sp: Start page of the item within the container.
        ep: End page of the item within the container.
        vol: Volume number of the container.
    """

    edition: str | None = None
    iss: str | None = None
    issnLinking: str | None = None
    issnOnline: str | None = None
    issnPrinted: str | None = None
    name: str | None = None
    sp: str | None = None
    ep: str | None = None
    vol: str | None = None

    model_config = ConfigDict(extra="allow")

GeoLocation

Bases: BaseModel

Represents geolocation information, typically for datasets.

Attributes:

Name Type Description
box str | None

A bounding box defining a geographical area, often as a string of coordinates (e.g., "minLon,minLat,maxLon,maxLat").

place str | None

A human-readable name for the geographical location.

Source code in src/aireloom/models/research_product.py
378
379
380
381
382
383
384
385
386
387
388
389
390
class GeoLocation(BaseModel):
    """Represents geolocation information, typically for datasets.

    Attributes:
        box: A bounding box defining a geographical area, often as a string
             of coordinates (e.g., "minLon,minLat,maxLon,maxLat").
        place: A human-readable name for the geographical location.
    """

    box: str | None = None
    place: str | None = None

    model_config = ConfigDict(extra="allow")

Indicator

Bases: BaseModel

Container for various impact indicators of a research product.

Attributes:

Name Type Description
citationImpact CitationImpact | None

A CitationImpact object detailing citation metrics.

usageCounts UsageCounts | None

A UsageCounts object detailing view and download counts.

Source code in src/aireloom/models/research_product.py
176
177
178
179
180
181
182
183
184
185
186
187
class Indicator(BaseModel):
    """Container for various impact indicators of a research product.

    Attributes:
        citationImpact: A `CitationImpact` object detailing citation metrics.
        usageCounts: A `UsageCounts` object detailing view and download counts.
    """

    citationImpact: CitationImpact | None = None
    usageCounts: UsageCounts | None = None

    model_config = ConfigDict(extra="allow")

Instance

Bases: BaseModel

Represents a specific instance or manifestation of a research product.

A research product can have multiple instances, for example, a preprint version, a published version in a journal, a copy in a repository, etc. Each instance can have its own access rights, license, and location.

Attributes:

Name Type Description
accessRight AccessRight | None

An AccessRight object detailing the access conditions for this instance.

alternateIdentifier list[dict[str, str]]

A list of alternative identifiers for this instance.

articleProcessingCharge ArticleProcessingCharge | None

An ArticleProcessingCharge object, if applicable.

license str | None

A string representing the license of this instance. (Note: API sometimes provides this as a simple string).

collectedFrom dict[str, str] | None

Information about the data source from which this instance was collected.

hostedBy dict[str, str] | None

Information about the data source hosting this instance.

distributionLocation str | None

The primary URL or location where this instance can be accessed.

embargoEndDate str | None

The date when an embargo on this instance ends (YYYY-MM-DD string).

instanceId str | None

A unique identifier for this specific instance.

publicationDate str | None

The publication date of this specific instance (YYYY-MM-DD string).

refereed RefereedType | None

The refereed status of this instance (RefereedType).

type str | None

The type of this instance (e.g., "fulltext", "abstract").

urls list[str]

A list of URLs associated with this instance.

Source code in src/aireloom/models/research_product.py
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
class Instance(BaseModel):
    """Represents a specific instance or manifestation of a research product.

    A research product can have multiple instances, for example, a preprint version,
    a published version in a journal, a copy in a repository, etc. Each instance
    can have its own access rights, license, and location.

    Attributes:
        accessRight: An `AccessRight` object detailing the access conditions for this instance.
        alternateIdentifier: A list of alternative identifiers for this instance.
        articleProcessingCharge: An `ArticleProcessingCharge` object, if applicable.
        license: A string representing the license of this instance.
                 (Note: API sometimes provides this as a simple string).
        collectedFrom: Information about the data source from which this instance was collected.
        hostedBy: Information about the data source hosting this instance.
        distributionLocation: The primary URL or location where this instance can be accessed.
        embargoEndDate: The date when an embargo on this instance ends (YYYY-MM-DD string).
        instanceId: A unique identifier for this specific instance.
        publicationDate: The publication date of this specific instance (YYYY-MM-DD string).
        refereed: The refereed status of this instance (`RefereedType`).
        type: The type of this instance (e.g., "fulltext", "abstract").
        urls: A list of URLs associated with this instance.
    """

    accessRight: AccessRight | None = None
    alternateIdentifier: list[dict[str, str]] = Field(default_factory=list)
    articleProcessingCharge: ArticleProcessingCharge | None = None
    license: str | None = None
    collectedFrom: dict[str, str] | None = None
    hostedBy: dict[str, str] | None = None
    distributionLocation: str | None = None
    embargoEndDate: str | None = None
    instanceId: str | None = None
    publicationDate: str | None = None
    refereed: RefereedType | None = None
    type: str | None = None
    urls: list[str] = Field(default_factory=list)

    '''
    @field_validator("license", mode="before")
    @classmethod
    def handle_string_license(cls, v: Any) -> License | None:
        """Handle cases where license is provided as a simple string instead of an object."""
        if v is None:
            return None
        if isinstance(v, str):
            # If it's a string, create a License object with the string as both code and label
            return License(code=v, label=v)
        if isinstance(v, dict):
            return License(**v)
        if isinstance(v, License):
            return v
        logger.warning(
            f"Unexpected license format: {v}. Expected string, dict, or License object."
        )
        return None
    '''
    model_config = ConfigDict(extra="allow")

urls = Field(default_factory=list) class-attribute instance-attribute

@field_validator("license", mode="before") @classmethod def handle_string_license(cls, v: Any) -> License | None: """Handle cases where license is provided as a simple string instead of an object.""" if v is None: return None if isinstance(v, str): # If it's a string, create a License object with the string as both code and label return License(code=v, label=v) if isinstance(v, dict): return License(**v) if isinstance(v, License): return v logger.warning( f"Unexpected license format: {v}. Expected string, dict, or License object." ) return None

Language

Bases: BaseModel

Represents a language associated with a research product.

Attributes:

Name Type Description
code str | None

The language code (e.g., "en", "fr").

label str | None

The human-readable name of the language (e.g., "English").

Source code in src/aireloom/models/research_product.py
317
318
319
320
321
322
323
324
325
326
327
328
class Language(BaseModel):
    """Represents a language associated with a research product.

    Attributes:
        code: The language code (e.g., "en", "fr").
        label: The human-readable name of the language (e.g., "English").
    """

    code: str | None = None
    label: str | None = None

    model_config = ConfigDict(extra="allow")

License

Bases: BaseModel

Represents license information.

Note: This model was marked as potentially unused in the original API response analysis. It's kept for completeness but might not be populated. The Instance.license field is currently a simple string.

Attributes:

Name Type Description
code str | None

A code for the license (e.g., "CC-BY-4.0").

label str | None

A human-readable label for the license.

Source code in src/aireloom/models/research_product.py
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
class License(BaseModel):
    """Represents license information.

    Note: This model was marked as potentially unused in the original API response
    analysis. It's kept for completeness but might not be populated.
    The `Instance.license` field is currently a simple string.

    Attributes:
        code: A code for the license (e.g., "CC-BY-4.0").
        label: A human-readable label for the license.
    """

    code: str | None = None
    label: str | None = None

    model_config = ConfigDict(extra="allow")

Pid

Bases: BaseModel

Represents a Persistent Identifier (PID) with its scheme and value.

Attributes:

Name Type Description
scheme str | None

The scheme of the PID (e.g., "doi", "orcid", "handle").

value str | None

The actual value of the PID.

Source code in src/aireloom/models/research_product.py
46
47
48
49
50
51
52
53
54
55
56
57
class Pid(BaseModel):
    """Represents a Persistent Identifier (PID) with its scheme and value.

    Attributes:
        scheme: The scheme of the PID (e.g., "doi", "orcid", "handle").
        value: The actual value of the PID.
    """

    scheme: str | None = None
    value: str | None = None

    model_config = ConfigDict(extra="allow")

ResearchProduct

Bases: BaseEntity

Model representing an OpenAIRE Research Product entity.

This is a central model in OpenAIRE, representing various outputs of research such as publications, datasets, software, or other types. It aggregates numerous metadata fields. Inherits id from BaseEntity.

Attributes:

Name Type Description
originalIds list[str] | None

A list of original identifiers for the research product.

pids list[Pid] | None

A list of Pid objects representing persistent identifiers.

type ResearchProductType | None

The ResearchProductType (e.g., "publication", "dataset").

title str | None

The main title of the research product.

authors list[Author] | None

A list of Author objects.

bestAccessRight BestAccessRight | None

A BestAccessRight object indicating the determined access status.

country ResultCountry | None

A ResultCountry object indicating the country associated with the product.

description str | None

A textual description or abstract of the research product.

publicationDate str | None

The publication date of the research product (YYYY-MM-DD string).

publisher str | None

The name of the publisher.

indicators Indicator | None

An Indicator object containing citation and usage metrics.

instances list[Instance] | None

A list of Instance objects representing different manifestations or versions of the research product.

language Language | None

A Language object for the primary language of the product.

subjects list[Subject] | None

A list of Subject objects.

container Container | None

A Container object if the product is part of a larger collection (e.g., a journal for an article).

geoLocation GeoLocation | None

A GeoLocation object, typically for datasets.

keywords list[str] | None

A list of keywords. A validator attempts to parse comma-separated strings.

journal Container | None

An alias or alternative field for container, often used for journal details. (Note: API might use 'container' or 'journal' field for similar info).

Source code in src/aireloom/models/research_product.py
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
class ResearchProduct(BaseEntity):
    """Model representing an OpenAIRE Research Product entity.

    This is a central model in OpenAIRE, representing various outputs of research
    such as publications, datasets, software, or other types. It aggregates
    numerous metadata fields. Inherits `id` from `BaseEntity`.

    Attributes:
        originalIds: A list of original identifiers for the research product.
        pids: A list of `Pid` objects representing persistent identifiers.
        type: The `ResearchProductType` (e.g., "publication", "dataset").
        title: The main title of the research product.
        authors: A list of `Author` objects.
        bestAccessRight: A `BestAccessRight` object indicating the determined access status.
        country: A `ResultCountry` object indicating the country associated with the product.
        description: A textual description or abstract of the research product.
        publicationDate: The publication date of the research product (YYYY-MM-DD string).
        publisher: The name of the publisher.
        indicators: An `Indicator` object containing citation and usage metrics.
        instances: A list of `Instance` objects representing different manifestations
                   or versions of the research product.
        language: A `Language` object for the primary language of the product.
        subjects: A list of `Subject` objects.
        container: A `Container` object if the product is part of a larger collection
                   (e.g., a journal for an article).
        geoLocation: A `GeoLocation` object, typically for datasets.
        keywords: A list of keywords. A validator attempts to parse comma-separated strings.
        journal: An alias or alternative field for `container`, often used for journal details.
                 (Note: API might use 'container' or 'journal' field for similar info).
    """

    # id is inherited from BaseEntity
    originalIds: list[str] | None = Field(default_factory=list)
    pids: list[Pid] | None = Field(default_factory=list)
    type: ResearchProductType | None = None
    title: str | None = None
    authors: list[Author] | None = Field(default_factory=list)
    bestAccessRight: BestAccessRight | None = None
    country: ResultCountry | None = None
    description: str | None = None
    publicationDate: str | None = None
    publisher: str | None = None
    indicators: Indicator | None = None
    instances: list[Instance] | None = Field(default_factory=list)
    language: Language | None = None
    subjects: list[Subject] | None = Field(default_factory=list)
    container: Container | None = None
    geoLocation: GeoLocation | None = None
    keywords: list[str] | None = Field(default_factory=list)
    journal: Container | None = None

    model_config = ConfigDict(extra="allow", populate_by_name=True)

    @field_validator("keywords", mode="before")
    @classmethod
    def split_keywords(cls, v: Any) -> list[str] | None:
        """Attempts to split a comma-separated string of keywords into a list.

        If the input `v` is a string, it's split by commas, and each part is stripped
        of whitespace. If `v` is None or not a string, it's returned as is (or None
        if the string was empty after stripping).

        Args:
            v: The value to parse, expected to be a string or None.

        Returns:
            A list of keyword strings, or None if input was None or empty.
        """
        if v is None:
            return None
        if isinstance(v, str):
            return [kw.strip() for kw in v.split(",") if kw.strip()]
        logger.warning(
            f"Unexpected value for ResearchProduct.keywords: {v}. Expected string or None."
        )
        return None  # Or raise ValueError if strictness is preferred

    @model_validator(mode="before")
    @classmethod
    def get_title_from_main_title(cls, data: Any) -> Any:
        """Populates the `title` field from `mainTitle` if `title` is not present.

        The OpenAIRE API sometimes uses `mainTitle` for the primary title. This
        validator ensures that the `title` field in the Pydantic model is populated
        using `mainTitle` if `title` itself is missing in the input data, effectively
        aliasing `mainTitle` to `title`.

        Args:
            data: The raw input data dictionary before validation.

        Returns:
            The (potentially modified) input data dictionary.
        """
        if isinstance(data, dict) and "mainTitle" in data:
            if (
                "title" not in data or data["title"] is None
            ):  # Ensure we don't overwrite an existing title
                data["title"] = data.pop("mainTitle")
            else:  # title exists, no need to pop mainTitle if it's just a duplicate
                data.pop("mainTitle", None)
        return data

get_title_from_main_title(data) classmethod

Populates the title field from mainTitle if title is not present.

The OpenAIRE API sometimes uses mainTitle for the primary title. This validator ensures that the title field in the Pydantic model is populated using mainTitle if title itself is missing in the input data, effectively aliasing mainTitle to title.

Parameters:

Name Type Description Default
data Any

The raw input data dictionary before validation.

required

Returns:

Type Description
Any

The (potentially modified) input data dictionary.

Source code in src/aireloom/models/research_product.py
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
@model_validator(mode="before")
@classmethod
def get_title_from_main_title(cls, data: Any) -> Any:
    """Populates the `title` field from `mainTitle` if `title` is not present.

    The OpenAIRE API sometimes uses `mainTitle` for the primary title. This
    validator ensures that the `title` field in the Pydantic model is populated
    using `mainTitle` if `title` itself is missing in the input data, effectively
    aliasing `mainTitle` to `title`.

    Args:
        data: The raw input data dictionary before validation.

    Returns:
        The (potentially modified) input data dictionary.
    """
    if isinstance(data, dict) and "mainTitle" in data:
        if (
            "title" not in data or data["title"] is None
        ):  # Ensure we don't overwrite an existing title
            data["title"] = data.pop("mainTitle")
        else:  # title exists, no need to pop mainTitle if it's just a duplicate
            data.pop("mainTitle", None)
    return data

split_keywords(v) classmethod

Attempts to split a comma-separated string of keywords into a list.

If the input v is a string, it's split by commas, and each part is stripped of whitespace. If v is None or not a string, it's returned as is (or None if the string was empty after stripping).

Parameters:

Name Type Description Default
v Any

The value to parse, expected to be a string or None.

required

Returns:

Type Description
list[str] | None

A list of keyword strings, or None if input was None or empty.

Source code in src/aireloom/models/research_product.py
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
@field_validator("keywords", mode="before")
@classmethod
def split_keywords(cls, v: Any) -> list[str] | None:
    """Attempts to split a comma-separated string of keywords into a list.

    If the input `v` is a string, it's split by commas, and each part is stripped
    of whitespace. If `v` is None or not a string, it's returned as is (or None
    if the string was empty after stripping).

    Args:
        v: The value to parse, expected to be a string or None.

    Returns:
        A list of keyword strings, or None if input was None or empty.
    """
    if v is None:
        return None
    if isinstance(v, str):
        return [kw.strip() for kw in v.split(",") if kw.strip()]
    logger.warning(
        f"Unexpected value for ResearchProduct.keywords: {v}. Expected string or None."
    )
    return None  # Or raise ValueError if strictness is preferred

ResultCountry

Bases: BaseModel

Represents the country associated with a research product or entity.

Attributes:

Name Type Description
code str | None

The ISO 3166-1 alpha-2 country code.

label str | None

The human-readable name of the country.

Source code in src/aireloom/models/research_product.py
 96
 97
 98
 99
100
101
102
103
104
105
106
107
class ResultCountry(BaseModel):
    """Represents the country associated with a research product or entity.

    Attributes:
        code: The ISO 3166-1 alpha-2 country code.
        label: The human-readable name of the country.
    """

    code: str | None = None
    label: str | None = None

    model_config = ConfigDict(extra="allow")

ResultPid

Bases: BaseModel

Represents a Persistent Identifier (PID) within a result context.

Note: This model appears functionally identical to the top-level Pid model. Consider aliasing or reusing Pid if their semantics are indeed the same.

Attributes:

Name Type Description
scheme str | None

The scheme of the PID.

value str | None

The value of the PID.

Source code in src/aireloom/models/research_product.py
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
class ResultPid(BaseModel):
    """Represents a Persistent Identifier (PID) within a result context.

    Note: This model appears functionally identical to the top-level `Pid` model.
    Consider aliasing or reusing `Pid` if their semantics are indeed the same.

    Attributes:
        scheme: The scheme of the PID.
        value: The value of the PID.
    """

    scheme: str | None = None
    value: str | None = None

    model_config = ConfigDict(extra="allow")

Subject

Bases: BaseModel

Represents a subject classification for a research product.

The API often returns this as a nested dictionary where the key is the scheme (e.g., "ddc", "mesh") and the value is the subject term or code. This model captures that structure directly.

Attributes:

Name Type Description
subject dict[str, str] | None

A dictionary where keys are subject schemes and values are subject terms/codes. Example: {"fos": "Field of Science", "mesh": "D000001"}

Source code in src/aireloom/models/research_product.py
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
class Subject(BaseModel):
    """Represents a subject classification for a research product.

    The API often returns this as a nested dictionary where the key is the
    scheme (e.g., "ddc", "mesh") and the value is the subject term or code.
    This model captures that structure directly.

    Attributes:
        subject: A dictionary where keys are subject schemes and values are subject terms/codes.
                 Example: `{"fos": "Field of Science", "mesh": "D000001"}`
    """

    subject: dict[str, str] | None = None

    model_config = ConfigDict(extra="allow")

UsageCounts

Bases: BaseModel

Represents usage counts for a research product, like downloads and views.

Includes a validator to coerce string values from the API into integers.

Attributes:

Name Type Description
downloads int | None

The number of times the research product has been downloaded.

views int | None

The number of times the research product has been viewed.

Source code in src/aireloom/models/research_product.py
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
class UsageCounts(BaseModel):
    """Represents usage counts for a research product, like downloads and views.

    Includes a validator to coerce string values from the API into integers.

    Attributes:
        downloads: The number of times the research product has been downloaded.
        views: The number of times the research product has been viewed.
    """

    downloads: int | None = None
    views: int | None = None

    @field_validator("downloads", "views", mode="before")
    @classmethod
    def coerce_str_to_int(cls, v: Any) -> int | None:
        """Coerces string count values to integers, also handling None and logging errors.

        Args:
            v: The value to coerce.

        Returns:
            The value as an integer, or None if coercion is not possible or input is None.
        """
        if v is None:
            return None
        if isinstance(v, str):
            try:
                return int(v)
            except (ValueError, TypeError):
                logger.warning(f"Could not coerce UsageCounts value '{v}' to int.")
                return None
        if isinstance(v, int):
            return v
        logger.warning(f"Unexpected type {type(v)} for UsageCounts value '{v}'.")
        return None

    model_config = ConfigDict(extra="allow")

coerce_str_to_int(v) classmethod

Coerces string count values to integers, also handling None and logging errors.

Parameters:

Name Type Description Default
v Any

The value to coerce.

required

Returns:

Type Description
int | None

The value as an integer, or None if coercion is not possible or input is None.

Source code in src/aireloom/models/research_product.py
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
@field_validator("downloads", "views", mode="before")
@classmethod
def coerce_str_to_int(cls, v: Any) -> int | None:
    """Coerces string count values to integers, also handling None and logging errors.

    Args:
        v: The value to coerce.

    Returns:
        The value as an integer, or None if coercion is not possible or input is None.
    """
    if v is None:
        return None
    if isinstance(v, str):
        try:
            return int(v)
        except (ValueError, TypeError):
            logger.warning(f"Could not coerce UsageCounts value '{v}' to int.")
            return None
    if isinstance(v, int):
        return v
    logger.warning(f"Unexpected type {type(v)} for UsageCounts value '{v}'.")
    return None

Filters

Bases: BaseModel

Filter model for Research Products API endpoint.

Attributes:

Name Type Description
search str | None

Search term for the research product.

mainTitle str | None

Main title of the research product.

description str | None

Description of the research product.

id str | None

OpenAIRE id for the research product.

pid str | None

Persistent identifier for the research product.

originalId str | None

Original identifier for the research product.

type Literal['publication', 'dataset', 'software', 'other'] | None

Type of the research product.

fromPublicationDate date | None

Start date of publication (inclusive).

toPublicationDate date | None

End date of publication (inclusive).

subjects list[str] | None

List of subjects associated with the research product.

countryCode str | None

Country code of the research product.

authorFullName str | None

Full name of the author.

authorOrcid str | None

ORCID of the author.

publisher str | None

Publisher of the research product.

bestOpenAccessRightLabel str | None

Best open access right label.

influenceClass str | None

Influence class of the research product.

impulseClass str | None

Impulse class of the research product.

popularityClass str | None

Popularity class of the research product.

citationCountClass str | None

Citation count class of the research product.

instanceType str | None

Instance type of the research product.

sdg list[str] | None

List of SDG goals associated with the research product.

fos list[str] | None

List of field of studies associated with the research product.

isPeerReviewed bool | None

Flag indicating if the research product is peer-reviewed.

isInDiamondJournal bool | None

Flag indicating if the research product is in a diamond journal.

isPubliclyFunded bool | None

Flag indicating if the research product is publicly funded.

isGreen bool | None

Flag indicating if the research product is green open access.

openAccessColor str | None

Color representing the open access status.

relOrganizationId str | None

Related organization ID.

relCommunityId str | None

Related community ID.

relProjectId str | None

Related project ID.

relProjectCode str | None

Related project code.

hasProjectRel bool | None

Flag indicating if the research product has a related project.

relProjectFundingShortName str | None

Short name of the project funding.

relProjectFundingStreamId str | None

ID of the project funding stream.

relHostingDataSourceId str | None

ID of the hosting data source.

relCollectedFromDatasourceId str | None

ID of the datasource from which this was collected.

Source code in src/aireloom/endpoints.py
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
class ResearchProductsFilters(BaseModel):
    """Filter model for Research Products API endpoint.

    Attributes:
        search (str | None): Search term for the research product.
        mainTitle (str | None): Main title of the research product.
        description (str | None): Description of the research product.
        id (str | None): OpenAIRE id for the research product.
        pid (str | None): Persistent identifier for the research product.
        originalId (str | None): Original identifier for the research product.
        type (Literal["publication", "dataset", "software", "other"] | None): Type of the research product.
        fromPublicationDate (date | None): Start date of publication (inclusive).
        toPublicationDate (date | None): End date of publication (inclusive).
        subjects (list[str] | None): List of subjects associated with the research product.
        countryCode (str | None): Country code of the research product.
        authorFullName (str | None): Full name of the author.
        authorOrcid (str | None): ORCID of the author.
        publisher (str | None): Publisher of the research product.
        bestOpenAccessRightLabel (str | None): Best open access right label.
        influenceClass (str | None): Influence class of the research product.
        impulseClass (str | None): Impulse class of the research product.
        popularityClass (str | None): Popularity class of the research product.
        citationCountClass (str | None): Citation count class of the research product.
        instanceType (str | None): Instance type of the research product.
        sdg (list[str] | None): List of SDG goals associated with the research product.
        fos (list[str] | None): List of field of studies associated with the research product.
        isPeerReviewed (bool | None): Flag indicating if the research product is peer-reviewed.
        isInDiamondJournal (bool | None): Flag indicating if the research product is in a diamond journal.
        isPubliclyFunded (bool | None): Flag indicating if the research product is publicly funded.
        isGreen (bool | None): Flag indicating if the research product is green open access.
        openAccessColor (str | None): Color representing the open access status.
        relOrganizationId (str | None): Related organization ID.
        relCommunityId (str | None): Related community ID.
        relProjectId (str | None): Related project ID.
        relProjectCode (str | None): Related project code.
        hasProjectRel (bool | None): Flag indicating if the research product has a related project.
        relProjectFundingShortName (str | None): Short name of the project funding.
        relProjectFundingStreamId (str | None): ID of the project funding stream.
        relHostingDataSourceId (str | None): ID of the hosting data source.
        relCollectedFromDatasourceId (str | None): ID of the datasource from which this was collected.


    """

    search: str | None = None
    mainTitle: str | None = None
    description: str | None = None
    id: str | None = None
    pid: str | None = None
    originalId: str | None = None
    type: Literal["publication", "dataset", "software", "other"] | None = None
    fromPublicationDate: date | None = None
    toPublicationDate: date | None = None
    subjects: list[str] | None = None
    countryCode: str | None = None
    authorFullName: str | None = None
    authorOrcid: str | None = None
    publisher: str | None = None
    bestOpenAccessRightLabel: str | None = None
    influenceClass: str | None = None
    impulseClass: str | None = None
    popularityClass: str | None = None
    citationCountClass: str | None = None
    instanceType: str | None = None
    sdg: list[str] | None = None
    fos: list[str] | None = None
    isPeerReviewed: bool | None = None
    isInDiamondJournal: bool | None = None
    isPubliclyFunded: bool | None = None
    isGreen: bool | None = None
    openAccessColor: str | None = None
    relOrganizationId: str | None = None
    relCommunityId: str | None = None
    relProjectId: str | None = None
    relProjectCode: str | None = None
    hasProjectRel: bool | None = None
    relProjectFundingShortName: str | None = None
    relProjectFundingStreamId: str | None = None
    relHostingDataSourceId: str | None = None
    relCollectedFromDatasourceId: str | None = None

    model_config = ConfigDict(extra="forbid")

Client

Client for interacting with the OpenAIRE Research Products API endpoint.

This module provides the ResearchProductsClient, which facilitates access to OpenAIRE's research product data (e.g., publications, datasets, software). It leverages generic mixins from bibliofabric.resources for common API operations like retrieving individual entities, searching, and iterating through result sets.

ResearchProductsClient

Bases: GettableMixin, SearchableMixin, CursorIterableMixin, BaseResourceClient

Client for the OpenAIRE Research Products API endpoint.

This client provides standardized methods (get, search, iterate) for accessing research product data, by inheriting from bibliofabric mixins. It is configured with the specific API path and Pydantic models relevant to OpenAIRE research products.

Attributes:

Name Type Description
_entity_path str

The API path for research products.

_entity_model type[ResearchProduct]

Pydantic model for a single research product.

_search_response_model type[ResearchProductResponse]

Pydantic model for the search response envelope.

_valid_sort_fields set[str]

A set of field names that are valid for sorting results from this endpoint.

Source code in src/aireloom/resources/research_products_client.py
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
class ResearchProductsClient(
    GettableMixin, SearchableMixin, CursorIterableMixin, BaseResourceClient
):
    """Client for the OpenAIRE Research Products API endpoint.

    This client provides standardized methods (`get`, `search`, `iterate`) for
    accessing research product data, by inheriting from `bibliofabric` mixins.
    It is configured with the specific API path and Pydantic models relevant
    to OpenAIRE research products.

    Attributes:
        _entity_path (str): The API path for research products.
        _entity_model (type[ResearchProduct]): Pydantic model for a single research product.
        _search_response_model (type[ResearchProductResponse]): Pydantic model for the
                                                                search response envelope.
        _valid_sort_fields (set[str]): A set of field names that are valid for sorting
                                       results from this endpoint.
    """

    _entity_path: str = RESEARCH_PRODUCTS
    _entity_model: type[ResearchProduct] = ResearchProduct
    _search_response_model: type[ResearchProductResponse] = ResearchProductResponse
    _valid_sort_fields = {
        "bestaccessright",
        "publicationdate",
        "relevance",
        "title",
    }

    def __init__(self, api_client: "AireloomClient"):
        """Initializes the ResearchProductsClient.

        Args:
            api_client: An instance of AireloomClient.
        """
        super().__init__(api_client)
        logger.debug(
            f"ResearchProductsClient initialized for path: {self._entity_path}"
        )

__init__(api_client)

Initializes the ResearchProductsClient.

Parameters:

Name Type Description Default
api_client AireloomClient

An instance of AireloomClient.

required
Source code in src/aireloom/resources/research_products_client.py
56
57
58
59
60
61
62
63
64
65
def __init__(self, api_client: "AireloomClient"):
    """Initializes the ResearchProductsClient.

    Args:
        api_client: An instance of AireloomClient.
    """
    super().__init__(api_client)
    logger.debug(
        f"ResearchProductsClient initialized for path: {self._entity_path}"
    )