Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master' into afo-register
Browse files Browse the repository at this point in the history
  • Loading branch information
khoidt committed Nov 22, 2023
2 parents 9d25757 + ed6c504 commit faaf8fb
Show file tree
Hide file tree
Showing 21 changed files with 166 additions and 54 deletions.
16 changes: 16 additions & 0 deletions ebl/common/application/schemas.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from marshmallow import Schema, fields, validate, post_load
from ebl.common.domain.accession import Accession


class AbstractMuseumNumberSchema(Schema):
prefix = fields.String(required=True, validate=validate.Length(min=1))
number = fields.String(
required=True, validate=(validate.Length(min=1), validate.ContainsNoneOf("."))
)
suffix = fields.String(required=True, validate=validate.ContainsNoneOf("."))


class AccessionSchema(AbstractMuseumNumberSchema):
@post_load
def create_accession(self, data, **kwargs) -> Accession:
return Accession(**data)
15 changes: 15 additions & 0 deletions ebl/common/domain/accession.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from ebl.transliteration.domain.museum_number import MuseumNumber
import functools
import attr
import re


@functools.total_ordering
@attr.s(auto_attribs=True, frozen=True, order=False)
class Accession(MuseumNumber):
@staticmethod
def of(source: str) -> "Accession":
if match := re.compile(r"(.+?)\.([^.]+)(?:\.([^.]+))?").fullmatch(source):
return Accession(match[1], match[2], match[3] or "")
else:
raise ValueError(f"'{source}' is not a valid accession number.")
27 changes: 13 additions & 14 deletions ebl/fragmentarium/application/archaeology_schemas.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,24 @@
from ebl.common.application.schemas import AbstractMuseumNumberSchema
from ebl.bibliography.application.reference_schema import ReferenceSchema
from ebl.fragmentarium.application.date_schemas import (
DateRangeSchema,
DateWithNotesSchema,
)
from ebl.fragmentarium.domain.archaeology import Archaeology
from ebl.fragmentarium.domain.findspot import BuildingType, ExcavationPlan, Findspot
from ebl.fragmentarium.domain.archaeology import (
Archaeology,
ExcavationNumber,
)
from ebl.fragmentarium.domain.findspot import (
BuildingType,
ExcavationPlan,
Findspot,
ExcavationSite,
)
from ebl.schemas import NameEnumField
from marshmallow import Schema, fields, post_load, validate
from ebl.transliteration.domain.museum_number import MuseumNumber as ExcavationNumber
from ebl.corpus.domain.provenance import Provenance as ExcavationSite

from marshmallow import Schema, fields, post_load

class ExcavationNumberSchema(Schema):
prefix = fields.String(
required=True, validate=(validate.Length(min=1), validate.ContainsNoneOf("."))
)
number = fields.String(
required=True, validate=(validate.Length(min=1), validate.ContainsNoneOf("."))
)
suffix = fields.String(required=True, validate=validate.ContainsNoneOf("."))

class ExcavationNumberSchema(AbstractMuseumNumberSchema):
@post_load
def create_excavation_number(self, data, **kwargs) -> ExcavationNumber:
return ExcavationNumber(**data)
Expand Down
3 changes: 2 additions & 1 deletion ebl/fragmentarium/application/fragment_info_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
ReferenceSchema,
ApiReferenceSchema,
)
from ebl.common.application.schemas import AccessionSchema
from ebl.fragmentarium.application.fragment_schema import ScriptSchema
from ebl.fragmentarium.application.genre_schema import GenreSchema
from ebl.fragmentarium.domain.fragment_infos_pagination import FragmentInfosPagination
Expand All @@ -13,7 +14,7 @@

class FragmentInfoSchema(Schema):
number: fields.Field = fields.Nested(MuseumNumberSchema, required=True)
accession = fields.String(required=True)
accession = fields.Nested(AccessionSchema, allow_none=True, load_default=None)
script = fields.Nested(ScriptSchema, required=True)
description = fields.String(required=True)
editor = fields.String(load_default="")
Expand Down
3 changes: 2 additions & 1 deletion ebl/fragmentarium/application/fragment_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from marshmallow import Schema, fields, post_dump, post_load, EXCLUDE

from ebl.bibliography.application.reference_schema import ReferenceSchema
from ebl.common.application.schemas import AccessionSchema
from ebl.common.domain.period import Period, PeriodModifier
from ebl.fragmentarium.application.archaeology_schemas import ArchaeologySchema
from ebl.fragmentarium.application.genre_schema import GenreSchema
Expand Down Expand Up @@ -159,7 +160,7 @@ def omit_empty_numbers(self, data, **kwargs):

class FragmentSchema(Schema):
number = fields.Nested(MuseumNumberSchema, required=True, data_key="museumNumber")
accession = fields.String(required=True)
accession = fields.Nested(AccessionSchema, allow_none=True, load_default=None)
edited_in_oracc_project = fields.String(
required=True, data_key="editedInOraccProject"
)
Expand Down
15 changes: 12 additions & 3 deletions ebl/fragmentarium/domain/archaeology.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
from typing import Optional, Sequence
import attr
from ebl.fragmentarium.domain.iso_date import DateWithNotes
from ebl.transliteration.domain.museum_number import MuseumNumber as ExcavationNumber
from ebl.corpus.domain.provenance import Provenance as ExcavationSite
from ebl.fragmentarium.domain.findspot import Findspot
from ebl.transliteration.domain.museum_number import MuseumNumber
from ebl.fragmentarium.domain.findspot import Findspot, ExcavationSite
import re


class ExcavationNumber(MuseumNumber):
@staticmethod
def of(source: str) -> "ExcavationNumber":
if match := re.compile(r"(.+?)\.([^.]+)(?:\.([^.]+))?").fullmatch(source):
return ExcavationNumber(match[1], match[2], match[3] or "")
else:
raise ValueError(f"'{source}' is not a valid excavation number.")


@attr.s(auto_attribs=True, frozen=True)
Expand Down
5 changes: 4 additions & 1 deletion ebl/fragmentarium/domain/findspot.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@
from enum import Enum, auto
from ebl.bibliography.domain.reference import Reference
from ebl.fragmentarium.domain.iso_date import DateRange
from ebl.corpus.domain.provenance import Provenance as ExcavationSite
from ebl.corpus.domain.provenance import Provenance


ExcavationSite = Provenance


class BuildingType(Enum):
Expand Down
3 changes: 2 additions & 1 deletion ebl/fragmentarium/domain/fragment.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import pydash

from ebl.bibliography.domain.reference import Reference
from ebl.common.domain.accession import Accession
from ebl.common.domain.period import Period, PeriodModifier
from ebl.common.domain.scopes import Scope
from ebl.fragmentarium.application.matches.create_line_to_vec import create_line_to_vec
Expand Down Expand Up @@ -113,7 +114,7 @@ class ExternalNumbers:
@attr.s(auto_attribs=True, frozen=True)
class Fragment:
number: MuseumNumber
accession: str = ""
accession: Optional[Accession] = None
edited_in_oracc_project: str = ""
publication: str = ""
description: str = ""
Expand Down
3 changes: 2 additions & 1 deletion ebl/fragmentarium/domain/fragment_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import attr

from ebl.bibliography.domain.reference import Reference
from ebl.common.domain.accession import Accession
from ebl.fragmentarium.domain.fragment import Fragment, Genre, Script
from ebl.fragmentarium.domain.record import RecordEntry, RecordType
from ebl.transliteration.domain.museum_number import MuseumNumber
Expand All @@ -12,7 +13,7 @@
@attr.s(frozen=True, auto_attribs=True)
class FragmentInfo:
number: MuseumNumber
accession: str
accession: Optional[Accession]
script: Script
description: str
matching_lines: Optional[Text]
Expand Down
6 changes: 3 additions & 3 deletions ebl/fragmentarium/infrastructure/mongo_fragment_repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
from ebl.transliteration.application.museum_number_schema import MuseumNumberSchema
from ebl.transliteration.domain.museum_number import MuseumNumber
from ebl.transliteration.infrastructure.collections import FRAGMENTS_COLLECTION
from ebl.transliteration.infrastructure.queries import museum_number_is
from ebl.transliteration.infrastructure.queries import query_number_is

RETRIEVE_ALL_LIMIT = 1000

Expand Down Expand Up @@ -171,7 +171,7 @@ def query_by_museum_number(
):
data = self._fragments.aggregate(
[
{"$match": museum_number_is(number)},
{"$match": query_number_is(number)},
*(
self._omit_text_lines()
if exclude_lines
Expand Down Expand Up @@ -206,7 +206,7 @@ def fetch_date(self, number: MuseumNumber) -> Optional[Date]:
def fetch_scopes(self, number: MuseumNumber) -> List[Scope]:
fragment = next(
self._fragments.find_many(
museum_number_is(number), projection={"authorizedScopes": True}
query_number_is(number), projection={"authorizedScopes": True}
),
{},
)
Expand Down
18 changes: 11 additions & 7 deletions ebl/fragmentarium/infrastructure/queries.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from typing import List, Sequence
from ebl.common.domain.accession import Accession
from ebl.common.domain.scopes import Scope
from ebl.fragmentarium.domain.archaeology import ExcavationNumber

from ebl.fragmentarium.domain.fragment import Fragment
from ebl.fragmentarium.domain.record import RecordType
Expand All @@ -9,7 +11,7 @@
FRAGMENTS_COLLECTION,
FINDSPOTS_COLLECTION,
)
from ebl.transliteration.infrastructure.queries import museum_number_is
from ebl.transliteration.infrastructure.queries import query_number_is

HAS_TRANSLITERATION: dict = {"text.lines.type": {"$exists": True}}
NUMBER_OF_LATEST_TRANSLITERATIONS: int = 50
Expand All @@ -18,15 +20,17 @@


def fragment_is(fragment: Fragment) -> dict:
return museum_number_is(fragment.number)
return query_number_is(fragment.number)


def number_is(number: str) -> dict:
or_ = [{"externalNumbers.cdliNumber": number}, {"accession": number}]
try:
or_.append(museum_number_is(MuseumNumber.of(number)))
except ValueError:
pass
or_ = [{"externalNumbers.cdliNumber": number}]

for number_class in [MuseumNumber, Accession, ExcavationNumber]:
try:
or_.append(query_number_is(number_class.of(number)))
except ValueError:
pass
return {"$or": or_}


Expand Down
24 changes: 24 additions & 0 deletions ebl/tests/common/test_accession.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import pytest
from ebl.common.application.schemas import AccessionSchema
from ebl.common.domain.accession import Accession


ACCESSION = Accession("A", "38")
ACCESSION_DTO = {"prefix": "A", "number": "38", "suffix": ""}


def test_of():
assert Accession.of("A.38") == ACCESSION


def test_of_invalid():
with pytest.raises(ValueError, match="'invalid.' is not a valid accession number."):
Accession.of("invalid.")


def test_serialize():
assert AccessionSchema().dump(ACCESSION) == ACCESSION_DTO


def test_deserialize():
assert AccessionSchema().load(ACCESSION_DTO) == ACCESSION
3 changes: 1 addition & 2 deletions ebl/tests/factories/archaeology.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
from ebl.fragmentarium.domain.archaeology import Archaeology
from ebl.fragmentarium.domain.archaeology import Archaeology, ExcavationNumber
from ebl.fragmentarium.domain.iso_date import DateRange, DateWithNotes
from ebl.fragmentarium.domain.findspot import BuildingType, ExcavationPlan, Findspot
from ebl.tests.factories.bibliography import ReferenceFactory
from ebl.tests.factories.collections import TupleFactory
from ebl.transliteration.domain.museum_number import MuseumNumber as ExcavationNumber
from ebl.corpus.domain.provenance import Provenance as ExcavationSite
import factory.fuzzy

Expand Down
3 changes: 2 additions & 1 deletion ebl/tests/factories/fragment.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import factory.fuzzy
import random
from ebl.common.domain.accession import Accession
from ebl.common.domain.period import Period, PeriodModifier
from ebl.common.domain.project import ResearchProject

Expand Down Expand Up @@ -181,7 +182,7 @@ class Meta:

number = factory.Sequence(lambda n: MuseumNumber("X", str(n)))
edited_in_oracc_project = factory.Sequence(lambda n: f"editedInOracc-{n}")
accession = factory.Sequence(lambda n: f"accession-{n}")
accession = factory.Sequence(lambda n: Accession("A", str(n)))
museum = factory.Faker("word")
collection = factory.Faker("word")
publication = factory.Faker("sentence")
Expand Down
5 changes: 3 additions & 2 deletions ebl/tests/fragmentarium/test_dtos.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import attr
import pydash
import pytest
from ebl.common.application.schemas import AccessionSchema

from ebl.errors import DataError
from ebl.fragmentarium.application.archaeology_schemas import ArchaeologySchema
Expand Down Expand Up @@ -44,7 +45,7 @@ def expected_dto(lemmatized_fragment, has_photo):
return pydash.omit_by(
{
"museumNumber": attr.asdict(lemmatized_fragment.number),
"accession": lemmatized_fragment.accession,
"accession": AccessionSchema().dump(lemmatized_fragment.accession),
"editedInOraccProject": lemmatized_fragment.edited_in_oracc_project,
"publication": lemmatized_fragment.publication,
"description": lemmatized_fragment.description,
Expand Down Expand Up @@ -131,7 +132,7 @@ def test_create_fragment_info_dto():
is_transliteration = record_entry.type == RecordType.TRANSLITERATION
assert ApiFragmentInfoSchema().dump(info) == {
"number": str(info.number),
"accession": info.accession,
"accession": AccessionSchema().dump(info.accession),
"script": ScriptSchema().dump(info.script),
"description": info.description,
"matchingLines": TextSchema().dump(text),
Expand Down
11 changes: 7 additions & 4 deletions ebl/tests/fragmentarium/test_fragment_archaeology_route.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,19 @@
import falcon
import pytest
from ebl.fragmentarium.application.archaeology_schemas import ArchaeologySchema
from ebl.fragmentarium.domain.archaeology import Archaeology
from ebl.fragmentarium.domain.archaeology import (
Archaeology,
ExcavationNumber,
)
from ebl.fragmentarium.domain.findspot import ExcavationSite
from ebl.fragmentarium.domain.fragment import Fragment

from ebl.fragmentarium.web.dtos import create_response_dto
from ebl.tests.factories.archaeology import DateWithNotesFactory
from ebl.tests.factories.fragment import FragmentFactory
from ebl.transliteration.domain.museum_number import MuseumNumber
from ebl.corpus.domain.provenance import Provenance as ExcavationSite

ARCHAEOLOGY = Archaeology(MuseumNumber("F", "1"), ExcavationSite.KALHU)

ARCHAEOLOGY = Archaeology(ExcavationNumber("F", "1"), ExcavationSite.KALHU)
ARCHAEOLOGIES = [
ARCHAEOLOGY,
attr.evolve(ARCHAEOLOGY, site=None),
Expand Down
13 changes: 13 additions & 0 deletions ebl/tests/fragmentarium/test_fragment_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,16 @@ def test_scope_deserialization():
"authorizedScopes": SERIALIZED_SCOPES,
}
assert FragmentSchema().load(data).authorized_scopes == SCOPES


def test_empty_accession_serialization():
fragment = FragmentFactory.build(accession=None)
assert "accession" not in FragmentSchema().dump(fragment)


def test_empty_accession_deserialization():
data = {
**FragmentSchema().dump(FragmentFactory.build()),
"accession": None,
}
assert FragmentSchema().load(data).accession is None
3 changes: 2 additions & 1 deletion ebl/tests/fragmentarium/test_fragments_search_route.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ def query_item_of(
[
lambda fragment: str(fragment.number),
lambda fragment: fragment.cdli_number,
lambda fragment: fragment.accession,
lambda fragment: str(fragment.accession),
lambda fragment: str(fragment.archaeology.excavation_number),
],
)
def test_query_fragmentarium_number(get_number, client, fragmentarium):
Expand Down
12 changes: 3 additions & 9 deletions ebl/transliteration/application/museum_number_schema.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,9 @@
from marshmallow import Schema, fields, post_load, validate

from marshmallow import post_load
from ebl.transliteration.domain.museum_number import MuseumNumber
from ebl.common.application.schemas import AbstractMuseumNumberSchema


class MuseumNumberSchema(Schema):
prefix = fields.String(required=True, validate=validate.Length(min=1))
number = fields.String(
required=True, validate=(validate.Length(min=1), validate.ContainsNoneOf("."))
)
suffix = fields.String(required=True, validate=validate.ContainsNoneOf("."))

class MuseumNumberSchema(AbstractMuseumNumberSchema):
@post_load
def create_museum_number(self, data, **kwargs) -> MuseumNumber:
return MuseumNumber(**data)
Loading

0 comments on commit faaf8fb

Please sign in to comment.