Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
G
GEOMS2CF
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package Registry
Container Registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
geoms
GEOMS2CF
Commits
d1c50fb3
Commit
d1c50fb3
authored
2 weeks ago
by
Bavo Langerock
Browse files
Options
Downloads
Patches
Plain Diff
added support for PDINST with an InstrumentMetadata class
parent
58cdd44e
No related branches found
Branches containing commit
No related tags found
No related merge requests found
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
doi_classes.py
+55
-9
55 additions, 9 deletions
doi_classes.py
with
55 additions
and
9 deletions
doi_classes.py
+
55
−
9
View file @
d1c50fb3
...
...
@@ -36,13 +36,17 @@ class WIKIDATA_mixin:
@dataclasses.dataclass
class
Identifier
:
value
:
str
itype
:
typing
.
Literal
[
'
DOI
'
]
=
'
DOI
'
#only th
is
value
is
allowed
itype
:
typing
.
Literal
[
'
DOI
'
,
'
Handle
'
]
=
'
DOI
'
#only th
ese
value
s are
allowed
@property
def
xml
(
self
):
return
jinja2
.
Template
(
"""
<identifier identifierType=
"
{{item.itype}}
"
>{{item.value}}</identifier>
"""
).
render
(
item
=
self
)
@property
def
evdc_html
(
self
):
return
jinja2
.
Template
(
"""
<h3>{{item.itype}}</h3><p>{{item.value}}</p>
"""
).
render
(
item
=
self
)
@property
def
url
(
self
):
return
os
.
path
.
join
(
DOIRelationFactory
.
base
,
self
.
value
)
#DOIRelationFactory.base is the https://doi.org/ prefix
def
url
(
self
):
if
self
.
itype
==
'
DOI
'
:
return
os
.
path
.
join
(
DOIRelationFactory
.
base
,
self
.
value
)
#DOIRelationFactory.base is the https://doi.org/ prefix
elif
self
.
itype
==
'
Handle
'
:
return
os
.
path
.
join
(
'
https://hdl.handle.net
'
,
self
.
value
)
@property
def
json
(
self
):
return
{
"
identifierValue
"
:
self
.
url
,
"
identifierType
"
:
self
.
itype
}
########
# Dates https://datacite-metadata-schema.readthedocs.io/en/4.5/properties/date/
########
...
...
@@ -58,6 +62,8 @@ class DateTime:
def
html_paragraph
(
self
):
return
jinja2
.
Template
(
"""
<p>{{item.role}}: {{item.value.strftime(item.ISO8601)}}</p>
"""
).
render
(
item
=
self
)
@property
def
djson
(
self
):
return
{
'
date
'
:
self
.
value
.
strftime
(
self
.
ISO8601
),
'
dateType
'
:
self
.
role
,
'
dateInformation
'
:
None
}
@property
def
pjson
(
self
):
out
=
self
.
djson
;
out
.
pop
(
'
dateInformation
'
);
return
out
@classmethod
def
from_djson
(
cls
,
js
:
dict
):
return
cls
(
value
=
dt
.
datetime
.
fromisoformat
(
js
[
'
date
'
]),
role
=
js
[
'
dateType
'
])
...
...
@@ -105,14 +111,23 @@ class Organisation:
if
self
.
Scheme
:
return
f
"
<
{
xtype
}
{
xtype
}
Identifier=
\"
{
self
.
identifier
}
\"
{
xtype
}
IdentifierScheme=
\"
{
self
.
Scheme
}
\"
schemeURI=
\"
{
self
.
schemeURI
}
\"
>
{
self
.
name
}
</
{
xtype
}
>
"
else
:
return
f
"
<
{
xtype
}
>
{
self
.
name
}
</
{
xtype
}
>
"
#datacite
@property
def
djson
(
self
):
return
{
'
name
'
:
self
.
name
,
'
affiliationIdentifier
'
:
self
.
identifier
,
'
affiliationIdentifierScheme
'
:
self
.
Scheme
,
'
schemeURI
'
:
self
.
schemeURI
}
if
self
.
identifier
else
self
.
name
@property
def
publisher_djson
(
self
):
return
{
"
name
"
:
self
.
name
,
"
publisherIdentifier
"
:
self
.
identifier
,
"
publisherIdentifierScheme
"
:
self
.
Scheme
,
"
schemeUri
"
:
self
.
schemeURI
}
if
self
.
identifier
else
self
.
name
#pdinst
def
_pdinst
(
self
,
t
:
str
)
->
dict
:
return
{
f
"
{
t
}
Name
"
:
self
.
name
,
f
"
{
t
}
Identifier
"
:
{
f
"
{
t
}
IdentifierValue
"
:
self
.
identifier
.
removeprefix
(
self
.
schemeURI
).
strip
(
'
/
'
),
f
"
{
t
}
IdentifierType
"
:
self
.
Scheme
}}
if
self
.
identifier
else
{
f
"
{
t
}
Name
"
:
self
.
name
}
@property
def
owner_pjson
(
self
):
return
self
.
_pdinst
(
'
owner
'
)
@property
def
manufacturer_pjson
(
self
):
return
self
.
_pdinst
(
'
manufacturer
'
)
#datacite xml
@property
def
affiliation_xml
(
self
):
return
self
.
_xml
(
'
affiliation
'
)
@property
def
publisher_xml
(
self
):
return
self
.
_xml
(
'
publisher
'
)
#html
@property
def
logo_html
(
self
):
return
jinja2
.
Template
(
"""
{% if item.logo_url %}{% if item.home_url %}<a href=
"
{{item.home_url}}
"
>{% endif %}<img src=
"
{{item.logo_url}}
"
alt=
"
{{item.shortname}} Logo
"
height=
"
200
"
>{% if item.home_url %}</a>{% endif %}{% endif %}
"""
).
render
(
item
=
self
)
@property
...
...
@@ -267,6 +282,10 @@ class Subject: #abstract class ... GND, DDC and WIKIDATASubject can be used
return
jinja2
.
Template
(
"""
<p>{% if item.valueURI|length %} <a href=
"
{{item.valueURI}}
"
>{{item.Scheme}} {{item.value}}</a>{% else %}{{item.Scheme}} {{item.value}}{% endif %}</p>
"""
).
render
(
item
=
self
)
@property
def
djson
(
self
):
return
{
'
subject
'
:
self
.
value
,
'
subjectScheme
'
:
self
.
Scheme
,
'
schemeUri
'
:
self
.
schemeURI
,
'
lang
'
:
self
.
lang
}
def
pjson
(
self
,
ptype
=
'
instrumentType
'
):
out
=
{
f
"
{
ptype
}
Name
"
:
self
.
value
}
if
self
.
valueURI
:
out
[
f
"
{
ptype
}
Identifier
"
]
=
{
f
"
{
ptype
}
IdentifierValue
"
:
self
.
valueURI
,
f
"
{
ptype
}
IdentifierType
"
:
"
URL
"
}
return
out
@property
def
tag
(
self
):
return
self
.
alias
or
self
.
value
.
split
(
None
,
1
)[
-
1
]
...
...
@@ -284,6 +303,7 @@ class WIKIDATASubject(WIKIDATA_mixin,Subject):
"""
here we can calculate the valueURI
"""
super
().
__init__
(
*
args
,
**
kargs
)
self
.
valueURI
=
os
.
path
.
join
(
self
.
schemeURI
,
self
.
value
.
split
()[
0
])
def
pjson
(
self
,
ptype
):
out
=
super
().
pjson
(
ptype
);
out
[
f
"
{
ptype
}
Name
"
]
=
self
.
value
.
split
(
None
,
1
)[
-
1
];
return
out
class
SubjectsFactory
:
"""
definitions is a dict eg REMOTE.SENSING:(Subject1,Subject2,...)
...
...
@@ -509,23 +529,23 @@ class Metadata:
#sort contributors
ordering
=
typing
.
get_args
({
fi
.
name
:
fi
.
type
for
fi
in
dataclasses
.
fields
(
Person
)
if
fi
.
name
==
'
role
'
}.
pop
(
'
role
'
))
self
.
contributors
=
tuple
(
sorted
(
self
.
contributors
,
key
=
lambda
c
:
ordering
.
index
(
c
.
role
)))
def
is_completed
(
self
):
return
bool
(
self
.
identifier
is
not
None
and
self
.
publisher
is
not
None
and
self
.
publicationyear
>
1900
)
def
is_completed
(
self
):
return
bool
(
self
.
identifier
is
not
None
and
self
.
publisher
is
not
None
and
self
.
publicationyear
>
1900
)
def
merge_with_existing_metadata
(
self
,
old_metadata
:
dict
=
{}):
"""
old_metadata is a json output of api.datacite
"""
if
not
old_metadata
:
old_metadata
=
DataCiteAPI
.
get_registered_metadata
(
self
.
identifier
.
value
)
dates
=
tuple
(
Date
.
from_djson
(
djson
)
for
djson
in
old_metadata
[
'
data
'
][
'
attributes
'
].
get
(
'
dates
'
,[]))
specialdates
=
{
d
.
role
:
d
for
d
in
dates
if
d
.
role
in
(
'
Issued
'
,)}
self
.
dates
=
tuple
(
specialdates
.
get
(
nd
.
role
,
nd
)
for
nd
in
self
.
dates
)
#do not change the Issued date
@property
@check_completed
def
prefix
(
self
):
return
self
.
identifier
.
value
.
split
(
'
/
'
,
1
)[
0
]
@property
@check_completed
def
suffix
(
self
):
cs
=
self
.
identifier
.
value
.
split
(
'
/
'
,
1
);
return
(
''
if
len
(
cs
)
==
1
else
cs
[
-
1
])
@property
def
principal_investigator
(
self
):
for
p
in
self
.
contributors
:
...
...
@@ -652,7 +672,32 @@ class Metadata:
if
self
.
suffix
:
payload
[
'
data
'
][
'
attributes
'
].
update
(
doi
=
self
.
identifier
.
value
)
return
payload
@dataclasses.dataclass
class
InstrumentMetadata
:
identifier
:
Identifier
name
:
str
owners
:
tuple
[
Organisation
,...]
manufacturers
:
tuple
[
Organisation
,...]
model
:
Subject
dates
:
tuple
[
Date
,...]
serial
:
str
instrument_types
:
tuple
[
Subject
,...]
landingpage
:
str
=
''
def
to_pdinst_json
(
self
):
return
{
"
SchemaVersion
"
:
"
1.0
"
,
"
LandingPage
"
:
self
.
landingpage
,
"
Name
"
:
self
.
name
,
"
Owners
"
:
[{
'
owner
'
:
o
.
owner_pjson
}
for
o
in
self
.
owners
],
"
Manufacturers
"
:
[{
'
manufacturer
'
:
m
.
manufacturer_pjson
}
for
m
in
self
.
manufacturers
],
"
Model
"
:
self
.
model
.
pjson
(
'
model
'
),
"
Identifier
"
:
self
.
identifier
.
json
,
#"Description": "Placed on the North side of the Remote sensing site at 1m elevation",
"
InstrumentType
"
:
[{
'
instrumentType
'
:
i
.
pjson
(
'
instrumentType
'
)}
for
i
in
self
.
instrument_types
],
#"MeasuredVariables": [{"measuredVariable": {"variableMeasured": "precipitation intensity"}}, {"measuredVariable": {"variableMeasured": "drop size distribution"}}],
"
Dates
"
:
[{
"
date
"
:
d
.
pjson
}
for
d
in
self
.
dates
],
"
AlternateIdentifiers
"
:
[{
"
alternateIdentifier
"
:
{
"
alternateIdentifierValue
"
:
self
.
serial
,
"
alternateIdentifierType
"
:
"
SerialNumber
"
}}]}
@dataclasses.dataclass
class
DataCiteAPI
:
"""
DataCite API wrapper: implements some methods from https://support.datacite.org/reference/post_dois
...
...
@@ -672,7 +717,7 @@ class DataCiteAPI:
def
authorization
(
self
):
return
(
self
.
username
,
self
.
password
)
@property
def
headers
(
self
):
return
{
"
content-type
"
:
"
application/json
"
,
"
accept
"
:
"
application/vnd.api+json
"
}
@classmethod
def
get_registered_metadata
(
cls
,
doi
:
str
)
->
dict
:
return
requests
.
get
(
cls
.
api_url
+
'
/
'
+
doi
).
json
()
...
...
@@ -715,3 +760,4 @@ class DataCiteAPI:
payload
=
{
"
data
"
:
{
'
type
'
:
"
dois
"
,
'
attributes
'
:{
'
url
'
:
landingpage
,
'
doi
'
:
ids
}}}
return
requests
.
put
(
url
,
json
=
payload
,
headers
=
self
.
headers
,
auth
=
self
.
authorization
)
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment