trevorld / findpython
Showing 1 of 9 files from the diff.

@@ -1,16 +1,16 @@
Loading
1 1
# Copyright (c) 2012-2018 Trevor L. Davis
2 2
# Copyright (c) 2014 Paul Gilbert
3 -
# 
3 +
#
4 4
# Permission is hereby granted, free of charge, to any person obtaining a copy
5 5
# of this software and associated documentation files (the "Software"), to deal
6 6
# in the Software without restriction, including without limitation the rights
7 7
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 8
# copies of the Software, and to permit persons to whom the Software is
9 9
# furnished to do so, subject to the following conditions:
10 -
# 
10 +
#
11 11
# The above copyright notice and this permission notice shall be included in
12 12
# all copies or substantial portions of the Software.
13 -
# 
13 +
#
14 14
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 15
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 16
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -25,15 +25,15 @@
Loading
25 25
#' desired features (minimum and/or maximum version number and/or access to
26 26
#' certain modules).
27 27
#'
28 -
#' @param path The path to a given python binary.  
28 +
#' @param path The path to a given python binary.
29 29
#'      If binary is on system path just the binary name will work.
30 -
#' @param minimum_version The minimum version of python it should be.  
31 -
#'      Should be a string with major and minor number separated by a '.'.
32 -
#'      If left NULL won't impose such a restriction.  
33 -
#' @param maximum_version The maximum version of python it should be. 
34 -
#'      Should be a string with major and minor number separated by a '.'.
30 +
#' @param minimum_version The minimum version of python it should be.
31 +
#'      Should be a string with major and minor number separated by a \sQuote{.}.
35 32
#'      If left NULL won't impose such a restriction.
36 -
#' @param required_modules Which modules should be required.  
33 +
#' @param maximum_version The maximum version of python it should be.
34 +
#'      Should be a string with major and minor number separated by a \sQuote{.}.
35 +
#'      If left NULL won't impose such a restriction.
36 +
#' @param required_modules Which modules should be required.
37 37
#'      Can use a single "|" to represent a single either-or requirement like "json|simplejson".
38 38
#'      If left NULL won't impose such a restriction.
39 39
#' @return \code{TRUE} or \code{FALSE} depending on whether the python binary met all requirements
@@ -41,22 +41,19 @@
Loading
41 41
is_python_sufficient <- function(path, minimum_version=NULL,
42 42
                                 maximum_version=NULL, required_modules=NULL) {
43 43
    python_code <- vector("character")
44 -
    if(!is.null(required_modules)) {
44 +
    if (!is.null(required_modules)) {
45 45
        import_code <- .create_import_code(required_modules)
46 46
        python_code <- append(python_code, import_code)
47 47
    }
48 48
    version_code <- .create_version_checking_code(minimum_version, maximum_version)
49 49
    python_code <- append(python_code, version_code)
50 50
    ok_message <- "Everything worked out okay"
51 -
    python_code <- append(python_code, paste("print(", shQuote(ok_message), ")", sep=""))
51 +
    python_code <- append(python_code, paste("print(", shQuote(ok_message), ")", sep = ""))
52 52
    tryCatch({
53 -
            output <- system(path, intern=TRUE, input=python_code, ignore.stderr=TRUE)
53 +
            output <- system(path, intern = TRUE, input = python_code, ignore.stderr = TRUE)
54 54
            any(grepl(ok_message, output))
55 -
        }, 
56 -
        warning = function(w) { 
57 -
            # qpath <- sQuote(path)
58 -
            # warning(qpath, 
59 -
            #     "Doesn't seem to have required modules or is of insufficient version")
55 +
        },
56 +
        warning = function(w) {
60 57
            FALSE
61 58
        },
62 59
        error = function(e) {
@@ -72,76 +69,89 @@
Loading
72 69
#' @param error_message What error message the user will see if couldn't find a sufficient python binary.
73 70
#'     If left NULL will print out a default message.
74 71
#' @return The path to an appropriate python binary.  If such a path wasn't found then it will throw an error.
75 -
#' @examples 
72 +
#' @examples
76 73
#'      \dontrun{
77 74
#'              find_python_cmd()
78 -
#'              find_python_cmd(minimum_version='2.6', maximum_version='2.7')
79 -
#'              find_python_cmd(required_modules = c('argparse', 'json | simplejson'))
75 +
#'              find_python_cmd(minimum_version = "2.6", maximum_version = "2.7")
76 +
#'              find_python_cmd(required_modules = c("argparse", "json | simplejson"))
80 77
#'      }
81 78
#' @seealso \code{\link{can_find_python_cmd}} for a wrapper which doesn't throw an error
82 79
#' @export
83 -
find_python_cmd <- function(minimum_version=NULL, maximum_version=NULL,
84 -
                            required_modules=NULL, error_message=NULL) {
85 -
    python_cmds <- c(getOption("python_cmd", ""), "python", Sys.getenv("PYTHON", ""), 
86 -
                    sprintf("python%.1f", c(seq(4.9, 2.0, by=-0.1))), 
87 -
                    "python4", "python3", "python2", "pypy",
88 -
                    Sys.getenv("PYTHON4", ""), Sys.getenv("PYTHON3", ""), 
89 -
                    Sys.getenv("PYTHON2", ""), sprintf("C:/Python%s/python", c(49:20)))
90 -
    python_cmds <- unique(python_cmds)
91 -
    python_cmds <- Sys.which(python_cmds)
92 -
    python_cmds <- python_cmds[which(python_cmds != "")]
93 -
    for(cmd in python_cmds) {
94 -
        if(is_python_sufficient(cmd, minimum_version, maximum_version, required_modules)) { 
80 +
find_python_cmd <- function(minimum_version = NULL, maximum_version = NULL,
81 +
                            required_modules = NULL, error_message = NULL) {
82 +
    python_cmds <- get_python_cmds()
83 +
    for (cmd in python_cmds) {
84 +
        if (is_python_sufficient(cmd, minimum_version, maximum_version, required_modules)) {
95 85
            return(cmd)
96 86
        }
97 87
    }
98 88
    # Try using reticulate::py_discover_config()$python_versions if can't find a suitable command
99 -
    if (requireNamespace("reticulate", quietly=TRUE)) { 
89 +
    if (requireNamespace("reticulate", quietly = TRUE)) {
100 90
        python_cmds <- reticulate::py_discover_config()$python_versions
101 -
        for(cmd in python_cmds) {
102 -
            if(is_python_sufficient(cmd, minimum_version, maximum_version, required_modules)) { 
91 +
        for (cmd in python_cmds) {
92 +
            if (is_python_sufficient(cmd, minimum_version, maximum_version, required_modules)) {
103 93
                return(cmd)
104 94
            }
105 95
        }
106 96
    }
107 -
    if (is.null(error_message)) { 
108 -
        error_message <- paste("Couldn't find a sufficient Python binary.",
109 -
                    "If you haven't installed the Python dependency yet please do so.",
110 -
                    "If you have but it isn't on the system path (as is default on Windows) please add it to path",
111 -
                    "or set options('python_cmd'='/path/to/binary') ",
112 -
                    "or set the PYTHON, PYTHON2, or PYTHON3 environmental variables.",
113 -
                    if(!is.null(minimum_version)) paste('Python must be at least version', minimum_version),
114 -
                    if(!is.null(maximum_version)) paste('Python must be at most version', maximum_version),
115 -
                    if(!is.null(required_modules)) paste('Python must have access to the modules:', 
116 -
                                                         paste(required_modules, collapse=', ')))}
97 +
    if (is.null(error_message)) {
98 +
        error_message <- default_error_message(minimum_version, maximum_version, required_modules)
99 +
    }
117 100
    stop(error_message)
118 101
}
119 -
#' Determines whether or not it can find a suitable python cmd 
102 +
103 +
default_error_message <- function(minimum_version = NULL, maximum_version = NULL, required_modules = NULL) {
104 +
    paste("Couldn't find a sufficient Python binary.",
105 +
          "If you haven't installed the Python dependency yet please do so.",
106 +
          "If you have but it isn't on the system path (as is default on Windows) please add it to path",
107 +
          "or set options('python_cmd'='/path/to/binary') ",
108 +
          "or set the PYTHON, PYTHON2, or PYTHON3 environmental variables.",
109 +
          if (!is.null(minimum_version)) paste("Python must be at least version", minimum_version),
110 +
          if (!is.null(maximum_version)) paste("Python must be at most version", maximum_version),
111 +
          if (!is.null(required_modules)) paste("Python must have access to the modules:",
112 +
                                                paste(required_modules, collapse = ", ")))
113 +
114 +
}
115 +
116 +
get_python_cmds <- function() {
117 +
    python_cmds <- c(getOption("python_cmd", ""), "python", Sys.getenv("PYTHON", ""),
118 +
                    sprintf("python%.1f", c(seq(4.9, 2.0, by = -0.1))),
119 +
                    "python4", "python3", "python2", "pypy",
120 +
                    Sys.getenv("PYTHON4", ""), Sys.getenv("PYTHON3", ""),
121 +
                    Sys.getenv("PYTHON2", ""), sprintf("C:/Python%s/python", c(49:20)))
122 +
    python_cmds <- unique(python_cmds)
123 +
    python_cmds <- Sys.which(python_cmds)
124 +
    python_cmds[which(python_cmds != "")]
125 +
}
126 +
127 +
#' Determines whether or not it can find a suitable python cmd
120 128
#'
121 -
#' \code{can_find_python_cmd} runs \code{find_python_cmd} and returns whether it could find a suitable python cmd.  If it was successful its output also saves the found command as an attribute. 
129 +
#' \code{can_find_python_cmd} runs \code{find_python_cmd} and returns whether it could find a suitable python cmd.
130 +
#'  If it was successful its output also saves the found command as an attribute.
122 131
#'
123 132
#' @inheritParams find_python_cmd
124 133
#' @param silent Passed to \code{try}, whether any error messages from \code{find_python_cmd} should be suppressed
125 -
#' @return \code{TRUE} or \code{FALSE} depending on whether \code{find_python_cmd} could find an appropriate python binary.
134 +
#' @return \code{TRUE} or \code{FALSE} depending on whether
135 +
#'     \code{find_python_cmd} could find an appropriate python binary.
126 136
#'     If \code{TRUE} the path to an appropriate python binary is also set as an attribute.
127 -
#' @examples 
137 +
#' @examples
128 138
#'      did_find_cmd <- can_find_python_cmd()
129 139
#'      python_cmd <- attr(did_find_cmd, "python_cmd")
130 140
#' @seealso \code{\link{find_python_cmd}}
131 141
#' @export
132 142
can_find_python_cmd <- function(minimum_version = NULL,
133 -
          maximum_version = NULL, required_modules = NULL, 
143 +
          maximum_version = NULL, required_modules = NULL,
134 144
          error_message = NULL, silent = FALSE) {
135 145
    python_cmd <- try(find_python_cmd(minimum_version = minimum_version,
136 146
                          maximum_version = maximum_version,
137 147
                          required_modules = required_modules,
138 148
                          error_message = error_message),
139 149
                    silent = silent)
140 -
    if(inherits(python_cmd, "try-error")) {
150 +
    if (inherits(python_cmd, "try-error")) {
141 151
        r <- FALSE
142 152
    } else {
143 153
        r <- TRUE
144 -
        attr(r, 'python_cmd') <- python_cmd
154 +
        attr(r, "python_cmd") <- python_cmd
145 155
    }
146 156
    r
147 157
}
@@ -149,14 +159,14 @@
Loading
149 159
# Create appropriate module import code
150 160
.create_import_code <- function(required_modules) {
151 161
    import_code <- vector("character")
152 -
    for(module in required_modules) {
153 -
        if(grepl("\\|", module)) {
162 +
    for (module in required_modules) {
163 +
        if (grepl("\\|", module)) {
154 164
            module <- gsub(" ", "", module)
155 165
            module <- strsplit(module, "\\|")[[1]]
156 -
            import_code <- append(import_code, 
157 -
                                  c("try:", 
166 +
            import_code <- append(import_code,
167 +
                                  c("try:",
158 168
                                   paste("    import", module[1]),
159 -
                                   "except ImportError:", 
169 +
                                   "except ImportError:",
160 170
                                   paste("    import", module[2])))
161 171
        } else {
162 172
            import_code <- append(import_code, paste("import", module))
@@ -167,31 +177,31 @@
Loading
167 177
168 178
# Create appropriate version checking code
169 179
.create_version_checking_code <- function(minimum_version = NULL, maximum_version = NULL) {
170 -
    if(is.null(minimum_version) && is.null(maximum_version)) 
180 +
    if (is.null(minimum_version) && is.null(maximum_version)) {
171 181
        return(c())
172 -
    else {
182 +
     } else {
173 183
        version_code <- c("import sys")
174 184
    }
175 -
    if(!is.null(minimum_version)) {
176 -
        min_version <- strsplit(minimum_version, '\\.')[[1]]
177 -
        major = min_version[1]
178 -
        minor = min_version[2]
179 -
        version_code <- append(version_code, 
180 -
                           c(paste("if sys.version_info.major <", major, 
185 +
    if (!is.null(minimum_version)) {
186 +
        min_version <- strsplit(minimum_version, "\\.")[[1]]
187 +
        major <- min_version[1]
188 +
        minor <- min_version[2]
189 +
        version_code <- append(version_code,
190 +
                           c(paste("if sys.version_info.major <", major,
181 191
                                 ": raise Exception('Major version too low')"),
182 -
                           paste("if sys.version_info.major ==", major, 
183 -
                                 "and sys.version_info.minor <", minor, 
192 +
                           paste("if sys.version_info.major ==", major,
193 +
                                 "and sys.version_info.minor <", minor,
184 194
                                 ": raise Exception('Minor version too low')")))
185 195
    }
186 -
    if(!is.null(maximum_version)) {
187 -
        max_version <- strsplit(maximum_version, '\\.')[[1]]
188 -
        major = max_version[1]
189 -
        minor = max_version[2]
190 -
        version_code <- append(version_code, 
191 -
                           c(paste("if sys.version_info.major >", major, 
196 +
    if (!is.null(maximum_version)) {
197 +
        max_version <- strsplit(maximum_version, "\\.")[[1]]
198 +
        major <- max_version[1]
199 +
        minor <- max_version[2]
200 +
        version_code <- append(version_code,
201 +
                           c(paste("if sys.version_info.major >", major,
192 202
                                 ": raise Exception('Major version too high')"),
193 -
                           paste("if sys.version_info.major ==", major, 
194 -
                                 "and sys.version_info.minor >", minor, 
203 +
                           paste("if sys.version_info.major ==", major,
204 +
                                 "and sys.version_info.minor >", minor,
195 205
                                 ": raise Exception('Minor version too high')")))
196 206
    }
197 207
    version_code
Files Coverage
R/find_python_cmd.r 97.78%
Project Totals (1 files) 97.78%
Notifications are pending CI completion. Waiting for GitHub's status webhook to queue notifications. Push notifications now.
a9hm4r1iiwib76s9
ymdkr09hbvf4kj6c

No yaml found.

Create your codecov.yml to customize your Codecov experience

Sunburst
The inner-most circle is the entire project, moving away from the center are folders then, finally, a single file. The size and color of each slice is representing the number of statements and the coverage, respectively.
Icicle
The top section represents the entire project. Proceeding with folders and finally individual files. The size and color of each slice is representing the number of statements and the coverage, respectively.
Grid
Each block represents a single file in the project. The size and color of each block is represented by the number of statements and the coverage, respectively.
Loading