Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
beat.editor
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Model registry
Operate
Environments
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
beat
beat.editor
Commits
ff9e8660
Commit
ff9e8660
authored
6 years ago
by
Samuel GAIST
Browse files
Options
Downloads
Patches
Plain Diff
[cleanup] Removed resources.py as not used anymore
parent
f4b8a049
No related branches found
No related tags found
No related merge requests found
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
beat/editor/resources.py
+0
-373
0 additions, 373 deletions
beat/editor/resources.py
beat/editor/test/test_resources.py
+0
-62
0 additions, 62 deletions
beat/editor/test/test_resources.py
with
0 additions
and
435 deletions
beat/editor/resources.py
deleted
100644 → 0
+
0
−
373
View file @
f4b8a049
#!/usr/bin/env python
# -*- coding: utf-8 -*-
###############################################################################
# #
# Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ #
# Contact: beat.support@idiap.ch #
# #
# This file is part of the beat.editor module of the BEAT platform. #
# #
# Commercial License Usage #
# Licensees holding valid commercial BEAT licenses may use this file in #
# accordance with the terms contained in a written agreement between you #
# and Idiap. For further information contact tto@idiap.ch #
# #
# Alternatively, this file may be used under the terms of the GNU Affero #
# Public License version 3 as published by the Free Software and appearing #
# in the file LICENSE.AGPL included in the packaging of this file. #
# The BEAT platform is distributed in the hope that it will be useful, but #
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY #
# or FITNESS FOR A PARTICULAR PURPOSE. #
# #
# You should have received a copy of the GNU Affero Public License along #
# with the BEAT platform. If not, see http://www.gnu.org/licenses/. #
# #
###############################################################################
'''
Server resources (API endpoints)
'''
import
os
import
glob
import
shutil
import
subprocess
import
simplejson
from
flask
import
request
from
flask_restful
import
Resource
import
logging
logger
=
logging
.
getLogger
(
__name__
)
from
.
import
utils
from
beat.core.dock
import
Host
from
beat.core.environments
import
enumerate_packages
def
make_error
(
status_code
,
message
):
"""
Overrides flask-restful
'
s response handling to return a custom error message
Adapted from https://stackoverflow.com/a/21639552
Parameters:
status_code (int): The HTTP status code to return
message (str): The error message text to return
"""
response
=
simplejson
.
dumps
({
'
status
'
:
status_code
,
'
message
'
:
message
})
response
.
status_code
=
status_code
return
response
class
Layout
(
Resource
):
"""
Exposes toolchain layout functionality
"""
def
__init__
(
self
,
config
):
self
.
config
=
config
def
post
(
self
):
data
=
request
.
get_json
()
if
data
!=
None
and
'
toolchain
'
in
data
:
from
beat.core.toolchain
import
Toolchain
obj
=
Toolchain
(
self
.
config
.
path
,
data
[
'
toolchain
'
])
diagram
=
obj
.
dot_diagram
(
is_layout
=
True
)
diagram
.
format
=
'
json
'
return
diagram
.
pipe
().
decode
()
else
:
raise
RuntimeError
(
'
Invalid post content for tc layout!
'
)
class
Environments
(
Resource
):
"""
Exposes local environment info
"""
def
get
(
self
):
"""
Uses beat.core to get the local environment (docker) information
and returns a list of environments
"""
host
=
Host
(
raise_on_errors
=
False
)
envs
=
host
.
processing_environments
for
env
in
envs
.
keys
():
envs
[
env
][
'
queues
'
]
=
{}
try
:
envs
[
env
][
'
packages
'
]
=
enumerate_packages
(
host
,
env
)
except
:
envs
[
env
][
'
packages
'
]
=
[]
return
envs
class
Templates
(
Resource
):
"""
Endpoint for generating template files
"""
def
__init__
(
self
,
config
):
self
.
config
=
config
def
post
(
self
):
data
=
request
.
get_json
()
entity
=
data
.
pop
(
'
entity
'
)
name
=
data
.
pop
(
'
name
'
)
confirm
=
data
.
pop
(
'
confirm
'
)
utils
.
generate_python_template
(
entity
,
name
,
confirm
,
self
.
config
,
**
data
)
class
Settings
(
Resource
):
"""
Exposes the prefix
"""
def
__init__
(
self
,
config
):
self
.
config
=
config
def
get
(
self
):
"""
Uses beat.cmdline to get the prefix
"""
return
{
'
prefix
'
:
self
.
config
.
path
}
def
path_to_dict
(
path
):
"""
Generates a dict of the given file/folder in the BEAT prefix
"""
d
=
dict
(
name
=
os
.
path
.
basename
(
path
))
if
os
.
path
.
isdir
(
path
):
d
[
'
type
'
]
=
"
directory
"
d
[
'
children
'
]
=
[
path_to_dict
(
os
.
path
.
join
(
path
,
x
))
for
x
in
os
.
listdir
(
path
)]
elif
os
.
path
.
isfile
(
path
):
d
[
'
type
'
]
=
"
file
"
fname
,
fext
=
os
.
path
.
splitext
(
path
)
if
fext
==
'
.json
'
:
with
open
(
path
,
'
rt
'
)
as
f
:
d
[
'
json
'
]
=
simplejson
.
loads
(
f
.
read
())
return
d
VALID_ENTITIES
=
[
'
dataformats
'
,
'
databases
'
,
'
libraries
'
,
'
algorithms
'
,
'
toolchains
'
,
'
experiments
'
,
'
plotters
'
,
'
plotterparameters
'
,
]
"""
List of valid BEAT object entitities
"""
def
assert_valid_entity
(
v
):
"""
Asserts the passed value corresponds to a valid BEAT entity
"""
assert
v
in
VALID_ENTITIES
,
'
%s is not a valid BEAT entity
'
\
'
(valid values are %s)
'
%
(
v
,
'
,
'
.
join
(
VALID_ENTITIES
))
def
generate_file_tree
(
entity
,
config
):
"""
Generates a file tree (of dicts) given a specific BEAT entity
"""
assert_valid_entity
(
entity
)
resource_path
=
os
.
path
.
join
(
config
.
path
,
entity
)
if
not
os
.
path
.
isdir
(
resource_path
):
raise
IOError
(
'
Invalid resource path %s
'
%
resource_path
)
return
path_to_dict
(
resource_path
)
def
generate_json_entity
(
fto
,
parent_names
):
"""
Generates info for a file in the BEAT path
"""
if
fto
[
'
type
'
]
!=
'
file
'
:
raise
Exception
(
'
bad file tree obj
'
)
fname
,
fext
=
os
.
path
.
splitext
(
fto
[
'
name
'
])
name_str
=
''
for
name
in
parent_names
:
name_str
+=
name
+
'
/
'
name_str
+=
fname
return
{
'
name
'
:
name_str
,
'
contents
'
:
fto
[
'
json
'
]
}
def
generate_entity_tree
(
entity
,
config
):
"""
Generates the entire tree for an entity type from the prefix
"""
file_tree
=
generate_file_tree
(
entity
,
config
)
entity_tree
=
{}
user_and_name
=
[
'
dataformats
'
,
'
libraries
'
,
'
algorithms
'
,
'
toolchains
'
,
'
plotters
'
,
'
plotterparameters
'
,
]
if
entity
in
user_and_name
:
for
user
in
file_tree
[
'
children
'
]:
entity_tree
[
user
[
'
name
'
]]
=
{}
for
obj
in
user
[
'
children
'
]:
entity_tree
[
user
[
'
name
'
]][
obj
[
'
name
'
]]
=
list
()
for
f
in
obj
[
'
children
'
]:
fname
,
fext
=
os
.
path
.
splitext
(
f
[
'
name
'
])
if
fext
!=
'
.json
'
:
continue
parent_names
=
[
user
[
'
name
'
],
obj
[
'
name
'
]]
json_obj
=
generate_json_entity
(
f
,
parent_names
)
entity_tree
[
user
[
'
name
'
]][
obj
[
'
name
'
]].
append
(
json_obj
)
elif
entity
==
'
databases
'
:
for
obj
in
file_tree
[
'
children
'
]:
entity_tree
[
obj
[
'
name
'
]]
=
list
()
for
f
in
obj
[
'
children
'
]:
fname
,
fext
=
os
.
path
.
splitext
(
f
[
'
name
'
])
if
fext
!=
'
.json
'
:
continue
parent_names
=
[
obj
[
'
name
'
]]
json_obj
=
generate_json_entity
(
f
,
parent_names
)
entity_tree
[
obj
[
'
name
'
]].
append
(
json_obj
)
elif
entity
==
'
experiments
'
:
for
user
in
file_tree
[
'
children
'
]:
uname
=
user
[
'
name
'
]
entity_tree
[
uname
]
=
{}
for
tc_user
in
user
[
'
children
'
]:
tcuname
=
tc_user
[
'
name
'
]
entity_tree
[
uname
][
tcuname
]
=
{}
for
tc_name
in
tc_user
[
'
children
'
]:
tcname
=
tc_name
[
'
name
'
]
entity_tree
[
uname
][
tcuname
][
tcname
]
=
{}
for
tc_version
in
tc_name
[
'
children
'
]:
tcv
=
tc_version
[
'
name
'
]
entity_tree
[
uname
][
tcuname
][
tcname
][
tcv
]
=
list
()
for
exp_name
in
tc_version
[
'
children
'
]:
fname
,
fext
=
os
.
path
.
splitext
(
exp_name
[
'
name
'
])
if
fext
!=
'
.json
'
:
continue
parent_names
=
[
uname
,
tcuname
,
tcname
,
tcv
]
json_obj
=
generate_json_entity
(
exp_name
,
parent_names
)
entity_tree
[
uname
][
tcuname
][
tcname
][
tcv
].
append
(
json_obj
)
return
entity_tree
def
write_json
(
config
,
entity
,
obj
,
mode
,
copy_obj_name
=
''
):
"""
Writes JSON from a webapp request to the prefix using the specified
mode
"""
assert_valid_entity
(
entity
)
resource_path
=
os
.
path
.
join
(
config
.
path
,
entity
)
name
=
obj
[
'
name
'
]
name_segs
=
name
.
split
(
'
/
'
)
contents
=
obj
[
'
contents
'
]
stringified
=
simplejson
.
dumps
(
contents
,
indent
=
4
,
sort_keys
=
True
)
folder_path
=
os
.
path
.
join
(
resource_path
,
'
/
'
.
join
(
name_segs
[:
-
1
]))
file_subpath
=
os
.
path
.
join
(
resource_path
,
name
)
file_path
=
file_subpath
+
'
.json
'
if
mode
==
'
update
'
:
os
.
makedirs
(
folder_path
,
exist_ok
=
True
)
with
open
(
file_path
,
'
w
'
)
as
f
:
f
.
write
(
stringified
)
elif
mode
==
'
create
'
:
if
not
os
.
path
.
isfile
(
file_path
):
os
.
makedirs
(
folder_path
,
exist_ok
=
True
)
if
copy_obj_name
!=
''
:
copy_obj_path
=
os
.
path
.
join
(
resource_path
,
copy_obj_name
)
if
os
.
path
.
isfile
(
copy_obj_path
+
'
.json
'
):
files_to_copy
=
glob
.
glob
(
'
%s.*
'
%
copy_obj_path
)
copy_locations
=
[
'
%s%s
'
%
(
file_subpath
,
os
.
path
.
splitext
(
f
)[
1
])
for
f
in
files_to_copy
]
for
i
in
range
(
0
,
len
(
files_to_copy
)):
if
files_to_copy
[
i
].
endswith
(
'
.json
'
):
continue
shutil
.
copy
(
files_to_copy
[
i
],
copy_locations
[
i
])
with
open
(
file_path
,
'
w
'
)
as
f
:
f
.
write
(
stringified
)
elif
mode
==
'
delete
'
:
if
os
.
path
.
isfile
(
file_path
):
files_to_delete
=
glob
.
glob
(
'
%s.*
'
%
file_subpath
)
for
f
in
files_to_delete
:
os
.
remove
(
f
)
# taken from https://stackoverflow.com/a/23488980
def
remove_empty_dirs
(
path
):
"""
Remove empty directories recursively
"""
for
root
,
dirnames
,
filenames
in
os
.
walk
(
path
,
topdown
=
False
):
for
dirname
in
dirnames
:
remove_empty_dirs
(
os
.
path
.
realpath
(
os
.
path
.
join
(
root
,
dirname
)
)
)
if
not
os
.
listdir
(
path
):
os
.
rmdir
(
path
)
remove_empty_dirs
(
folder_path
)
else
:
raise
ValueError
(
'
Invalid write-mode `%s
\'
'
%
mode
)
def
gen_endpoint
(
entity
):
"""
Generates an endpoint for the given BEAT entity
Exposes actions to perform on the prefix
"""
class
Endpoint
(
Resource
):
"""
A class representing the template for an endpoint for a BEAT entity
"""
def
__init__
(
self
,
config
):
self
.
config
=
config
def
refresh
(
self
):
"""
Regenerates the entity tree
"""
try
:
return
generate_entity_tree
(
entity
,
self
.
config
)
except
IOError
:
return
[]
def
get
(
self
):
"""
Returns the entity tree
"""
return
self
.
refresh
()
def
post
(
self
):
"""
Creates a new object
"""
obj_list
=
request
.
get_json
()
if
not
isinstance
(
obj_list
,
list
):
obj_list
=
[
obj_list
]
for
o
in
obj_list
:
# two fields:
# - "obj" field (the object to create)
# - "copyObjName" field (the object that was copied, blank if
# not copied)
obj
=
o
[
'
obj
'
]
copy_obj_name
=
o
[
'
copiedObjName
'
]
write_json
(
self
.
config
,
entity
,
obj
,
'
create
'
,
copy_obj_name
)
return
self
.
refresh
()
def
put
(
self
):
"""
Updates an already-existing object
"""
obj_list
=
request
.
get_json
()
if
not
isinstance
(
obj_list
,
list
):
obj_list
=
[
obj_list
]
for
obj
in
obj_list
:
write_json
(
self
.
config
,
entity
,
obj
,
'
update
'
)
return
self
.
refresh
()
def
delete
(
self
):
"""
Deletes an object
"""
obj
=
request
.
get_json
()
write_json
(
self
.
config
,
entity
,
obj
,
'
delete
'
)
return
self
.
refresh
()
Endpoint
.
__name__
=
entity
return
Endpoint
This diff is collapsed.
Click to expand it.
beat/editor/test/test_resources.py
deleted
100644 → 0
+
0
−
62
View file @
f4b8a049
#!/usr/bin/env python
# vim: set fileencoding=utf-8 :
###############################################################################
# #
# Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ #
# Contact: beat.support@idiap.ch #
# #
# This file is part of the beat.cmdline module of the BEAT platform. #
# #
# Commercial License Usage #
# Licensees holding valid commercial BEAT licenses may use this file in #
# accordance with the terms contained in a written agreement between you #
# and Idiap. For further information contact tto@idiap.ch #
# #
# Alternatively, this file may be used under the terms of the GNU Affero #
# Public License version 3 as published by the Free Software and appearing #
# in the file LICENSE.AGPL included in the packaging of this file. #
# The BEAT platform is distributed in the hope that it will be useful, but #
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY #
# or FITNESS FOR A PARTICULAR PURPOSE. #
# #
# You should have received a copy of the GNU Affero Public License along #
# with the BEAT platform. If not, see http://www.gnu.org/licenses/. #
# #
###############################################################################
# test the resources.py file
# (mostly endpoints and working with the filesystem)
import
nose.tools
import
os
from
..
import
resources
# the func names the endpoint the given name
def
test_check_valid_generated_endpoint_name
():
name
=
'
TestEndpoint
'
endpoint
=
resources
.
gen_endpoint
(
name
)
nose
.
tools
.
eq_
(
endpoint
.
__name__
,
name
)
# the func doesnt accept non-entity names
@nose.tools.raises
(
AssertionError
)
def
test_assert_valid_entity_invalid
():
resources
.
assert_valid_entity
(
'
notanentity
'
)
# the func parses this file
def
test_path_to_dict_file
():
currfile
=
os
.
path
.
realpath
(
__file__
)
res
=
resources
.
path_to_dict
(
currfile
)
# in python 3 the first case works but in python 2 the second case works
assert
res
==
{
'
name
'
:
'
test_resources.py
'
,
'
type
'
:
'
file
'
}
or
res
==
{
'
name
'
:
'
test_resources.pyc
'
,
'
type
'
:
'
file
'
}
# the func parses this folder
def
test_path_to_dict_folder
():
currfolder
=
os
.
path
.
dirname
(
os
.
path
.
realpath
(
__file__
))
res
=
resources
.
path_to_dict
(
currfolder
)
nose
.
tools
.
eq_
(
res
[
'
name
'
],
'
test
'
)
nose
.
tools
.
eq_
(
res
[
'
type
'
],
'
directory
'
)
nose
.
tools
.
ok_
({
'
name
'
:
'
__init__.py
'
,
'
type
'
:
'
file
'
}
in
res
[
'
children
'
])
nose
.
tools
.
ok_
({
'
name
'
:
'
test_resources.py
'
,
'
type
'
:
'
file
'
}
in
res
[
'
children
'
])
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