Skip to content

Commit faa8fe6

Browse files
committed
typing added
1 parent 8bbaada commit faa8fe6

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+520
-416
lines changed

mypy.ini

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
[mypy]
2+
python_version = 3.13
3+
plugins = mypy_django_plugin.main
4+
5+
strict = True
6+
ignore_missing_imports = True
7+
show_column_numbers = True
8+
pretty = True
9+
10+
# Вимикаємо перевірку всього, що не готове
11+
exclude = ^(benchmarks/|github/|api/|app/|db/|how-to/|osf_ouath2_adapter/|project/|share/|share.egg-info/|templates/|tests/|venv/)
12+
13+
disallow_untyped_defs = True
14+
warn_unused_ignores = True
15+
warn_redundant_casts = True
16+
warn_return_any = True
17+
18+
[mypy.plugins.django-stubs]
19+
django_settings_module = project.settings
20+
21+
[mypy-trove.derive.osfmap_json]
22+
disable_error_code = no-any-return

share/admin/util.py

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
1+
from typing import Callable, Any, Optional, Sequence, Type, TypeVar
2+
13
from django.contrib.admin import SimpleListFilter
24
from django.core.paginator import Paginator
35
from django.db import connection, transaction, OperationalError
6+
from django.db.models import Model
47
from django.utils.functional import cached_property
58
from django.urls import reverse
69
from django.utils.html import format_html
710

811
from share.models import SourceConfig
9-
12+
T = TypeVar('T', bound=Type[Model])
1013

1114
# TimeLimitedPaginator from https://hakibenita.com/optimizing-the-django-admin-paginator
1215
class TimeLimitedPaginator(Paginator):
@@ -46,7 +49,7 @@ def admin_link_html(linked_obj):
4649
return format_html('<a href="{}">{}</a>', url, repr(linked_obj))
4750

4851

49-
def linked_fk(field_name):
52+
def linked_fk(field_name: str) -> Callable[[Any], Any]:
5053
"""Decorator that adds a link for a foreign key field
5154
"""
5255
def add_link(cls):
@@ -62,11 +65,15 @@ def link(self, instance):
6265
return add_link
6366

6467

65-
def linked_many(field_name, order_by=None, select_related=None, defer=None):
66-
"""Decorator that adds links for a *-to-many field
67-
"""
68-
def add_links(cls):
69-
def links(self, instance):
68+
def linked_many(
69+
field_name: str,
70+
order_by: Optional[Sequence[str]] = None,
71+
select_related: Optional[Sequence[str]] = None,
72+
defer: Optional[Sequence[str]] = None,
73+
) -> Callable[[T], T]:
74+
"""Decorator that adds links for a *-to-many field"""
75+
def add_links(cls: T) -> T:
76+
def links(self, instance: Model) -> str:
7077
linked_qs = getattr(instance, field_name).all()
7178
if select_related:
7279
linked_qs = linked_qs.select_related(*select_related)
@@ -81,15 +88,14 @@ def links(self, instance):
8188
for obj in linked_qs
8289
))
8390
)
84-
links_field = '{}_links'.format(field_name)
91+
links_field = f'{field_name}_links'
8592
links.short_description = field_name.replace('_', ' ')
8693
setattr(cls, links_field, links)
8794
append_to_cls_property(cls, 'readonly_fields', links_field)
8895
append_to_cls_property(cls, 'exclude', field_name)
8996
return cls
9097
return add_links
9198

92-
9399
class SourceConfigFilter(SimpleListFilter):
94100
title = 'Source Config'
95101
parameter_name = 'source_config'

share/models/ingest.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ def __str__(self):
7070

7171

7272
class SourceConfigManager(NaturalKeyManager):
73-
def get_or_create_push_config(self, user, transformer_key=None):
73+
def get_or_create_push_config(self, user, transformer_key=None) -> 'SourceConfig':
7474
assert isinstance(user, ShareUser)
7575
_config_label = '.'.join((
7676
user.username,
@@ -231,7 +231,7 @@ class RawDatum(models.Model):
231231

232232
objects = RawDatumManager()
233233

234-
def is_latest(self):
234+
def is_latest(self) -> bool:
235235
return (
236236
RawDatum.objects
237237
.latest_by_suid_id(self.suid_id)

share/oaipmh/util.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
1+
import datetime
2+
from typing import Type, Optional
3+
from xml.etree.ElementTree import SubElement
4+
15
from lxml import etree
26
from primitive_metadata import primitive_rdf
37

48
from share.util.fromisoformat import fromisoformat
59
from trove.vocab.namespaces import OAI, OAI_DC
610

711

8-
def format_datetime(dt):
12+
def format_datetime(dt) -> datetime:
913
"""OAI-PMH has specific time format requirements -- comply.
1014
"""
1115
if isinstance(dt, primitive_rdf.Literal):
@@ -25,15 +29,15 @@ def format_datetime(dt):
2529
}
2630

2731

28-
def ns(namespace_prefix, tag_name):
32+
def ns(namespace_prefix, tag_name) -> str:
2933
"""format XML tag/attribute name with full namespace URI
3034
3135
see https://lxml.de/tutorial.html#namespaces
3236
"""
3337
return f'{{{XML_NAMESPACES[namespace_prefix]}}}{tag_name}'
3438

3539

36-
def nsmap(*namespace_prefixes, default=None):
40+
def nsmap(*namespace_prefixes, default=None) -> dict[Optional[str], str]:
3741
"""build a namespace map suitable for lxml
3842
3943
see https://lxml.de/tutorial.html#namespaces
@@ -49,7 +53,7 @@ def nsmap(*namespace_prefixes, default=None):
4953

5054

5155
# wrapper for lxml.etree.SubElement, adds `text` kwarg for convenience
52-
def SubEl(parent, tag_name, text=None, **kwargs):
56+
def SubEl(parent, tag_name, text=None, **kwargs) -> Type[SubElement]:
5357
element = etree.SubElement(parent, tag_name, **kwargs)
5458
if isinstance(text, primitive_rdf.Literal):
5559
_language_tag = text.language

share/search/index_messenger.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
from share.search.messages import MessagesChunk, MessageType
1414
from share.search import index_strategy
15-
15+
from trove.models import Indexcard
1616

1717
logger = logging.getLogger(__name__)
1818

@@ -25,15 +25,15 @@ class IndexMessenger:
2525
'max_retries': 30, # give up after 30 tries.
2626
}
2727

28-
def __init__(self, *, celery_app=None, index_strategys=None):
28+
def __init__(self, *, celery_app=None, index_strategys=None) -> None:
2929
self.celery_app = (
3030
celery.current_app
3131
if celery_app is None
3232
else celery_app
3333
)
3434
self.index_strategys = index_strategys or tuple(index_strategy.each_strategy())
3535

36-
def notify_indexcard_update(self, indexcards, *, urgent=False):
36+
def notify_indexcard_update(self, indexcards: list[Indexcard], *, urgent=False) -> None:
3737
self.send_messages_chunk(
3838
MessagesChunk(
3939
MessageType.UPDATE_INDEXCARD,
@@ -53,7 +53,7 @@ def notify_indexcard_update(self, indexcards, *, urgent=False):
5353
urgent=urgent,
5454
)
5555

56-
def notify_suid_update(self, suid_ids, *, urgent=False):
56+
def notify_suid_update(self, suid_ids, *, urgent=False) -> None:
5757
self.send_messages_chunk(
5858
MessagesChunk(MessageType.INDEX_SUID, suid_ids),
5959
urgent=urgent,

share/util/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ class IDObfuscator:
2424
ID_RE = re.compile(r'([0-9A-Fa-f]{2,})([0-9A-Fa-f]{3})-([0-9A-Fa-f]{3})-([0-9A-Fa-f]{3})')
2525

2626
@classmethod
27-
def encode(cls, instance):
27+
def encode(cls, instance) -> str:
2828
return cls.encode_id(instance.id, instance._meta.model)
2929

3030
@classmethod

share/util/checksum_iri.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import dataclasses
22
import hashlib
33
import json
4+
from typing import Self
45

56

67
def _ensure_bytes(bytes_or_something) -> bytes:
@@ -37,7 +38,7 @@ def __str__(self):
3738
return f'urn:checksum:{self.checksumalgorithm_name}:{self.salt}:{self.hexdigest}'
3839

3940
@classmethod
40-
def digest(cls, checksumalgorithm_name, *, salt, raw_data):
41+
def digest(cls, checksumalgorithm_name, *, salt, raw_data) -> Self:
4142
try:
4243
hexdigest_fn = CHECKSUM_ALGORITHMS[checksumalgorithm_name]
4344
except KeyError:

trove/admin.py

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from typing import Any, Self
12
from django.contrib import admin
23
from django.utils.html import format_html
34

@@ -17,7 +18,7 @@
1718
@admin.register(ResourceIdentifier, site=admin_site)
1819
@linked_many('suid_set')
1920
@linked_many('indexcard_set')
20-
class ResourceIdentifierAdmin(admin.ModelAdmin):
21+
class ResourceIdentifierAdmin(admin.ModelAdmin): #type: ignore
2122
readonly_fields = (
2223
'created',
2324
'modified',
@@ -37,7 +38,7 @@ class ResourceIdentifierAdmin(admin.ModelAdmin):
3738
@linked_fk('source_record_suid')
3839
@linked_many('focustype_identifier_set')
3940
@linked_many('focus_identifier_set')
40-
class IndexcardAdmin(admin.ModelAdmin):
41+
class IndexcardAdmin(admin.ModelAdmin): #type: ignore
4142
readonly_fields = (
4243
'uuid',
4344
'created',
@@ -52,15 +53,15 @@ class IndexcardAdmin(admin.ModelAdmin):
5253
list_filter = ('deleted', 'source_record_suid__source_config')
5354
actions = ('_freshen_index',)
5455

55-
def _freshen_index(self, request, queryset):
56+
def _freshen_index(self, queryset: list[Indexcard]) -> None:
5657
IndexMessenger().notify_indexcard_update(queryset)
57-
_freshen_index.short_description = 'freshen indexcard in search index'
58+
_freshen_index.short_description = 'freshen indexcard in search index' # type: ignore
5859

5960

6061
@admin.register(LatestIndexcardRdf, site=admin_site)
6162
@linked_fk('from_raw_datum')
6263
@linked_fk('indexcard')
63-
class LatestIndexcardRdfAdmin(admin.ModelAdmin):
64+
class LatestIndexcardRdfAdmin(admin.ModelAdmin): #type: ignore
6465
readonly_fields = (
6566
'created',
6667
'modified',
@@ -74,15 +75,15 @@ class LatestIndexcardRdfAdmin(admin.ModelAdmin):
7475
list_select_related = ('indexcard',)
7576
show_full_result_count = False
7677

77-
def rdf_as_turtle__pre(self, instance):
78+
def rdf_as_turtle__pre(self, instance: Any) -> str:
7879
return format_html('<pre>{}</pre>', instance.rdf_as_turtle)
79-
rdf_as_turtle__pre.short_description = 'rdf as turtle'
80+
rdf_as_turtle__pre.short_description = 'rdf as turtle' # type: ignore[attr-defined]
8081

8182

8283
@admin.register(ArchivedIndexcardRdf, site=admin_site)
8384
@linked_fk('from_raw_datum')
8485
@linked_fk('indexcard')
85-
class ArchivedIndexcardRdfAdmin(admin.ModelAdmin):
86+
class ArchivedIndexcardRdfAdmin(admin.ModelAdmin): #type: ignore
8687
readonly_fields = (
8788
'created',
8889
'modified',
@@ -96,16 +97,16 @@ class ArchivedIndexcardRdfAdmin(admin.ModelAdmin):
9697
list_select_related = ('indexcard', 'from_raw_datum',)
9798
show_full_result_count = False
9899

99-
def rdf_as_turtle__pre(self, instance):
100+
def rdf_as_turtle__pre(self, instance: Any) -> str:
100101
return format_html('<pre>{}</pre>', instance.rdf_as_turtle)
101-
rdf_as_turtle__pre.short_description = 'rdf as turtle'
102+
rdf_as_turtle__pre.short_description = 'rdf as turtle' # type: ignore[attr-defined]
102103

103104

104105
@admin.register(SupplementaryIndexcardRdf, site=admin_site)
105106
@linked_fk('from_raw_datum')
106107
@linked_fk('indexcard')
107108
@linked_fk('supplementary_suid')
108-
class SupplementaryIndexcardRdfAdmin(admin.ModelAdmin):
109+
class SupplementaryIndexcardRdfAdmin(admin.ModelAdmin): #type: ignore
109110
readonly_fields = (
110111
'created',
111112
'modified',
@@ -119,15 +120,14 @@ class SupplementaryIndexcardRdfAdmin(admin.ModelAdmin):
119120
list_select_related = ('indexcard', 'from_raw_datum',)
120121
show_full_result_count = False
121122

122-
def rdf_as_turtle__pre(self, instance):
123+
def rdf_as_turtle__pre(self, instance: SupplementaryIndexcardRdf) -> str:
123124
return format_html('<pre>{}</pre>', instance.rdf_as_turtle)
124-
rdf_as_turtle__pre.short_description = 'rdf as turtle'
125-
125+
rdf_as_turtle__pre.short_description = 'rdf as turtle' # type: ignore[attr-defined]
126126

127127
@admin.register(DerivedIndexcard, site=admin_site)
128128
@linked_fk('upriver_indexcard')
129129
@linked_fk('deriver_identifier')
130-
class DerivedIndexcardAdmin(admin.ModelAdmin):
130+
class DerivedIndexcardAdmin(admin.ModelAdmin): #type: ignore
131131
readonly_fields = (
132132
'created',
133133
'modified',

trove/derive/__init__.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from typing import Iterable, Type, Union
12
from . import (
23
sharev2_elastic,
34
osfmap_json,
@@ -16,8 +17,15 @@
1617
# osfmap_jsonld_minimal?
1718
)
1819

20+
DeriverType = Type[
21+
sharev2_elastic.ShareV2ElasticDeriver |
22+
osfmap_json.OsfmapJsonDeriver |
23+
oaidc_xml.OaiDcXmlDeriver
24+
]
1925

20-
def get_deriver_classes(deriver_iri_filter=None):
26+
def get_deriver_classes(
27+
deriver_iri_filter: Iterable[str] | None = None,
28+
) -> Union[list[DeriverType], tuple[DeriverType, ...]]:
2129
if deriver_iri_filter is None:
2230
return DERIVER_SET
2331
return [

trove/derive/_base.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import abc
2+
from typing import Any
23

34
from primitive_metadata import primitive_rdf
45

@@ -15,7 +16,7 @@ def __init__(self, upriver_rdf: IndexcardRdf):
1516
self.focus_iri = upriver_rdf.focus_iri
1617
self.data = upriver_rdf.as_rdfdoc_with_supplements()
1718

18-
def q(self, pathset):
19+
def q(self, pathset: Any) -> Any:
1920
# convenience for querying self.data on self.focus_iri
2021
return self.data.q(self.focus_iri, pathset)
2122

0 commit comments

Comments
 (0)