tabpy 2.9.0__tar.gz → 2.10.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {tabpy-2.9.0 → tabpy-2.10.0}/.github/workflows/pull_request.yml +3 -2
- {tabpy-2.9.0 → tabpy-2.10.0}/.github/workflows/push.yml +4 -3
- {tabpy-2.9.0 → tabpy-2.10.0}/.scrutinizer.yml +7 -1
- {tabpy-2.9.0 → tabpy-2.10.0}/CHANGELOG +8 -0
- {tabpy-2.9.0/tabpy.egg-info → tabpy-2.10.0}/PKG-INFO +34 -1
- {tabpy-2.9.0 → tabpy-2.10.0}/README.md +12 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/docs/server-config.md +8 -4
- {tabpy-2.9.0 → tabpy-2.10.0}/docs/server-install.md +11 -1
- tabpy-2.10.0/tabpy/VERSION +1 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tabpy/tabpy_server/app/app.py +22 -4
- {tabpy-2.9.0 → tabpy-2.10.0}/tabpy/tabpy_server/app/app_parameters.py +2 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tabpy/tabpy_server/app/util.py +1 -1
- {tabpy-2.9.0 → tabpy-2.10.0}/tabpy/tabpy_server/common/default.conf +1 -0
- {tabpy-2.9.0 → tabpy-2.10.0/tabpy.egg-info}/PKG-INFO +34 -1
- {tabpy-2.9.0 → tabpy-2.10.0}/tabpy.egg-info/SOURCES.txt +1 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tests/integration/integ_test_base.py +2 -1
- tabpy-2.10.0/tests/integration/test_minimum_tls_version.py +54 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tests/unit/server_tests/test_config.py +14 -0
- tabpy-2.9.0/tabpy/VERSION +0 -1
- {tabpy-2.9.0 → tabpy-2.10.0}/.github/ISSUE_TEMPLATE/tabpy-issue-report.md +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/.github/workflows/coverage.yml +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/.github/workflows/docker-publish.yml +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/.github/workflows/lint.yml +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/.gitignore +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/.pep8speaks.yml +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/CONTRIBUTING.md +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/Dockerfile +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/LICENSE +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/MANIFEST.in +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/Procfile +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/_config.yml +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/app.json +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/codeql-analysis.yml +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/docs/TableauConfiguration.md +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/docs/about.md +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/docs/deploy-to-heroku.md +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/docs/img/Example1-SimpleFunctionCall.png +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/docs/img/Example2-MultipleFunctionCalls.png +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/docs/img/python-calculated-field.png +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/docs/security.md +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/docs/server-rest.md +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/docs/tabpy-tools.md +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/docs/tabpy-virtualenv.md +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/misc/TabPy.postman_collection.json +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/misc/TabPy.yml +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/requirements.txt +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/requirements_dev.txt +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/setup.cfg +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/setup.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/start.sh +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tabpy/__init__.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tabpy/models/__init__.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tabpy/models/deploy_models.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tabpy/models/scripts/ANOVA.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tabpy/models/scripts/PCA.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tabpy/models/scripts/SentimentAnalysis.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tabpy/models/scripts/__init__.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tabpy/models/scripts/tTest.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tabpy/models/utils/__init__.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tabpy/models/utils/setup_utils.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tabpy/tabpy.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tabpy/tabpy_server/__init__.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tabpy/tabpy_server/app/__init__.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tabpy/tabpy_server/app/arrow_server.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tabpy/tabpy_server/common/__init__.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tabpy/tabpy_server/common/endpoint_file_mgr.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tabpy/tabpy_server/common/messages.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tabpy/tabpy_server/common/util.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tabpy/tabpy_server/handlers/__init__.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tabpy/tabpy_server/handlers/base_handler.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tabpy/tabpy_server/handlers/basic_auth_server_middleware_factory.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tabpy/tabpy_server/handlers/endpoint_handler.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tabpy/tabpy_server/handlers/endpoints_handler.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tabpy/tabpy_server/handlers/evaluation_plane_handler.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tabpy/tabpy_server/handlers/management_handler.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tabpy/tabpy_server/handlers/no_op_auth_handler.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tabpy/tabpy_server/handlers/query_plane_handler.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tabpy/tabpy_server/handlers/service_info_handler.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tabpy/tabpy_server/handlers/status_handler.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tabpy/tabpy_server/handlers/upload_destination_handler.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tabpy/tabpy_server/handlers/util.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tabpy/tabpy_server/management/__init__.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tabpy/tabpy_server/management/state.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tabpy/tabpy_server/management/util.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tabpy/tabpy_server/psws/__init__.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tabpy/tabpy_server/psws/callbacks.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tabpy/tabpy_server/psws/python_service.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tabpy/tabpy_server/state.ini.template +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tabpy/tabpy_server/static/TabPy_logo.png +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tabpy/tabpy_server/static/index.html +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tabpy/tabpy_server/static/tableau.png +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tabpy/tabpy_tools/__init__.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tabpy/tabpy_tools/client.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tabpy/tabpy_tools/custom_query_object.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tabpy/tabpy_tools/query_object.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tabpy/tabpy_tools/rest.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tabpy/tabpy_tools/rest_client.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tabpy/tabpy_tools/schema.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tabpy/utils/__init__.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tabpy/utils/tabpy_user.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tabpy.egg-info/dependency_links.txt +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tabpy.egg-info/entry_points.txt +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tabpy.egg-info/requires.txt +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tabpy.egg-info/top_level.txt +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tests/__init__.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tests/integration/__init__.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tests/integration/resources/2019_04_24_to_3018_08_25.crt +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tests/integration/resources/2019_04_24_to_3018_08_25.key +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tests/integration/resources/data.csv +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tests/integration/resources/deploy_and_evaluate_model.conf +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tests/integration/resources/deploy_and_evaluate_model_auth.conf +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tests/integration/resources/pwdfile.txt +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tests/integration/test_arrow_server.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tests/integration/test_auth.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tests/integration/test_custom_evaluate_timeout.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tests/integration/test_deploy_and_evaluate_model.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tests/integration/test_deploy_and_evaluate_model_auth_on.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tests/integration/test_deploy_and_evaluate_model_ssl.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tests/integration/test_deploy_model_ssl_off_auth_off.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tests/integration/test_deploy_model_ssl_off_auth_on.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tests/integration/test_deploy_model_ssl_on_auth_off.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tests/integration/test_deploy_model_ssl_on_auth_on.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tests/integration/test_evaluate.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tests/integration/test_gzip.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tests/integration/test_url.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tests/integration/test_url_ssl.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tests/unit/__init__.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tests/unit/server_tests/__init__.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tests/unit/server_tests/resources/expired.crt +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tests/unit/server_tests/resources/future.crt +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tests/unit/server_tests/resources/valid.crt +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tests/unit/server_tests/test_endpoint_file_manager.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tests/unit/server_tests/test_endpoint_handler.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tests/unit/server_tests/test_endpoints_handler.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tests/unit/server_tests/test_evaluation_plane_handler.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tests/unit/server_tests/test_pwd_file.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tests/unit/server_tests/test_service_info_handler.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tests/unit/tools_tests/__init__.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tests/unit/tools_tests/test_client.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tests/unit/tools_tests/test_rest.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tests/unit/tools_tests/test_rest_object.py +0 -0
- {tabpy-2.9.0 → tabpy-2.10.0}/tests/unit/tools_tests/test_schema.py +0 -0
|
@@ -11,8 +11,9 @@ jobs:
|
|
|
11
11
|
matrix:
|
|
12
12
|
# TODO: Add 3.7 to python-versions after GitHub action regression is resolved.
|
|
13
13
|
# https://github.com/actions/setup-python/issues/682
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
# TODO: switch macos-13 to macos-latest@arm64
|
|
15
|
+
python-version: ['3.8', '3.9', '3.10']
|
|
16
|
+
os: [ubuntu-latest, windows-latest, macos-13]
|
|
16
17
|
|
|
17
18
|
steps:
|
|
18
19
|
- uses: actions/checkout@v1
|
|
@@ -11,9 +11,10 @@ jobs:
|
|
|
11
11
|
matrix:
|
|
12
12
|
# TODO: Add 3.7 to python-versions after GitHub action regression is resolved.
|
|
13
13
|
# https://github.com/actions/setup-python/issues/682
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
# TODO: switch macos-13 to macos-latest@arm64
|
|
15
|
+
python-version: ['3.8', '3.9', '3.10']
|
|
16
|
+
os: [ubuntu-latest, windows-latest, macos-13]
|
|
17
|
+
|
|
17
18
|
steps:
|
|
18
19
|
- uses: actions/checkout@v1
|
|
19
20
|
|
|
@@ -10,6 +10,7 @@ build:
|
|
|
10
10
|
tests:
|
|
11
11
|
override:
|
|
12
12
|
- command: 'pytest tests --cov=tabpy --cov-config=setup.cfg'
|
|
13
|
+
idle_timeout: 600
|
|
13
14
|
coverage:
|
|
14
15
|
file: '.coverage'
|
|
15
16
|
config_file: 'setup.cfg'
|
|
@@ -20,10 +21,15 @@ build:
|
|
|
20
21
|
- pip install -r requirements.txt
|
|
21
22
|
tests:
|
|
22
23
|
override: [py-scrutinizer-run]
|
|
24
|
+
dependencies:
|
|
25
|
+
override:
|
|
26
|
+
- pip install .
|
|
23
27
|
tests:
|
|
24
28
|
before:
|
|
25
29
|
- pip install -r requirements.txt
|
|
26
|
-
override:
|
|
30
|
+
override:
|
|
31
|
+
pytest:
|
|
32
|
+
idle_timeout: 600
|
|
27
33
|
checks:
|
|
28
34
|
python:
|
|
29
35
|
code_rating: true
|
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v2.10.0
|
|
4
|
+
|
|
5
|
+
### Improvements
|
|
6
|
+
|
|
7
|
+
- Add TabPy parameter (TABPY_MINIMUM_TLS_VERSION) to specify the minimum TLS
|
|
8
|
+
version that the server will accept for secure connections. Default is
|
|
9
|
+
set to TLSv1_2.
|
|
10
|
+
|
|
3
11
|
## v2.9.0
|
|
4
12
|
|
|
5
13
|
### Improvements
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: tabpy
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.10.0
|
|
4
4
|
Summary: Web server Tableau uses to run Python scripts.
|
|
5
5
|
Home-page: https://github.com/tableau/TabPy
|
|
6
6
|
Download-URL: https://pypi.org/project/tabpy
|
|
@@ -33,6 +33,31 @@ Classifier: Operating System :: MacOS
|
|
|
33
33
|
Requires-Python: >=3.7
|
|
34
34
|
Description-Content-Type: text/markdown
|
|
35
35
|
License-File: LICENSE
|
|
36
|
+
Requires-Dist: cloudpickle
|
|
37
|
+
Requires-Dist: configparser
|
|
38
|
+
Requires-Dist: coverage
|
|
39
|
+
Requires-Dist: coveralls
|
|
40
|
+
Requires-Dist: docopt
|
|
41
|
+
Requires-Dist: future
|
|
42
|
+
Requires-Dist: genson
|
|
43
|
+
Requires-Dist: hypothesis
|
|
44
|
+
Requires-Dist: jsonschema
|
|
45
|
+
Requires-Dist: mock
|
|
46
|
+
Requires-Dist: nltk
|
|
47
|
+
Requires-Dist: numpy
|
|
48
|
+
Requires-Dist: pandas
|
|
49
|
+
Requires-Dist: pyopenssl
|
|
50
|
+
Requires-Dist: pytest
|
|
51
|
+
Requires-Dist: pytest-cov
|
|
52
|
+
Requires-Dist: requests
|
|
53
|
+
Requires-Dist: scipy
|
|
54
|
+
Requires-Dist: simplejson
|
|
55
|
+
Requires-Dist: scikit-learn
|
|
56
|
+
Requires-Dist: textblob
|
|
57
|
+
Requires-Dist: tornado
|
|
58
|
+
Requires-Dist: twisted
|
|
59
|
+
Requires-Dist: urllib3
|
|
60
|
+
Requires-Dist: pyarrow
|
|
36
61
|
|
|
37
62
|
|
|
38
63
|
TabPy (the Tableau Python Server) is an external service implementation
|
|
@@ -41,6 +66,14 @@ scripts and saved functions via Tableau's table calculations.
|
|
|
41
66
|
|
|
42
67
|
# Changelog
|
|
43
68
|
|
|
69
|
+
## v2.10.0
|
|
70
|
+
|
|
71
|
+
### Improvements
|
|
72
|
+
|
|
73
|
+
- Add TabPy parameter (TABPY_MINIMUM_TLS_VERSION) to specify the minimum TLS
|
|
74
|
+
version that the server will accept for secure connections. Default is
|
|
75
|
+
set to TLSv1_2.
|
|
76
|
+
|
|
44
77
|
## v2.9.0
|
|
45
78
|
|
|
46
79
|
### Improvements
|
|
@@ -27,6 +27,18 @@ Consider reading TabPy documentation in the following order:
|
|
|
27
27
|
* [Authoring Python calculations in Tableau](docs/TableauConfiguration.md).
|
|
28
28
|
* [TabPy Tools](docs/tabpy-tools.md)
|
|
29
29
|
|
|
30
|
+
Important security note:
|
|
31
|
+
|
|
32
|
+
* By default, TabPy is configured without username/password authentication.
|
|
33
|
+
We strongly advise using TabPy only with authentication enabled. For more
|
|
34
|
+
information, see
|
|
35
|
+
[TabPy Server Configuration Instructions](docs/server-config.md#authentication).
|
|
36
|
+
Without authentication in place, if the TABPY_EVALUATE_ENABLE feature is
|
|
37
|
+
enabled (as it is by default), there is the possibility that unauthenticated
|
|
38
|
+
individuals could remotely execute code on the machine running TabPy.
|
|
39
|
+
Leaving these two settings in their default states together is highly
|
|
40
|
+
discouraged.
|
|
41
|
+
|
|
30
42
|
Troubleshooting:
|
|
31
43
|
|
|
32
44
|
* [TabPy Wiki](https://github.com/tableau/TabPy/wiki)
|
|
@@ -8,7 +8,6 @@
|
|
|
8
8
|
* [Configuration File Content](#configuration-file-content)
|
|
9
9
|
* [Configuration File Example](#configuration-file-example)
|
|
10
10
|
- [Configuring HTTP vs HTTPS](#configuring-http-vs-https)
|
|
11
|
-
- [Configuring TPS](#configuring-http-vs-https)
|
|
12
11
|
- [Authentication](#authentication)
|
|
13
12
|
* [Enabling Authentication](#enabling-authentication)
|
|
14
13
|
* [Password File](#password-file)
|
|
@@ -83,6 +82,10 @@ at [`logging.config` documentation page](https://docs.python.org/3.6/library/log
|
|
|
83
82
|
- `TABPY_KEY_FILE` - absolute path to private key file to run TabPy with.
|
|
84
83
|
Only used with `TABPY_TRANSFER_PROTOCOL` set to `https`. Default value -
|
|
85
84
|
not set.
|
|
85
|
+
- `TABPY_MINIMUM_TLS_VERSION` - set the minimum TLS version that the server
|
|
86
|
+
will accept for secure connections (`TLSv1_2`, `TLSv1_3`, etc). Refer to
|
|
87
|
+
[docs.python.org](https://docs.python.org/3/library/ssl.html#ssl.TLSVersion.MINIMUM_SUPPORTED)
|
|
88
|
+
for acceptable values. Default value - `TLSv1_2`.
|
|
86
89
|
- `TABPY_LOG_DETAILS` - when set to `true` additional call information
|
|
87
90
|
(caller IP, URL, client info, etc.) is logged. Default value - `false`.
|
|
88
91
|
- `TABPY_MAX_REQUEST_SIZE_MB` - maximal request size supported by TabPy server
|
|
@@ -124,6 +127,7 @@ settings._
|
|
|
124
127
|
# TABPY_TRANSFER_PROTOCOL = https
|
|
125
128
|
# TABPY_CERTIFICATE_FILE = /path/to/certificate/file.crt
|
|
126
129
|
# TABPY_KEY_FILE = /path/to/key/file.key
|
|
130
|
+
# TABPY_MINIMUM_TLS_VERSION = TLSv1_2
|
|
127
131
|
|
|
128
132
|
# Log additional request details including caller IP, full URL, client
|
|
129
133
|
# end user info if provided.
|
|
@@ -314,14 +318,14 @@ For extended logging (e.g. for auditing purposes) additional logging can be turn
|
|
|
314
318
|
on with setting `TABPY_LOG_DETAILS` configuration file parameter to `true`.
|
|
315
319
|
|
|
316
320
|
With the feature on additional information is logged for HTTP requests: caller ip,
|
|
317
|
-
URL, client infomation (Tableau Desktop\Server)
|
|
318
|
-
|
|
321
|
+
URL, client infomation (Tableau Desktop\Server) and TabPy user name as shown in
|
|
322
|
+
the example below:
|
|
319
323
|
|
|
320
324
|
<!-- markdownlint-disable MD013 -->
|
|
321
325
|
<!-- markdownlint-disable MD040 -->
|
|
322
326
|
|
|
323
327
|
```
|
|
324
|
-
2019-05-02,13:50:08 [INFO] (base_handler.py:base_handler:90): Call ID: 934073bd-0d29-46d3-b693-b1e4b1efa9e4, Caller: ::1, Method: POST, Resource: http://localhost:9004/evaluate, Client: Postman for manual testing
|
|
328
|
+
2019-05-02,13:50:08 [INFO] (base_handler.py:base_handler:90): Call ID: 934073bd-0d29-46d3-b693-b1e4b1efa9e4, Caller: ::1, Method: POST, Resource: http://localhost:9004/evaluate, Client: Postman for manual testing
|
|
325
329
|
2019-05-02,13:50:08 [DEBUG] (base_handler.py:base_handler:120): Checking if need to handle authentication, <<
|
|
326
330
|
call ID: 934073bd-0d29-46d3-b693-b1e4b1efa9e4>>
|
|
327
331
|
2019-05-02,13:50:08 [DEBUG] (base_handler.py:base_handler:120): Handling authentication, <<call ID: 934073bd-
|
|
@@ -15,6 +15,16 @@ These instructions explain how to install and start up TabPy Server.
|
|
|
15
15
|
|
|
16
16
|
## TabPy Installation
|
|
17
17
|
|
|
18
|
+
### Prerequisites
|
|
19
|
+
|
|
20
|
+
- TabPy only supports Python versions 3.7, 3.8, 3.9, and 3.10
|
|
21
|
+
- TabPy 2.7.0 added support for data streaming via
|
|
22
|
+
Apache Arrow Flight (`pyarrow`). When using TabPy >= 2.7.0, we
|
|
23
|
+
recommend using a Python 64-bit installer to avoid incompatibility issues
|
|
24
|
+
related to `pyarrow`.
|
|
25
|
+
|
|
26
|
+
### Installation
|
|
27
|
+
|
|
18
28
|
To install TabPy on to an environment `pip` needs to be installed and
|
|
19
29
|
updated first:
|
|
20
30
|
|
|
@@ -30,7 +40,7 @@ pip install tabpy
|
|
|
30
40
|
|
|
31
41
|
## Starting TabPy
|
|
32
42
|
|
|
33
|
-
To start TabPy with default
|
|
43
|
+
To start TabPy with default settings run the following command:
|
|
34
44
|
|
|
35
45
|
```sh
|
|
36
46
|
tabpy
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
2.10.0
|
|
@@ -5,6 +5,7 @@ import multiprocessing
|
|
|
5
5
|
import os
|
|
6
6
|
import shutil
|
|
7
7
|
import signal
|
|
8
|
+
import ssl
|
|
8
9
|
import sys
|
|
9
10
|
import _thread
|
|
10
11
|
|
|
@@ -83,6 +84,24 @@ class TabPyApp:
|
|
|
83
84
|
|
|
84
85
|
self._parse_config(config_file)
|
|
85
86
|
|
|
87
|
+
def _initialize_ssl_context(self):
|
|
88
|
+
ssl_context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
|
|
89
|
+
|
|
90
|
+
ssl_context.load_cert_chain(
|
|
91
|
+
certfile=self.settings[SettingsParameters.CertificateFile],
|
|
92
|
+
keyfile=self.settings[SettingsParameters.KeyFile]
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
min_tls = self.settings[SettingsParameters.MinimumTLSVersion]
|
|
96
|
+
if not hasattr(ssl.TLSVersion, min_tls):
|
|
97
|
+
logger.warning(f"Unrecognized value for TABPY_MINIMUM_TLS_VERSION: {min_tls}")
|
|
98
|
+
min_tls = "TLSv1_2"
|
|
99
|
+
|
|
100
|
+
logger.info(f"Setting minimum TLS version to {min_tls}")
|
|
101
|
+
ssl_context.minimum_version = ssl.TLSVersion[min_tls]
|
|
102
|
+
|
|
103
|
+
return ssl_context
|
|
104
|
+
|
|
86
105
|
def _get_tls_certificates(self, config):
|
|
87
106
|
tls_certificates = []
|
|
88
107
|
cert = config[SettingsParameters.CertificateFile]
|
|
@@ -127,10 +146,7 @@ class TabPyApp:
|
|
|
127
146
|
protocol = self.settings[SettingsParameters.TransferProtocol]
|
|
128
147
|
ssl_options = None
|
|
129
148
|
if protocol == "https":
|
|
130
|
-
ssl_options =
|
|
131
|
-
"certfile": self.settings[SettingsParameters.CertificateFile],
|
|
132
|
-
"keyfile": self.settings[SettingsParameters.KeyFile],
|
|
133
|
-
}
|
|
149
|
+
ssl_options = self._initialize_ssl_context()
|
|
134
150
|
elif protocol != "http":
|
|
135
151
|
msg = f"Unsupported transfer protocol {protocol}."
|
|
136
152
|
logger.critical(msg)
|
|
@@ -328,6 +344,8 @@ class TabPyApp:
|
|
|
328
344
|
(SettingsParameters.CertificateFile, ConfigParameters.TABPY_CERTIFICATE_FILE,
|
|
329
345
|
None, None),
|
|
330
346
|
(SettingsParameters.KeyFile, ConfigParameters.TABPY_KEY_FILE, None, None),
|
|
347
|
+
(SettingsParameters.MinimumTLSVersion, ConfigParameters.TABPY_MINIMUM_TLS_VERSION,
|
|
348
|
+
"TLSv1_2", None),
|
|
331
349
|
(SettingsParameters.StateFilePath, ConfigParameters.TABPY_STATE_PATH,
|
|
332
350
|
os.path.join(pkg_path, "tabpy_server"), None),
|
|
333
351
|
(SettingsParameters.StaticPath, ConfigParameters.TABPY_STATIC_PATH,
|
|
@@ -10,6 +10,7 @@ class ConfigParameters:
|
|
|
10
10
|
TABPY_TRANSFER_PROTOCOL = "TABPY_TRANSFER_PROTOCOL"
|
|
11
11
|
TABPY_CERTIFICATE_FILE = "TABPY_CERTIFICATE_FILE"
|
|
12
12
|
TABPY_KEY_FILE = "TABPY_KEY_FILE"
|
|
13
|
+
TABPY_MINIMUM_TLS_VERSION = "TABPY_MINIMUM_TLS_VERSION"
|
|
13
14
|
TABPY_LOG_DETAILS = "TABPY_LOG_DETAILS"
|
|
14
15
|
TABPY_STATIC_PATH = "TABPY_STATIC_PATH"
|
|
15
16
|
TABPY_MAX_REQUEST_SIZE_MB = "TABPY_MAX_REQUEST_SIZE_MB"
|
|
@@ -33,6 +34,7 @@ class SettingsParameters:
|
|
|
33
34
|
UploadDir = "upload_dir"
|
|
34
35
|
CertificateFile = "certificate_file"
|
|
35
36
|
KeyFile = "key_file"
|
|
37
|
+
MinimumTLSVersion = "minimum_tls_version"
|
|
36
38
|
StateFilePath = "state_file_path"
|
|
37
39
|
ApiVersions = "versions"
|
|
38
40
|
LogRequestContext = "log_request_context"
|
|
@@ -17,7 +17,7 @@ def validate_cert(cert_file_path):
|
|
|
17
17
|
date_format, encoding = "%Y%m%d%H%M%SZ", "ascii"
|
|
18
18
|
not_before = datetime.strptime(cert.get_notBefore().decode(encoding), date_format)
|
|
19
19
|
not_after = datetime.strptime(cert.get_notAfter().decode(encoding), date_format)
|
|
20
|
-
now = datetime.
|
|
20
|
+
now = datetime.utcnow()
|
|
21
21
|
|
|
22
22
|
https_error = "Error using HTTPS: "
|
|
23
23
|
if now < not_before:
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
# TABPY_TRANSFER_PROTOCOL = https
|
|
16
16
|
# TABPY_CERTIFICATE_FILE = /path/to/certificate/file.crt
|
|
17
17
|
# TABPY_KEY_FILE = /path/to/key/file.key
|
|
18
|
+
# TABPY_MINIMUM_TLS_VERSION = TLSv1_2
|
|
18
19
|
|
|
19
20
|
# Log additional request details including caller IP, full URL, client
|
|
20
21
|
# end user info if provided.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: tabpy
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.10.0
|
|
4
4
|
Summary: Web server Tableau uses to run Python scripts.
|
|
5
5
|
Home-page: https://github.com/tableau/TabPy
|
|
6
6
|
Download-URL: https://pypi.org/project/tabpy
|
|
@@ -33,6 +33,31 @@ Classifier: Operating System :: MacOS
|
|
|
33
33
|
Requires-Python: >=3.7
|
|
34
34
|
Description-Content-Type: text/markdown
|
|
35
35
|
License-File: LICENSE
|
|
36
|
+
Requires-Dist: cloudpickle
|
|
37
|
+
Requires-Dist: configparser
|
|
38
|
+
Requires-Dist: coverage
|
|
39
|
+
Requires-Dist: coveralls
|
|
40
|
+
Requires-Dist: docopt
|
|
41
|
+
Requires-Dist: future
|
|
42
|
+
Requires-Dist: genson
|
|
43
|
+
Requires-Dist: hypothesis
|
|
44
|
+
Requires-Dist: jsonschema
|
|
45
|
+
Requires-Dist: mock
|
|
46
|
+
Requires-Dist: nltk
|
|
47
|
+
Requires-Dist: numpy
|
|
48
|
+
Requires-Dist: pandas
|
|
49
|
+
Requires-Dist: pyopenssl
|
|
50
|
+
Requires-Dist: pytest
|
|
51
|
+
Requires-Dist: pytest-cov
|
|
52
|
+
Requires-Dist: requests
|
|
53
|
+
Requires-Dist: scipy
|
|
54
|
+
Requires-Dist: simplejson
|
|
55
|
+
Requires-Dist: scikit-learn
|
|
56
|
+
Requires-Dist: textblob
|
|
57
|
+
Requires-Dist: tornado
|
|
58
|
+
Requires-Dist: twisted
|
|
59
|
+
Requires-Dist: urllib3
|
|
60
|
+
Requires-Dist: pyarrow
|
|
36
61
|
|
|
37
62
|
|
|
38
63
|
TabPy (the Tableau Python Server) is an external service implementation
|
|
@@ -41,6 +66,14 @@ scripts and saved functions via Tableau's table calculations.
|
|
|
41
66
|
|
|
42
67
|
# Changelog
|
|
43
68
|
|
|
69
|
+
## v2.10.0
|
|
70
|
+
|
|
71
|
+
### Improvements
|
|
72
|
+
|
|
73
|
+
- Add TabPy parameter (TABPY_MINIMUM_TLS_VERSION) to specify the minimum TLS
|
|
74
|
+
version that the server will accept for secure connections. Default is
|
|
75
|
+
set to TLSv1_2.
|
|
76
|
+
|
|
44
77
|
## v2.9.0
|
|
45
78
|
|
|
46
79
|
### Improvements
|
|
@@ -113,6 +113,7 @@ tests/integration/test_deploy_model_ssl_on_auth_off.py
|
|
|
113
113
|
tests/integration/test_deploy_model_ssl_on_auth_on.py
|
|
114
114
|
tests/integration/test_evaluate.py
|
|
115
115
|
tests/integration/test_gzip.py
|
|
116
|
+
tests/integration/test_minimum_tls_version.py
|
|
116
117
|
tests/integration/test_url.py
|
|
117
118
|
tests/integration/test_url_ssl.py
|
|
118
119
|
tests/integration/resources/2019_04_24_to_3018_08_25.crt
|
|
@@ -225,7 +225,8 @@ class IntegTestBase(unittest.TestCase):
|
|
|
225
225
|
|
|
226
226
|
# Platform specific - for integration tests we want to engage
|
|
227
227
|
# startup script
|
|
228
|
-
|
|
228
|
+
self.log_file_path = os.path.join(self.tmp_dir, "output.txt")
|
|
229
|
+
with open(self.log_file_path, "w") as outfile:
|
|
229
230
|
cmd = ["tabpy", "--config=" + self.config_file_name, "--disable-auth-warning"]
|
|
230
231
|
preexec_fn = None
|
|
231
232
|
if platform.system() == "Windows":
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
from . import integ_test_base
|
|
2
|
+
import os
|
|
3
|
+
|
|
4
|
+
class TestMinimumTLSVersion(integ_test_base.IntegTestBase):
|
|
5
|
+
def _get_log_contents(self):
|
|
6
|
+
with open(self.log_file_path, 'r') as f:
|
|
7
|
+
return f.read()
|
|
8
|
+
|
|
9
|
+
def _get_config_file_name(self, tls_version: str) -> str:
|
|
10
|
+
config_file = open(os.path.join(self.tmp_dir, "test.conf"), "w+")
|
|
11
|
+
config_file.write(
|
|
12
|
+
"[TabPy]\n"
|
|
13
|
+
"TABPY_PORT = 9005\n"
|
|
14
|
+
"TABPY_TRANSFER_PROTOCOL = https\n"
|
|
15
|
+
"TABPY_CERTIFICATE_FILE = ./tests/integration/resources/2019_04_24_to_3018_08_25.crt\n"
|
|
16
|
+
"TABPY_KEY_FILE = ./tests/integration/resources/2019_04_24_to_3018_08_25.key\n"
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
if tls_version is not None:
|
|
20
|
+
config_file.write(f"TABPY_MINIMUM_TLS_VERSION = {tls_version}")
|
|
21
|
+
|
|
22
|
+
pwd_file = self._get_pwd_file()
|
|
23
|
+
if pwd_file is not None:
|
|
24
|
+
pwd_file = os.path.abspath(pwd_file)
|
|
25
|
+
config_file.write(f"TABPY_PWD_FILE = {pwd_file}\n")
|
|
26
|
+
|
|
27
|
+
config_file.close()
|
|
28
|
+
self.delete_config_file = True
|
|
29
|
+
return config_file.name
|
|
30
|
+
|
|
31
|
+
class TestMinimumTLSVersionValid(TestMinimumTLSVersion):
|
|
32
|
+
def _get_config_file_name(self) -> str:
|
|
33
|
+
return super()._get_config_file_name("TLSv1_3")
|
|
34
|
+
|
|
35
|
+
def test_minimum_tls_version_valid(self):
|
|
36
|
+
log_contents = self._get_log_contents()
|
|
37
|
+
self.assertIn("Setting minimum TLS version to TLSv1_3", log_contents)
|
|
38
|
+
|
|
39
|
+
class TestMinimumTLSVersionInvalid(TestMinimumTLSVersion):
|
|
40
|
+
def _get_config_file_name(self) -> str:
|
|
41
|
+
return super()._get_config_file_name("TLSv-1.3")
|
|
42
|
+
|
|
43
|
+
def test_minimum_tls_version_invalid(self):
|
|
44
|
+
log_contents = self._get_log_contents()
|
|
45
|
+
self.assertIn("Unrecognized value for TABPY_MINIMUM_TLS_VERSION", log_contents)
|
|
46
|
+
self.assertIn("Setting minimum TLS version to TLSv1_2", log_contents)
|
|
47
|
+
|
|
48
|
+
class TestMinimumTLSVersionNotSpecified(TestMinimumTLSVersion):
|
|
49
|
+
def _get_config_file_name(self) -> str:
|
|
50
|
+
return super()._get_config_file_name(None)
|
|
51
|
+
|
|
52
|
+
def test_minimum_tls_version_not_specified(self):
|
|
53
|
+
log_contents = self._get_log_contents()
|
|
54
|
+
self.assertIn("Setting minimum TLS version to TLSv1_2", log_contents)
|
|
@@ -209,6 +209,20 @@ class TestPartialConfigFile(unittest.TestCase):
|
|
|
209
209
|
app = TabPyApp(self.config_file.name)
|
|
210
210
|
self.assertEqual(app.settings["gzip_enabled"], False)
|
|
211
211
|
|
|
212
|
+
@patch("tabpy.tabpy_server.app.app.os.path.exists", return_value=True)
|
|
213
|
+
@patch("tabpy.tabpy_server.app.app._get_state_from_file")
|
|
214
|
+
@patch("tabpy.tabpy_server.app.app.TabPyState")
|
|
215
|
+
def test_min_tls_setting_valid(
|
|
216
|
+
self, mock_state, mock_get_state_from_file, mock_path_exists
|
|
217
|
+
):
|
|
218
|
+
self.assertTrue(self.config_file is not None)
|
|
219
|
+
config_file = self.config_file
|
|
220
|
+
config_file.write("[TabPy]\n" "TABPY_MINIMUM_TLS_VERSION = TLSv1_3".encode())
|
|
221
|
+
config_file.close()
|
|
222
|
+
|
|
223
|
+
app = TabPyApp(self.config_file.name)
|
|
224
|
+
self.assertEqual(app.settings["minimum_tls_version"], "TLSv1_3")
|
|
225
|
+
|
|
212
226
|
class TestTransferProtocolValidation(unittest.TestCase):
|
|
213
227
|
def assertTabPyAppRaisesRuntimeError(self, expected_message):
|
|
214
228
|
with self.assertRaises(RuntimeError) as err:
|
tabpy-2.9.0/tabpy/VERSION
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
2.9.0
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tabpy-2.9.0 → tabpy-2.10.0}/tabpy/tabpy_server/handlers/basic_auth_server_middleware_factory.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tabpy-2.9.0 → tabpy-2.10.0}/tests/integration/resources/deploy_and_evaluate_model_auth.conf
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|