pam-python 0.2.17__tar.gz → 0.2.18__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.
- {pam_python-0.2.17/pam_python.egg-info → pam_python-0.2.18}/PKG-INFO +2 -1
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/__init__.py +1 -1
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/api.py +9 -4
- {pam_python-0.2.17 → pam_python-0.2.18/pam_python.egg-info}/PKG-INFO +2 -1
- {pam_python-0.2.17 → pam_python-0.2.18}/pam_python.egg-info/requires.txt +1 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pyproject.toml +1 -0
- pam_python-0.2.18/tests/test_api.py +102 -0
- pam_python-0.2.17/tests/test_api.py +0 -44
- {pam_python-0.2.17 → pam_python-0.2.18}/LICENSE.txt +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/README.md +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/cli.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/datetime_utils.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/interface_task_manager.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/logger.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/models/__init__.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/models/data_input_v2.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/models/request_command.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/models/sqlite_download.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/reports/__init__.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/reports/area.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/reports/axis.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/reports/bar.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/reports/box_plot.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/reports/bubble.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/reports/candlestick.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/reports/collection.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/reports/definition.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/reports/donut.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/reports/errors.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/reports/fields.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/reports/heatmap.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/reports/line.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/reports/manager.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/reports/metric.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/reports/pie.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/reports/polar_area.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/reports/radar.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/reports/radial_bar.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/reports/range_area.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/reports/range_bar.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/reports/range_transform.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/reports/record.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/reports/report.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/reports/scatter.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/reports/schema.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/reports/store.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/reports/table.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/reports/temporal.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/reports/transport.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/reports/treemap.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/request_file_format.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/result_batch_uploader.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/server.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/service.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/sqlite.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/task_manager.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/temp_file_utils.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/templates/buildcmd/pamb +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/templates/buildcmd/pamb-base.sh +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/templates/init/AGENT.md +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/templates/init/REPORTS-th.md +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/templates/init/REPORTS.md +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/templates/init/dockerignore.tmpl +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/templates/init/gitignore.tmpl +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/templates/init/main.tmpl +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/templates/init/pylintrc.tmpl +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/templates/init/run_unit_test.bat +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/templates/init/run_unit_test.ps1 +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/templates/init/run_unit_test.sh +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/templates/project/pip/Dockerfile +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/templates/project/pip/requirements.txt +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/templates/project/uv/Dockerfile +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/templates/project/uv/pyproject.toml +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/templates/project/uv/python-version +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/templates/service/common/service.yaml +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/templates/service/pandas/functions.tmpl +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/templates/service/pandas/service.test.tmpl +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/templates/service/pandas/service_class.tmpl +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/templates/service/polars/functions.tmpl +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/templates/service/polars/service.test.tmpl +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/templates/service/polars/service_class.tmpl +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/tester_task.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam/utils.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam_python.egg-info/SOURCES.txt +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam_python.egg-info/dependency_links.txt +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam_python.egg-info/entry_points.txt +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/pam_python.egg-info/top_level.txt +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/setup.cfg +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/tests/test_cli_templates.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/tests/test_data_error_v2.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/tests/test_data_input_v2.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/tests/test_data_timeout_v2.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/tests/test_datetime_utils.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/tests/test_range_transform.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/tests/test_report_store.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/tests/test_request_data_v2.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/tests/test_result_batch_uploader.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/tests/test_service_dataframe_output.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/tests/test_sqlite_download_v2.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/tests/test_task_manager_upload_token.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/tests/test_temp_file_utils.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/tests/test_temporal_mode.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/tests/test_typed_area_report.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/tests/test_typed_bar_report.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/tests/test_typed_box_plot_report.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/tests/test_typed_bubble_report.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/tests/test_typed_candlestick_report.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/tests/test_typed_donut_report.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/tests/test_typed_heatmap_report.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/tests/test_typed_line_report.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/tests/test_typed_metric_report.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/tests/test_typed_pie_report.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/tests/test_typed_polar_area_report.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/tests/test_typed_radar_report.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/tests/test_typed_radial_bar_report.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/tests/test_typed_range_area_report.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/tests/test_typed_range_bar_report.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/tests/test_typed_scatter_report.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/tests/test_typed_table_report.py +0 -0
- {pam_python-0.2.17 → pam_python-0.2.18}/tests/test_typed_treemap_report.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pam-python
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.18
|
|
4
4
|
Summary: Pam Python Library
|
|
5
5
|
Author-email: Narongrit Kanhanoi <narongrit@pams.ai>
|
|
6
6
|
Project-URL: Homepage, https://github.com/heart/pam-python
|
|
@@ -15,6 +15,7 @@ Description-Content-Type: text/markdown
|
|
|
15
15
|
License-File: LICENSE.txt
|
|
16
16
|
Requires-Dist: Flask>=3.0.2
|
|
17
17
|
Requires-Dist: requests>=2.32.3
|
|
18
|
+
Requires-Dist: requests-toolbelt>=1.0.0
|
|
18
19
|
Requires-Dist: PyYAML>=6.0.2
|
|
19
20
|
Dynamic: license-file
|
|
20
21
|
|
|
@@ -2,6 +2,7 @@ from pathlib import Path
|
|
|
2
2
|
import os
|
|
3
3
|
import sqlite3
|
|
4
4
|
import requests
|
|
5
|
+
from requests_toolbelt.multipart.encoder import MultipartEncoder
|
|
5
6
|
from pam.models.sqlite_download import SQLiteDownloadResult, SQLiteDownloadStatus
|
|
6
7
|
from pam.utils import log
|
|
7
8
|
|
|
@@ -36,7 +37,7 @@ class API:
|
|
|
36
37
|
|
|
37
38
|
def http_upload(self, url: str, file_path: str, payload: dict = None) -> requests.Response | None:
|
|
38
39
|
"""
|
|
39
|
-
|
|
40
|
+
Streams a file as multipart form data without buffering the whole file.
|
|
40
41
|
|
|
41
42
|
:param url: The URL to upload the file to.
|
|
42
43
|
:param file_path: The path to the file to be uploaded.
|
|
@@ -49,11 +50,15 @@ class API:
|
|
|
49
50
|
|
|
50
51
|
try:
|
|
51
52
|
with open(file_path, 'rb') as file:
|
|
52
|
-
|
|
53
|
+
fields = dict(payload or {})
|
|
54
|
+
fields['file'] = (Path(file_path).name, file)
|
|
55
|
+
# requests' files= buffers the entire multipart body. This encoder
|
|
56
|
+
# reads the open file incrementally and provides Content-Length.
|
|
57
|
+
body = MultipartEncoder(fields=fields)
|
|
53
58
|
response = self.session.post(
|
|
54
59
|
url,
|
|
55
|
-
|
|
56
|
-
|
|
60
|
+
data=body,
|
|
61
|
+
headers={'Content-Type': body.content_type},
|
|
57
62
|
timeout=300
|
|
58
63
|
)
|
|
59
64
|
response.raise_for_status()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pam-python
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.18
|
|
4
4
|
Summary: Pam Python Library
|
|
5
5
|
Author-email: Narongrit Kanhanoi <narongrit@pams.ai>
|
|
6
6
|
Project-URL: Homepage, https://github.com/heart/pam-python
|
|
@@ -15,6 +15,7 @@ Description-Content-Type: text/markdown
|
|
|
15
15
|
License-File: LICENSE.txt
|
|
16
16
|
Requires-Dist: Flask>=3.0.2
|
|
17
17
|
Requires-Dist: requests>=2.32.3
|
|
18
|
+
Requires-Dist: requests-toolbelt>=1.0.0
|
|
18
19
|
Requires-Dist: PyYAML>=6.0.2
|
|
19
20
|
Dynamic: license-file
|
|
20
21
|
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
import tempfile
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from email.parser import BytesParser
|
|
5
|
+
from email.policy import default
|
|
6
|
+
from unittest import mock
|
|
7
|
+
|
|
8
|
+
import requests
|
|
9
|
+
|
|
10
|
+
from pam.api import API
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class APITest(unittest.TestCase):
|
|
14
|
+
def test_http_upload_streams_file_and_preserves_multipart_fields(self):
|
|
15
|
+
api = API()
|
|
16
|
+
content = b'SQLite format 3\x00' * 65536
|
|
17
|
+
payload = {'token': 'test-token', 'file_name': 'state', 'is_shared': 'false'}
|
|
18
|
+
response = requests.Response()
|
|
19
|
+
response.status_code = 200
|
|
20
|
+
with tempfile.TemporaryDirectory() as directory:
|
|
21
|
+
path = Path(directory) / 'state.sqlite'
|
|
22
|
+
path.write_bytes(content)
|
|
23
|
+
real_open = open
|
|
24
|
+
opened = []
|
|
25
|
+
|
|
26
|
+
def guarded_open(*args, **kwargs):
|
|
27
|
+
file = real_open(*args, **kwargs)
|
|
28
|
+
opened.append(file)
|
|
29
|
+
original_read = file.read
|
|
30
|
+
|
|
31
|
+
def bounded_read(size=-1):
|
|
32
|
+
self.assertGreaterEqual(size, 0)
|
|
33
|
+
self.assertLessEqual(size, 16384)
|
|
34
|
+
return original_read(size)
|
|
35
|
+
|
|
36
|
+
file.read = bounded_read
|
|
37
|
+
return file
|
|
38
|
+
|
|
39
|
+
def post(url, **kwargs):
|
|
40
|
+
self.assertNotIn('files', kwargs)
|
|
41
|
+
prepared = requests.Request('POST', url, **{
|
|
42
|
+
key: kwargs[key] for key in ('data', 'headers')
|
|
43
|
+
}).prepare()
|
|
44
|
+
self.assertIs(prepared.body, kwargs['data'])
|
|
45
|
+
chunks = []
|
|
46
|
+
while chunk := prepared.body.read(16384):
|
|
47
|
+
chunks.append(chunk)
|
|
48
|
+
body = b''.join(chunks)
|
|
49
|
+
self.assertEqual(int(prepared.headers['Content-Length']), len(body))
|
|
50
|
+
message = BytesParser(policy=default).parsebytes(
|
|
51
|
+
('Content-Type: ' + prepared.headers['Content-Type'] + '\r\n\r\n').encode() + body
|
|
52
|
+
)
|
|
53
|
+
parts = {part.get_param('name', header='content-disposition'): part
|
|
54
|
+
for part in message.iter_parts()}
|
|
55
|
+
for key, value in payload.items():
|
|
56
|
+
self.assertEqual(parts[key].get_payload(decode=True).decode(), value)
|
|
57
|
+
self.assertEqual(parts['file'].get_filename(), path.name)
|
|
58
|
+
self.assertEqual(parts['file'].get_payload(decode=True), content)
|
|
59
|
+
self.assertEqual(kwargs['timeout'], 300)
|
|
60
|
+
return response
|
|
61
|
+
|
|
62
|
+
api.session.post = mock.Mock(side_effect=post)
|
|
63
|
+
with mock.patch('pam.api.open', side_effect=guarded_open):
|
|
64
|
+
self.assertIs(api.http_upload('http://pam/sqlite_upload', str(path), payload), response)
|
|
65
|
+
self.assertTrue(opened[0].closed)
|
|
66
|
+
self.assertNotIn('file', payload)
|
|
67
|
+
|
|
68
|
+
def test_http_post_logs_error_response_body(self):
|
|
69
|
+
api = API()
|
|
70
|
+
response = requests.Response()
|
|
71
|
+
response.status_code = 404
|
|
72
|
+
response.url = "http://pam/api/dataadapter/adapter-1/log"
|
|
73
|
+
response._content = (
|
|
74
|
+
b'{"code":"NOT_FOUND","error_code":"ADAPTER_LOG_NOT_FOUND",'
|
|
75
|
+
b'"message":"Adapter execution log was not found"}'
|
|
76
|
+
)
|
|
77
|
+
api.session.post = mock.Mock(return_value=response)
|
|
78
|
+
|
|
79
|
+
with mock.patch("pam.api.log") as log_mock:
|
|
80
|
+
result = api.http_post(response.url, {"token": "secret"})
|
|
81
|
+
|
|
82
|
+
self.assertIsNone(result)
|
|
83
|
+
logged_message = log_mock.call_args.args[0]
|
|
84
|
+
self.assertIn("404 Client Error", logged_message)
|
|
85
|
+
self.assertIn('"error_code":"ADAPTER_LOG_NOT_FOUND"', logged_message)
|
|
86
|
+
self.assertNotIn("secret", logged_message)
|
|
87
|
+
|
|
88
|
+
def test_http_post_without_response_does_not_add_response_detail(self):
|
|
89
|
+
api = API()
|
|
90
|
+
api.session.post = mock.Mock(side_effect=requests.ConnectionError("offline"))
|
|
91
|
+
|
|
92
|
+
with mock.patch("pam.api.log") as log_mock:
|
|
93
|
+
result = api.http_post("http://pam/log", {})
|
|
94
|
+
|
|
95
|
+
self.assertIsNone(result)
|
|
96
|
+
logged_message = log_mock.call_args.args[0]
|
|
97
|
+
self.assertIn("offline", logged_message)
|
|
98
|
+
self.assertNotIn("Response:", logged_message)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
if __name__ == "__main__":
|
|
102
|
+
unittest.main()
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import unittest
|
|
2
|
-
from unittest import mock
|
|
3
|
-
|
|
4
|
-
import requests
|
|
5
|
-
|
|
6
|
-
from pam.api import API
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
class APITest(unittest.TestCase):
|
|
10
|
-
def test_http_post_logs_error_response_body(self):
|
|
11
|
-
api = API()
|
|
12
|
-
response = requests.Response()
|
|
13
|
-
response.status_code = 404
|
|
14
|
-
response.url = "http://pam/api/dataadapter/adapter-1/log"
|
|
15
|
-
response._content = (
|
|
16
|
-
b'{"code":"NOT_FOUND","error_code":"ADAPTER_LOG_NOT_FOUND",'
|
|
17
|
-
b'"message":"Adapter execution log was not found"}'
|
|
18
|
-
)
|
|
19
|
-
api.session.post = mock.Mock(return_value=response)
|
|
20
|
-
|
|
21
|
-
with mock.patch("pam.api.log") as log_mock:
|
|
22
|
-
result = api.http_post(response.url, {"token": "secret"})
|
|
23
|
-
|
|
24
|
-
self.assertIsNone(result)
|
|
25
|
-
logged_message = log_mock.call_args.args[0]
|
|
26
|
-
self.assertIn("404 Client Error", logged_message)
|
|
27
|
-
self.assertIn('"error_code":"ADAPTER_LOG_NOT_FOUND"', logged_message)
|
|
28
|
-
self.assertNotIn("secret", logged_message)
|
|
29
|
-
|
|
30
|
-
def test_http_post_without_response_does_not_add_response_detail(self):
|
|
31
|
-
api = API()
|
|
32
|
-
api.session.post = mock.Mock(side_effect=requests.ConnectionError("offline"))
|
|
33
|
-
|
|
34
|
-
with mock.patch("pam.api.log") as log_mock:
|
|
35
|
-
result = api.http_post("http://pam/log", {})
|
|
36
|
-
|
|
37
|
-
self.assertIsNone(result)
|
|
38
|
-
logged_message = log_mock.call_args.args[0]
|
|
39
|
-
self.assertIn("offline", logged_message)
|
|
40
|
-
self.assertNotIn("Response:", logged_message)
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
if __name__ == "__main__":
|
|
44
|
-
unittest.main()
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|