PyPtt 2.2.4__tar.gz → 2.2.5__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 (99) hide show
  1. {pyptt-2.2.4 → pyptt-2.2.5}/PKG-INFO +1 -1
  2. {pyptt-2.2.4 → pyptt-2.2.5}/PyPtt/PTT.py +33 -0
  3. {pyptt-2.2.4 → pyptt-2.2.5}/PyPtt/__init__.py +1 -1
  4. pyptt-2.2.5/PyPtt/_api_set_signature_file.py +86 -0
  5. {pyptt-2.2.4 → pyptt-2.2.5}/PyPtt/lang_en_US.py +1 -0
  6. {pyptt-2.2.4 → pyptt-2.2.5}/PyPtt/lang_zh_TW.py +1 -0
  7. {pyptt-2.2.4 → pyptt-2.2.5}/PyPtt.egg-info/PKG-INFO +1 -1
  8. {pyptt-2.2.4 → pyptt-2.2.5}/PyPtt.egg-info/SOURCES.txt +2 -0
  9. pyptt-2.2.5/tests/test_set_signature_file.py +32 -0
  10. {pyptt-2.2.4 → pyptt-2.2.5}/LICENSE +0 -0
  11. {pyptt-2.2.4 → pyptt-2.2.5}/PyPtt/_api_bucket.py +0 -0
  12. {pyptt-2.2.4 → pyptt-2.2.5}/PyPtt/_api_call_status.py +0 -0
  13. {pyptt-2.2.4 → pyptt-2.2.5}/PyPtt/_api_change_pw.py +0 -0
  14. {pyptt-2.2.4 → pyptt-2.2.5}/PyPtt/_api_comment.py +0 -0
  15. {pyptt-2.2.4 → pyptt-2.2.5}/PyPtt/_api_del_post.py +0 -0
  16. {pyptt-2.2.4 → pyptt-2.2.5}/PyPtt/_api_get_board_info.py +0 -0
  17. {pyptt-2.2.4 → pyptt-2.2.5}/PyPtt/_api_get_board_list.py +0 -0
  18. {pyptt-2.2.4 → pyptt-2.2.5}/PyPtt/_api_get_bottom_post_list.py +0 -0
  19. {pyptt-2.2.4 → pyptt-2.2.5}/PyPtt/_api_get_favourite_board.py +0 -0
  20. {pyptt-2.2.4 → pyptt-2.2.5}/PyPtt/_api_get_newest_index.py +0 -0
  21. {pyptt-2.2.4 → pyptt-2.2.5}/PyPtt/_api_get_post.py +0 -0
  22. {pyptt-2.2.4 → pyptt-2.2.5}/PyPtt/_api_get_post_index.py +0 -0
  23. {pyptt-2.2.4 → pyptt-2.2.5}/PyPtt/_api_get_post_list.py +0 -0
  24. {pyptt-2.2.4 → pyptt-2.2.5}/PyPtt/_api_get_time.py +0 -0
  25. {pyptt-2.2.4 → pyptt-2.2.5}/PyPtt/_api_get_user.py +0 -0
  26. {pyptt-2.2.4 → pyptt-2.2.5}/PyPtt/_api_get_waterball.py +0 -0
  27. {pyptt-2.2.4 → pyptt-2.2.5}/PyPtt/_api_give_money.py +0 -0
  28. {pyptt-2.2.4 → pyptt-2.2.5}/PyPtt/_api_has_new_mail.py +0 -0
  29. {pyptt-2.2.4 → pyptt-2.2.5}/PyPtt/_api_loginout.py +0 -0
  30. {pyptt-2.2.4 → pyptt-2.2.5}/PyPtt/_api_lottery.py +0 -0
  31. {pyptt-2.2.4 → pyptt-2.2.5}/PyPtt/_api_mail.py +0 -0
  32. {pyptt-2.2.4 → pyptt-2.2.5}/PyPtt/_api_mark_post.py +0 -0
  33. {pyptt-2.2.4 → pyptt-2.2.5}/PyPtt/_api_post.py +0 -0
  34. {pyptt-2.2.4 → pyptt-2.2.5}/PyPtt/_api_reply_post.py +0 -0
  35. {pyptt-2.2.4 → pyptt-2.2.5}/PyPtt/_api_search_user.py +0 -0
  36. {pyptt-2.2.4 → pyptt-2.2.5}/PyPtt/_api_set_board_title.py +0 -0
  37. {pyptt-2.2.4 → pyptt-2.2.5}/PyPtt/_api_util.py +0 -0
  38. {pyptt-2.2.4 → pyptt-2.2.5}/PyPtt/_uao/LICENSE +0 -0
  39. {pyptt-2.2.4 → pyptt-2.2.5}/PyPtt/_uao/__init__.py +0 -0
  40. {pyptt-2.2.4 → pyptt-2.2.5}/PyPtt/_uao/b2u.py +0 -0
  41. {pyptt-2.2.4 → pyptt-2.2.5}/PyPtt/_uao/u2b.py +0 -0
  42. {pyptt-2.2.4 → pyptt-2.2.5}/PyPtt/api_server.py +0 -0
  43. {pyptt-2.2.4 → pyptt-2.2.5}/PyPtt/check_value.py +0 -0
  44. {pyptt-2.2.4 → pyptt-2.2.5}/PyPtt/command.py +0 -0
  45. {pyptt-2.2.4 → pyptt-2.2.5}/PyPtt/config.py +0 -0
  46. {pyptt-2.2.4 → pyptt-2.2.5}/PyPtt/connect_core.py +0 -0
  47. {pyptt-2.2.4 → pyptt-2.2.5}/PyPtt/data_type.py +0 -0
  48. {pyptt-2.2.4 → pyptt-2.2.5}/PyPtt/exceptions.py +0 -0
  49. {pyptt-2.2.4 → pyptt-2.2.5}/PyPtt/i18n.py +0 -0
  50. {pyptt-2.2.4 → pyptt-2.2.5}/PyPtt/lib_util.py +0 -0
  51. {pyptt-2.2.4 → pyptt-2.2.5}/PyPtt/log.py +0 -0
  52. {pyptt-2.2.4 → pyptt-2.2.5}/PyPtt/screens.py +0 -0
  53. {pyptt-2.2.4 → pyptt-2.2.5}/PyPtt/service.py +0 -0
  54. {pyptt-2.2.4 → pyptt-2.2.5}/PyPtt/ssl_config.py +0 -0
  55. {pyptt-2.2.4 → pyptt-2.2.5}/PyPtt.egg-info/dependency_links.txt +0 -0
  56. {pyptt-2.2.4 → pyptt-2.2.5}/PyPtt.egg-info/requires.txt +0 -0
  57. {pyptt-2.2.4 → pyptt-2.2.5}/PyPtt.egg-info/top_level.txt +0 -0
  58. {pyptt-2.2.4 → pyptt-2.2.5}/README.md +0 -0
  59. {pyptt-2.2.4 → pyptt-2.2.5}/pyproject.toml +0 -0
  60. {pyptt-2.2.4 → pyptt-2.2.5}/setup.cfg +0 -0
  61. {pyptt-2.2.4 → pyptt-2.2.5}/setup.py +0 -0
  62. {pyptt-2.2.4 → pyptt-2.2.5}/tests/test_bucket.py +0 -0
  63. {pyptt-2.2.4 → pyptt-2.2.5}/tests/test_change_pw.py +0 -0
  64. {pyptt-2.2.4 → pyptt-2.2.5}/tests/test_comment.py +0 -0
  65. {pyptt-2.2.4 → pyptt-2.2.5}/tests/test_del_post.py +0 -0
  66. {pyptt-2.2.4 → pyptt-2.2.5}/tests/test_del_post_unit.py +0 -0
  67. {pyptt-2.2.4 → pyptt-2.2.5}/tests/test_exceptions.py +0 -0
  68. {pyptt-2.2.4 → pyptt-2.2.5}/tests/test_fast_post.py +0 -0
  69. {pyptt-2.2.4 → pyptt-2.2.5}/tests/test_get_board_info.py +0 -0
  70. {pyptt-2.2.4 → pyptt-2.2.5}/tests/test_get_board_list.py +0 -0
  71. {pyptt-2.2.4 → pyptt-2.2.5}/tests/test_get_bottom_post_list.py +0 -0
  72. {pyptt-2.2.4 → pyptt-2.2.5}/tests/test_get_content_formula.py +0 -0
  73. {pyptt-2.2.4 → pyptt-2.2.5}/tests/test_get_favourite_boards.py +0 -0
  74. {pyptt-2.2.4 → pyptt-2.2.5}/tests/test_get_mail.py +0 -0
  75. {pyptt-2.2.4 → pyptt-2.2.5}/tests/test_get_newest_index.py +0 -0
  76. {pyptt-2.2.4 → pyptt-2.2.5}/tests/test_get_post.py +0 -0
  77. {pyptt-2.2.4 → pyptt-2.2.5}/tests/test_get_post_list.py +0 -0
  78. {pyptt-2.2.4 → pyptt-2.2.5}/tests/test_get_post_list_parser.py +0 -0
  79. {pyptt-2.2.4 → pyptt-2.2.5}/tests/test_get_post_parser.py +0 -0
  80. {pyptt-2.2.4 → pyptt-2.2.5}/tests/test_get_time.py +0 -0
  81. {pyptt-2.2.4 → pyptt-2.2.5}/tests/test_get_user.py +0 -0
  82. {pyptt-2.2.4 → pyptt-2.2.5}/tests/test_get_waterball.py +0 -0
  83. {pyptt-2.2.4 → pyptt-2.2.5}/tests/test_give_money.py +0 -0
  84. {pyptt-2.2.4 → pyptt-2.2.5}/tests/test_i18n.py +0 -0
  85. {pyptt-2.2.4 → pyptt-2.2.5}/tests/test_init.py +0 -0
  86. {pyptt-2.2.4 → pyptt-2.2.5}/tests/test_logger.py +0 -0
  87. {pyptt-2.2.4 → pyptt-2.2.5}/tests/test_login_logout.py +0 -0
  88. {pyptt-2.2.4 → pyptt-2.2.5}/tests/test_lottery.py +0 -0
  89. {pyptt-2.2.4 → pyptt-2.2.5}/tests/test_mail_send_and_del.py +0 -0
  90. {pyptt-2.2.4 → pyptt-2.2.5}/tests/test_mark_post.py +0 -0
  91. {pyptt-2.2.4 → pyptt-2.2.5}/tests/test_parse_query_post.py +0 -0
  92. {pyptt-2.2.4 → pyptt-2.2.5}/tests/test_post.py +0 -0
  93. {pyptt-2.2.4 → pyptt-2.2.5}/tests/test_post_anonymous.py +0 -0
  94. {pyptt-2.2.4 → pyptt-2.2.5}/tests/test_pyte_parity.py +0 -0
  95. {pyptt-2.2.4 → pyptt-2.2.5}/tests/test_reply_post.py +0 -0
  96. {pyptt-2.2.4 → pyptt-2.2.5}/tests/test_search_user.py +0 -0
  97. {pyptt-2.2.4 → pyptt-2.2.5}/tests/test_service.py +0 -0
  98. {pyptt-2.2.4 → pyptt-2.2.5}/tests/test_set_board_title.py +0 -0
  99. {pyptt-2.2.4 → pyptt-2.2.5}/tests/test_vt100_parser.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PyPtt
3
- Version: 2.2.4
3
+ Version: 2.2.5
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)
@@ -28,6 +28,7 @@ from . import _api_post
28
28
  from . import _api_reply_post
29
29
  from . import _api_search_user
30
30
  from . import _api_set_board_title
31
+ from . import _api_set_signature_file
31
32
  from . import check_value
32
33
  from . import config
33
34
  from . import connect_core
@@ -806,6 +807,38 @@ class API:
806
807
 
807
808
  _api_set_board_title.set_board_title(self, board, new_title)
808
809
 
810
+ def set_signature_file(self, content: str) -> None:
811
+
812
+ """
813
+ 更新登入帳號的名片檔(PTT 的 plan),對應【個人設定】->【個人檔案】
814
+ ->(Q)ueryEdit 編輯名片檔的功能。`get_user()` 回傳的 `signature_file`
815
+ 欄位讀的就是這份內容。
816
+
817
+ Args:
818
+ content (str): 新的名片檔內容,會整份取代原本的內容。
819
+
820
+ Returns:
821
+ None
822
+
823
+ Raises:
824
+ RequireLogin: 需要登入。
825
+
826
+ 範例::
827
+
828
+ import PyPtt
829
+
830
+ ptt_bot = PyPtt.API()
831
+ try:
832
+ # .. login ..
833
+ ptt_bot.set_signature_file(content='你好,我是 PyPtt')
834
+ # .. do something ..
835
+ finally:
836
+ ptt_bot.logout()
837
+
838
+ """
839
+
840
+ _api_set_signature_file.set_signature_file(self, content)
841
+
809
842
  def mark_post(self, mark_type: int, board: str, aid: Optional[str] = None, index: int = 0, search_type: int = 0,
810
843
  search_condition: Optional[str] = None) -> None:
811
844
  """
@@ -1,4 +1,4 @@
1
- __version__ = '2.2.4'
1
+ __version__ = '2.2.5'
2
2
  __author__ = 'CodingMan'
3
3
  __email__ = 'pttcodingman@gmail.com'
4
4
 
@@ -0,0 +1,86 @@
1
+ from . import _api_util
2
+ from . import check_value
3
+ from . import command
4
+ from . import connect_core
5
+ from . import exceptions
6
+ from . import i18n
7
+ from . import lib_util
8
+ from . import log
9
+
10
+
11
+ def set_signature_file(api, content: str) -> None:
12
+ _api_util.one_thread(api)
13
+
14
+ if not api._is_login:
15
+ raise exceptions.RequireLogin(i18n.require_login)
16
+
17
+ check_value.check_type(content, str, 'content')
18
+
19
+ log.logger.info(i18n.set_signature_file)
20
+
21
+ cmd_list = []
22
+ cmd_list.append(command.go_main_menu)
23
+ cmd_list.append('U')
24
+ cmd_list.append(command.enter)
25
+ cmd_list.append('M')
26
+ cmd_list.append(command.enter)
27
+ cmd_list.append('Q')
28
+ cmd_list.append(command.enter)
29
+ cmd = ''.join(cmd_list)
30
+
31
+ target_list = [
32
+ # Existing signature file -> getans asks Delete/Edit/Cancel first.
33
+ # max_match=1: the echoed prompt text can linger on the next
34
+ # screen refresh while waiting for the editor to draw (same
35
+ # quirk documented for '確定要儲存檔案嗎' in _api_post.py); without
36
+ # it this would re-fire 'E' + Enter into the editor buffer.
37
+ connect_core.TargetUnit('名片 (D)刪除', response='E' + command.enter, max_match=1),
38
+ # Empty signature file skips the getans prompt and opens the
39
+ # editor directly.
40
+ connect_core.TargetUnit('編輯文章', break_detect=True),
41
+ ]
42
+ index = api.connect_core.send(
43
+ cmd,
44
+ target_list,
45
+ screen_timeout=api.config.screen_long_timeout)
46
+ if index < 0:
47
+ ori_screen = api.connect_core.get_screen_queue()[-1]
48
+ raise exceptions.UnknownError(ori_screen)
49
+
50
+ content = lib_util.uniform_new_line(content)
51
+
52
+ cmd_list = []
53
+ # ponytail: unlike post's blank template, the card-file editor preloads
54
+ # the account's existing signature file, so it has to be cleared line by
55
+ # line before writing the new content. ctrl_y*60 is a "clear up to 60
56
+ # pre-loaded lines" ceiling -- bump it if a real card file ever runs
57
+ # longer than that.
58
+ cmd_list.append(command.ctrl_y * 60)
59
+ cmd_list.append(content)
60
+ cmd_list.append(command.ctrl_x)
61
+ cmd = ''.join(cmd_list)
62
+
63
+ target_list = [
64
+ connect_core.TargetUnit('確定要儲存檔案嗎', response='s' + command.enter, max_match=1),
65
+ connect_core.TargetUnit('名片更新完畢', break_detect=True),
66
+ ]
67
+ index = api.connect_core.send(
68
+ cmd,
69
+ target_list,
70
+ screen_timeout=api.config.screen_long_timeout)
71
+ if index < 0:
72
+ ori_screen = api.connect_core.get_screen_queue()[-1]
73
+ raise exceptions.UnknownError(ori_screen)
74
+
75
+ # The leading space in go_main_menu dismisses the "請按任意鍵繼續" banner
76
+ # left by the save; the trailing left-arrows walk back out of the
77
+ # 個人設定/個人檔案 submenus to the main menu.
78
+ target_list = [
79
+ connect_core.TargetUnit('主功能表', break_detect=True),
80
+ ]
81
+ api.connect_core.send(
82
+ command.go_main_menu,
83
+ target_list,
84
+ screen_timeout=api.config.screen_long_timeout)
85
+
86
+ log.logger.info(i18n.set_signature_file, '...', i18n.success)
@@ -106,6 +106,7 @@ string_data = {
106
106
  "set_connect_host": "Set up the connect host",
107
107
  "set_connect_mode": "Set up the connect mode",
108
108
  "set_contact_mail_first": "Password can only be changed after setting the contact mailbox",
109
+ "set_signature_file": "Update signature file",
109
110
  "set_up_lang_module": "Set up language module",
110
111
  "spend_time": "Spend time",
111
112
  "substandard_post": "Substandard post",
@@ -106,6 +106,7 @@ string_data = {
106
106
  "set_connect_host": "設定連線主機",
107
107
  "set_connect_mode": "設定連線模式",
108
108
  "set_contact_mail_first": "請先設定聯絡信箱後才能修改密碼",
109
+ "set_signature_file": "更新名片檔",
109
110
  "set_up_lang_module": "設定語言模組",
110
111
  "spend_time": "花費時間",
111
112
  "substandard_post": "不合規範文章",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PyPtt
3
- Version: 2.2.4
3
+ Version: 2.2.5
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)
@@ -30,6 +30,7 @@ PyPtt/_api_post.py
30
30
  PyPtt/_api_reply_post.py
31
31
  PyPtt/_api_search_user.py
32
32
  PyPtt/_api_set_board_title.py
33
+ PyPtt/_api_set_signature_file.py
33
34
  PyPtt/_api_util.py
34
35
  PyPtt/api_server.py
35
36
  PyPtt/check_value.py
@@ -92,4 +93,5 @@ tests/test_reply_post.py
92
93
  tests/test_search_user.py
93
94
  tests/test_service.py
94
95
  tests/test_set_board_title.py
96
+ tests/test_set_signature_file.py
95
97
  tests/test_vt100_parser.py
@@ -0,0 +1,32 @@
1
+ """Integration test for set_signature_file (the PTT "名片檔"/plan).
2
+
3
+ Self-restoring round-trip: capture the account's current signature file via
4
+ `get_user`, overwrite it with an identifiable marker, verify the marker shows
5
+ up on a fresh `get_user` read, then set it back to the original content so
6
+ the test doesn't leave a permanent change on the account.
7
+ """
8
+ import time
9
+
10
+ from PyPtt import UserField
11
+
12
+
13
+ def test_set_signature_file_round_trip(ptt_bots):
14
+ for ptt_bot in ptt_bots:
15
+ original = ptt_bot.get_user(ptt_bot.ptt_id)[UserField.signature_file]
16
+
17
+ marker = f'PyPtt set_signature_file test {int(time.time())}'
18
+ try:
19
+ ptt_bot.set_signature_file(marker)
20
+ time.sleep(1)
21
+
22
+ updated = ptt_bot.get_user(ptt_bot.ptt_id)[UserField.signature_file]
23
+ assert marker in updated.strip()
24
+ finally:
25
+ # Restore -- must always run, even if the assertion above fails.
26
+ ptt_bot.set_signature_file(original)
27
+ time.sleep(1)
28
+
29
+ restored = ptt_bot.get_user(ptt_bot.ptt_id)[UserField.signature_file]
30
+ # Tolerate trailing whitespace/blank-line drift from the
31
+ # editor round-trip; compare on stripped content.
32
+ assert restored.strip() == original.strip()
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes