Mentions légales du service
Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
python_client
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
Model registry
Operate
Environments
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
allgo
API-Clients
python_client
Commits
8da0bdb7
Commit
8da0bdb7
authored
5 years ago
by
LETORT Sebastien
Browse files
Options
Downloads
Patches
Plain Diff
Major update, the client has been rewritten.
parent
fc55d0dd
Branches
Branches containing commit
No related tags found
1 merge request
!4
Client api
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
allgo/__init__.py
+184
-87
184 additions, 87 deletions
allgo/__init__.py
setup.py
+9
-7
9 additions, 7 deletions
setup.py
with
193 additions
and
94 deletions
allgo/__init__.py
+
184
−
87
View file @
8da0bdb7
#! /usr/bin/env python
# -*- coding: utf-8 -*-
"""
Python client for the Allgo API.
This module provides a class that simplify the use of the Allgo API
"""
# standard libs
import
logging
import
os
import
time
try
:
from
urllib.parse
import
urlparse
,
urlencode
from
urllib.request
import
urlopen
,
Request
from
urllib.error
import
HTTPError
except
ImportError
:
from
urlparse
import
urlparse
from
urllib
import
urlencode
from
urllib2
import
urlopen
,
Request
,
HTTPError
import
sys
# from json.decoder import JSONDecodeError # python3
from
os.path
import
expanduser
import
requests
log
=
logging
.
getLogger
(
'
allgo
'
)
__version__
=
'
0.1.11
'
__version__
=
'
0.2.0
'
#: The default Allgo url used.
MAIN_INSTANCE_URL
=
"
https://allgo18.inria.fr
"
#: The file containing the user token.
#: It is read in last resort to get a token.
TOKEN_FILE
=
os
.
path
.
join
(
expanduser
(
"
~
"
),
'
.allgo_token
'
)
# ===============================================================
class
AllgoError
(
Exception
):
"""
Generic error generated by this module.
"""
class
TokenError
(
AllgoError
):
"""
Raise TokenError when none is set.
"""
def
__init__
(
self
):
err_msg
=
"
You must provide a token in parameter
"
err_msg
+=
"
or define an environment variable
'
ALLGO_TOKEN
'"
err_msg
+=
"
or write your token in {}
"
.
format
(
TOKEN_FILE
)
super
(
TokenError
,
self
).
__init__
(
err_msg
)
def
local_token
():
from
os.path
import
expanduser
home
=
expanduser
(
"
~
"
)
filetoken
=
os
.
path
.
join
(
home
,
'
.allgo_token
'
)
if
os
.
path
.
exists
(
filetoken
):
with
open
(
filetoken
)
as
f
:
class
StatusError
(
AllgoError
):
"""
Raise StatusError when API does not return a 200 code.
"""
def
__init__
(
self
,
status_code
,
response
,
*
args
,
**
kwargs
):
"""
TODO
"""
self
.
_status_code
=
status_code
self
.
_response
=
response
AllgoError
.
__init__
(
self
,
*
args
,
**
kwargs
)
@property
def
status_code
(
self
):
return
self
.
_status_code
@property
def
msg
(
self
):
return
self
.
_response
.
json
()[
'
error
'
]
def
_local_token
():
"""
read and return the content of TOKEN_FILE or None.
"""
if
os
.
path
.
exists
(
TOKEN_FILE
):
with
open
(
TOKEN_FILE
)
as
f
:
return
f
.
read
()
return
None
class
App
:
# ---------------------------------------------------------------
class
Client
:
"""
AllGo app submission object
manage connexions to the API and provide methods to deal with it.
"""
def
__init__
(
self
,
name
,
token
=
None
):
def
__init__
(
self
,
token
=
None
,
allgo_url
=
MAIN_INSTANCE_URL
,
verify_tls
=
True
):
"""
Build an object to manage the parameters of a user-connexion to an Allgo-instance.
"""
Constructor
:param name: name of the application in lower case
:param token: if not provided, we check ALLGO_TOKEN env variable and notebook parameters
self
.
_allgo_url
=
allgo_url
self
.
_verify_tls
=
verify_tls
self
.
_token
=
token
or
os
.
getenv
(
'
ALLGO_TOKEN
'
)
or
_local_token
()
if
None
is
self
.
_token
:
raise
TokenError
()
@property
def
token
(
self
):
"""
return the user token for the querying all instance.
"""
return
self
.
_token
@property
def
allgo_url
(
self
):
"""
return the url of the querying allgo instance.
"""
return
self
.
_allgo_url
@property
def
verify_tls
(
self
):
"""
return the _verify_tls attribute.
"""
return
self
.
_verify_tls
def
_request_api
(
self
,
method
,
url_end
,
**
kwargs
):
"""
Build and launch a http request on the Allgo instance API.
"""
self
.
name
=
name
if
token
:
self
.
token
=
token
elif
'
ALLGO_TOKEN
'
in
os
.
environ
.
keys
():
self
.
token
=
os
.
environ
.
get
(
'
ALLGO_TOKEN
'
)
elif
local_token
():
self
.
token
=
local_token
()
else
:
err_msg
=
"
You must provide a token in parameter
"
err_msg
+=
"
or define an environment variable
'
ALLGO_TOKEN
'"
raise
Exception
(
err_msg
)
def
run
(
self
,
files
,
outputdir
=
'
.
'
,
params
=
''
,
verify_tls
=
True
):
headers
=
{
'
Authorization
'
:
'
Token token={}
'
.
format
(
self
.
token
)}
url
=
'
{}/api/v1/{}
'
.
format
(
self
.
allgo_url
,
url_end
)
logging
.
debug
(
"
querying
'
{}
'
with method
'
{}
'"
.
format
(
url
,
method
))
logging
.
debug
(
"
and with data = {}
"
.
format
(
kwargs
))
actions
=
{
'
post
'
:
requests
.
post
,
'
get
'
:
requests
.
get
,
}
try
:
resp
=
actions
[
method
](
url
,
headers
=
headers
,
verify
=
self
.
verify_tls
,
**
kwargs
)
logging
.
debug
(
"
raw API answer : {}
"
.
format
(
resp
.
content
))
if
resp
.
status_code
!=
requests
.
codes
.
ok
:
logging
.
debug
(
"
req.status_code = {}
"
.
format
(
resp
.
status_code
))
raise
StatusError
(
resp
.
status_code
,
resp
)
return
resp
.
json
()
except
ValueError
:
# pure python3 should use JSONDecodeError
# this happens when response content cannot be converted to json
# for example when downloading a file.
return
resp
except
KeyError
as
err
:
msg
=
"
method {} is not allowed to request the API.
"
.
format
(
method
)
msg
+=
"
KeyError: {}
"
.
format
(
str
(
err
))
raise
AllgoError
(
msg
)
def
create_job
(
self
,
app
,
version
=
None
,
params
=
''
,
files
=
None
):
"""
Create a job for app, with params.
"""
Submit the job
:param files: input files
:param outputdir: by default current directory
:param params: a string parameters see the application documentation
:param verify_tls: [True] the value is pass to the verify arg of requests.post
:return:
data
=
{
"
job[webapp_name]
"
:
app
,
"
job[webapp_id]
"
:
app
,
"
job[param]
"
:
params
,
"
job[version]
"
:
version
}
file_dict
=
{}
if
None
is
files
:
files
=
[]
for
i
,
file_
in
enumerate
(
files
):
key
=
"
file[{}]
"
.
format
(
i
)
file_dict
[
key
]
=
open
(
file_
,
'
rb
'
)
return
self
.
_request_api
(
'
post
'
,
url_end
=
'
jobs
'
,
data
=
data
,
files
=
file_dict
)
def
job_status
(
self
,
job_id
):
"""
Get the status of a job as a dict.
"""
headers
=
{
'
Authorization
'
:
'
Token token={}
'
.
format
(
self
.
token
)}
data
=
{
"
job[webapp_name]
"
:
self
.
name
,
"
job[webapp_id]
"
:
self
.
name
,
"
job[param]
"
:
params
}
ALLGO_URL
=
os
.
environ
.
get
(
'
ALLGO_URL
'
,
"
https://allgo.inria.fr
"
)
url
=
'
%s/api/v1/jobs
'
%
ALLGO_URL
r
=
requests
.
post
(
url
,
headers
=
headers
,
files
=
files
,
data
=
data
,
verify
=
verify_tls
)
r
.
raise_for_status
()
r
=
r
.
json
()
if
'
id
'
in
r
.
keys
():
jobid
=
r
[
'
id
'
]
else
:
jobid
=
list
(
r
.
keys
())[
0
]
results
=
None
url
=
'
jobs/{}
'
.
format
(
job_id
)
return
self
.
_request_api
(
'
get
'
,
url
)
def
app_metrics
(
self
,
app_id
,
what
,
from_
=
None
,
to_
=
None
,
step
=
None
):
"""
query the instance for some metrics.
**Not yet implemented.**
"""
raise
NotImplementedError
(
"
metrics API has not been integrated yet.
"
)
# --------------------------------------------
# -- Accessory methods, to ease user work.
# --------------------------------------------
def
run_job
(
self
,
app
,
version
=
None
,
params
=
''
,
files
=
None
,
sleep_duration
=
2
,
verbose
=
False
):
"""
Create a job and wait for it to terminate.
"""
from
time
import
sleep
# Note: states new, and deleted are almost impossible to get.
STATES
=
[
'
NEW
'
,
'
WAITING
'
,
'
RUNNING
'
,
'
ARCHIVED
'
,
'
DONE
'
,
'
DELETED
'
,
'
ABORTING
'
]
out_dict
=
self
.
create_job
(
app
,
version
=
version
,
params
=
params
,
files
=
files
)
job_id
=
out_dict
[
'
id
'
]
flags
=
{
s
.
lower
():
False
for
s
in
STATES
}
while
True
:
url
=
'
{}/api/v1/jobs/{}
'
.
format
(
ALLGO_URL
,
jobid
)
r
=
requests
.
get
(
url
,
headers
=
headers
,
verify
=
verify_tls
)
r
.
raise_for_status
()
results
=
r
.
json
()
if
'
status
'
in
results
.
keys
():
status
=
results
[
'
status
'
]
else
:
status
=
list
(
results
.
values
())[
0
][
'
status
'
]
if
status
in
[
'
created
'
,
'
waiting
'
,
'
running
'
,
'
in progress
'
]:
log
.
info
(
"
wait for job %s in status %s
"
,
jobid
,
status
)
time
.
sleep
(
2
)
else
:
break
if
status
!=
'
done
'
:
raise
Exception
(
'
Job %s failed with status %s
'
,
(
jobid
,
status
))
elif
status
==
'
done
'
and
results
:
if
'
id
'
in
results
.
keys
():
files
=
results
[
str
(
jobid
)].
items
()
else
:
files
=
results
[
str
(
jobid
)][
'
files
'
].
items
()
for
filename
,
url
in
files
:
filepath
=
os
.
path
.
join
(
outputdir
,
filename
)
with
requests
.
get
(
url
,
headers
=
headers
,
verify
=
verify_tls
,
stream
=
True
)
as
r
:
r
.
raise_for_status
()
with
open
(
filepath
,
'
wb
'
)
as
f
:
for
chunk
in
r
.
iter_content
(
chunk_size
=
8192
):
if
chunk
:
f
.
write
(
chunk
)
sleep
(
sleep_duration
)
out_dict
=
self
.
job_status
(
job_id
)
status
=
out_dict
[
'
status
'
]
if
True
is
verbose
:
if
False
is
flags
[
status
]:
print
(
"
\n
{}
\t
"
.
format
(
status
),
end
=
''
)
flags
[
status
]
=
True
else
:
print
(
"
.
"
,
end
=
''
)
sys
.
stdout
.
flush
()
if
status
==
'
done
'
:
if
True
is
verbose
:
print
(
""
)
# to get a return line
out_dict
[
'
id
'
]
=
job_id
return
out_dict
# should never goes here
return
out_dict
This diff is collapsed.
Click to expand it.
setup.py
+
9
−
7
View file @
8da0bdb7
...
...
@@ -5,21 +5,23 @@ import allgo
setup
(
name
=
'
allgo
'
,
version
=
allgo
.
__version__
,
packages
=
find_packages
(),
author
=
"
Sebastien Campion
"
,
author_email
=
"
sebastien.campion@inria.fr
"
,
description
=
"
AllGo client module
"
,
install_requires
=
[
'
requests
'
],
packages
=
find_packages
(
exclude
=
[
'
doc
'
,
'
test*
'
]),
author
=
"
Sebastien Letort
"
,
author_email
=
"
sebastien.letort@inria.fr
"
,
description
=
"
AllGo client-API module
"
,
long_description
=
open
(
'
README.md
'
).
read
(),
long_description_content_type
=
'
text/markdown
'
,
include_package_data
=
True
,
url
=
'
https://gitlab.inria.fr/allgo/client
'
,
url
=
'
https://gitlab.inria.fr/allgo/
api-clients/python_
client
'
,
classifiers
=
[
"
Programming Language :: Python
"
,
"
Development Status ::
1
-
Planning
"
,
"
Programming Language :: Python
:: 3
"
,
"
Development Status ::
3
-
Alpha
"
,
"
License :: OSI Approved
"
,
"
Natural Language :: French
"
,
"
Operating System :: OS Independent
"
,
"
Programming Language :: Python :: 2.7
"
,
"
Programming Language :: Python :: 3
"
,
"
Topic :: Communications
"
,
],
license
=
"
AGPL
"
,
...
...
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