Skip to content

Commit

Permalink
Merge pull request #19 from rgbkrk/path_ported
Browse files Browse the repository at this point in the history
Paths ported from jupyter_core
  • Loading branch information
willwhitney committed May 23, 2015
2 parents 4ecda4b + b302b46 commit 8e209ed
Show file tree
Hide file tree
Showing 5 changed files with 214 additions and 76 deletions.
12 changes: 3 additions & 9 deletions lib/kernel-manager.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,12 @@ path = require 'path'
_ = require 'lodash'
exec = require('child_process').exec

{jupyterPath} = require './paths'

Kernel = require './kernel'
homePath = process.env[if process.platform == 'win32' then 'USERPROFILE' else 'HOME']

module.exports = KernelManager =
kernelsDirOptions: [
path.join(homePath, '.jupyter/kernels'),
path.join(homePath, 'Library/Jupyter/kernels'),
'/usr/local/Cellar/python/2.7.9/Frameworks/Python.framework/Versions/2.7/share/jupyter/kernels',
'/usr/local/share/jupyter/kernels',
'/usr/share/jupyter/kernels',
path.join(homePath, '.ipython/kernels')
]
kernelsDirOptions: jupyterPath('kernels')
runningKernels: {}
pythonInfo:
display_name: "Python"
Expand Down
139 changes: 139 additions & 0 deletions lib/paths.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
# Port of jupyter_core.paths

fs = require('fs')
path = require('path')

# Access `sys.prefix` from Python, to handle particular conda and virtualenv setups
# TODO: Think of something more sensible here, possibly doing this asynchronously elsewhere
# TODO: Provide a timeout, handle error
{execSync} = require('child_process')
response = execSync 'python -c "import sys; print(sys.prefix)"'
sysPrefix = response.toString().replace /^\s+|\s+$/g, ""

# Compute default system configurations
if process.platform == 'win32'
programData = process.env['PROGRAMDATA']
if programData
SYSTEM_JUPYTER_PATH = [path.join(programData, 'jupyter')]
else
SYSTEM_JUPYTER_PATH = [path.join(sysPrefix, 'share', 'jupyter')]
else
SYSTEM_JUPYTER_PATH = [
"/usr/local/share/jupyter",
"/usr/share/jupyter"
]

ENV_JUPYTER_PATH = [path.join(sysPrefix, 'share', 'jupyter')]

# Returns the home specified by environment variable or
# node's built in path.resolve('~')
userHome = ->
homeDir = process.env['HOME'] or process.env['USERPROFILE'] or path.resolve('~')
homeDir = fs.realpathSync(homeDir)
return homeDir

# Get the Jupyter config directory for this platform and user.
# Reutrns env[JUPYTER_CONFIG_DIR] if defined, else ~/.jupyter
jupyterConfigDir = ->
homeDir = userHome()
if process.env['JUPYTER_CONFIG_DIR']
return process.env['JUPYTER_CONFIG_DIR']
return path.join(homeDir, '.jupyter')

# Get the config directory for Jupyter data files.
#
# These are non-transient, non-configuration files.
#
# Returns process.env[JUPYTER_DATA_DIR] if defined,
# else a platform-appropriate path.
jupyterDataDir = ->
if process.env['JUPYTER_DATA_DIR']
return process.env['JUPYTER_DATA_DIR']
else if process.platform == 'win32'
appData = process.env['APPDATA']
if appData
return path.join appData, 'jupyter'
else
return path.join jupyterConfigDir(), 'data'
else if process.platform == 'darwin'
return path.join(userHome(), 'Library', 'Jupyter')
else
# Linux, non-OS X Unix, AIX, etc.
xdg = process.env['XDG_DATA_HOME']
if not xdg
xdg = path.join(userHome(), '.local', 'share')
return path.join(xdg, 'jupyter')


# Returns the path for ~/.ipython
ipythonDataDir = ->
return path.join(userHome(), '.ipython')

# Return the runtime dir for transient jupyter files.
#
# Returns process.env[JUPYTER_RUNTIME_DIR] if defined.
#
# Respects XDG_RUNTIME_DIR on non-OS X, non-Windows,
# falls back on data_dir/runtime otherwise.
jupyterRuntimeDir = ->
if process.env['JUPYTER_RUNTIME_DIR']
return process.env['JUPYTER_RUNTIME_DIR']

if process.platform == 'darwin' or process.platform == 'win32'
return path.join(jupyterDataDir(), 'runtime')
else
# Linux, non-OS X Unix, AIX, etc.
xdg = process.env['XDG_RUNTIME_DIR']
if xdg
# Ref https://github.com/jupyter/jupyter_core/commit/176b7a9067bfc20bfa97be5dae93912e2930a427#commitcomment-11331375
return path.join(xdg, 'jupyter')
return path.join(jupyterDataDir, 'runtime')

# Return the list of directories to search
#
# JUPYTER_PATH environment variable has highest priority.
#
# If subdirs are given, that subdirectory path will be added to each element.
# Examples:
#
# > jupyterPath()
# ['/Users/rgbkrk/.local/jupyter', '/usr/local/share/jupyter']
#
# >jupyterPath
# ['/Users/rgbkrk/.local/jupyter/kernels', '/usr/local/share/jupyter/kernels']
jupyterPath = (subdirs...) ->
paths = []

# highest priority is env
if process.env['JUPYTER_PATH']
jupyterPathEnvSplit = process.env['JUPYTER_PATH'].split(path.delimiter)
for p in jupyterPathEnvSplit
# Strip off the path separator from the right
normalizedP = p.replace ///#{path.sep}+$///g, ""
paths.push normalizedP
# Next up, user directory
paths.push jupyterDataDir()

# Oh boy, it's sys.prefix
for p in ENV_JUPYTER_PATH
if p not in SYSTEM_JUPYTER_PATH
paths.push p

# Last is SYSTEM_JUPYTER_PATH
for p in SYSTEM_JUPYTER_PATH
paths.push p

paths.push ipythonDataDir()

# Append the subdir
if subdirs
paths = (path.join(p, subdirs...) for p in paths)
return paths

module.exports = {
jupyterPath: jupyterPath,
jupyterConfigDir: jupyterConfigDir,
jupyterDataDir: jupyterDataDir,
jupyterRuntimeDir: jupyterRuntimeDir,
userHome: userHome
}
62 changes: 0 additions & 62 deletions spec/atom-repl-spec.coffee

This file was deleted.

5 changes: 0 additions & 5 deletions spec/atom-repl-view-spec.coffee

This file was deleted.

72 changes: 72 additions & 0 deletions spec/paths-spec.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
path = require('path')

# TODO: mock process.env
# TODO: mock process.platform

describe "JupyterPath", ->
# Because `paths` shells out to Python, we need a chance to mock it first
[jupyterPath, jupyterConfigDir, jupyterDataDir, jupyterRuntimeDir] = []

beforeEach ->
# Do the require directly at least
{jupyterPath, jupyterConfigDir,
jupyterDataDir, jupyterRuntimeDir, userHome} = require '../lib/paths'

describe "when jupyterPath is called", ->
it "it returns an array of path strings", ->
kernelspecs = jupyterPath()
expect(Array.isArray(kernelspecs)).toBeTruthy()

for kernelspec in kernelspecs
expect(typeof(kernelspec)).toBe('string')

parsed = path.parse(kernelspec)

expect(parsed.root).toBe('/')
expect(parsed.dir)

describe "when jupyterPath is called with kernels", ->
it "has 'kernels' at the end of each path", ->
kernelspecs = jupyterPath('kernels')
for kernelspec in kernelspecs
parsed = path.parse(kernelspec)
expect(parsed.base).toBe('kernels')

describe "JupyterPath mocked", ->
describe "when on OS X", ->
it "has OS X specific system directories", ->
spyOn(process, 'platform')
process.platform = 'darwin'

{jupyterDataDir} = require '../lib/paths'

expect(jupyterDataDir()).toContain("/Library/Jupyter")

describe "Windows Path testing", ->

beforeEach ->
# process.platform is not writeable but it can be overridden with
# defineProperty
Object.defineProperty(process, 'platform', {
value: 'win32'
})

path.sep = path.win32.sep
Object.defineProperty(path, 'sep', {
value: "\\"
})

path.separator = path.win32.separator
Object.defineProperty(path, 'separator', {
value: "\\"
})


describe "when on Windows", ->
it "respects APPDATA", ->
process.env['APPDATA'] = "C:\\USERS\\Jovyan\\AppData"

{jupyterPath, jupyterConfigDir,
jupyterDataDir, jupyterRuntimeDir, userHome} = require '../lib/paths'

expect(jupyterDataDir()).toContain("C:\\USERS\\Jovyan\\AppData")

0 comments on commit 8e209ed

Please sign in to comment.