tabpy 2.9.0__tar.gz → 2.11.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.
Files changed (143) hide show
  1. {tabpy-2.9.0 → tabpy-2.11.0}/.github/workflows/coverage.yml +1 -1
  2. {tabpy-2.9.0 → tabpy-2.11.0}/.github/workflows/lint.yml +1 -1
  3. {tabpy-2.9.0 → tabpy-2.11.0}/.github/workflows/pull_request.yml +3 -4
  4. {tabpy-2.9.0 → tabpy-2.11.0}/.github/workflows/push.yml +4 -5
  5. {tabpy-2.9.0 → tabpy-2.11.0}/.scrutinizer.yml +8 -2
  6. {tabpy-2.9.0 → tabpy-2.11.0}/CHANGELOG +15 -0
  7. {tabpy-2.9.0 → tabpy-2.11.0}/CONTRIBUTING.md +2 -2
  8. {tabpy-2.9.0 → tabpy-2.11.0}/LICENSE +1 -1
  9. {tabpy-2.9.0 → tabpy-2.11.0}/PKG-INFO +44 -3
  10. {tabpy-2.9.0 → tabpy-2.11.0}/README.md +12 -1
  11. {tabpy-2.9.0 → tabpy-2.11.0}/docs/server-config.md +8 -4
  12. {tabpy-2.9.0 → tabpy-2.11.0}/docs/server-install.md +7 -1
  13. {tabpy-2.9.0 → tabpy-2.11.0}/docs/tabpy-virtualenv.md +1 -1
  14. {tabpy-2.9.0 → tabpy-2.11.0}/setup.py +3 -2
  15. tabpy-2.11.0/tabpy/VERSION +1 -0
  16. {tabpy-2.9.0 → tabpy-2.11.0}/tabpy/tabpy_server/app/app.py +22 -4
  17. {tabpy-2.9.0 → tabpy-2.11.0}/tabpy/tabpy_server/app/app_parameters.py +2 -0
  18. {tabpy-2.9.0 → tabpy-2.11.0}/tabpy/tabpy_server/app/util.py +1 -1
  19. {tabpy-2.9.0 → tabpy-2.11.0}/tabpy/tabpy_server/common/default.conf +1 -0
  20. {tabpy-2.9.0 → tabpy-2.11.0}/tabpy.egg-info/PKG-INFO +44 -3
  21. {tabpy-2.9.0 → tabpy-2.11.0}/tabpy.egg-info/SOURCES.txt +1 -0
  22. {tabpy-2.9.0 → tabpy-2.11.0}/tests/integration/integ_test_base.py +2 -1
  23. tabpy-2.11.0/tests/integration/test_minimum_tls_version.py +54 -0
  24. {tabpy-2.9.0 → tabpy-2.11.0}/tests/unit/server_tests/test_config.py +14 -0
  25. tabpy-2.9.0/tabpy/VERSION +0 -1
  26. {tabpy-2.9.0 → tabpy-2.11.0}/.github/ISSUE_TEMPLATE/tabpy-issue-report.md +0 -0
  27. {tabpy-2.9.0 → tabpy-2.11.0}/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md +0 -0
  28. {tabpy-2.9.0 → tabpy-2.11.0}/.github/workflows/docker-publish.yml +0 -0
  29. {tabpy-2.9.0 → tabpy-2.11.0}/.gitignore +0 -0
  30. {tabpy-2.9.0 → tabpy-2.11.0}/.pep8speaks.yml +0 -0
  31. {tabpy-2.9.0 → tabpy-2.11.0}/Dockerfile +0 -0
  32. {tabpy-2.9.0 → tabpy-2.11.0}/MANIFEST.in +0 -0
  33. {tabpy-2.9.0 → tabpy-2.11.0}/Procfile +0 -0
  34. {tabpy-2.9.0 → tabpy-2.11.0}/_config.yml +0 -0
  35. {tabpy-2.9.0 → tabpy-2.11.0}/app.json +0 -0
  36. {tabpy-2.9.0 → tabpy-2.11.0}/codeql-analysis.yml +0 -0
  37. {tabpy-2.9.0 → tabpy-2.11.0}/docs/TableauConfiguration.md +0 -0
  38. {tabpy-2.9.0 → tabpy-2.11.0}/docs/about.md +0 -0
  39. {tabpy-2.9.0 → tabpy-2.11.0}/docs/deploy-to-heroku.md +0 -0
  40. {tabpy-2.9.0 → tabpy-2.11.0}/docs/img/Example1-SimpleFunctionCall.png +0 -0
  41. {tabpy-2.9.0 → tabpy-2.11.0}/docs/img/Example2-MultipleFunctionCalls.png +0 -0
  42. {tabpy-2.9.0 → tabpy-2.11.0}/docs/img/python-calculated-field.png +0 -0
  43. {tabpy-2.9.0 → tabpy-2.11.0}/docs/security.md +0 -0
  44. {tabpy-2.9.0 → tabpy-2.11.0}/docs/server-rest.md +0 -0
  45. {tabpy-2.9.0 → tabpy-2.11.0}/docs/tabpy-tools.md +0 -0
  46. {tabpy-2.9.0 → tabpy-2.11.0}/misc/TabPy.postman_collection.json +0 -0
  47. {tabpy-2.9.0 → tabpy-2.11.0}/misc/TabPy.yml +0 -0
  48. {tabpy-2.9.0 → tabpy-2.11.0}/requirements.txt +0 -0
  49. {tabpy-2.9.0 → tabpy-2.11.0}/requirements_dev.txt +0 -0
  50. {tabpy-2.9.0 → tabpy-2.11.0}/setup.cfg +0 -0
  51. {tabpy-2.9.0 → tabpy-2.11.0}/start.sh +0 -0
  52. {tabpy-2.9.0 → tabpy-2.11.0}/tabpy/__init__.py +0 -0
  53. {tabpy-2.9.0 → tabpy-2.11.0}/tabpy/models/__init__.py +0 -0
  54. {tabpy-2.9.0 → tabpy-2.11.0}/tabpy/models/deploy_models.py +0 -0
  55. {tabpy-2.9.0 → tabpy-2.11.0}/tabpy/models/scripts/ANOVA.py +0 -0
  56. {tabpy-2.9.0 → tabpy-2.11.0}/tabpy/models/scripts/PCA.py +0 -0
  57. {tabpy-2.9.0 → tabpy-2.11.0}/tabpy/models/scripts/SentimentAnalysis.py +0 -0
  58. {tabpy-2.9.0 → tabpy-2.11.0}/tabpy/models/scripts/__init__.py +0 -0
  59. {tabpy-2.9.0 → tabpy-2.11.0}/tabpy/models/scripts/tTest.py +0 -0
  60. {tabpy-2.9.0 → tabpy-2.11.0}/tabpy/models/utils/__init__.py +0 -0
  61. {tabpy-2.9.0 → tabpy-2.11.0}/tabpy/models/utils/setup_utils.py +0 -0
  62. {tabpy-2.9.0 → tabpy-2.11.0}/tabpy/tabpy.py +0 -0
  63. {tabpy-2.9.0 → tabpy-2.11.0}/tabpy/tabpy_server/__init__.py +0 -0
  64. {tabpy-2.9.0 → tabpy-2.11.0}/tabpy/tabpy_server/app/__init__.py +0 -0
  65. {tabpy-2.9.0 → tabpy-2.11.0}/tabpy/tabpy_server/app/arrow_server.py +0 -0
  66. {tabpy-2.9.0 → tabpy-2.11.0}/tabpy/tabpy_server/common/__init__.py +0 -0
  67. {tabpy-2.9.0 → tabpy-2.11.0}/tabpy/tabpy_server/common/endpoint_file_mgr.py +0 -0
  68. {tabpy-2.9.0 → tabpy-2.11.0}/tabpy/tabpy_server/common/messages.py +0 -0
  69. {tabpy-2.9.0 → tabpy-2.11.0}/tabpy/tabpy_server/common/util.py +0 -0
  70. {tabpy-2.9.0 → tabpy-2.11.0}/tabpy/tabpy_server/handlers/__init__.py +0 -0
  71. {tabpy-2.9.0 → tabpy-2.11.0}/tabpy/tabpy_server/handlers/base_handler.py +0 -0
  72. {tabpy-2.9.0 → tabpy-2.11.0}/tabpy/tabpy_server/handlers/basic_auth_server_middleware_factory.py +0 -0
  73. {tabpy-2.9.0 → tabpy-2.11.0}/tabpy/tabpy_server/handlers/endpoint_handler.py +0 -0
  74. {tabpy-2.9.0 → tabpy-2.11.0}/tabpy/tabpy_server/handlers/endpoints_handler.py +0 -0
  75. {tabpy-2.9.0 → tabpy-2.11.0}/tabpy/tabpy_server/handlers/evaluation_plane_handler.py +0 -0
  76. {tabpy-2.9.0 → tabpy-2.11.0}/tabpy/tabpy_server/handlers/management_handler.py +0 -0
  77. {tabpy-2.9.0 → tabpy-2.11.0}/tabpy/tabpy_server/handlers/no_op_auth_handler.py +0 -0
  78. {tabpy-2.9.0 → tabpy-2.11.0}/tabpy/tabpy_server/handlers/query_plane_handler.py +0 -0
  79. {tabpy-2.9.0 → tabpy-2.11.0}/tabpy/tabpy_server/handlers/service_info_handler.py +0 -0
  80. {tabpy-2.9.0 → tabpy-2.11.0}/tabpy/tabpy_server/handlers/status_handler.py +0 -0
  81. {tabpy-2.9.0 → tabpy-2.11.0}/tabpy/tabpy_server/handlers/upload_destination_handler.py +0 -0
  82. {tabpy-2.9.0 → tabpy-2.11.0}/tabpy/tabpy_server/handlers/util.py +0 -0
  83. {tabpy-2.9.0 → tabpy-2.11.0}/tabpy/tabpy_server/management/__init__.py +0 -0
  84. {tabpy-2.9.0 → tabpy-2.11.0}/tabpy/tabpy_server/management/state.py +0 -0
  85. {tabpy-2.9.0 → tabpy-2.11.0}/tabpy/tabpy_server/management/util.py +0 -0
  86. {tabpy-2.9.0 → tabpy-2.11.0}/tabpy/tabpy_server/psws/__init__.py +0 -0
  87. {tabpy-2.9.0 → tabpy-2.11.0}/tabpy/tabpy_server/psws/callbacks.py +0 -0
  88. {tabpy-2.9.0 → tabpy-2.11.0}/tabpy/tabpy_server/psws/python_service.py +0 -0
  89. {tabpy-2.9.0 → tabpy-2.11.0}/tabpy/tabpy_server/state.ini.template +0 -0
  90. {tabpy-2.9.0 → tabpy-2.11.0}/tabpy/tabpy_server/static/TabPy_logo.png +0 -0
  91. {tabpy-2.9.0 → tabpy-2.11.0}/tabpy/tabpy_server/static/index.html +0 -0
  92. {tabpy-2.9.0 → tabpy-2.11.0}/tabpy/tabpy_server/static/tableau.png +0 -0
  93. {tabpy-2.9.0 → tabpy-2.11.0}/tabpy/tabpy_tools/__init__.py +0 -0
  94. {tabpy-2.9.0 → tabpy-2.11.0}/tabpy/tabpy_tools/client.py +0 -0
  95. {tabpy-2.9.0 → tabpy-2.11.0}/tabpy/tabpy_tools/custom_query_object.py +0 -0
  96. {tabpy-2.9.0 → tabpy-2.11.0}/tabpy/tabpy_tools/query_object.py +0 -0
  97. {tabpy-2.9.0 → tabpy-2.11.0}/tabpy/tabpy_tools/rest.py +0 -0
  98. {tabpy-2.9.0 → tabpy-2.11.0}/tabpy/tabpy_tools/rest_client.py +0 -0
  99. {tabpy-2.9.0 → tabpy-2.11.0}/tabpy/tabpy_tools/schema.py +0 -0
  100. {tabpy-2.9.0 → tabpy-2.11.0}/tabpy/utils/__init__.py +0 -0
  101. {tabpy-2.9.0 → tabpy-2.11.0}/tabpy/utils/tabpy_user.py +0 -0
  102. {tabpy-2.9.0 → tabpy-2.11.0}/tabpy.egg-info/dependency_links.txt +0 -0
  103. {tabpy-2.9.0 → tabpy-2.11.0}/tabpy.egg-info/entry_points.txt +0 -0
  104. {tabpy-2.9.0 → tabpy-2.11.0}/tabpy.egg-info/requires.txt +0 -0
  105. {tabpy-2.9.0 → tabpy-2.11.0}/tabpy.egg-info/top_level.txt +0 -0
  106. {tabpy-2.9.0 → tabpy-2.11.0}/tests/__init__.py +0 -0
  107. {tabpy-2.9.0 → tabpy-2.11.0}/tests/integration/__init__.py +0 -0
  108. {tabpy-2.9.0 → tabpy-2.11.0}/tests/integration/resources/2019_04_24_to_3018_08_25.crt +0 -0
  109. {tabpy-2.9.0 → tabpy-2.11.0}/tests/integration/resources/2019_04_24_to_3018_08_25.key +0 -0
  110. {tabpy-2.9.0 → tabpy-2.11.0}/tests/integration/resources/data.csv +0 -0
  111. {tabpy-2.9.0 → tabpy-2.11.0}/tests/integration/resources/deploy_and_evaluate_model.conf +0 -0
  112. {tabpy-2.9.0 → tabpy-2.11.0}/tests/integration/resources/deploy_and_evaluate_model_auth.conf +0 -0
  113. {tabpy-2.9.0 → tabpy-2.11.0}/tests/integration/resources/pwdfile.txt +0 -0
  114. {tabpy-2.9.0 → tabpy-2.11.0}/tests/integration/test_arrow_server.py +0 -0
  115. {tabpy-2.9.0 → tabpy-2.11.0}/tests/integration/test_auth.py +0 -0
  116. {tabpy-2.9.0 → tabpy-2.11.0}/tests/integration/test_custom_evaluate_timeout.py +0 -0
  117. {tabpy-2.9.0 → tabpy-2.11.0}/tests/integration/test_deploy_and_evaluate_model.py +0 -0
  118. {tabpy-2.9.0 → tabpy-2.11.0}/tests/integration/test_deploy_and_evaluate_model_auth_on.py +0 -0
  119. {tabpy-2.9.0 → tabpy-2.11.0}/tests/integration/test_deploy_and_evaluate_model_ssl.py +0 -0
  120. {tabpy-2.9.0 → tabpy-2.11.0}/tests/integration/test_deploy_model_ssl_off_auth_off.py +0 -0
  121. {tabpy-2.9.0 → tabpy-2.11.0}/tests/integration/test_deploy_model_ssl_off_auth_on.py +0 -0
  122. {tabpy-2.9.0 → tabpy-2.11.0}/tests/integration/test_deploy_model_ssl_on_auth_off.py +0 -0
  123. {tabpy-2.9.0 → tabpy-2.11.0}/tests/integration/test_deploy_model_ssl_on_auth_on.py +0 -0
  124. {tabpy-2.9.0 → tabpy-2.11.0}/tests/integration/test_evaluate.py +0 -0
  125. {tabpy-2.9.0 → tabpy-2.11.0}/tests/integration/test_gzip.py +0 -0
  126. {tabpy-2.9.0 → tabpy-2.11.0}/tests/integration/test_url.py +0 -0
  127. {tabpy-2.9.0 → tabpy-2.11.0}/tests/integration/test_url_ssl.py +0 -0
  128. {tabpy-2.9.0 → tabpy-2.11.0}/tests/unit/__init__.py +0 -0
  129. {tabpy-2.9.0 → tabpy-2.11.0}/tests/unit/server_tests/__init__.py +0 -0
  130. {tabpy-2.9.0 → tabpy-2.11.0}/tests/unit/server_tests/resources/expired.crt +0 -0
  131. {tabpy-2.9.0 → tabpy-2.11.0}/tests/unit/server_tests/resources/future.crt +0 -0
  132. {tabpy-2.9.0 → tabpy-2.11.0}/tests/unit/server_tests/resources/valid.crt +0 -0
  133. {tabpy-2.9.0 → tabpy-2.11.0}/tests/unit/server_tests/test_endpoint_file_manager.py +0 -0
  134. {tabpy-2.9.0 → tabpy-2.11.0}/tests/unit/server_tests/test_endpoint_handler.py +0 -0
  135. {tabpy-2.9.0 → tabpy-2.11.0}/tests/unit/server_tests/test_endpoints_handler.py +0 -0
  136. {tabpy-2.9.0 → tabpy-2.11.0}/tests/unit/server_tests/test_evaluation_plane_handler.py +0 -0
  137. {tabpy-2.9.0 → tabpy-2.11.0}/tests/unit/server_tests/test_pwd_file.py +0 -0
  138. {tabpy-2.9.0 → tabpy-2.11.0}/tests/unit/server_tests/test_service_info_handler.py +0 -0
  139. {tabpy-2.9.0 → tabpy-2.11.0}/tests/unit/tools_tests/__init__.py +0 -0
  140. {tabpy-2.9.0 → tabpy-2.11.0}/tests/unit/tools_tests/test_client.py +0 -0
  141. {tabpy-2.9.0 → tabpy-2.11.0}/tests/unit/tools_tests/test_rest.py +0 -0
  142. {tabpy-2.9.0 → tabpy-2.11.0}/tests/unit/tools_tests/test_rest_object.py +0 -0
  143. {tabpy-2.9.0 → tabpy-2.11.0}/tests/unit/tools_tests/test_schema.py +0 -0
@@ -9,7 +9,7 @@ jobs:
9
9
 
10
10
  strategy:
11
11
  matrix:
12
- python-version: [3.7]
12
+ python-version: [3.12]
13
13
  os: [ubuntu-latest]
14
14
 
15
15
  steps:
@@ -9,7 +9,7 @@ jobs:
9
9
 
10
10
  strategy:
11
11
  matrix:
12
- python-version: [3.7]
12
+ python-version: [3.12]
13
13
  os: [ubuntu-latest]
14
14
 
15
15
  steps:
@@ -9,10 +9,9 @@ jobs:
9
9
 
10
10
  strategy:
11
11
  matrix:
12
- # TODO: Add 3.7 to python-versions after GitHub action regression is resolved.
13
- # https://github.com/actions/setup-python/issues/682
14
- python-version: [3.8, 3.9]
15
- os: [ubuntu-latest, windows-latest, macos-latest]
12
+ python-version: ['3.9', '3.10', '3.11', '3.12']
13
+ # TODO: switch macos-13 to macos-latest
14
+ os: [ubuntu-latest, windows-latest, macos-13]
16
15
 
17
16
  steps:
18
17
  - uses: actions/checkout@v1
@@ -9,11 +9,10 @@ jobs:
9
9
 
10
10
  strategy:
11
11
  matrix:
12
- # TODO: Add 3.7 to python-versions after GitHub action regression is resolved.
13
- # https://github.com/actions/setup-python/issues/682
14
- python-version: [3.8, 3.9]
15
- os: [ubuntu-latest, windows-latest, macos-latest]
16
-
12
+ python-version: ['3.9', '3.10', '3.11', '3.12']
13
+ # TODO: switch macos-13 to macos-latest
14
+ os: [ubuntu-latest, windows-latest, macos-13]
15
+
17
16
  steps:
18
17
  - uses: actions/checkout@v1
19
18
 
@@ -1,6 +1,6 @@
1
1
  build:
2
2
  environment:
3
- python: 3.7.6
3
+ python: 3.12.5
4
4
  nodes:
5
5
  coverage:
6
6
  project_setup:
@@ -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: [pytest]
30
+ override:
31
+ pytest:
32
+ idle_timeout: 600
27
33
  checks:
28
34
  python:
29
35
  code_rating: true
@@ -1,5 +1,20 @@
1
1
  # Changelog
2
2
 
3
+ ## v2.11.0
4
+
5
+ ### Improvements
6
+
7
+ - Add support for Python 3.10, 3.11, and 3.12. End support Python for
8
+ 3.7 and 3.8.
9
+
10
+ ## v2.10.0
11
+
12
+ ### Improvements
13
+
14
+ - Add TabPy parameter (TABPY_MINIMUM_TLS_VERSION) to specify the minimum TLS
15
+ version that the server will accept for secure connections. Default is
16
+ set to TLSv1_2.
17
+
3
18
  ## v2.9.0
4
19
 
5
20
  ### Improvements
@@ -30,8 +30,8 @@ and run it locally.
30
30
  These are prerequisites for an environment required for a contributor to
31
31
  be able to work on TabPy changes:
32
32
 
33
- - Python 3.7, 3.8 or 3.9:
34
- - To see which version of Python you have installed, run `python --version`.
33
+ - Supported 64-bit Python version (see
34
+ [README](https://github.com/tableau/TabPy) for a list of compatible versions).
35
35
  - git
36
36
  - Node.js for npm packages - install from <https://nodejs.org>.
37
37
  - NPM packages - install all with
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2016 Tableau Software, LLC
3
+ Copyright (c) 2024 Salesforce, Inc.
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: tabpy
3
- Version: 2.9.0
3
+ Version: 2.11.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
@@ -21,9 +21,10 @@ Classifier: Development Status :: 5 - Production/Stable
21
21
  Classifier: Intended Audience :: Developers
22
22
  Classifier: Intended Audience :: Science/Research
23
23
  Classifier: License :: OSI Approved :: MIT License
24
- Classifier: Programming Language :: Python :: 3.7
25
- Classifier: Programming Language :: Python :: 3.8
26
24
  Classifier: Programming Language :: Python :: 3.9
25
+ Classifier: Programming Language :: Python :: 3.10
26
+ Classifier: Programming Language :: Python :: 3.11
27
+ Classifier: Programming Language :: Python :: 3.12
27
28
  Classifier: Topic :: Scientific/Engineering
28
29
  Classifier: Topic :: Scientific/Engineering :: Information Analysis
29
30
  Classifier: Operating System :: Microsoft :: Windows
@@ -33,6 +34,31 @@ Classifier: Operating System :: MacOS
33
34
  Requires-Python: >=3.7
34
35
  Description-Content-Type: text/markdown
35
36
  License-File: LICENSE
37
+ Requires-Dist: cloudpickle
38
+ Requires-Dist: configparser
39
+ Requires-Dist: coverage
40
+ Requires-Dist: coveralls
41
+ Requires-Dist: docopt
42
+ Requires-Dist: future
43
+ Requires-Dist: genson
44
+ Requires-Dist: hypothesis
45
+ Requires-Dist: jsonschema
46
+ Requires-Dist: mock
47
+ Requires-Dist: nltk
48
+ Requires-Dist: numpy
49
+ Requires-Dist: pandas
50
+ Requires-Dist: pyopenssl
51
+ Requires-Dist: pytest
52
+ Requires-Dist: pytest-cov
53
+ Requires-Dist: requests
54
+ Requires-Dist: scipy
55
+ Requires-Dist: simplejson
56
+ Requires-Dist: scikit-learn
57
+ Requires-Dist: textblob
58
+ Requires-Dist: tornado
59
+ Requires-Dist: twisted
60
+ Requires-Dist: urllib3
61
+ Requires-Dist: pyarrow
36
62
 
37
63
 
38
64
  TabPy (the Tableau Python Server) is an external service implementation
@@ -41,6 +67,21 @@ scripts and saved functions via Tableau's table calculations.
41
67
 
42
68
  # Changelog
43
69
 
70
+ ## v2.11.0
71
+
72
+ ### Improvements
73
+
74
+ - Add support for Python 3.10, 3.11, and 3.12. End support Python for
75
+ 3.7 and 3.8.
76
+
77
+ ## v2.10.0
78
+
79
+ ### Improvements
80
+
81
+ - Add TabPy parameter (TABPY_MINIMUM_TLS_VERSION) to specify the minimum TLS
82
+ version that the server will accept for secure connections. Default is
83
+ set to TLSv1_2.
84
+
44
85
  ## v2.9.0
45
86
 
46
87
  ### Improvements
@@ -6,7 +6,6 @@
6
6
  [![GitHub Workflow Status](https://img.shields.io/github/workflow/status/tableau/tabpy/Test%20Run%20on%20Push)](https://github.com/tableau/TabPy/actions?query=workflow%3A%22Test+Run+on+Push%22)
7
7
  [![Coverage Status](https://coveralls.io/repos/github/tableau/TabPy/badge.svg?branch=master)](https://coveralls.io/github/tableau/TabPy?branch=master)
8
8
  [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/tableau/TabPy/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/tableau/TabPy/?branch=master)
9
- [![Requirements Status](https://requires.io/github/tableau/TabPy/requirements.svg?branch=master)](https://requires.io/github/tableau/TabPy/requirements/?branch=master)
10
9
 
11
10
  ![PyPI - Python Version](https://img.shields.io/pypi/pyversions/tabpy?label=PyPI%20Python%20versions)
12
11
  [![PyPI version](https://badge.fury.io/py/tabpy.svg)](https://pypi.python.org/pypi/tabpy/)
@@ -27,6 +26,18 @@ Consider reading TabPy documentation in the following order:
27
26
  * [Authoring Python calculations in Tableau](docs/TableauConfiguration.md).
28
27
  * [TabPy Tools](docs/tabpy-tools.md)
29
28
 
29
+ Important security note:
30
+
31
+ * By default, TabPy is configured without username/password authentication.
32
+ We strongly advise using TabPy only with authentication enabled. For more
33
+ information, see
34
+ [TabPy Server Configuration Instructions](docs/server-config.md#authentication).
35
+ Without authentication in place, if the TABPY_EVALUATE_ENABLE feature is
36
+ enabled (as it is by default), there is the possibility that unauthenticated
37
+ individuals could remotely execute code on the machine running TabPy.
38
+ Leaving these two settings in their default states together is highly
39
+ discouraged.
40
+
30
41
  Troubleshooting:
31
42
 
32
43
  * [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), Tableau user name (for Tableau Server)
318
- and TabPy user name as shown in the example below:
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, Tableau user: ogolovatyi
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,12 @@ These instructions explain how to install and start up TabPy Server.
15
15
 
16
16
  ## TabPy Installation
17
17
 
18
+ First, ensure that you are using a supported 64-bit Python version.
19
+ Refer to the [README](https://github.com/tableau/TabPy) for a list
20
+ of compatible versions.
21
+
22
+ ### Installation
23
+
18
24
  To install TabPy on to an environment `pip` needs to be installed and
19
25
  updated first:
20
26
 
@@ -30,7 +36,7 @@ pip install tabpy
30
36
 
31
37
  ## Starting TabPy
32
38
 
33
- To start TabPy with default setting run the following command:
39
+ To start TabPy with default settings run the following command:
34
40
 
35
41
  ```sh
36
42
  tabpy
@@ -86,7 +86,7 @@ Linux and Mac run shell.
86
86
  3. Create the virtual Anaconda environment
87
87
 
88
88
  ```sh
89
- conda create --name my-tabpy-env python=3.7
89
+ conda create --name my-tabpy-env python=3.12
90
90
  ```
91
91
 
92
92
  4. Activate your virtual environment
@@ -39,9 +39,10 @@ def setup_package():
39
39
  "Intended Audience :: Developers",
40
40
  "Intended Audience :: Science/Research",
41
41
  "License :: OSI Approved :: MIT License",
42
- "Programming Language :: Python :: 3.7",
43
- "Programming Language :: Python :: 3.8",
44
42
  "Programming Language :: Python :: 3.9",
43
+ "Programming Language :: Python :: 3.10",
44
+ "Programming Language :: Python :: 3.11",
45
+ "Programming Language :: Python :: 3.12",
45
46
  "Topic :: Scientific/Engineering",
46
47
  "Topic :: Scientific/Engineering :: Information Analysis",
47
48
  "Operating System :: Microsoft :: Windows",
@@ -0,0 +1 @@
1
+ 2.11.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.now()
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.9.0
3
+ Version: 2.11.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
@@ -21,9 +21,10 @@ Classifier: Development Status :: 5 - Production/Stable
21
21
  Classifier: Intended Audience :: Developers
22
22
  Classifier: Intended Audience :: Science/Research
23
23
  Classifier: License :: OSI Approved :: MIT License
24
- Classifier: Programming Language :: Python :: 3.7
25
- Classifier: Programming Language :: Python :: 3.8
26
24
  Classifier: Programming Language :: Python :: 3.9
25
+ Classifier: Programming Language :: Python :: 3.10
26
+ Classifier: Programming Language :: Python :: 3.11
27
+ Classifier: Programming Language :: Python :: 3.12
27
28
  Classifier: Topic :: Scientific/Engineering
28
29
  Classifier: Topic :: Scientific/Engineering :: Information Analysis
29
30
  Classifier: Operating System :: Microsoft :: Windows
@@ -33,6 +34,31 @@ Classifier: Operating System :: MacOS
33
34
  Requires-Python: >=3.7
34
35
  Description-Content-Type: text/markdown
35
36
  License-File: LICENSE
37
+ Requires-Dist: cloudpickle
38
+ Requires-Dist: configparser
39
+ Requires-Dist: coverage
40
+ Requires-Dist: coveralls
41
+ Requires-Dist: docopt
42
+ Requires-Dist: future
43
+ Requires-Dist: genson
44
+ Requires-Dist: hypothesis
45
+ Requires-Dist: jsonschema
46
+ Requires-Dist: mock
47
+ Requires-Dist: nltk
48
+ Requires-Dist: numpy
49
+ Requires-Dist: pandas
50
+ Requires-Dist: pyopenssl
51
+ Requires-Dist: pytest
52
+ Requires-Dist: pytest-cov
53
+ Requires-Dist: requests
54
+ Requires-Dist: scipy
55
+ Requires-Dist: simplejson
56
+ Requires-Dist: scikit-learn
57
+ Requires-Dist: textblob
58
+ Requires-Dist: tornado
59
+ Requires-Dist: twisted
60
+ Requires-Dist: urllib3
61
+ Requires-Dist: pyarrow
36
62
 
37
63
 
38
64
  TabPy (the Tableau Python Server) is an external service implementation
@@ -41,6 +67,21 @@ scripts and saved functions via Tableau's table calculations.
41
67
 
42
68
  # Changelog
43
69
 
70
+ ## v2.11.0
71
+
72
+ ### Improvements
73
+
74
+ - Add support for Python 3.10, 3.11, and 3.12. End support Python for
75
+ 3.7 and 3.8.
76
+
77
+ ## v2.10.0
78
+
79
+ ### Improvements
80
+
81
+ - Add TabPy parameter (TABPY_MINIMUM_TLS_VERSION) to specify the minimum TLS
82
+ version that the server will accept for secure connections. Default is
83
+ set to TLSv1_2.
84
+
44
85
  ## v2.9.0
45
86
 
46
87
  ### 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
- with open(self.tmp_dir + "/output.txt", "w") as outfile:
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