Skip to content
This repository has been archived by the owner on Jan 21, 2021. It is now read-only.

Commit

Permalink
Merge branch 'multi_platform_imp_runserver' into dev
Browse files Browse the repository at this point in the history
  • Loading branch information
jochemb committed Mar 11, 2016
2 parents 06d7d28 + ddcce55 commit 9a29af8
Show file tree
Hide file tree
Showing 4 changed files with 206 additions and 26 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ venv/
arborist-settings.json
*.pyc
dist/
*.egg-info/
*.egg*
build/
77 changes: 55 additions & 22 deletions arborist/__init__.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@

import os
import sys
from collections import OrderedDict

from flask import Flask, flash, request, redirect, url_for, render_template, \
json, Response, send_from_directory
from werkzeug import secure_filename
from werkzeug.routing import BaseConverter, ValidationError

import urllib
from markupsafe import Markup
Expand All @@ -20,14 +22,57 @@
STUDIES_FOLDER = 'studies'
ALLOWED_EXTENSIONS = set(['txt', 'tsv'])

app = Flask(__name__)
path = os.path.dirname(os.path.realpath(__file__))
# See if the application is run from windows executable.
if path.find('library.zip') >= 0:
pos = path.find('library.zip')
path = path[:pos]
app = Flask(__name__,
static_folder=path+'static',
template_folder=path+'templates')

# See if the application is run from inside a .app (MacOSX)
elif path.find('.app/Contents/Resources/') >= 0:
pos = path.rfind('lib/')
path = path[:pos]
app = Flask(__name__,
static_folder=path + 'static',
template_folder=path + 'templates')
else:
app = Flask(__name__)

app.secret_key = 'not_so_secret'

app.jinja_env.add_extension("jinja2.ext.do")
app.jinja_env.trim_blocks = True
app.jinja_env.lstrip_blocks = True
app.jinja_env.filters['path_join'] = lambda paths: os.path.join(*paths)


def add_slash_if_not_windows(url_path):
if sys.platform != 'win32':
url_path = '/' + url_path
print "not windows: "+url_path
else:
print "windows: "+url_path
return url_path


class FolderPathConverter(BaseConverter):
def __init__(self, url_map):
print "init!"
super(FolderPathConverter, self).__init__(url_map)
self.regex = '.*'

def to_python(self, value):
print "FolderPathConverter: "+value
return add_slash_if_not_windows(value)

def to_url(self, value):
return value

app.url_map.converters['folderpath'] = FolderPathConverter

if not os.path.isdir(STUDIES_FOLDER):
os.mkdir(STUDIES_FOLDER)

Expand Down Expand Up @@ -57,9 +102,8 @@ def index():


@app.route('/folder/create/', defaults={'studiesfolder': ''}, methods=['POST'])
@app.route('/folder/<path:studiesfolder>/create/', methods=['POST'])
@app.route('/folder/<folderpath:studiesfolder>/create/', methods=['POST'])
def create_folder(studiesfolder):
studiesfolder = '/'+studiesfolder
if 'foldername' in request.form:
foldername = os.path.join(studiesfolder,
request.form['foldername'])
Expand All @@ -72,9 +116,8 @@ def create_folder(studiesfolder):


@app.route('/folder/', defaults={'studiesfolder': ''})
@app.route('/folder/<path:studiesfolder>/')
@app.route('/folder/<folderpath:studiesfolder>/')
def studies_overview(studiesfolder):
studiesfolder = '/'+studiesfolder
parentfolder = os.path.abspath(os.path.join(studiesfolder, os.pardir))
studies = {}

Expand All @@ -98,10 +141,8 @@ def studies_overview(studiesfolder):


@app.route('/folder/s/<study>/', defaults={'studiesfolder': ''})
@app.route('/folder/<path:studiesfolder>/s/<study>/')
@app.route('/folder/<folderpath:studiesfolder>/s/<study>/')
def study_page(studiesfolder, study):
studiesfolder = '/'+studiesfolder

paramsdict = {}

for datatype in possible_datatypes:
Expand Down Expand Up @@ -148,9 +189,8 @@ def study_page(studiesfolder, study):
possible_datatypes=possible_datatypes)


@app.route(('/folder/<path:studiesfolder>/s/<study>/clinical/create/'))
@app.route(('/folder/<folderpath:studiesfolder>/s/<study>/clinical/create/'))
def create_mapping_file(studiesfolder, study):
studiesfolder = '/'+studiesfolder
columnmappingfile = 'COLUMN_MAP_FILE'
wordmappingfile = 'WORD_MAP_FILE'

Expand Down Expand Up @@ -179,9 +219,8 @@ def create_mapping_file(studiesfolder, study):
return json.jsonify(mappingfilename=mappingfilename)


@app.route('/folder/<path:studiesfolder>/s/<study>/params/<datatype>/create/')
@app.route('/folder/<folderpath:studiesfolder>/s/<study>/params/<datatype>/create/')
def create_params(studiesfolder, study, datatype):
studiesfolder = '/'+studiesfolder
feedback = get_feedback_dict()
paramsfile = os.path.join(studiesfolder, study, datatype+'.params')

Expand All @@ -201,10 +240,9 @@ def create_params(studiesfolder, study, datatype):
datatype=datatype))


@app.route('/folder/<path:studiesfolder>/s/<study>/params/<datatype>/',
@app.route('/folder/<folderpath:studiesfolder>/s/<study>/params/<datatype>/',
methods=['GET', 'POST'])
def edit_params(studiesfolder, study, datatype):
studiesfolder = '/'+studiesfolder
feedback = get_feedback_dict()
paramsfile = os.path.join(studiesfolder, study, datatype+'.params')

Expand Down Expand Up @@ -275,11 +313,8 @@ def edit_params(studiesfolder, study, datatype):
feedback=feedback)


@app.route('/folder/<path:studiesfolder>/s/<study>/tree/')
@app.route('/folder/<folderpath:studiesfolder>/s/<study>/tree/')
def edit_tree(studiesfolder, study):
studiesfolder = '/'+studiesfolder

# Get column mapping file and paths in there
columnsfile = get_column_map_file(studiesfolder, study)
if columnsfile is not None:
tree_array = columns_to_tree(columnsfile)
Expand All @@ -306,10 +341,9 @@ def edit_tree(studiesfolder, study):
json=treejson)


@app.route('/folder/<path:studiesfolder>/s/<study>/tree/add/',
@app.route('/folder/<folderpath:studiesfolder>/s/<study>/tree/add/',
methods=['POST'])
def add_datafile(studiesfolder, study):
studiesfolder = '/'+studiesfolder
file = request.files['file']

if file and allowed_file(file.filename):
Expand All @@ -336,10 +370,9 @@ def add_datafile(studiesfolder, study):
study=study))


@app.route('/folder/<path:studiesfolder>/s/<study>/tree/save_columnsfile/',
@app.route('/folder/<folderpath:studiesfolder>/s/<study>/tree/save_columnsfile/',
methods=['POST'])
def save_columnsfile(studiesfolder, study):
studiesfolder = '/'+studiesfolder
feedback = get_feedback_dict()

tree = request.get_json()
Expand Down
24 changes: 23 additions & 1 deletion runserver.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,31 @@
#!/usr/bin/env python
from arborist import app
import socket
import argparse
import webbrowser

parser = argparse.ArgumentParser(description='Launch the Arborist')
parser.add_argument('--debug', action="store_true", default=False, help="Run in debug mode")
parser.add_argument('--port', type=int,
help="Set port to try to listen to. By default the OS is asked what port to use.")
args = parser.parse_args()

app.run(debug=args.debug)

def get_open_port():
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('', 0))
s.listen(1)
port = s.getsockname()[1]
s.close()
return port

if not args.port:
port = get_open_port()
else:
port = args.port

if not args.debug:
running_on = 'http://localhost:{}'.format(port)
webbrowser.open(running_on, new=0, autoraise=True)

app.run(debug=args.debug, port=port)
129 changes: 127 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,141 @@
"""
Setuptools and py2app/py2exe build script for transmart-arborist.
To install dependencies for your machine:
Usage:
python setup.py install
To build a packaged executable:
Usage (Mac OS X):
python setup.py py2app
Usage (Windows):
python setup.py py2exe
"""

import sys
import os
import glob
from setuptools import setup, find_packages

mainscript = 'runserver.py'
extra_options = {}
# Which directories to take all normal files from, these have to be specified explicitely.
patterns = [
'static/*',
'templates/*',
'static/img/*',
'static/img/message/*',
'static/img/tree/*',
'static/jstree/*',
'static/jstree/dist/*',
'static/jstree/dist/themes/*',
'static/jstree/dist/themes/default/*',
'static/jstree/dist/themes/default-dark/*',
]


def find_data_files(source, target, patterns):
"""Locates the specified data-files and returns the matches
in a data_files compatible format.
source is the root of the source data tree.
Use '' or '.' for current directory.
target is the root of the target data tree.
Use '' or '.' for the distribution directory.
patterns is a sequence of glob-patterns for the
files you want to copy.
"""
if glob.has_magic(source) or glob.has_magic(target):
raise ValueError("Magic not allowed in src, target")
ret = {}
for pattern in patterns:
pattern = os.path.join(source, pattern)
for filename in glob.glob(pattern):
if os.path.isfile(filename):
targetpath = os.path.join(target, os.path.relpath(filename, source))
path = os.path.dirname(targetpath)
ret.setdefault(path, []).append(filename)
return sorted(ret.items())


def osx_app_build_options():
"""
Collects additional requirements for building a MacOSX packaged executable. Only works on
OS X and must have py2app manually installed.
"""
data_files = find_data_files(source=os.getcwd() + '/arborist',
target='',
patterns=patterns)
py2app_options = {'argv_emulation': True,
'packages': ['jinja2',
'flask',
'email',
],
'includes': ['os',
'flask',
'sys',
],
'excludes': ['mime'],
}

extra_options = dict(setup_requires=['py2app'],
app=[mainscript],
options={'py2app': py2app_options},
data_files=data_files,
)
return extra_options


def win32_exe_build_options():
"""
This collects additional requirements for building a Windows executable.
only works when running from Windows and having manually
installed the py2exe package.
"""
import py2exe
data_files = find_data_files(source=os.getcwd() + r'/arborist',
target='',
patterns=patterns)
py2exe_options = {'packages': ['werkzeug',
'email.mime',
'jinja2',
],
'includes': ['os',
'flask',
'sys',
'jinja2.ext',
],
}

extra_options = dict(setup_requires=['py2exe'],
console=[mainscript],
options={'py2exe': py2exe_options},
data_files=data_files,
)
return extra_options


if sys.platform == 'darwin' and 'py2app' in sys.argv:
extra_options = osx_app_build_options()


elif sys.platform == 'win32' and 'py2exe' in sys.argv:
extra_options = win32_exe_build_options()


setup(
name='tranSMART Arborist',
version='1.3',
description='Graphical tool to help you prepare your data for loading into the tranSMART data warehouse',
url='https://github.com/thehyve/transmart-arborist',
author='Ward Weistra',
author='Ward Weistra and Jochem Bijlard',
author_email='[email protected]',
license='GNU General Public License V3',
packages=find_packages(),
include_package_data=True,
zip_safe=False,
install_requires=['Flask'],
scripts=['runserver.py']
scripts=[mainscript],
**extra_options
)

0 comments on commit 9a29af8

Please sign in to comment.