tumblrbot 1.4.0__tar.gz → 1.4.1__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tumblrbot
3
- Version: 1.4.0
3
+ Version: 1.4.1
4
4
  Summary: An updated bot that posts to Tumblr, based on your very own blog!
5
5
  Requires-Python: >= 3.13
6
6
  Description-Content-Type: text/markdown
@@ -73,6 +73,8 @@ Features:
73
73
 
74
74
  **To-Do:**
75
75
  - Add code documentation.
76
+ - Fix inaccurate post counts when downloading posts.
77
+ - Fix file not found error when starting fine-tuning.
76
78
 
77
79
 
78
80
  **Please submit an issue or contact us for features you want added/reimplemented.**
@@ -53,6 +53,8 @@ Features:
53
53
 
54
54
  **To-Do:**
55
55
  - Add code documentation.
56
+ - Fix inaccurate post counts when downloading posts.
57
+ - Fix file not found error when starting fine-tuning.
56
58
 
57
59
 
58
60
  **Please submit an issue or contact us for features you want added/reimplemented.**
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "tumblrbot"
3
- version = "1.4.0"
3
+ version = "1.4.1"
4
4
  description = "An updated bot that posts to Tumblr, based on your very own blog!"
5
5
  readme = "README.md"
6
6
  requires-python = ">= 3.13"
@@ -13,7 +13,7 @@ from tumblrbot.utils.tumblr import TumblrClient
13
13
  def main() -> None:
14
14
  install()
15
15
 
16
- tokens = Tokens()
16
+ tokens = Tokens.read_from_keyring()
17
17
  with (
18
18
  OpenAI(api_key=tokens.openai_api_key.get_secret_value(), http_client=DefaultHttpxClient(http2=True)) as openai,
19
19
  TumblrClient(tokens=tokens) as tumblr,
@@ -59,7 +59,7 @@ class ExamplesWriter(FlowClass):
59
59
  def get_filtered_posts(self) -> Generator[Post]:
60
60
  posts = list(self.get_valid_posts())
61
61
 
62
- if Confirm.ask("Remove posts flagged by the OpenAI moderation? This can sometimes resolve errors with fine-tuning validation, but is slow.", default=False):
62
+ if Confirm.ask("[gray62]Remove posts flagged by the OpenAI moderation? This can sometimes resolve errors with fine-tuning validation, but is slow.", default=False):
63
63
  removed = 0
64
64
  chunk_size = self.get_moderation_chunk_limit()
65
65
  with PreviewLive() as live:
@@ -1,5 +1,5 @@
1
1
  from collections.abc import Generator
2
- from typing import Annotated, Any, ClassVar, Literal, override
2
+ from typing import Annotated, Any, ClassVar, Literal, Self, override
3
3
 
4
4
  import rich
5
5
  from keyring import get_password, set_password
@@ -10,6 +10,14 @@ from requests_oauthlib import OAuth1Session
10
10
  from rich.panel import Panel
11
11
  from rich.prompt import Confirm, Prompt
12
12
 
13
+ type SerializableSecretStr = Annotated[
14
+ SecretStr,
15
+ PlainSerializer(
16
+ SecretStr.get_secret_value,
17
+ when_used="json-unless-none",
18
+ ),
19
+ ]
20
+
13
21
 
14
22
  class FullyValidatedModel(BaseModel):
15
23
  model_config = ConfigDict(
@@ -22,13 +30,17 @@ class FullyValidatedModel(BaseModel):
22
30
 
23
31
 
24
32
  class Tokens(FullyValidatedModel):
33
+ class Tumblr(FullyValidatedModel):
34
+ client_key: SerializableSecretStr = SecretStr("")
35
+ client_secret: SerializableSecretStr = SecretStr("")
36
+ resource_owner_key: SerializableSecretStr = SecretStr("")
37
+ resource_owner_secret: SerializableSecretStr = SecretStr("")
38
+
25
39
  service_name: ClassVar = "tumblrbot"
40
+ username: ClassVar = "tokens"
26
41
 
27
- openai_api_key: SecretStr = SecretStr("")
28
- tumblr_client_key: SecretStr = SecretStr("")
29
- tumblr_client_secret: SecretStr = SecretStr("")
30
- tumblr_resource_owner_key: SecretStr = SecretStr("")
31
- tumblr_resource_owner_secret: SecretStr = SecretStr("")
42
+ openai_api_key: SerializableSecretStr = SecretStr("")
43
+ tumblr: Tumblr = Tumblr()
32
44
 
33
45
  @staticmethod
34
46
  def online_token_prompt(url: str, *tokens: str) -> Generator[SecretStr]:
@@ -42,46 +54,44 @@ class Tokens(FullyValidatedModel):
42
54
 
43
55
  rich.print()
44
56
 
57
+ @classmethod
58
+ def read_from_keyring(cls) -> Self:
59
+ if json_data := get_password(cls.service_name, cls.username):
60
+ return cls.model_validate_json(json_data)
61
+ return cls()
62
+
45
63
  @override
46
64
  def model_post_init(self, context: object) -> None:
47
65
  super().model_post_init(context)
48
66
 
49
- for name, _ in self:
50
- if value := get_password(self.service_name, name):
51
- setattr(self, name, value)
52
-
53
67
  if not self.openai_api_key.get_secret_value() or Confirm.ask("Reset OpenAI API key?", default=False):
54
68
  (self.openai_api_key,) = self.online_token_prompt("https://platform.openai.com/api-keys", "API key")
55
69
 
56
- if not all(self.get_tumblr_tokens()) or Confirm.ask("Reset Tumblr API tokens?", default=False):
57
- self.tumblr_client_key, self.tumblr_client_secret = self.online_token_prompt("https://tumblr.com/oauth/apps", "consumer key", "consumer secret")
58
-
59
- oauth_session = OAuth1Session(*self.get_tumblr_tokens()[:2])
60
- fetch_response = oauth_session.fetch_request_token("http://tumblr.com/oauth/request_token")
61
- full_authorize_url = oauth_session.authorization_url("http://tumblr.com/oauth/authorize")
62
- (redirect_response,) = self.online_token_prompt(full_authorize_url, "full redirect URL")
63
- oauth_response = oauth_session.parse_authorization_response(redirect_response.get_secret_value())
64
- oauth_session = OAuth1Session(
65
- *self.get_tumblr_tokens()[:2],
70
+ if not all(self.tumblr.model_dump(mode="json").values()) or Confirm.ask("Reset Tumblr API tokens?", default=False):
71
+ self.tumblr.client_key, self.tumblr.client_secret = self.online_token_prompt("https://tumblr.com/oauth/apps", "consumer key", "consumer secret")
72
+
73
+ with OAuth1Session(
74
+ self.tumblr.client_key.get_secret_value(),
75
+ self.tumblr.client_secret.get_secret_value(),
76
+ ) as oauth_session:
77
+ fetch_response = oauth_session.fetch_request_token("http://tumblr.com/oauth/request_token")
78
+ full_authorize_url = oauth_session.authorization_url("http://tumblr.com/oauth/authorize")
79
+ (redirect_response,) = self.online_token_prompt(full_authorize_url, "full redirect URL")
80
+ oauth_response = oauth_session.parse_authorization_response(redirect_response.get_secret_value())
81
+
82
+ with OAuth1Session(
83
+ self.tumblr.client_key.get_secret_value(),
84
+ self.tumblr.client_secret.get_secret_value(),
66
85
  fetch_response["oauth_token"],
67
86
  fetch_response["oauth_token_secret"],
68
87
  verifier=oauth_response["oauth_verifier"],
69
- )
70
- oauth_tokens = oauth_session.fetch_access_token("http://tumblr.com/oauth/access_token")
71
- self.tumblr_resource_owner_key = oauth_tokens["oauth_token"]
72
- self.tumblr_resource_owner_secret = oauth_tokens["oauth_token_secret"]
73
-
74
- for name, value in self:
75
- if isinstance(value, SecretStr):
76
- set_password(self.service_name, name, value.get_secret_value())
77
-
78
- def get_tumblr_tokens(self) -> tuple[str, str, str, str]:
79
- return (
80
- self.tumblr_client_key.get_secret_value(),
81
- self.tumblr_client_secret.get_secret_value(),
82
- self.tumblr_resource_owner_key.get_secret_value(),
83
- self.tumblr_resource_owner_secret.get_secret_value(),
84
- )
88
+ ) as oauth_session:
89
+ oauth_tokens = oauth_session.fetch_access_token("http://tumblr.com/oauth/access_token")
90
+
91
+ self.tumblr.resource_owner_key = oauth_tokens["oauth_token"]
92
+ self.tumblr.resource_owner_secret = oauth_tokens["oauth_token_secret"]
93
+
94
+ set_password(self.service_name, self.username, self.model_dump_json())
85
95
 
86
96
 
87
97
  class Post(FullyValidatedModel):
@@ -16,7 +16,7 @@ class TumblrClient(Session, CacheMixin): # pyright: ignore[reportIncompatibleMe
16
16
  super().__init__(happy_eyeballs=True)
17
17
  CacheMixin.__init__(self, use_cache_dir=True)
18
18
 
19
- self.auth = OAuth1(*self.tokens.get_tumblr_tokens())
19
+ self.auth = OAuth1(**self.tokens.tumblr.model_dump(mode="json"))
20
20
  self.hooks["response"].append(self.response_hook)
21
21
 
22
22
  def __enter__(self) -> Self:
File without changes
File without changes