Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
nomad-FAIR
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
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
Service Desk
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
nomad-lab
nomad-FAIR
Commits
e2d16c2e
Commit
e2d16c2e
authored
5 years ago
by
Alvin Noe Ladines
Browse files
Options
Downloads
Patches
Plain Diff
Implemented building of python code snippets in archive and repo
parent
3f98dac7
No related branches found
No related tags found
1 merge request
!79
Release v0.7.2
Pipeline
#67142
failed
5 years ago
Stage: build
Stage: test
Stage: release
Changes
4
Pipelines
1
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
nomad/app/api/archive.py
+16
-3
16 additions, 3 deletions
nomad/app/api/archive.py
nomad/app/api/common.py
+41
-1
41 additions, 1 deletion
nomad/app/api/common.py
nomad/app/api/repo.py
+8
-1
8 additions, 1 deletion
nomad/app/api/repo.py
tests/app/test_api.py
+18
-0
18 additions, 0 deletions
tests/app/test_api.py
with
83 additions
and
5 deletions
nomad/app/api/archive.py
+
16
−
3
View file @
e2d16c2e
...
...
@@ -33,7 +33,7 @@ from nomad import utils, search
from
.auth
import
authenticate
,
create_authorization_predicate
from
.api
import
api
from
.repo
import
search_request_parser
,
add_query
from
.common
import
calc_route
,
streamed_zipfile
from
.common
import
calc_route
,
streamed_zipfile
,
build_snippet
,
to_json
ns
=
api
.
namespace
(
'
archive
'
,
...
...
@@ -112,6 +112,10 @@ archives_from_query_parser = search_request_parser.copy()
archives_from_query_parser
.
add_argument
(
name
=
'
compress
'
,
type
=
bool
,
help
=
'
Use compression on .zip files, default is not.
'
,
location
=
'
args
'
)
archives_from_query_parser
.
add_argument
(
name
=
'
res_type
'
,
type
=
str
,
help
=
'
Type of return value, can be zip of json.
'
,
location
=
'
args
'
)
@ns.route
(
'
/query
'
)
...
...
@@ -138,6 +142,7 @@ class ArchiveQueryResource(Resource):
try
:
args
=
archives_from_query_parser
.
parse_args
()
compress
=
args
.
get
(
'
compress
'
,
False
)
res_type
=
args
.
get
(
'
res_type
'
,
'
zip
'
)
except
Exception
:
abort
(
400
,
message
=
'
bad parameter types
'
)
...
...
@@ -192,8 +197,16 @@ class ArchiveQueryResource(Resource):
lambda
*
args
:
BytesIO
(
manifest_contents
),
lambda
*
args
:
len
(
manifest_contents
))
if
res_type
==
'
zip
'
:
return
streamed_zipfile
(
generator
(),
zipfile_name
=
'
nomad_archive.zip
'
,
compress
=
compress
)
elif
res_type
==
'
json
'
:
archive_data
=
to_json
(
generator
())
code_snippet
=
build_snippet
(
args
,
os
.
path
.
join
(
api
.
base_url
,
ns
.
name
,
'
query
'
))
data
=
{
'
archive_data
'
:
archive_data
,
'
code_snippet
'
:
code_snippet
}
return
data
,
200
else
:
raise
Exception
(
'
Unknown res_type %s
'
%
res_type
)
@ns.route
(
'
/metainfo/<string:metainfo_package_name>
'
)
...
...
This diff is collapsed.
Click to expand it.
nomad/app/api/common.py
+
41
−
1
View file @
e2d16c2e
...
...
@@ -16,10 +16,11 @@
Common data, variables, decorators, models used throughout the API.
"""
from
typing
import
Callable
,
IO
,
Set
,
Tuple
,
Iterable
from
flask_restplus
import
fields
from
flask_restplus
import
fields
,
abort
import
zipstream
from
flask
import
stream_with_context
,
Response
import
sys
import
json
from
nomad.app.utils
import
RFC3339DateTime
from
nomad.files
import
Restricted
...
...
@@ -153,3 +154,42 @@ def streamed_zipfile(
response
=
Response
(
stream_with_context
(
generator
()),
mimetype
=
'
application/zip
'
)
response
.
headers
[
'
Content-Disposition
'
]
=
'
attachment; filename={}
'
.
format
(
zipfile_name
)
return
response
def
to_json
(
files
:
Iterable
[
Tuple
[
str
,
str
,
Callable
[[
str
],
IO
],
Callable
[[
str
],
int
]]]):
data
=
{}
for
_
,
file_id
,
open_io
,
_
in
files
:
try
:
f
=
open_io
(
file_id
)
data
[
file_id
]
=
json
.
loads
(
f
.
read
())
except
KeyError
:
pass
except
Restricted
:
abort
(
401
,
message
=
'
Not authorized to access %s.
'
%
file_id
)
return
data
def
build_snippet
(
args
,
base_url
):
str_code
=
'
import requests
\n
'
str_code
+=
'
from urllib.parse import urlencode
\n
'
str_code
+=
'
\n\n
'
str_code
+=
'
def query_repository(args, base_url):
\n
'
str_code
+=
'
url =
"
%s?%s
"
% (base_url, urlencode(args))
\n
'
str_code
+=
'
response = requests.get(url)
\n
'
str_code
+=
'
if response.status_code != 200:
\n
'
str_code
+=
'
raise Exception(
"
nomad return status %d
"
% response.status_code)
\n
'
str_code
+=
'
return response.json()
\n
'
str_code
+=
'
\n\n
'
str_code
+=
'
args = {
'
for
key
,
val
in
args
.
items
():
if
val
is
None
:
continue
if
isinstance
(
val
,
str
):
str_code
+=
'"
%s
"
:
"
%s
"
,
'
%
(
key
,
val
)
else
:
str_code
+=
'"
%s
"
: %s,
'
%
(
key
,
val
)
str_code
+=
'
}
\n
'
str_code
+=
'
base_url =
"
%s
"
\n
'
%
base_url
str_code
+=
'
JSON_DATA = query_repository(args, base_url)
\n
'
return
str_code
This diff is collapsed.
Click to expand it.
nomad/app/api/repo.py
+
8
−
1
View file @
e2d16c2e
...
...
@@ -24,6 +24,7 @@ from elasticsearch_dsl import Q
from
elasticsearch.exceptions
import
NotFoundError
import
elasticsearch.helpers
from
datetime
import
datetime
import
os.path
from
nomad
import
search
,
utils
,
datamodel
,
processing
as
proc
,
infrastructure
from
nomad.app.utils
import
rfc3339DateTime
,
RFC3339DateTime
,
with_logger
...
...
@@ -32,7 +33,7 @@ from nomad.datamodel import UserMetadata, Dataset, User
from
.api
import
api
from
.auth
import
authenticate
from
.common
import
pagination_model
,
pagination_request_parser
,
calc_route
from
.common
import
pagination_model
,
pagination_request_parser
,
calc_route
,
build_snippet
ns
=
api
.
namespace
(
'
repo
'
,
description
=
'
Access repository metadata.
'
)
...
...
@@ -80,6 +81,8 @@ repo_calcs_model_fields = {
'
value and quantity value as key. The possible metrics are code runs(calcs), %s.
'
'
There is a pseudo quantity
"
total
"
with a single value
"
all
"
that contains the
'
'
metrics over all results.
'
%
'
,
'
.
join
(
datamodel
.
Domain
.
instance
.
metrics_names
))),
'
code_snippet
'
:
fields
.
String
(
description
=
(
'
A string of python code snippet which can be executed to reproduce the api result.
'
)),
}
for
group_name
,
(
group_quantity
,
_
)
in
search
.
groups
.
items
():
repo_calcs_model_fields
[
group_name
]
=
fields
.
Nested
(
api
.
model
(
'
RepoDatasets
'
,
{
...
...
@@ -300,6 +303,10 @@ class RepoCalcsResource(Resource):
if
args
.
get
(
group_name
,
False
):
results
[
group_name
]
=
quantities
[
group_quantity
]
# build python code snippet
snippet
=
build_snippet
(
args
,
os
.
path
.
join
(
api
.
base_url
,
ns
.
name
,
''
))
results
[
'
code_snippet
'
]
=
snippet
return
results
,
200
except
search
.
ScrollIdNotFound
:
abort
(
400
,
'
The given scroll_id does not exist.
'
)
...
...
This diff is collapsed.
Click to expand it.
tests/app/test_api.py
+
18
−
0
View file @
e2d16c2e
...
...
@@ -667,6 +667,16 @@ class TestArchive(UploadFilesBasedTests):
assert
rv
.
status_code
==
200
assert_zip_file
(
rv
,
files
=
1
)
def
test_code_snippet
(
self
,
api
,
processeds
,
test_user_auth
):
query_params
=
{
'
atoms
'
:
'
Si
'
,
'
res_type
'
:
'
json
'
}
url
=
'
/archive/query?%s
'
%
urlencode
(
query_params
)
rv
=
api
.
get
(
url
,
headers
=
test_user_auth
)
assert
rv
.
status_code
==
200
data
=
json
.
loads
(
rv
.
data
)
assert
isinstance
(
data
,
dict
)
assert
data
[
'
code_snippet
'
]
is
not
None
class
TestRepo
():
@pytest.fixture
(
scope
=
'
class
'
)
...
...
@@ -1058,6 +1068,14 @@ class TestRepo():
data
=
json
.
loads
(
rv
.
data
)
assert
data
[
'
pagination
'
][
'
total
'
]
>
0
def
test_code_snippet
(
self
,
api
,
example_elastic_calcs
,
test_user_auth
):
rv
=
api
.
get
(
'
/repo/?per_page=10
'
,
headers
=
test_user_auth
)
assert
rv
.
status_code
==
200
data
=
json
.
loads
(
rv
.
data
)
assert
data
[
'
code_snippet
'
]
is
not
None
# exec does not seem to work
# exec(data['code_snippet'])
class
TestEditRepo
():
...
...
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