Skip to content

Commit

Permalink
forgot to include these files
Browse files Browse the repository at this point in the history
  • Loading branch information
sbabayan committed May 7, 2019
1 parent 259d4c2 commit 4c49b8b
Show file tree
Hide file tree
Showing 9 changed files with 117 additions and 24 deletions.
5 changes: 3 additions & 2 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
# TabPy Changelog

This file list notable changes for TabPy project releases.
This file lists notable changes for TabPy project releases.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

## v0.5

### Improvements
- Scripts & documentation for models

- Scripts, documentation, and integration tests for models

## v0.4.1

Expand Down
2 changes: 2 additions & 0 deletions docs/security.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

The following security issues should be kept in mind as you use TabPy with Tableau:

- tabpy_tools client does not validate that the tabpy server cert is signed
by a trusted CA
- REST server and Python execution context are the same meaning they share
Python session, e.g. HTTP requests are served in the same space where
user scripts are evaluated.
Expand Down
20 changes: 16 additions & 4 deletions docs/tabpy-tools.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,13 +163,13 @@ client.remove('WillItDefault')
To setup models download the latest version of TabPy and follow the [instructions](server-download.md)
to install and start up your server. Once your server is running, navigate to the
models directory and run setup.py. If your TabPy server is running on the default
port (9004), you do not need to specify a port when launching the script. If your
server is running on a port other than 9004 you can specify a different port in
the command line like so:
config (default.conf), you do not need to specify a config file when launching the
script. If your server is running using a custom config you can specify the config
in the command line like so:

```sh

python setup.py 4047
python setup.py custom.conf

```

Expand All @@ -187,6 +187,18 @@ copy any python file to the `./models/scripts` directory and modify setup.py to
include all necessary packages when installing dependencies or alternatively install
all the required dependencies manually.

You can deploy models individually by navigating to models/scripts/ and running
each file in isolation like so:

```sh

python PCA.py

```

Similarly to the setup script, if your server is running using a custom config,
you can specify the config's file path through the command line.

### Principal Component Analysis (PCA)

[Principal component analysis](https://en.wikipedia.org/wiki/Principal_component_analysis)
Expand Down
38 changes: 32 additions & 6 deletions models/scripts/PCA.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
from sklearn.preprocessing import LabelEncoder
from sklearn.preprocessing import OneHotEncoder
import sys

import getpass
from pathlib import Path
import configparser

def PCA(component, _arg1, _arg2, *_argN):
'''
Expand All @@ -21,7 +23,7 @@ def PCA(component, _arg1, _arg2, *_argN):
oneHotEncoder = OneHotEncoder(categories='auto', sparse=False)

for col in cols:
if (type(col[0]) is int or type(col[0]) is float):
if isinstance(col[0], (int,float)):
encodedCols.append(col)
elif (type(col[0]) is bool):
intCol = array(col)
Expand All @@ -39,7 +41,7 @@ def PCA(component, _arg1, _arg2, *_argN):

dataDict = {}
for i in range(len(encodedCols)):
dataDict['col' + str(1 + i)] = list(encodedCols[i])
dataDict[f'col{1 + i}'] = list(encodedCols[i])

if (component <= 0 or component > len(dataDict)):
print('ERROR: Component specified must be >= 0 and '
Expand All @@ -57,9 +59,33 @@ def PCA(component, _arg1, _arg2, *_argN):


if __name__ == '__main__':
port = sys.argv[1]
# to do: once auth is enabled in tabpy-tools this will need to be updated
connection = Client('http://localhost:' + port + '/')
#running from setup.py
if (len(sys.argv) > 1):
config_file_path = sys.argv[1]
else:
config_file_path = str(Path(__file__).resolve().parent.parent.parent
/ 'tabpy-server' / 'tabpy_server' / 'common'
/ 'default.conf')
config = configparser.ConfigParser()
config.read(config_file_path)
tabpy_config = config['TabPy']
port = tabpy_config['TABPY_PORT']
auth_on = 'TABPY_PWD_FILE' in tabpy_config
ssl_on = 'TABPY_TRANSFER_PROTOCOL' in tabpy_config and 'TABPY_CERTIFICATE_FILE' in tabpy_config and 'TABPY_KEY_FILE' in tabpy_config
prefix = "https" if ssl_on else "http"

connection = Client(f'{prefix}://localhost:{port}/')

if(auth_on):
#credentials are passed in from setup.py
if(len(sys.argv) == 4):
user, passwd = sys.argv[2], sys.argv[3]
#running PCA independently
else:
user = input("Username: ")
passwd = getpass.getpass("Password: ")
connection.set_credentials(user, passwd)

connection.deploy('PCA', PCA,
'Returns the specified principal component.',
override=True)
Expand Down
33 changes: 30 additions & 3 deletions models/scripts/SentimentAnalysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
from textblob import TextBlob
from nltk.sentiment import SentimentIntensityAnalyzer
import sys
import configparser
import getpass
from pathlib import Path


def SentimentAnalysis(_arg1, library='nltk'):
Expand Down Expand Up @@ -33,9 +36,33 @@ def SentimentAnalysis(_arg1, library='nltk'):


if __name__ == '__main__':
port = sys.argv[1]
# to do: once auth is enabled in tabpy-tools this will need to be updated
connection = Client('http://localhost:' + port + '/')
#running from setup.py
if (len(sys.argv) > 1):
config_file_path = sys.argv[1]
else:
config_file_path = str(Path(__file__).resolve().parent.parent.parent
/ 'tabpy-server' / 'tabpy_server' / 'common'
/ 'default.conf')
config = configparser.ConfigParser()
config.read(config_file_path)
tabpy_config = config['TabPy']
port = tabpy_config['TABPY_PORT']
auth_on = 'TABPY_PWD_FILE' in tabpy_config
ssl_on = 'TABPY_TRANSFER_PROTOCOL' in tabpy_config and 'TABPY_CERTIFICATE_FILE' in tabpy_config and 'TABPY_KEY_FILE' in tabpy_config
prefix = "https" if ssl_on else "http"

connection = Client(f'{prefix}://localhost:{port}/')

if(auth_on):
#credentials are passed in from setup.py
if(len(sys.argv) == 4):
user, passwd = sys.argv[2], sys.argv[3]
#running Sentiment Analysis independently
else:
user = input("Username: ")
passwd = getpass.getpass("Password: ")
connection.set_credentials(user, passwd)

connection.deploy('Sentiment Analysis', SentimentAnalysis,
'Returns a sentiment score between -1 and '
'1 for a given string.', override=True)
Expand Down
37 changes: 29 additions & 8 deletions models/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
import os
import sys
import platform
import subprocess
import getpass
from pathlib import Path
import configparser

# pip 10.0 introduced a breaking change that moves the location of main
try:
Expand All @@ -21,20 +25,37 @@ def install_dependencies(packages):
if __name__ == '__main__':
install_dependencies(['sklearn', 'pandas', 'numpy',
'textblob', 'nltk', 'scipy'])
print('===================================================================')
# Determine if we run python or python3
if platform.system() == 'Windows':
py = 'python '
else:
py = 'python3 '

# When no port is specified we will assume the default of 9004
if len(sys.argv) == 1:
port = 9004
if (len(sys.argv) > 1):
config_file_path = sys.argv[1]
else:
config_file_path = str(Path(__file__).resolve().parent.parent
/ 'tabpy-server' / 'tabpy_server'
/ 'common' / 'default.conf')
print(f'Using config file at {config_file_path}')
config = configparser.ConfigParser()
config.read(config_file_path)
auth_on = 'TABPY_PWD_FILE' in config['TabPy']
if (auth_on):
if sys.stdin.isatty():
user = input("Username: ")
passwd = getpass.getpass("Password: ")
else:
user = sys.stdin.readline().rstrip()
passwd = sys.stdin.readline().rstrip()
auth_args = [user, passwd]
else:
port = sys.argv[1]
auth_args = []

directory = str(Path(__file__).resolve().parent / 'scripts')
# Deploy each model in the scripts directory
directory = os.path.join(os.path.dirname(os.path.abspath(__file__)),
'scripts/')
for filename in os.listdir(directory):
path = py + directory + filename + ' ' + str(port)
os.system(path)
subprocess.call([py, f'{directory}/{filename}', config_file_path]
+ auth_args)

2 changes: 2 additions & 0 deletions tabpy-tools/tabpy_tools/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ def __init__(self,
self._endpoint = endpoint

session = requests.session()
session.verify = False
requests.packages.urllib3.disable_warnings()

# Setup the communications layer.
network_wrapper = RequestsNetworkWrapper(session)
Expand Down
2 changes: 2 additions & 0 deletions tests/integration/integ_test_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,11 +202,13 @@ def setUp(self):
# startup script
with open(self.tmp_dir + '/output.txt', 'w') as outfile:
if platform.system() == 'Windows':
self.py = 'python'
self.process = subprocess.Popen(
['startup.cmd', self.config_file_name],
stdout=outfile,
stderr=outfile)
else:
self.py = 'python3'
self.process = subprocess.Popen(
['./startup.sh',
'--config=' + self.config_file_name],
Expand Down
2 changes: 1 addition & 1 deletion tests/integration/test_deploy_model_ssl_off_auth_on.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class TestDeployModelSSLOffAuthOn(integ_test_base.IntegTestBase):
def _get_pwd_file(self) -> str:
return './tests/integration/resources/pwdfile.txt'

def test_deploy_ssl_off_auth_on_valid_credentials(self):
def test_deploy_ssl_off_auth_on(self):
path = str(Path('models', 'setup.py'))
p = subprocess.run([self.py, path, self._get_config_file_name()],
input=b'user1\nP@ssw0rd\n')
Expand Down

0 comments on commit 4c49b8b

Please sign in to comment.