Skip to content
This repository has been archived by the owner on Oct 28, 2019. It is now read-only.

Commit

Permalink
Merge branch 'dev'
Browse files Browse the repository at this point in the history
* dev:
  Bump version number to 0.2.12
  Fail immediately in consume() if error code is 400. #57
  Remove importFrom(utils, data)
  Remove vignette artefacts
  Rebuild vignettes
  Implement workarounds to pass R CMD check in wrapper.R
  Suppress warnings in download.datasets() to deal with some csv samples containing missing final line, i.e. missing line break. #115
  Rebuild documentation using roxygen2 v5
  Document how to use different regions. #105
  Rename arguments from tries to .retry #116
  Fixed typo in URL. #105
  Update date
  Refactor, and catch error with NA values. #115
  • Loading branch information
andrie committed Jul 13, 2016
2 parents 2310f2c + fc0369b commit d0ee0dd
Show file tree
Hide file tree
Showing 40 changed files with 308 additions and 1,392 deletions.
4 changes: 2 additions & 2 deletions DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ Title: Interface with Azure Machine Learning Datasets, Experiments and Web Servi
Description: Functions and datasets to support Azure Machine Learning. This
allows you to interact with datasets, as well as publish and consume R functions
as API services.
Version: 0.2.11
Date: 2016-07-01
Version: 0.2.12
Date: 2016-07-13
Authors@R: c(
person("Andrie", "de Vries", role=c("aut", "cre"), email="[email protected]"),
person(family="Microsoft Corporation", role="cph"),
Expand Down
2 changes: 1 addition & 1 deletion NAMESPACE
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Generated by roxygen2 (4.1.1): do not edit by hand
# Generated by roxygen2: do not edit by hand

S3method(print,Datasets)
S3method(print,Experiments)
Expand Down
11 changes: 6 additions & 5 deletions R/consume.R
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#' @export
#'
#' @inheritParams refresh
#' @inheritParams publishWebService
#' @param endpoint Either an AzureML web service endpoint returned by \code{\link{publishWebService}}, \code{\link{endpoints}}, or simply an AzureML web service from \code{\link{services}}; in the latter case the default endpoint for the service will be used.
#' @param ... variable number of requests entered as lists in key-value format; optionally a single data frame argument.
#' @param globalParam global parameters entered as a list, default value is an empty list
Expand All @@ -43,7 +44,7 @@
#' @family consumption functions
#' @importFrom jsonlite fromJSON
#' @example inst/examples/example_publish.R
consume <- function(endpoint, ..., globalParam, retryDelay = 10, output = "output1", tries = 5)
consume <- function(endpoint, ..., globalParam, retryDelay = 10, output = "output1", .retry = 5)
{
if(is.Service(endpoint))
{
Expand Down Expand Up @@ -73,7 +74,7 @@ consume <- function(endpoint, ..., globalParam, retryDelay = 10, output = "outpu
}
}
# Make API call with parameters
result <- callAPI(apiKey, requestUrl, requestsLists, globalParam, retryDelay, tries = tries)
result <- callAPI(apiKey, requestUrl, requestsLists, globalParam, retryDelay, .retry = .retry)
if(inherits(result, "error")) stop("AzureML returned an error code")

# Access output by converting from JSON into list and indexing into Results
Expand Down Expand Up @@ -104,14 +105,14 @@ consume <- function(endpoint, ..., globalParam, retryDelay = 10, output = "outpu
# @param keyvalues the data to be passed to the web service
# @param globalParam the global parameters for the web service
# @param retryDelay number of seconds to wait after failing (max 3 tries) to try again
# @param tries the number of retry attempts
# @param .retry the number of retry attempts
# @return result the response
#
# @importFrom jsonlite toJSON
# @importFrom curl handle_setheaders new_handle handle_setopt curl_fetch_memory
# @keywords internal
callAPI <- function(apiKey, requestUrl, keyvalues, globalParam,
retryDelay=10, tries = 5) {
retryDelay=10, .retry = 5) {
# Set number of tries and HTTP status to 0
result <- NULL
# Construct request payload
Expand All @@ -136,7 +137,7 @@ callAPI <- function(apiKey, requestUrl, keyvalues, globalParam,
postfields = body
)
)
r <- try_fetch(requestUrl, h, delay = retryDelay, tries = tries)
r <- try_fetch(requestUrl, h, no_retry_on = 400, delay = retryDelay, .retry = .retry)
result <- fromJSON(rawToChar(r$content))
if(r$status_code >= 400) {
stop(paste(capture.output(result), collapse="\n"))
Expand Down
2 changes: 1 addition & 1 deletion R/datasets.R
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ delete.datasets <- function(ws, name, host){
curl_escape(ws$id),
curl_escape(familyId)
)
z <- try_fetch(uri, h, tries = 3, delay = 2)
z <- try_fetch(uri, h, .retry = 3, delay = 2)
z$status_code
}
status_code <- vapply(datasets$FamilyId, delete_one, FUN.VALUE = numeric(1), USE.NAMES = FALSE)
Expand Down
38 changes: 5 additions & 33 deletions R/discover.R
Original file line number Diff line number Diff line change
Expand Up @@ -86,43 +86,15 @@ discoverSchema <- function(helpURL, scheme = "https",

# Accesses the names of the columns in the example
# and stores it in a list of column names
# columnNames <- vector("list", length = length(inputExample))
# columnNames <- list()
# for(i in seq_along(inputExample)) {
# columnNames[[i]] = names(inputExample)[i]
# }
columnNames <- lapply(seq_along(inputExample), function(i)names(inputExample[i]))

# Uses multiple nested loops to access the various paths in the
# swagger document and find the execution path
foundExecPath = FALSE
pathNo = 0
execPathNo = -1
for(execPath in swagger$paths) {
pathNo = pathNo + 1
for(operationpath in execPath) {
for(operation in operationpath) {
# Goes through the characteristcs in every operation e.g. operationId
for(charac in operation) {
# Finds the path in which the
# operationId (characteristic of the path) == execute
# and sets the execution path number
if(charac[1] == "execute")
{
#Sets found execution path to true
foundExecPath = TRUE
execPathNo = pathNo
break
}
}
}
}
execPathNo <- grep("/execute\\?", names(swagger$paths))
if(is.numeric(execPathNo)) {
executePath <- names(swagger$paths)[[execPathNo]]
} else {
"Path not found"
}

# Stores the execution path
executePath <- if(foundExecPath) names(swagger$paths)[[execPathNo]]
else "Path not found"

# Constructs the request URL with the parameters as well as execution path found.
# The separator is set to an empty string
requestUrl <- paste0(scheme,"://", host,
Expand Down
16 changes: 11 additions & 5 deletions R/fetch.R
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ validate_response <- function(r){
# @param uri the uri to fetch
# @param handle a curl handle
# @param retry_on HTTP status codes that result in retry
# @param tries number of tries before failing
# @param .retry number of tries before failing
# @param delay in seconds between retries, subject to exponent
# @param exponent increment each successive delay by delay^exponent
# @param no_message_threshold Only show messages if delay is greater than this limit
Expand All @@ -76,20 +76,26 @@ validate_response <- function(r){
# @return the result of curl_fetch_memory(uri, handle)
#
try_fetch <- function(uri, handle,
retry_on = c(400, 401, 440, 503, 504, 509),
tries = 6,
retry_on = c(400, 401, 440, 503, 504, 509),
no_retry_on,
.retry = 6,
delay = 1, exponent = 2,
no_message_threshold = 1)
{
r = curl_fetch_memory(uri, handle)
# if(r$status_code == 400) validate_response(r)
# if(r$status_code == 400){
# validate_response(r)
# }
if(!missing(no_retry_on) && !is.null(no_retry_on)){
retry_on <- setdiff(retry_on, no_retry_on)
}
if(!(r$status_code %in% retry_on)) {
validate_response(r)
return(r)
}
collisions = 1
printed_message <- FALSE
while(collisions < (tries)) {
while(collisions < (.retry)) {
r = curl_fetch_memory(uri, handle)
if(!(r$status_code %in% retry_on)) {
validate_response(r)
Expand Down
4 changes: 2 additions & 2 deletions R/internal.R
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ get_datasets <- function(ws) {
h = new_handle()
handle_setheaders(h, .list = ws$.headers)
uri <- sprintf("%s/workspaces/%s/datasources", ws$.studioapi, ws$id)
r <- try_fetch(uri = uri, handle = h, delay = 0.25, tries = 3)
r <- try_fetch(uri = uri, handle = h, delay = 0.25, .retry = 3)

msg <- paste("No results returned from datasets(ws).",
"Please check your workspace credentials and api_endpoint are correct.")
Expand Down Expand Up @@ -89,7 +89,7 @@ get_experiments <- function(ws) {
h = new_handle()
handle_setheaders(h, .list=ws$.headers)
uri = sprintf("%s/workspaces/%s/experiments", ws$.studioapi, ws$id)
r <- try_fetch(uri = uri, handle = h, delay = 0.25, tries = 3)
r <- try_fetch(uri = uri, handle = h, delay = 0.25, .retry = 3)

msg <- paste("No results returned from experiments(ws).",
"Please check your workspace credentials and api_endpoint are correct.")
Expand Down
26 changes: 9 additions & 17 deletions R/publish.R
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#' @export
#'
#' @inheritParams refresh
#' @inheritParams workspace
#' @param fun a function to publish; the function must have at least one argument.
#' @param name name of the new web service; ignored when \code{serviceId} is specified (when updating an existing web service).
#'
Expand All @@ -43,6 +44,7 @@
#' @param serviceId optional Azure web service ID; use to update an existing service (see Note below).
#' @param host optional Azure regional host, defaulting to the global \code{management_endpoint} set in \code{\link{workspace}}
#' @param data.frame \code{TRUE} indicates that the function \code{fun} accepts a data frame as input and returns a data frame output; automatically set to \code{TRUE} when \code{inputSchema} is a data frame.
#' @param .retry number of tries before failing
#'
#' @return A data.frame describing the new service endpoints, cf. \code{\link{endpoints}}. The output can be directly used by the \code{\link{consume}} function.
#'
Expand Down Expand Up @@ -83,11 +85,12 @@
#' @importFrom uuid UUIDgenerate
#' @importFrom curl new_handle handle_setheaders handle_setopt
publishWebService <- function(ws, fun, name,
inputSchema, outputSchema, `data.frame`=FALSE,
export=character(0),
noexport=character(0),
inputSchema, outputSchema,
`data.frame` = FALSE,
export = character(0),
noexport = character(0),
packages,
version="3.1.0",
version = "3.1.0",
serviceId,
host = ws$.management_endpoint,
.retry = 3)
Expand Down Expand Up @@ -130,18 +133,7 @@ publishWebService <- function(ws, fun, name,
}

}
# inputSchema <- azureSchema(inputSchema)
# outputSchema <- azureSchema(outputSchema)
# if(`data.frame`) {
# if(length(formals(fun)) != 1) {
# stop("when data.frame=TRUE fun must only take one data.frame argument")
# }
# } else {
# if(length(formals(fun)) != length(inputSchema)) {
# stop("length(inputSchema) does not match the number of function arguments")
# }
# }


### Get and encode the dependencies

if(missing(packages)) packages=NULL
Expand Down Expand Up @@ -191,7 +183,7 @@ publishWebService <- function(ws, fun, name,
)
handle_setheaders(h, .list = httpheader)
handle_setopt(h, .list = opts)
r = try_fetch(publishURL, handle = h, tries = .retry)
r = try_fetch(publishURL, handle = h, .retry = .retry)
result = rawToChar(r$content)
if(r$status_code >= 400) stop(result)
newService = fromJSON(result)
Expand Down
2 changes: 1 addition & 1 deletion R/services.R
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ services <- function(ws, service_id, name, host = ws$.management_endpoint)
}

uri <- sprintf("%s/workspaces/%s/webservices%s", host, ws$id, service_id)
r <- try_fetch(uri = uri, handle = h, delay = 0.25, tries = 3)
r <- try_fetch(uri = uri, handle = h, delay = 0.25, .retry = 3)
# if(inherits(r, "error")){
# msg <- paste("No results returned from datasets(ws).",
# "Please check your workspace credentials and api_endpoint are correct.")
Expand Down
33 changes: 31 additions & 2 deletions R/workspace.R
Original file line number Diff line number Diff line change
Expand Up @@ -73,22 +73,51 @@ default_api <- function(api_endpoint = "https://studioapi.azureml.net"){
#' \if{html}{\figure{authorization_token.png}{options: width="60\%" alt="Figure: authorization_token.png"}}
#' \if{latex}{\figure{authorizationToken.pdf}{options: width=7cm}}
#'
#' @section Using a \code{settings.json} file:
#'
#' @section Using a settings.json file:
#' If any of the \code{id}, \code{auth}, \code{api_endpoint} or \code{management_endpoint} arguments are missing, the function attempts to read values from the \code{config} file with JSON format:
#' \preformatted{
#' {"workspace":{
#' "id": "enter your AzureML workspace id here",
#' "authorization_token": "enter your AzureML authorization token here",
#' "api_endpoint": "https://studioapi.azureml.net",
#' }}
#' }
#'
#' To explicitly add the management endpoint in the JSON file, use:
#' \preformatted{
#' {"workspace":{
#' "id": "enter your AzureML workspace id here",
#' "authorization_token": "enter your AzureML authorization token here",
#' "api_endpoint": "https://studioapi.azureml.net",
#' "management_endpoint": "https://management.azureml.net"
#' }}
#' }
#'
#' @section Using a workspace in different Azure Machine Learning regions:
#'
#' By default, the Azure Machine Learning workspace is located in US South Central, but it is possible to create a workspace in different regions, including Europe West and Asia Southeast.
#'
#' To use a workspace in Asia Southeast, you can modify the api endpoint line in the JSON file:
#' \preformatted{
#' {"workspace": {
#' "api_endpoint": ["https://asiasoutheast.studio.azureml.net"]
#' }}
#' }
#'
#' Similarly, for a workspace in Europe West:
#' \preformatted{
#' {"workspace": {
#' "api_endpoint": ["https://europewest.studio.azureml.net"]
#' }}
#' }
#'

#'
#'
#' @param id Optional workspace id from ML studio -> settings -> WORKSPACE ID. See the section "Finding your AzureML credentials" for more details.
#' @param auth Optional authorization token from ML studio -> settings -> AUTHORIZATION TOKENS. See the section "Finding your AzureML credentials" for more details.
#' @param api_endpoint Optional AzureML API web service URI. Defaults to \code{https://studioap.azureml.net} if not provided and not specified in config. See note.
#' @param api_endpoint Optional AzureML API web service URI. Defaults to \code{https://studioapi.azureml.net} if not provided and not specified in config. See note.
#' @param management_endpoint Optional AzureML management web service URI. Defaults to \code{https://management.azureml.net} if not provided and not specified in config. See note.
#' @param config Optional settings file containing id and authorization info. Used if any of the other arguments are missing. The default config file is \code{~/.azureml/settings.json}, but you can change this location by setting \code{options(AzureML.config = "newlocation")}. See the section "Using a settings.json file" for more details.
#' @param ... ignored
Expand Down
Loading

0 comments on commit d0ee0dd

Please sign in to comment.