PyPtt 2.1.3__tar.gz → 2.1.4__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 (89) hide show
  1. {pyptt-2.1.3 → pyptt-2.1.4}/PKG-INFO +1 -1
  2. {pyptt-2.1.3 → pyptt-2.1.4}/PyPtt/__init__.py +1 -1
  3. {pyptt-2.1.3 → pyptt-2.1.4}/PyPtt/connect_core.py +12 -4
  4. {pyptt-2.1.3 → pyptt-2.1.4}/PyPtt/screens.py +3 -1
  5. pyptt-2.1.4/PyPtt/ssl_config.py +24 -0
  6. {pyptt-2.1.3 → pyptt-2.1.4}/PyPtt.egg-info/PKG-INFO +1 -1
  7. {pyptt-2.1.3 → pyptt-2.1.4}/tests/test_bucket.py +2 -1
  8. {pyptt-2.1.3 → pyptt-2.1.4}/tests/test_del_post.py +25 -3
  9. {pyptt-2.1.3 → pyptt-2.1.4}/tests/test_get_newest_index.py +12 -1
  10. {pyptt-2.1.3 → pyptt-2.1.4}/tests/test_get_waterball.py +7 -0
  11. {pyptt-2.1.3 → pyptt-2.1.4}/tests/test_give_money.py +5 -0
  12. {pyptt-2.1.3 → pyptt-2.1.4}/tests/test_mark_post.py +3 -2
  13. {pyptt-2.1.3 → pyptt-2.1.4}/tests/test_service.py +7 -1
  14. {pyptt-2.1.3 → pyptt-2.1.4}/tests/test_set_board_title.py +2 -1
  15. pyptt-2.1.3/PyPtt/ssl_config.py +0 -24
  16. {pyptt-2.1.3 → pyptt-2.1.4}/LICENSE +0 -0
  17. {pyptt-2.1.3 → pyptt-2.1.4}/PyPtt/PTT.py +0 -0
  18. {pyptt-2.1.3 → pyptt-2.1.4}/PyPtt/_api_bucket.py +0 -0
  19. {pyptt-2.1.3 → pyptt-2.1.4}/PyPtt/_api_call_status.py +0 -0
  20. {pyptt-2.1.3 → pyptt-2.1.4}/PyPtt/_api_change_pw.py +0 -0
  21. {pyptt-2.1.3 → pyptt-2.1.4}/PyPtt/_api_comment.py +0 -0
  22. {pyptt-2.1.3 → pyptt-2.1.4}/PyPtt/_api_del_post.py +0 -0
  23. {pyptt-2.1.3 → pyptt-2.1.4}/PyPtt/_api_get_board_info.py +0 -0
  24. {pyptt-2.1.3 → pyptt-2.1.4}/PyPtt/_api_get_board_list.py +0 -0
  25. {pyptt-2.1.3 → pyptt-2.1.4}/PyPtt/_api_get_bottom_post_list.py +0 -0
  26. {pyptt-2.1.3 → pyptt-2.1.4}/PyPtt/_api_get_favourite_board.py +0 -0
  27. {pyptt-2.1.3 → pyptt-2.1.4}/PyPtt/_api_get_newest_index.py +0 -0
  28. {pyptt-2.1.3 → pyptt-2.1.4}/PyPtt/_api_get_post.py +0 -0
  29. {pyptt-2.1.3 → pyptt-2.1.4}/PyPtt/_api_get_post_index.py +0 -0
  30. {pyptt-2.1.3 → pyptt-2.1.4}/PyPtt/_api_get_post_list.py +0 -0
  31. {pyptt-2.1.3 → pyptt-2.1.4}/PyPtt/_api_get_time.py +0 -0
  32. {pyptt-2.1.3 → pyptt-2.1.4}/PyPtt/_api_get_user.py +0 -0
  33. {pyptt-2.1.3 → pyptt-2.1.4}/PyPtt/_api_get_waterball.py +0 -0
  34. {pyptt-2.1.3 → pyptt-2.1.4}/PyPtt/_api_give_money.py +0 -0
  35. {pyptt-2.1.3 → pyptt-2.1.4}/PyPtt/_api_has_new_mail.py +0 -0
  36. {pyptt-2.1.3 → pyptt-2.1.4}/PyPtt/_api_loginout.py +0 -0
  37. {pyptt-2.1.3 → pyptt-2.1.4}/PyPtt/_api_mail.py +0 -0
  38. {pyptt-2.1.3 → pyptt-2.1.4}/PyPtt/_api_mark_post.py +0 -0
  39. {pyptt-2.1.3 → pyptt-2.1.4}/PyPtt/_api_post.py +0 -0
  40. {pyptt-2.1.3 → pyptt-2.1.4}/PyPtt/_api_reply_post.py +0 -0
  41. {pyptt-2.1.3 → pyptt-2.1.4}/PyPtt/_api_search_user.py +0 -0
  42. {pyptt-2.1.3 → pyptt-2.1.4}/PyPtt/_api_set_board_title.py +0 -0
  43. {pyptt-2.1.3 → pyptt-2.1.4}/PyPtt/_api_util.py +0 -0
  44. {pyptt-2.1.3 → pyptt-2.1.4}/PyPtt/api_server.py +0 -0
  45. {pyptt-2.1.3 → pyptt-2.1.4}/PyPtt/check_value.py +0 -0
  46. {pyptt-2.1.3 → pyptt-2.1.4}/PyPtt/command.py +0 -0
  47. {pyptt-2.1.3 → pyptt-2.1.4}/PyPtt/config.py +0 -0
  48. {pyptt-2.1.3 → pyptt-2.1.4}/PyPtt/data_type.py +0 -0
  49. {pyptt-2.1.3 → pyptt-2.1.4}/PyPtt/exceptions.py +0 -0
  50. {pyptt-2.1.3 → pyptt-2.1.4}/PyPtt/i18n.py +0 -0
  51. {pyptt-2.1.3 → pyptt-2.1.4}/PyPtt/lang_en_US.py +0 -0
  52. {pyptt-2.1.3 → pyptt-2.1.4}/PyPtt/lang_zh_TW.py +0 -0
  53. {pyptt-2.1.3 → pyptt-2.1.4}/PyPtt/lib_util.py +0 -0
  54. {pyptt-2.1.3 → pyptt-2.1.4}/PyPtt/log.py +0 -0
  55. {pyptt-2.1.3 → pyptt-2.1.4}/PyPtt/service.py +0 -0
  56. {pyptt-2.1.3 → pyptt-2.1.4}/PyPtt.egg-info/SOURCES.txt +0 -0
  57. {pyptt-2.1.3 → pyptt-2.1.4}/PyPtt.egg-info/dependency_links.txt +0 -0
  58. {pyptt-2.1.3 → pyptt-2.1.4}/PyPtt.egg-info/requires.txt +0 -0
  59. {pyptt-2.1.3 → pyptt-2.1.4}/PyPtt.egg-info/top_level.txt +0 -0
  60. {pyptt-2.1.3 → pyptt-2.1.4}/README.md +0 -0
  61. {pyptt-2.1.3 → pyptt-2.1.4}/pyproject.toml +0 -0
  62. {pyptt-2.1.3 → pyptt-2.1.4}/setup.cfg +0 -0
  63. {pyptt-2.1.3 → pyptt-2.1.4}/setup.py +0 -0
  64. {pyptt-2.1.3 → pyptt-2.1.4}/tests/test_change_pw.py +0 -0
  65. {pyptt-2.1.3 → pyptt-2.1.4}/tests/test_comment.py +0 -0
  66. {pyptt-2.1.3 → pyptt-2.1.4}/tests/test_exceptions.py +0 -0
  67. {pyptt-2.1.3 → pyptt-2.1.4}/tests/test_fast_post.py +0 -0
  68. {pyptt-2.1.3 → pyptt-2.1.4}/tests/test_get_board_info.py +0 -0
  69. {pyptt-2.1.3 → pyptt-2.1.4}/tests/test_get_board_list.py +0 -0
  70. {pyptt-2.1.3 → pyptt-2.1.4}/tests/test_get_bottom_post_list.py +0 -0
  71. {pyptt-2.1.3 → pyptt-2.1.4}/tests/test_get_content_formula.py +0 -0
  72. {pyptt-2.1.3 → pyptt-2.1.4}/tests/test_get_favourite_boards.py +0 -0
  73. {pyptt-2.1.3 → pyptt-2.1.4}/tests/test_get_mail.py +0 -0
  74. {pyptt-2.1.3 → pyptt-2.1.4}/tests/test_get_post.py +0 -0
  75. {pyptt-2.1.3 → pyptt-2.1.4}/tests/test_get_post_list.py +0 -0
  76. {pyptt-2.1.3 → pyptt-2.1.4}/tests/test_get_post_list_parser.py +0 -0
  77. {pyptt-2.1.3 → pyptt-2.1.4}/tests/test_get_post_parser.py +0 -0
  78. {pyptt-2.1.3 → pyptt-2.1.4}/tests/test_get_time.py +0 -0
  79. {pyptt-2.1.3 → pyptt-2.1.4}/tests/test_get_user.py +0 -0
  80. {pyptt-2.1.3 → pyptt-2.1.4}/tests/test_i18n.py +0 -0
  81. {pyptt-2.1.3 → pyptt-2.1.4}/tests/test_init.py +0 -0
  82. {pyptt-2.1.3 → pyptt-2.1.4}/tests/test_logger.py +0 -0
  83. {pyptt-2.1.3 → pyptt-2.1.4}/tests/test_mail_send_and_del.py +0 -0
  84. {pyptt-2.1.3 → pyptt-2.1.4}/tests/test_parse_query_post.py +0 -0
  85. {pyptt-2.1.3 → pyptt-2.1.4}/tests/test_post.py +0 -0
  86. {pyptt-2.1.3 → pyptt-2.1.4}/tests/test_pyte_parity.py +0 -0
  87. {pyptt-2.1.3 → pyptt-2.1.4}/tests/test_reply_post.py +0 -0
  88. {pyptt-2.1.3 → pyptt-2.1.4}/tests/test_search_user.py +0 -0
  89. {pyptt-2.1.3 → pyptt-2.1.4}/tests/test_vt100_parser.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PyPtt
3
- Version: 2.1.3
3
+ Version: 2.1.4
4
4
  Summary: PyPtt github: https://github.com/PyPtt/PyPtt
5
5
  Author-email: CodingMan <pttcodingman@gmail.com>
6
6
  License: GNU Lesser General Public License v3 (LGPLv3)
@@ -1,4 +1,4 @@
1
- __version__ = '2.1.3'
1
+ __version__ = '2.1.4'
2
2
  __author__ = 'CodingMan'
3
3
  __email__ = 'pttcodingman@gmail.com'
4
4
 
@@ -196,8 +196,12 @@ class API(object):
196
196
  websocket_host = 'wss://ws.ptt2.cc/bbs/'
197
197
  websocket_origin = 'https://term.ptt2.cc'
198
198
  elif self.config.host == data_type.HOST.LOCALHOST:
199
- websocket_host = 'wss://localhost'
200
- websocket_origin = 'https://term.ptt.cc'
199
+ # ponytail: local pttbbs docker image (bbsdocker/imageptt) serves plain ws
200
+ # (no TLS) on 48763; config.port defaults to 23 (telnet default) so treat
201
+ # that as "not set" and fall back to imageptt's default port
202
+ port = self.config.port if self.config.port != 23 else 48763
203
+ websocket_host = f'ws://localhost:{port}/bbs'
204
+ websocket_origin = 'http://localhost'
201
205
  else:
202
206
  websocket_host = f'wss://{self.config.host}'
203
207
  websocket_origin = 'https://term.ptt.cc'
@@ -209,11 +213,15 @@ class API(object):
209
213
  try:
210
214
  log.logger.debug('USER_AGENT',
211
215
  websockets.http11.USER_AGENT if use_http11 else websockets.http.USER_AGENT)
216
+ # ponytail: ws:// (local docker target) can't take an ssl context —
217
+ # websockets errors out if you pass one on a non-wss URI
218
+ connect_kwargs = {'origin': websocket_origin}
219
+ if websocket_host.startswith('wss://'):
220
+ connect_kwargs['ssl'] = self._ssl_context
212
221
  self._core = loop.run_until_complete(
213
222
  websockets.connect(
214
223
  websocket_host,
215
- origin=websocket_origin,
216
- ssl=self._ssl_context))
224
+ **connect_kwargs))
217
225
  # Respond to PTT's IAC DO NAWS (ff fd 1f) and announce terminal size.
218
226
  # PTT honours any height >= 24; larger values reduce get_content iterations.
219
227
  # PTT's hard cap is 100 rows regardless of what we send.
@@ -199,7 +199,9 @@ class Target:
199
199
  content_end_list = [
200
200
  '--\n※ 發信站: 批踢踢實業坊',
201
201
  '--\n※ 發信站: 批踢踢兔(ptt2.cc)',
202
- '--\n※ 發信站: 新批踢踢(ptt2.twbbs.org.tw)'
202
+ '--\n※ 發信站: 新批踢踢(ptt2.twbbs.org.tw)',
203
+ # bbsdocker/imageptt (HOST.LOCALHOST test container) site name.
204
+ '--\n※ 發信站: 批踢踢 docker(pttdocker.test)'
203
205
  ]
204
206
 
205
207
  OnlineUser = [
@@ -0,0 +1,24 @@
1
+ key = """-----BEGIN EC PARAMETERS-----
2
+ BggqhkjOPQMBBw==
3
+ -----END EC PARAMETERS-----
4
+ -----BEGIN EC PRIVATE KEY-----
5
+ MHcCAQEEIPSUMd0VM3Lz9oHqzRjDOoA7mMSwkff1CvCmOhswqdeToAoGCCqGSM49
6
+ AwEHoUQDQgAEFL8NgpDyAYc1AfvrY4QeOOF5bEaj3fQyrfF+SQhRzgqnKFPxCVVs
7
+ qPE3yCC7L/2VweGjoPMg1YPOsSTsiliqlg==
8
+ -----END EC PRIVATE KEY-----
9
+ """
10
+
11
+ cert = """-----BEGIN CERTIFICATE-----
12
+ MIIB6jCCAY8CFFnMpZwQZ949yt925TXsbCqq9/+SMAoGCCqGSM49BAMCMHcxCzAJ
13
+ BgNVBAYTAlRXMQ4wDAYDVQQIDAVTdGF0ZTENMAsGA1UEBwwEQ2l0eTEVMBMGA1UE
14
+ CgwMT3JnYW5pemF0aW9uMRwwGgYDVQQLDBNPcmdhbml6YXRpb25hbCBVbml0MRQw
15
+ EgYDVQQDDAtDb21tb24gTmFtZTAeFw0yNjA3MTMxNTE4MDhaFw0zNjA3MTAxNTE4
16
+ MDhaMHcxCzAJBgNVBAYTAlRXMQ4wDAYDVQQIDAVTdGF0ZTENMAsGA1UEBwwEQ2l0
17
+ eTEVMBMGA1UECgwMT3JnYW5pemF0aW9uMRwwGgYDVQQLDBNPcmdhbml6YXRpb25h
18
+ bCBVbml0MRQwEgYDVQQDDAtDb21tb24gTmFtZTBZMBMGByqGSM49AgEGCCqGSM49
19
+ AwEHA0IABBS/DYKQ8gGHNQH762OEHjjheWxGo930Mq3xfkkIUc4KpyhT8QlVbKjx
20
+ N8gguy/9lcHho6DzINWDzrEk7IpYqpYwCgYIKoZIzj0EAwIDSQAwRgIhAJaKKQ+t
21
+ oEPH2j3xs3Rg3F3IR/8EdlzdD+mFPoXtjl9dAiEAhvHMefijy34Ya268zOGArdNz
22
+ 5msfSDH5QT27scqencw=
23
+ -----END CERTIFICATE-----
24
+ """
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PyPtt
3
- Version: 2.1.3
3
+ Version: 2.1.4
4
4
  Summary: PyPtt github: https://github.com/PyPtt/PyPtt
5
5
  Author-email: CodingMan <pttcodingman@gmail.com>
6
6
  License: GNU Lesser General Public License v3 (LGPLv3)
@@ -17,6 +17,7 @@ import pytest
17
17
 
18
18
  import PyPtt
19
19
  from tests import config
20
+ from tests import util
20
21
 
21
22
 
22
23
  def test_bucket_nonexistent_user_raises(ptt_bots):
@@ -38,7 +39,7 @@ def test_bucket_on_moderated_board(ptt_bots):
38
39
  if not config.MOD_BOARD:
39
40
  pytest.skip('MOD_BOARD env var not set')
40
41
  for ptt_bot in ptt_bots:
41
- if ptt_bot.host != PyPtt.HOST.PTT1:
42
+ if not util.is_primary_host(ptt_bot, ptt_bots):
42
43
  continue
43
44
  try:
44
45
  ptt_bot.bucket(
@@ -5,6 +5,7 @@ import pytest
5
5
 
6
6
  import PyPtt
7
7
  from tests import config
8
+ from tests import util
8
9
 
9
10
 
10
11
  def test_del_own_post(ptt_bots):
@@ -25,6 +26,8 @@ def test_del_own_post(ptt_bots):
25
26
 
26
27
  # 2. Verify we found our post
27
28
  for i in range(5):
29
+ if newest_index - i <= 0:
30
+ continue
28
31
  post_data = ptt_bot.get_post('Test', index=newest_index - i)
29
32
 
30
33
  if post_data['author'].startswith(ptt_bot.ptt_id):
@@ -36,13 +39,24 @@ def test_del_own_post(ptt_bots):
36
39
  # 3. Delete the post
37
40
 
38
41
  for i in range(5): # Retry up to 3 times in case of transient issues
42
+ if newest_index - i <= 0:
43
+ continue
39
44
  try:
40
45
  ptt_bot.del_post(board='Test', index=newest_index - i)
41
46
  except PyPtt.exceptions.NoPermission:
42
47
  pass
43
48
 
44
49
  for i in range(5):
45
- deleted_post_data = ptt_bot.get_post('Test', index=newest_index - i)
50
+ if newest_index - i <= 0:
51
+ continue
52
+ try:
53
+ deleted_post_data = ptt_bot.get_post('Test', index=newest_index - i)
54
+ except PyPtt.exceptions.ParameterError:
55
+ # On a small local board, deleting every remaining post can
56
+ # shrink the board's live index range out from under this
57
+ # stale `newest_index`; an out-of-range index unambiguously
58
+ # means the post is gone, which is what this loop checks for.
59
+ continue
46
60
 
47
61
  print(json.dumps(deleted_post_data, ensure_ascii=False, indent=2))
48
62
 
@@ -72,6 +86,8 @@ def test_del_other_post_permission_error(ptt_bots):
72
86
  target_index = -1
73
87
  for i in range(10): # Check the last 10 posts
74
88
  index_to_check = newest_index - i
89
+ if index_to_check <= 0:
90
+ continue
75
91
  try:
76
92
  post = ptt_bot.get_post(board, index=index_to_check, query=True)
77
93
  if post[PyPtt.PostField.post_status] == PyPtt.PostStatus.EXISTS and not post['author'].startswith(
@@ -101,6 +117,8 @@ def test_del_own_post_with_reason_raises(ptt_bots):
101
117
  newest_index = ptt_bot.get_newest_index(PyPtt.NewIndex.BOARD, board='Test')
102
118
  index = -1
103
119
  for i in range(5):
120
+ if newest_index - i <= 0:
121
+ continue
104
122
  post_data = ptt_bot.get_post('Test', index=newest_index - i)
105
123
  if post_data['author'].startswith(ptt_bot.ptt_id) and \
106
124
  post_data['title'] == f"[測試] {post_title}":
@@ -122,8 +140,12 @@ def test_del_other_post_with_reason_as_moderator(ptt_bots):
122
140
  if not config.MOD_BOARD:
123
141
  pytest.skip('MOD_BOARD env var not set')
124
142
  for ptt_bot in ptt_bots:
125
- if ptt_bot.host != PyPtt.HOST.PTT1:
126
- continue # MOD_BOARD is a PTT1 board
143
+ if not util.is_primary_host(ptt_bot, ptt_bots):
144
+ continue # MOD_BOARD is moderated by the primary bot
145
+
146
+ if ptt_bot.host == PyPtt.HOST.LOCALHOST:
147
+ pytest.skip('local imageptt hard-deletes and reindexes moderator '
148
+ 'posts, leaving no DELETED_BY_MODERATOR tombstone to read back')
127
149
 
128
150
  board = config.MOD_BOARD
129
151
  newest_index = ptt_bot.get_newest_index(PyPtt.NewIndex.BOARD, board=board)
@@ -20,6 +20,15 @@ PTT2_BOARD_CASES = [
20
20
  ('PttSuggest', PyPtt.SearchType.KEYWORD, '[問題]'),
21
21
  ]
22
22
 
23
+ # The PTT1/PTT2 cases above search real, host-specific historical posts and
24
+ # boards that don't exist on a local imageptt container. `Python` is seeded
25
+ # with at least one post by scripts/bootstrap_local_pttbbs.py and — unlike
26
+ # `Test` — no other test in the suite deletes from it, so its post count
27
+ # only ever grows across a full-suite run.
28
+ LOCALHOST_BOARD_CASES = [
29
+ ('Python', None, None),
30
+ ]
31
+
23
32
  def test_get_mail_index(ptt_bots):
24
33
  """Tests getting the newest mail index."""
25
34
  for ptt_bot in ptt_bots:
@@ -30,7 +39,9 @@ def test_get_mail_index(ptt_bots):
30
39
  def test_get_board_index(ptt_bots):
31
40
  """Tests getting the newest board index on PTT2 with various search parameters."""
32
41
  for ptt_bot in ptt_bots:
33
- if ptt_bot.config.host == PyPtt.HOST.PTT1:
42
+ if ptt_bot.config.host == PyPtt.HOST.LOCALHOST:
43
+ test_params = LOCALHOST_BOARD_CASES
44
+ elif ptt_bot.config.host == PyPtt.HOST.PTT1:
34
45
  test_params = PTT1_BOARD_CASES
35
46
  else:
36
47
  test_params = PTT2_BOARD_CASES
@@ -7,9 +7,16 @@ try:
7
7
  except KeyError:
8
8
  import config
9
9
 
10
+ import os
11
+
12
+ # ponytail: PTT_HOST=LOCALHOST points at a local imageptt docker container
13
+ # instead of the real PTT1 host; unset keeps the status quo.
14
+ _use_localhost = os.environ.get('PTT_HOST') == 'LOCALHOST'
15
+
10
16
 
11
17
  def test_get_waterball():
12
18
  ptt1_bot = PyPtt.API(
19
+ host=PyPtt.HOST.LOCALHOST if _use_localhost else PyPtt.HOST.PTT1,
13
20
  )
14
21
  ptt1_bot.login(ptt_id=config.PTT1_ID, ptt_pw=config.PTT1_PW, kick_other_session=True)
15
22
 
@@ -12,6 +12,11 @@ def test_give_money(ptt_bots):
12
12
  # PTT2 test host does not support giving money.
13
13
  if ptt_bot.host == PyPtt.HOST.PTT2:
14
14
  continue
15
+ # Can't give money to yourself — under LOCALHOST both bots share the
16
+ # same .host value, so the PTT2 skip above doesn't disambiguate them,
17
+ # and TEST_USER may legitimately be the PTT2 account's own ptt_id.
18
+ if ptt_bot.ptt_id.lower() == recipient_id.lower():
19
+ continue
15
20
 
16
21
  try:
17
22
  # This call should not raise an exception on success
@@ -13,6 +13,7 @@ import pytest
13
13
  import PyPtt
14
14
  from PyPtt import PostField, NewIndex
15
15
  from tests import config
16
+ from tests import util
16
17
 
17
18
 
18
19
  def _post_and_get_aid(ptt_bot, board: str) -> str:
@@ -39,8 +40,8 @@ def test_mark_post_on_moderated_board(ptt_bots):
39
40
  if not config.MOD_BOARD:
40
41
  pytest.skip('MOD_BOARD env var not set')
41
42
  for ptt_bot in ptt_bots:
42
- if ptt_bot.host != PyPtt.HOST.PTT1:
43
- continue # MOD_BOARD is a PTT1 board
43
+ if not util.is_primary_host(ptt_bot, ptt_bots):
44
+ continue # MOD_BOARD is moderated by the primary bot
44
45
  aid = _post_and_get_aid(ptt_bot, board=config.MOD_BOARD)
45
46
  try:
46
47
  ptt_bot.mark_post(
@@ -1,3 +1,5 @@
1
+ import os
2
+
1
3
  import pytest
2
4
  import PyPtt
3
5
  import threading
@@ -5,6 +7,10 @@ import time
5
7
  from PyPtt import Service, PostField
6
8
  from tests import config # Assuming config.py has PTT1_ID and PTT1_PW
7
9
 
10
+ # ponytail: PTT_HOST=LOCALHOST points at a local imageptt docker container
11
+ # instead of the real PTT1 host; unset keeps the status quo.
12
+ _use_localhost = os.environ.get('PTT_HOST') == 'LOCALHOST'
13
+
8
14
  class TestCallInterval:
9
15
  """Tests for call_interval feature (no network required)."""
10
16
 
@@ -56,7 +62,7 @@ class TestCallInterval:
56
62
  def service_instance():
57
63
  import time
58
64
 
59
- pyptt_init_config = {}
65
+ pyptt_init_config = {'host': PyPtt.HOST.LOCALHOST} if _use_localhost else {}
60
66
  service = Service(pyptt_init_config)
61
67
 
62
68
  max_retries = 3
@@ -16,6 +16,7 @@ import pytest
16
16
 
17
17
  import PyPtt
18
18
  from tests import config
19
+ from tests import util
19
20
 
20
21
 
21
22
  def test_a_set_board_title_without_moderator_perm_raises(ptt_bots):
@@ -36,7 +37,7 @@ def test_b_set_board_title_on_moderated_board(ptt_bots):
36
37
  if not config.MOD_BOARD:
37
38
  pytest.skip('MOD_BOARD env var not set')
38
39
  for ptt_bot in ptt_bots:
39
- if ptt_bot.host != PyPtt.HOST.PTT1:
40
+ if not util.is_primary_host(ptt_bot, ptt_bots):
40
41
  continue
41
42
  info = ptt_bot.get_board_info(board=config.MOD_BOARD)
42
43
  original = info[PyPtt.BoardField.mandarin_des]
@@ -1,24 +0,0 @@
1
- key = """-----BEGIN EC PARAMETERS-----
2
- BggqhkjOPQMBBw==
3
- -----END EC PARAMETERS-----
4
- -----BEGIN EC PRIVATE KEY-----
5
- MHcCAQEEIEkOJyMNiLY15Dbj6KQAQzcL8VCnyWHTZRAtIku05VDZoAoGCCqGSM49
6
- AwEHoUQDQgAEKUSVL5IptOLhRvvjbwASpbMm2u9g5bB+JzwZFipu7YcP/M3O/hdn
7
- itOTx/TQ1WUZzOO1K8VVP+PiJ848Gf7oXQ==
8
- -----END EC PRIVATE KEY-----
9
- """
10
-
11
- cert = """-----BEGIN CERTIFICATE-----
12
- MIIB6DCCAY8CFBQB2jo2W/VcD/OwELD8q619nPFLMAoGCCqGSM49BAMCMHcxCzAJ
13
- BgNVBAYTAlRXMQ4wDAYDVQQIDAVTdGF0ZTENMAsGA1UEBwwEQ2l0eTEVMBMGA1UE
14
- CgwMT3JnYW5pemF0aW9uMRwwGgYDVQQLDBNPcmdhbml6YXRpb25hbCBVbml0MRQw
15
- EgYDVQQDDAtDb21tb24gTmFtZTAeFw0yNjA2MjkxMzI5MjNaFw0zNjA2MjYxMzI5
16
- MjNaMHcxCzAJBgNVBAYTAlRXMQ4wDAYDVQQIDAVTdGF0ZTENMAsGA1UEBwwEQ2l0
17
- eTEVMBMGA1UECgwMT3JnYW5pemF0aW9uMRwwGgYDVQQLDBNPcmdhbml6YXRpb25h
18
- bCBVbml0MRQwEgYDVQQDDAtDb21tb24gTmFtZTBZMBMGByqGSM49AgEGCCqGSM49
19
- AwEHA0IABClElS+SKbTi4Ub7428AEqWzJtrvYOWwfic8GRYqbu2HD/zNzv4XZ4rT
20
- k8f00NVlGczjtSvFVT/j4ifOPBn+6F0wCgYIKoZIzj0EAwIDRwAwRAIgXp4Ylzan
21
- xWWkNTM2MrkPDIy06zA6vLWkKaXNaTRbc+8CICnfggxFK7IrkX5Z7ZOstjCaO+kd
22
- /xwJcAEv99IpTAr/
23
- -----END CERTIFICATE-----
24
- """
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