diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index c2ad067..d59d787 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -1,73 +1,73 @@ -name: バグ報告 -description: バグや不具合を報告する +name: Bug Report +description: Report a bug or issue title: "[Bug]: " labels: ["bug"] body: - type: markdown attributes: value: | - バグ報告ありがとうございます。 - 以下の項目をできるだけ詳しく記入してください。 + Thank you for reporting a bug. + Please fill in the following items as detailed as possible. - type: textarea id: description attributes: - label: 概要 - description: バグの内容を簡潔に説明してください - placeholder: どのような問題が発生していますか? + label: Summary + description: Please briefly describe the bug + placeholder: What problem are you experiencing? validations: required: true - type: textarea id: reproduction attributes: - label: 再現手順 - description: バグを再現する手順を記載してください + label: Steps to Reproduce + description: Please provide steps to reproduce the bug placeholder: | - 1. '...' を実行 - 2. '...' を呼び出し - 3. エラーが発生 + 1. Execute '...' + 2. Call '...' + 3. Error occurs validations: required: true - type: textarea id: expected attributes: - label: 期待される動作 - description: 本来どのように動作すべきかを記載してください + label: Expected Behavior + description: Please describe how it should work validations: required: true - type: textarea id: actual attributes: - label: 実際の動作 - description: 実際にどのような動作になっているかを記載してください + label: Actual Behavior + description: Please describe the actual behavior validations: required: true - type: textarea id: environment attributes: - label: 環境情報 - description: 問題が発生した環境を記載してください + label: Environment + description: Please provide your environment details placeholder: | - - wikidot.py バージョン: - - Python バージョン: + - wikidot.py version: + - Python version: - OS: - - 実行環境: (Jupyter Notebook / スクリプト / etc.) + - Execution environment: (Jupyter Notebook / script / etc.) validations: required: true - type: textarea id: logs attributes: - label: エラーログ・スタックトレース - description: エラーメッセージやスタックトレースがあれば貼り付けてください + label: Error Logs / Stack Trace + description: Please paste any error messages or stack traces if available render: shell - type: textarea id: additional attributes: - label: 補足情報 - description: その他、関連する情報があれば記載してください + label: Additional Information + description: Any other relevant information diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index e242158..5f0b5b4 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,5 +1,5 @@ blank_issues_enabled: true contact_links: - - name: 質問・ディスカッション + - name: Questions / Discussions url: https://github.com/ukwhatn/wikidot.py/discussions - about: バグ報告や機能要望以外の質問はこちらへ + about: For questions other than bug reports or feature requests diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml index b08534f..04f68fc 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -1,45 +1,45 @@ -name: 機能要望 -description: 新機能や改善の提案をする +name: Feature Request +description: Propose a new feature or improvement title: "[Feature]: " labels: ["enhancement"] body: - type: markdown attributes: value: | - 機能要望ありがとうございます。 - 以下の項目をできるだけ詳しく記入してください。 + Thank you for your feature request. + Please fill in the following items as detailed as possible. - type: textarea id: problem attributes: - label: 背景・課題 - description: どのような問題を解決したいですか?どのような場面で困っていますか? - placeholder: "例: 〇〇をしたいが、現在の実装では△△ができない" + label: Background / Problem + description: What problem are you trying to solve? What situation are you facing? + placeholder: "Example: I want to do X, but the current implementation doesn't support Y" validations: required: true - type: textarea id: solution attributes: - label: 提案する解決策 - description: どのような機能や変更があれば解決できると考えますか? + label: Proposed Solution + description: What feature or change would solve this problem? validations: required: true - type: textarea id: alternatives attributes: - label: 代替案 - description: 他に検討した解決策があれば記載してください + label: Alternatives Considered + description: Have you considered any other solutions? - type: textarea id: usecase attributes: - label: ユースケース - description: この機能がどのように使われるか、具体例があれば記載してください + label: Use Case + description: Please provide a concrete example of how this feature would be used placeholder: | ```python - # 使用例 + # Usage example client = wikidot.Client() # ... ``` @@ -47,5 +47,5 @@ body: - type: textarea id: additional attributes: - label: 補足情報 - description: 参考リンクや関連するIssueなど、その他の情報があれば記載してください + label: Additional Information + description: Reference links, related issues, or any other information diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 5ce992d..596a95b 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,46 +1,46 @@ -## 概要 +## Summary - + -## 関連Issue +## Related Issue - - + + -## 変更内容 +## Changes - + - -## 変更の種類 +## Type of Change - + -- [ ] バグ修正 (既存の機能を壊さない修正) -- [ ] 新機能 (既存の機能を壊さない追加) -- [ ] 破壊的変更 (既存の機能に影響を与える変更) -- [ ] ドキュメント更新 -- [ ] リファクタリング -- [ ] テスト追加・修正 -- [ ] CI/CD・ビルド関連 +- [ ] Bug fix (non-breaking change that fixes an issue) +- [ ] New feature (non-breaking change that adds functionality) +- [ ] Breaking change (fix or feature that would cause existing functionality to change) +- [ ] Documentation update +- [ ] Refactoring +- [ ] Test addition/modification +- [ ] CI/CD or build related -## テスト +## Testing - + -- [ ] `make format` パス -- [ ] `make lint` パス -- [ ] `make test` パス +- [ ] `make format` passes +- [ ] `make lint` passes +- [ ] `make test` passes -## チェックリスト +## Checklist - + -- [ ] コードがプロジェクトのスタイルガイドに従っている -- [ ] 必要に応じてドキュメントを更新した -- [ ] 変更に対するテストを追加した(該当する場合) +- [ ] Code follows the project's style guidelines +- [ ] Documentation has been updated as needed +- [ ] Tests have been added for the changes (if applicable) -## 補足情報 +## Additional Information - + diff --git a/README.md b/README.md index 84b3b15..184d1b2 100644 --- a/README.md +++ b/README.md @@ -2,67 +2,67 @@ [![Documentation Status](https://github.com/ukwhatn/wikidot.py/actions/workflows/docs.yml/badge.svg)](https://ukwhatn.github.io/wikidot.py/) -Pythonで簡単にWikidotサイトと対話するためのライブラリです。 +A Python library for easily interacting with Wikidot sites. -## 主な機能 +## Key Features -- サイト、ページ、ユーザー、フォーラムなどの情報取得と操作 -- ページの作成、編集、削除 -- フォーラムスレッドの取得、作成、返信 -- ユーザー管理とサイトメンバーシップ -- プライベートメッセージの送受信 -- ログイン不要の機能と認証が必要な機能両方をサポート +- Retrieve and manipulate sites, pages, users, forums, and more +- Create, edit, and delete pages +- Get, create, and reply to forum threads +- User management and site membership +- Send and receive private messages +- Supports both no-login features and authenticated features -## インストール +## Installation ```bash pip install wikidot ``` -## 使用例(基本) +## Basic Usage ```python import wikidot -# ログインなしでの使用 +# Use without login client = wikidot.Client() -# サイトとページの情報取得 +# Get site and page information site = client.site.get("scp-jp") page = site.page.get("scp-173") -print(f"タイトル: {page.title}") -print(f"評価: {page.rating}") -print(f"作成者: {page.created_by.name}") +print(f"Title: {page.title}") +print(f"Rating: {page.rating}") +print(f"Author: {page.created_by.name}") ``` -## ドキュメント +## Documentation -詳細な使用方法、APIリファレンス、例は公式ドキュメントをご覧ください: +For detailed usage, API reference, and examples, please see the official documentation: -📚 **[公式ドキュメント](https://ukwhatn.github.io/wikidot.py/)** +**[Official Documentation](https://ukwhatn.github.io/wikidot.py/)** -- [インストール方法](https://ukwhatn.github.io/wikidot.py/installation.html) -- [クイックスタート](https://ukwhatn.github.io/wikidot.py/quickstart.html) -- [使用例](https://ukwhatn.github.io/wikidot.py/examples.html) -- [APIリファレンス](https://ukwhatn.github.io/wikidot.py/reference/index.html) +- [Installation](https://ukwhatn.github.io/wikidot.py/installation.html) +- [Quickstart](https://ukwhatn.github.io/wikidot.py/quickstart.html) +- [Examples](https://ukwhatn.github.io/wikidot.py/examples.html) +- [API Reference](https://ukwhatn.github.io/wikidot.py/reference/index.html) -## ドキュメント構築 +## Building Documentation -ローカルでドキュメントを構築するには: +To build the documentation locally: ```bash -# ドキュメント生成に必要なパッケージをインストール +# Install packages required for documentation generation make docs-install -# ドキュメントをビルド +# Build the documentation make docs-build -# ローカルサーバーでドキュメントを確認(オプション) +# View documentation on local server (optional) make docs-serve ``` ## Contribution -- [ロードマップ](https://ukwhatn.notion.site/wikidot-py-roadmap?pvs=4) +- [Roadmap](https://ukwhatn.notion.site/wikidot-py-roadmap?pvs=4) - [Issue](https://github.com/ukwhatn/wikidot.py/issues) diff --git a/llms.txt b/llms.txt index f871595..bce678a 100644 --- a/llms.txt +++ b/llms.txt @@ -1,449 +1,449 @@ # wikidot.py -> Wikidotサイト(SCP Foundation等)と対話するためのPythonライブラリ +> A Python library for interacting with Wikidot sites (SCP Foundation, etc.) - Version: 4.0.0 - Python: 3.10+ -- 依存関係: httpx, beautifulsoup4, lxml -- ライセンス: MIT -- ドキュメント: https://ukwhatn.github.io/wikidot.py/ -- リポジトリ: https://github.com/ukwhatn/wikidot.py +- Dependencies: httpx, beautifulsoup4, lxml +- License: MIT +- Documentation: https://ukwhatn.github.io/wikidot.py/ +- Repository: https://github.com/ukwhatn/wikidot.py -## インストール +## Installation ```bash pip install wikidot ``` -## 基本的な使い方(メソッドチェーン) +## Basic Usage (Method Chaining) -このライブラリは基本的にメソッドチェーンで利用します。 +This library is primarily used with method chaining. ```python import wikidot -# 認証なしの場合 +# Without authentication with wikidot.Client() as client: site = client.site.get("scp-jp") page = site.page.get("scp-173") print(page.title, page.rating) -# 認証ありの場合 +# With authentication with wikidot.Client(username="user", password="pass") as client: site = client.site.get("scp-jp") - # ページ検索 + # Search pages pages = site.pages.search(category="scp", order="rating desc", limit=10) for page in pages: print(page.fullname, page.rating) - # 参加申請を全て承認 + # Accept all membership applications for application in site.applications: application.accept() - # PMを送信 + # Send PM user = client.user.get("target-user") - client.private_message.send(recipient=user, subject="件名", body="本文") + client.private_message.send(recipient=user, subject="Subject", body="Body") ``` --- -## API リファレンス +## API Reference -### Client(エントリポイント) +### Client (Entry Point) ```python with wikidot.Client(username=None, password=None) as client: - # client.site → サイト操作 - # client.user → ユーザー操作 - # client.private_message → PM操作 + # client.site -> Site operations + # client.user -> User operations + # client.private_message -> PM operations pass ``` -| チェーン | 説明 | -|---------|------| -| `client.site.get(unix_name)` | サイト取得 → Site | -| `client.user.get(name)` | ユーザー取得 → User | -| `client.user.get_bulk(names)` | 複数ユーザー取得 → UserCollection | -| `client.private_message.inbox` | 受信箱 → PrivateMessageInbox | -| `client.private_message.sentbox` | 送信箱 → PrivateMessageSentBox | -| `client.private_message.send(recipient, subject, body)` | PM送信 | -| `client.private_message.get_message(id)` | メッセージ取得 | -| `client.is_logged_in` | ログイン状態(bool) | -| `client.me` | 現在のユーザー | +| Chain | Description | +|-------|-------------| +| `client.site.get(unix_name)` | Get site -> Site | +| `client.user.get(name)` | Get user -> User | +| `client.user.get_bulk(names)` | Get multiple users -> UserCollection | +| `client.private_message.inbox` | Inbox -> PrivateMessageInbox | +| `client.private_message.sentbox` | Sent box -> PrivateMessageSentBox | +| `client.private_message.send(recipient, subject, body)` | Send PM | +| `client.private_message.get_message(id)` | Get message | +| `client.is_logged_in` | Login status (bool) | +| `client.me` | Current user | --- -### Site操作 +### Site Operations ```python site = client.site.get("scp-jp") ``` -#### Siteからのチェーン - -| チェーン | 説明 | -|---------|------| -| `site.page.get(fullname)` | ページ取得 → Page | -| `site.page.create(fullname, title, source, comment)` | ページ作成 → Page | -| `site.pages.search(**kwargs)` | ページ検索 → PageCollection | -| `site.forum.categories` | フォーラムカテゴリ → ForumCategoryCollection | -| `site.get_thread(thread_id)` | スレッド取得 → ForumThread | -| `site.get_threads(thread_ids)` | 複数スレッド取得 → list[ForumThread] | -| `site.members` | メンバー一覧 → list[SiteMember] | -| `site.moderators` | モデレーター一覧 → list[SiteMember] | -| `site.admins` | 管理者一覧 → list[SiteMember] | -| `site.member_lookup(user_name)` | メンバー検索 → SiteMember | -| `site.applications` | 参加申請一覧(要ログイン) → list[SiteApplication] | -| `site.invite_user(user, text)` | ユーザー招待(要ログイン) | -| `site.get_recent_changes(limit)` | サイト変更履歴 → list[SiteChange] | - -#### Siteプロパティ - -| プロパティ | 型 | 説明 | -|-----------|-----|------| -| `site.unix_name` | str | サイト識別名 | -| `site.name` | str | サイト名 | -| `site.title` | str | サイトタイトル | -| `site.url` | str | サイトURL | +#### Chains from Site + +| Chain | Description | +|-------|-------------| +| `site.page.get(fullname)` | Get page -> Page | +| `site.page.create(fullname, title, source, comment)` | Create page -> Page | +| `site.pages.search(**kwargs)` | Search pages -> PageCollection | +| `site.forum.categories` | Forum categories -> ForumCategoryCollection | +| `site.get_thread(thread_id)` | Get thread -> ForumThread | +| `site.get_threads(thread_ids)` | Get multiple threads -> list[ForumThread] | +| `site.members` | Member list -> list[SiteMember] | +| `site.moderators` | Moderator list -> list[SiteMember] | +| `site.admins` | Admin list -> list[SiteMember] | +| `site.member_lookup(user_name)` | Search member -> SiteMember | +| `site.applications` | Membership applications (login required) -> list[SiteApplication] | +| `site.invite_user(user, text)` | Invite user (login required) | +| `site.get_recent_changes(limit)` | Site change history -> list[SiteChange] | + +#### Site Properties + +| Property | Type | Description | +|----------|------|-------------| +| `site.unix_name` | str | Site identifier | +| `site.name` | str | Site name | +| `site.title` | str | Site title | +| `site.url` | str | Site URL | --- -### Page操作 +### Page Operations ```python -# 取得 +# Get page = site.page.get("scp-173") -page = site.page.get("scp-173", raise_when_not_found=False) # 見つからない場合None +page = site.page.get("scp-173", raise_when_not_found=False) # Returns None if not found -# 検索 +# Search pages = site.pages.search( - category="*", # カテゴリ("*"で全て) - tags=["scp", "euclid"], # タグフィルター(-で除外: "-tale") - order="rating desc", # ソート順 - limit=50 # 取得件数 + category="*", # Category ("*" for all) + tags=["scp", "euclid"], # Tag filter (use - to exclude: "-tale") + order="rating desc", # Sort order + limit=50 # Number of results ) ``` -#### 検索パラメータ一覧 - -パラメータはWikidotの[ListPagesモジュール](https://www.wikidot.com/doc-modules:listpages-module)を継承しています。 - -**Selection(ページ選択)** - -| パラメータ | 説明 | 例 | -|-----------|------|-----| -| `pagetype` | ページタイプ | `"*"`(全て), `"normal"`, `"hidden"` | -| `category` | カテゴリ | `"*"`(全て), `"scp"`, `"."`(現在) | -| `tags` | タグフィルター(空白区切りでOR、-で除外) | `["scp", "euclid"]`, `["scp", "-tale"]` | -| `parent` | 親ページ | `"parent-page"`, `"."`(子ページ), `"-"`(親なし) | -| `link_to` | リンク先ページ | `"scp-173"` | -| `created_by` | 作成者 | `"username"` またはUserオブジェクト | -| `created_at` | 作成日時 | `"2024"`, `"last 7 day"`, `">2024-01-01"` | -| `updated_at` | 更新日時 | `"last 1 week"`, `"<2024-12-31"` | -| `rating` | 評価値 | `">50"`, `">=100"` | -| `votes` | 投票数 | `">10"`, `">=5"` | -| `name` | ページ名パターン | `"scp-*"`, `"about"` | -| `fullname` | フルネーム(完全一致) | `"scp:scp-173"` | -| `range` | 範囲指定 | ページ範囲 | - -**Ordering(並べ替え)** - -| パラメータ | 説明 | 例 | -|-----------|------|-----| -| `order` | ソート順(プロパティ名 + desc/asc) | `"created_at desc"`(デフォルト), `"rating desc"`, `"name"`, `"updated_at"`, `"size"`, `"random"` | - -**Pagination(ページネーション)** - -| パラメータ | 説明 | デフォルト | -|-----------|------|-----------| -| `limit` | 取得件数上限 | 制限なし | -| `offset` | 取得開始位置 | `0` | -| `perPage` | 1リクエストあたりの取得件数 | `250`(最大250) | - -#### Pageプロパティ - -| プロパティ | 型 | 説明 | -|-----------|-----|------| -| `page.id` | int | ページID | -| `page.fullname` | str | フルネーム(category:name) | -| `page.name` | str | ページ名 | -| `page.category` | str | カテゴリ | -| `page.title` | str | タイトル | -| `page.created_at` | datetime | 作成日時 | -| `page.created_by` | AbstractUser | 作成者 | -| `page.updated_at` | datetime | 更新日時 | -| `page.updated_by` | AbstractUser | 更新者 | -| `page.rating` | int | 評価値 | -| `page.rating_votes` | int | 投票数 | -| `page.tags` | list[str] | タグ | -| `page.source` | PageSource | ソースコード | -| `page.source.wiki_text` | str | Wikidot記法のソース | -| `page.revisions` | PageRevisionCollection | リビジョン履歴 | -| `page.latest_revision` | PageRevision | 最新リビジョン | -| `page.votes` | PageVoteCollection | 投票一覧 | -| `page.metas` | dict[str, str] | メタタグ | -| `page.discussion` | ForumThread \| None | ディスカッションスレッド | -| `page.files` | PageFileCollection | 添付ファイル一覧 | - -#### Pageメソッド(書き込み) +#### Search Parameters + +Parameters inherit from Wikidot's [ListPages module](https://www.wikidot.com/doc-modules:listpages-module). + +**Selection** + +| Parameter | Description | Example | +|-----------|-------------|---------| +| `pagetype` | Page type | `"*"` (all), `"normal"`, `"hidden"` | +| `category` | Category | `"*"` (all), `"scp"`, `"."` (current) | +| `tags` | Tag filter (space-separated for OR, - for exclude) | `["scp", "euclid"]`, `["scp", "-tale"]` | +| `parent` | Parent page | `"parent-page"`, `"."` (child pages), `"-"` (no parent) | +| `link_to` | Link target page | `"scp-173"` | +| `created_by` | Author | `"username"` or User object | +| `created_at` | Created date | `"2024"`, `"last 7 day"`, `">2024-01-01"` | +| `updated_at` | Updated date | `"last 1 week"`, `"<2024-12-31"` | +| `rating` | Rating value | `">50"`, `">=100"` | +| `votes` | Vote count | `">10"`, `">=5"` | +| `name` | Page name pattern | `"scp-*"`, `"about"` | +| `fullname` | Fullname (exact match) | `"scp:scp-173"` | +| `range` | Range specification | Page range | + +**Ordering** + +| Parameter | Description | Example | +|-----------|-------------|---------| +| `order` | Sort order (property + desc/asc) | `"created_at desc"` (default), `"rating desc"`, `"name"`, `"updated_at"`, `"size"`, `"random"` | + +**Pagination** + +| Parameter | Description | Default | +|-----------|-------------|---------| +| `limit` | Maximum number of results | No limit | +| `offset` | Starting position | `0` | +| `perPage` | Results per request | `250` (max 250) | + +#### Page Properties + +| Property | Type | Description | +|----------|------|-------------| +| `page.id` | int | Page ID | +| `page.fullname` | str | Fullname (category:name) | +| `page.name` | str | Page name | +| `page.category` | str | Category | +| `page.title` | str | Title | +| `page.created_at` | datetime | Created date | +| `page.created_by` | AbstractUser | Author | +| `page.updated_at` | datetime | Updated date | +| `page.updated_by` | AbstractUser | Updater | +| `page.rating` | int | Rating value | +| `page.rating_votes` | int | Vote count | +| `page.tags` | list[str] | Tags | +| `page.source` | PageSource | Source code | +| `page.source.wiki_text` | str | Wikidot syntax source | +| `page.revisions` | PageRevisionCollection | Revision history | +| `page.latest_revision` | PageRevision | Latest revision | +| `page.votes` | PageVoteCollection | Vote list | +| `page.metas` | dict[str, str] | Meta tags | +| `page.discussion` | ForumThread \| None | Discussion thread | +| `page.files` | PageFileCollection | Attached file list | + +#### Page Methods (Write) ```python -# 作成 +# Create page = site.page.create( fullname="test:new-page", - title="新しいページ", - source="ページ内容", - comment="作成コメント" + title="New Page", + source="Page content", + comment="Creation comment" ) -# 編集 +# Edit page = page.edit( - title="新タイトル", # Noneで変更なし - source="新内容", # Noneで変更なし - comment="編集コメント" + title="New Title", # None for no change + source="New content", # None for no change + comment="Edit comment" ) -# 削除 +# Delete page.destroy() -# タグ変更 +# Tag changes page.tags.append("new-tag") page.tags.remove("old-tag") page.commit_tags() -# メタタグ設定 +# Set meta tags page.metas = {"key": "value"} -# 親ページ設定 -page.set_parent("parent-page") # 親を設定 -page.set_parent(None) # 親を解除 +# Set parent page +page.set_parent("parent-page") # Set parent +page.set_parent(None) # Remove parent -# ページ名変更 +# Rename page page.rename("new-fullname") -# 投票(要ログイン) -new_rating = page.vote(1) # +1投票、新rating返却 -new_rating = page.vote(-1) # -1投票 -new_rating = page.cancel_vote() # 投票取り消し +# Vote (login required) +new_rating = page.vote(1) # +1 vote, returns new rating +new_rating = page.vote(-1) # -1 vote +new_rating = page.cancel_vote() # Cancel vote ``` -#### PageCollection操作 +#### PageCollection Operations ```python pages = site.pages.search(category="scp") -# イテレーション +# Iteration for page in pages: print(page.title) -# 検索 +# Search page = pages.find("scp-173") -# 一括取得(効率的) -pages.get_page_ids() # 全ページのIDを取得 -pages.get_page_sources() # 全ページのソースを取得 -pages.get_page_revisions() # 全ページのリビジョンを取得 -pages.get_page_votes() # 全ページの投票を取得 +# Bulk fetch (efficient) +pages.get_page_ids() # Get all page IDs +pages.get_page_sources() # Get all page sources +pages.get_page_revisions() # Get all page revisions +pages.get_page_votes() # Get all page votes ``` --- -### User操作 +### User Operations ```python user = client.user.get("username") -user = client.user.get("username", raise_when_not_found=False) # 見つからない場合None +user = client.user.get("username", raise_when_not_found=False) # Returns None if not found users = client.user.get_bulk(["user1", "user2", "user3"]) ``` -#### Userプロパティ +#### User Properties -| プロパティ | 型 | 説明 | -|-----------|-----|------| -| `user.id` | int | ユーザーID | -| `user.name` | str | ユーザー名 | -| `user.unix_name` | str | Unix形式名 | -| `user.avatar_url` | str | アバターURL | +| Property | Type | Description | +|----------|------|-------------| +| `user.id` | int | User ID | +| `user.name` | str | Username | +| `user.unix_name` | str | Unix-style name | +| `user.avatar_url` | str | Avatar URL | -#### ユーザータイプ +#### User Types -`page.created_by` などで返されるユーザーは以下のいずれかの型: -- `User` - 通常の登録ユーザー -- `DeletedUser` - 削除されたユーザー -- `AnonymousUser` - 匿名ユーザー -- `GuestUser` - ゲストユーザー -- `WikidotUser` - Wikidotシステムユーザー +Users returned by `page.created_by` etc. are one of these types: +- `User` - Regular registered user +- `DeletedUser` - Deleted user +- `AnonymousUser` - Anonymous user +- `GuestUser` - Guest user +- `WikidotUser` - Wikidot system user --- -### SiteMember操作 +### SiteMember Operations ```python -# メンバー一覧 +# Member list for member in site.members: print(member.user.name, member.joined_at) -# 特定メンバー検索 +# Search specific member member = site.member_lookup("username") -# 権限変更(要ログイン) -member.to_moderator() # モデレーター昇格 -member.remove_moderator() # モデレーター解除 -member.to_admin() # 管理者昇格 -member.remove_admin() # 管理者解除 +# Change permissions (login required) +member.to_moderator() # Promote to moderator +member.remove_moderator() # Remove moderator +member.to_admin() # Promote to admin +member.remove_admin() # Remove admin ``` -#### SiteMemberプロパティ +#### SiteMember Properties -| プロパティ | 型 | 説明 | -|-----------|-----|------| -| `member.site` | Site | 所属サイト | -| `member.user` | User | ユーザー | -| `member.joined_at` | datetime | 参加日時 | +| Property | Type | Description | +|----------|------|-------------| +| `member.site` | Site | Belonging site | +| `member.user` | User | User | +| `member.joined_at` | datetime | Join date | --- -### SiteApplication操作(要ログイン) +### SiteApplication Operations (Login Required) ```python -# 申請一覧を取得して処理 +# Get and process application list for application in site.applications: - print(f"申請者: {application.user.name}") - application.accept() # 承認 - # application.decline() # 拒否 + print(f"Applicant: {application.user.name}") + application.accept() # Accept + # application.decline() # Decline ``` --- -### Forum操作 +### Forum Operations ```python -# カテゴリ一覧 +# Category list categories = site.forum.categories -# カテゴリ内スレッド +# Threads in category category = categories.find(category_id) for thread in category.threads: print(thread.title) -# スレッド取得 +# Get thread thread = site.get_thread(thread_id) threads = site.get_threads([id1, id2, id3]) -# スレッド作成 +# Create thread thread = category.create_thread( - title="スレッドタイトル", - description="スレッド説明", - source="最初の投稿内容(Wikidot記法)" + title="Thread Title", + description="Thread description", + source="First post content (Wikidot syntax)" ) ``` -#### ForumThreadプロパティ +#### ForumThread Properties -| プロパティ | 型 | 説明 | -|-----------|-----|------| -| `thread.id` | int | スレッドID | -| `thread.title` | str | タイトル | +| Property | Type | Description | +|----------|------|-------------| +| `thread.id` | int | Thread ID | +| `thread.title` | str | Title | | `thread.url` | str | URL | -| `thread.created_at` | datetime | 作成日時 | -| `thread.created_by` | AbstractUser | 作成者 | -| `thread.post_count` | int | 投稿数 | -| `thread.posts` | ForumPostCollection | 投稿一覧 | +| `thread.created_at` | datetime | Created date | +| `thread.created_by` | AbstractUser | Author | +| `thread.post_count` | int | Post count | +| `thread.posts` | ForumPostCollection | Post list | -#### ForumThreadメソッド +#### ForumThread Methods ```python -# スレッドに返信(要ログイン) -thread.reply(source="返信内容") -thread.reply(source="返信内容", title="タイトル") -thread.reply(source="返信内容", parent_post_id=12345) # 特定投稿への返信 +# Reply to thread (login required) +thread.reply(source="Reply content") +thread.reply(source="Reply content", title="Title") +thread.reply(source="Reply content", parent_post_id=12345) # Reply to specific post ``` -#### ForumPostプロパティ +#### ForumPost Properties -| プロパティ | 型 | 説明 | -|-----------|-----|------| -| `post.id` | int | 投稿ID | -| `post.title` | str | タイトル | -| `post.text` | str | 本文(HTML) | -| `post.source` | str | ソース(Wikidot記法) | -| `post.created_by` | AbstractUser | 投稿者 | -| `post.created_at` | datetime | 投稿日時 | -| `post.edited_by` | AbstractUser \| None | 編集者 | -| `post.edited_at` | datetime \| None | 編集日時 | -| `post.parent_id` | int \| None | 親投稿ID | +| Property | Type | Description | +|----------|------|-------------| +| `post.id` | int | Post ID | +| `post.title` | str | Title | +| `post.text` | str | Body (HTML) | +| `post.source` | str | Source (Wikidot syntax) | +| `post.created_by` | AbstractUser | Author | +| `post.created_at` | datetime | Post date | +| `post.edited_by` | AbstractUser \| None | Editor | +| `post.edited_at` | datetime \| None | Edit date | +| `post.parent_id` | int \| None | Parent post ID | -#### ForumPostメソッド +#### ForumPost Methods ```python -# 投稿を編集(要ログイン) -post.edit(source="新しい内容") -post.edit(source="新しい内容", title="新しいタイトル") +# Edit post (login required) +post.edit(source="New content") +post.edit(source="New content", title="New title") ``` --- -### PageRevision操作 +### PageRevision Operations ```python -# リビジョン一覧 +# Revision list for revision in page.revisions: print(revision.id, revision.created_at, revision.created_by.name) -# 最新リビジョン +# Latest revision latest = page.latest_revision -# ソース取得 +# Get source wiki_text = revision.source.wiki_text -# 一括取得(効率的) -page.revisions.get_sources() # 全リビジョンのソースを取得 -page.revisions.get_htmls() # 全リビジョンのHTMLを取得 +# Bulk fetch (efficient) +page.revisions.get_sources() # Get all revision sources +page.revisions.get_htmls() # Get all revision HTMLs ``` --- -### PageVote操作 +### PageVote Operations ```python for vote in page.votes: print(vote.user.name, vote.value) # value: +1 or -1 -# 特定ユーザーの投票を検索 +# Search specific user's vote vote = page.votes.find(user) ``` --- -### PageFile操作 +### PageFile Operations ```python -# ページの添付ファイル一覧 +# Page attached files list for file in page.files: print(file.name, file.size, file.mime_type) -# 特定ファイルを検索 +# Search specific file file = page.files.find(file_id) file = page.files.find_by_name("image.png") ``` -#### PageFileプロパティ +#### PageFile Properties -| プロパティ | 型 | 説明 | -|-----------|-----|------| -| `file.id` | int | ファイルID | -| `file.name` | str | ファイル名 | -| `file.url` | str | ダウンロードURL | -| `file.mime_type` | str | MIMEタイプ | -| `file.size` | int | ファイルサイズ(バイト) | +| Property | Type | Description | +|----------|------|-------------| +| `file.id` | int | File ID | +| `file.name` | str | File name | +| `file.url` | str | Download URL | +| `file.mime_type` | str | MIME type | +| `file.size` | int | File size (bytes) | --- -### SiteChange操作 +### SiteChange Operations ```python -# サイトの最近の変更履歴 +# Recent change history changes = site.get_recent_changes(limit=100) for change in changes: @@ -452,74 +452,74 @@ for change in changes: print(f" flags: {change.flags}, comment: {change.comment}") ``` -#### SiteChangeプロパティ +#### SiteChange Properties -| プロパティ | 型 | 説明 | -|-----------|-----|------| -| `change.page_fullname` | str | ページフルネーム | -| `change.page_title` | str | ページタイトル | -| `change.revision_no` | int | リビジョン番号 | -| `change.changed_by` | AbstractUser | 変更者 | -| `change.changed_at` | datetime | 変更日時 | -| `change.flags` | list[str] | 変更フラグ(N/S/T/R/M/F/A) | -| `change.comment` | str \| None | 変更コメント | +| Property | Type | Description | +|----------|------|-------------| +| `change.page_fullname` | str | Page fullname | +| `change.page_title` | str | Page title | +| `change.revision_no` | int | Revision number | +| `change.changed_by` | AbstractUser | Changed by | +| `change.changed_at` | datetime | Changed at | +| `change.flags` | list[str] | Change flags (N/S/T/R/M/F/A) | +| `change.comment` | str \| None | Change comment | -変更フラグ: N=新規作成, S=ソース変更, T=タイトル変更, R=名前変更, M=移動, F=ファイル, A=削除 +Change flags: N=New, S=Source changed, T=Title changed, R=Renamed, M=Moved, F=File, A=Deleted --- -### PrivateMessage操作(要ログイン) +### PrivateMessage Operations (Login Required) ```python -# PM送信 +# Send PM user = client.user.get("target-user") client.private_message.send( recipient=user, - subject="件名", - body="本文" + subject="Subject", + body="Body" ) -# 受信箱 +# Inbox for message in client.private_message.inbox: print(message.subject, message.sender.name) -# 送信箱 +# Sent box for message in client.private_message.sentbox: print(message.subject, message.recipient.name) -# 個別取得 +# Get individual message = client.private_message.get_message(message_id) ``` -#### PrivateMessageプロパティ +#### PrivateMessage Properties -| プロパティ | 型 | 説明 | -|-----------|-----|------| -| `message.id` | int | メッセージID | -| `message.subject` | str | 件名 | -| `message.body` | str | 本文 | -| `message.sender` | AbstractUser | 送信者 | -| `message.recipient` | AbstractUser | 受信者 | -| `message.created_at` | datetime | 送信日時 | +| Property | Type | Description | +|----------|------|-------------| +| `message.id` | int | Message ID | +| `message.subject` | str | Subject | +| `message.body` | str | Body | +| `message.sender` | AbstractUser | Sender | +| `message.recipient` | AbstractUser | Recipient | +| `message.created_at` | datetime | Sent date | --- -## 例外クラス +## Exception Classes ``` -WikidotException # 基底例外 -├── SessionCreateException # ログイン失敗 -├── LoginRequiredException # ログイン必要 -├── NotFoundException # リソース未発見 -├── TargetExistsException # リソース既存 -├── TargetErrorException # 操作不可 -├── ForbiddenException # 権限不足 -├── NoElementException # HTML要素未発見 -├── UnexpectedException # 予期しないエラー -└── AjaxModuleConnectorException # API基底例外 - ├── AMCHttpStatusCodeException # HTTPエラー - ├── WikidotStatusCodeException # Wikidot APIエラー - └── ResponseDataException # レスポンス不正 +WikidotException # Base exception +├── SessionCreateException # Login failed +├── LoginRequiredException # Login required +├── NotFoundException # Resource not found +├── TargetExistsException # Resource already exists +├── TargetErrorException # Operation not possible +├── ForbiddenException # Permission denied +├── NoElementException # HTML element not found +├── UnexpectedException # Unexpected error +└── AjaxModuleConnectorException # API base exception + ├── AMCHttpStatusCodeException # HTTP error + ├── WikidotStatusCodeException # Wikidot API error + └── ResponseDataException # Invalid response ``` ```python @@ -528,14 +528,14 @@ from wikidot.common.exceptions import NotFoundException, LoginRequiredException try: page = site.page.get("nonexistent") except NotFoundException: - print("ページが見つかりません") + print("Page not found") ``` --- -## コード例 +## Code Examples -### ページ情報取得 +### Get Page Information ```python import wikidot @@ -544,14 +544,14 @@ with wikidot.Client() as client: site = client.site.get("scp-jp") page = site.page.get("scp-173") - print(f"タイトル: {page.title}") - print(f"評価: {page.rating}") - print(f"作成者: {page.created_by.name}") - print(f"タグ: {page.tags}") - print(f"ソース: {page.source.wiki_text[:100]}...") + print(f"Title: {page.title}") + print(f"Rating: {page.rating}") + print(f"Author: {page.created_by.name}") + print(f"Tags: {page.tags}") + print(f"Source: {page.source.wiki_text[:100]}...") ``` -### ページ検索(評価順TOP10) +### Search Pages (Top 10 by Rating) ```python with wikidot.Client() as client: @@ -562,31 +562,31 @@ with wikidot.Client() as client: print(f"{page.fullname}: {page.rating}") ``` -### ページ作成・編集・削除 +### Create, Edit, Delete Page ```python with wikidot.Client(username="user", password="pass") as client: site = client.site.get("sandbox") - # 作成 + # Create page = site.page.create( fullname="test:my-page", - title="テストページ", - source="これはテストです。" + title="Test Page", + source="This is a test." ) - # 編集 - page = page.edit(title="更新タイトル", source="更新内容") + # Edit + page = page.edit(title="Updated Title", source="Updated content") - # タグ変更 + # Change tags page.tags.append("test") page.commit_tags() - # 削除 + # Delete page.destroy() ``` -### リビジョン履歴 +### Revision History ```python with wikidot.Client() as client: @@ -597,7 +597,7 @@ with wikidot.Client() as client: print(f"Rev {revision.id}: {revision.created_at} by {revision.created_by.name}") ``` -### フォーラムスレッド作成 +### Create Forum Thread ```python with wikidot.Client(username="user", password="pass") as client: @@ -605,81 +605,81 @@ with wikidot.Client(username="user", password="pass") as client: category = site.forum.categories.find(category_id) thread = category.create_thread( - title="新しいスレッド", - description="スレッドの説明", - source="最初の投稿内容" + title="New Thread", + description="Thread description", + source="First post content" ) - print(f"作成: {thread.url}") + print(f"Created: {thread.url}") ``` -### フォーラム投稿操作 +### Forum Post Operations ```python with wikidot.Client(username="user", password="pass") as client: site = client.site.get("scp-jp") thread = site.get_thread(thread_id) - # 投稿一覧 + # Post list for post in thread.posts: print(f"{post.title} by {post.created_by.name}") print(f" {post.source[:50]}...") - # スレッドに返信 - thread.reply(source="返信内容です", title="Re: タイトル") + # Reply to thread + thread.reply(source="Reply content", title="Re: Title") - # 特定投稿への返信 - thread.reply(source="返信内容", parent_post_id=post.id) + # Reply to specific post + thread.reply(source="Reply content", parent_post_id=post.id) - # 投稿を編集 + # Edit post post = thread.posts[0] - post.edit(source="編集後の内容", title="編集後のタイトル") + post.edit(source="Edited content", title="Edited title") ``` -### メンバー管理 +### Member Management ```python with wikidot.Client(username="admin", password="pass") as client: site = client.site.get("my-site") - # メンバー一覧 + # Member list for member in site.members: print(f"{member.user.name}: {member.joined_at}") - # 権限変更 + # Change permissions member = site.member_lookup("username") member.to_moderator() ``` -### 参加申請処理 +### Process Applications ```python with wikidot.Client(username="admin", password="pass") as client: site = client.site.get("my-site") for application in site.applications: - print(f"申請者: {application.user.name}") + print(f"Applicant: {application.user.name}") application.accept() ``` -### PM送信 +### Send PM ```python with wikidot.Client(username="user", password="pass") as client: user = client.user.get("target-user") client.private_message.send( recipient=user, - subject="こんにちは", - body="メッセージ本文です。" + subject="Hello", + body="This is a message." ) ``` -### サイト変更履歴 +### Site Change History ```python with wikidot.Client() as client: site = client.site.get("scp-jp") - # 最近の変更100件 + # Recent 100 changes changes = site.get_recent_changes(limit=100) for change in changes: @@ -688,30 +688,30 @@ with wikidot.Client() as client: print(f" by {change.changed_by.name} at {change.changed_at}") ``` -### ページディスカッション +### Page Discussion ```python with wikidot.Client() as client: site = client.site.get("scp-jp") page = site.page.get("scp-173") - # ディスカッションスレッドを取得 + # Get discussion thread if page.discussion: thread = page.discussion - print(f"コメント数: {thread.post_count}") + print(f"Comment count: {thread.post_count}") for post in thread.posts: print(f"{post.created_by.name}: {post.title}") ``` -### ページファイル一覧 +### Page File List ```python with wikidot.Client() as client: site = client.site.get("scp-jp") page = site.page.get("scp-173") - # 添付ファイル一覧 + # Attached files list for file in page.files: print(f"{file.name} ({file.size} bytes)") print(f" URL: {file.url}") @@ -720,8 +720,8 @@ with wikidot.Client() as client: --- -## 参考リンク +## Reference Links -- 公式ドキュメント: https://ukwhatn.github.io/wikidot.py/ +- Official Documentation: https://ukwhatn.github.io/wikidot.py/ - GitHub: https://github.com/ukwhatn/wikidot.py - PyPI: https://pypi.org/project/wikidot/ diff --git a/src/wikidot/__init__.py b/src/wikidot/__init__.py index 975e1e0..3417838 100644 --- a/src/wikidot/__init__.py +++ b/src/wikidot/__init__.py @@ -1,8 +1,8 @@ """ -Wikidotサイトとの対話を行うためのPythonライブラリ +A Python library for interacting with Wikidot sites -このパッケージはWikidotサイトのAPI操作を抽象化し、直感的なインターフェースを提供する。 -ユーザー、サイト、ページなどのWikidotの主要要素にアクセスするための各種クラスが含まれている。 +This package abstracts Wikidot site API operations and provides an intuitive interface. +It contains various classes for accessing major Wikidot elements such as users, sites, and pages. """ import importlib @@ -16,23 +16,22 @@ __version__ = "4.0.2" -# 全クラス・モジュールを公開する def _import_submodules() -> None: """ - パッケージ内の全サブモジュールからクラスをインポートしトップレベルで公開する関数 + Import classes from all submodules in the package and expose them at the top level - 各サブディレクトリ内のPythonファイルを走査し、含まれるクラスをトップレベルの名前空間に - インポートする。これにより、`wikidot.ClassName`のような形式でクラスにアクセスできる。 + Scans Python files within each subdirectory and imports contained classes + into the top-level namespace. This allows access to classes in the format + `wikidot.ClassName`. Notes ----- - '_'で始まるファイル名は無視される。 - インポートに失敗した場合は静かに無視される。 + Filenames starting with '_' are ignored. + Import failures are silently ignored. """ current_module = sys.modules[__name__] package_dir = os.path.dirname(__file__) - # 公開対象のディレクトリを走査 for base_dir in ["common", "connector", "module", "util"]: base_path = os.path.join(package_dir, base_dir) if not os.path.isdir(base_path): @@ -42,7 +41,7 @@ def _import_submodules() -> None: if filename.startswith("_") or not filename.endswith(".py"): continue - module_name = filename[:-3] # .py を除去 + module_name = filename[:-3] full_module_name = f"{__name__}.{base_dir}.{module_name}" try: diff --git a/src/wikidot/common/__init__.py b/src/wikidot/common/__init__.py index 84b88ab..0131cc9 100644 --- a/src/wikidot/common/__init__.py +++ b/src/wikidot/common/__init__.py @@ -1,8 +1,8 @@ """ -Wikidotライブラリの共通機能モジュール +Common functionality module for the Wikidot library -このパッケージは、ライブラリ全体で使用される共通機能を提供する。 -例外クラス、デコレータ、ロギング機能などの汎用的な機能が含まれる。 +This package provides common functionality used throughout the library. +It includes generic features such as exception classes, decorators, and logging functionality. """ from .logger import logger as wd_logger diff --git a/src/wikidot/common/decorators.py b/src/wikidot/common/decorators.py index d193e24..881d9a4 100644 --- a/src/wikidot/common/decorators.py +++ b/src/wikidot/common/decorators.py @@ -1,8 +1,8 @@ """ -各種デコレータを提供するモジュール +Module providing various decorators -このモジュールは、ライブラリ内で使用される共通のデコレータを提供する。 -現在は認証関連のデコレータが実装されている。 +This module provides common decorators used within the library. +Currently, authentication-related decorators are implemented. """ from collections.abc import Callable @@ -15,38 +15,38 @@ def login_required(func: Callable[P, T]) -> Callable[P, T]: """ - ログインが必要なメソッドや関数に適用するデコレータ + Decorator to apply to methods or functions that require login - このデコレータを適用したメソッドや関数は、実行前に自動的にログイン状態をチェックする。 - ログインしていない場合はLoginRequiredExceptionが送出される。 + Methods or functions with this decorator automatically check login status before execution. + If not logged in, LoginRequiredException is raised. - クライアントインスタンスは以下の優先順位で検索される: - 1. client という名前の引数 - 2. Client クラスのインスタンスである引数 - 3. self.client(呼び出し元オブジェクトの属性) - 4. selfが持つ属性が持つclientクラス(例:self.site.client) + The client instance is searched in the following priority order: + 1. Argument named "client" + 2. Argument that is an instance of Client class + 3. self.client (attribute of the calling object) + 4. Client class held by an attribute of self (e.g., self.site.client) Parameters ---------- func : callable - デコレートする関数またはメソッド + Function or method to decorate Returns ------- callable - ラップされた関数またはメソッド + Wrapped function or method Raises ------ ValueError - クライアントインスタンスが見つからない場合 + If client instance is not found LoginRequiredException - ログインしていない場合(client.login_check()による) + If not logged in (determined by client.login_check()) """ @wraps(func) def wrapper(*args: P.args, **kwargs: P.kwargs) -> T: - # 循環参照を避けるため、関数内でインポート + # Import inside function to avoid circular references from wikidot.module.client import Client client: Client | None = None @@ -61,7 +61,7 @@ def wrapper(*args: P.args, **kwargs: P.kwargs) -> T: client = arg break - # selfに存在するか? + # Check if it exists in self if client is None and args: self_obj: Any = args[0] if hasattr(self_obj, "client"): @@ -69,7 +69,7 @@ def wrapper(*args: P.args, **kwargs: P.kwargs) -> T: if isinstance(maybe_client, Client): client = maybe_client else: - # selfが持つ属性にclientが存在するか探索する + # Search for client in attributes held by self for attr_name in dir(self_obj): if attr_name.startswith("_"): continue diff --git a/src/wikidot/common/exceptions.py b/src/wikidot/common/exceptions.py index 5f37fb6..c8fa6c8 100644 --- a/src/wikidot/common/exceptions.py +++ b/src/wikidot/common/exceptions.py @@ -1,19 +1,19 @@ # --- -# 基底クラス +# Base class # --- class WikidotException(Exception): """ - wikidot.py独自の例外の基底クラス + Base class for wikidot.py specific exceptions - ライブラリ内で発生する全ての例外の親クラスとなる。 - 具体的な例外は各サブクラスで定義される。 + This serves as the parent class for all exceptions raised within the library. + Specific exceptions are defined in each subclass. Parameters ---------- message : str - 例外メッセージ + Exception message """ def __init__(self, message: str) -> None: @@ -21,21 +21,21 @@ def __init__(self, message: str) -> None: # --- -# ワイルドカード +# Wildcard # --- class UnexpectedException(WikidotException): """ - 予期せぬ例外が発生したときに送出される例外 + Exception raised when an unexpected error occurs - 特定のエラー状態に分類できない、予期しない状況で発生する。 - 通常は内部エラーやバグを示す。 + Raised in unexpected situations that cannot be classified into a specific error state. + Usually indicates an internal error or bug. Parameters ---------- message : str - 例外メッセージ + Exception message """ def __init__(self, message: str) -> None: @@ -43,21 +43,21 @@ def __init__(self, message: str) -> None: # --- -# セッション関連 +# Session related # --- class SessionCreateException(WikidotException): """ - セッションの作成に失敗したときに送出される例外 + Exception raised when session creation fails - ログイン処理やセッション確立時に問題が発生した場合に使用される。 - 通常は認証情報の誤りやサーバー側の問題が原因となる。 + Used when a problem occurs during login processing or session establishment. + Usually caused by incorrect credentials or server-side issues. Parameters ---------- message : str - 例外メッセージ + Exception message """ def __init__(self, message: str) -> None: @@ -66,14 +66,14 @@ def __init__(self, message: str) -> None: class LoginRequiredException(WikidotException): """ - ログインが必要なメソッドを未ログイン状態で呼び出したときに送出される例外 + Exception raised when calling a method that requires login while not logged in - 認証が必要な操作を実行する前に、ログイン状態をチェックする際に使用される。 + Used when checking login status before executing an operation that requires authentication. Parameters ---------- message : str - 例外メッセージ + Exception message """ def __init__(self, message: str) -> None: @@ -81,19 +81,20 @@ def __init__(self, message: str) -> None: # --- -# AMC関連 +# AMC related # --- class AjaxModuleConnectorException(WikidotException): """ - Ajax Module Connectorへのリクエストに関連する例外の基底クラス + Base class for exceptions related to Ajax Module Connector requests - ajax-module-connector.phpへのAPIリクエスト処理中に発生する例外の親クラス。 - 具体的なエラー状態は各サブクラスで表現される。 + Parent class for exceptions that occur during API request processing + to ajax-module-connector.php. + Specific error states are expressed in each subclass. Parameters ---------- message : str - 例外メッセージ + Exception message """ def __init__(self, message: str) -> None: @@ -102,21 +103,21 @@ def __init__(self, message: str) -> None: class AMCHttpStatusCodeException(AjaxModuleConnectorException): """ - AMCのHTTPステータスコードが200以外だった場合に送出される例外 + Exception raised when the AMC HTTP status code is not 200 - Ajax Module ConnectorへのリクエストでHTTPレベルのエラーが発生した場合に使用される。 + Used when an HTTP-level error occurs in a request to the Ajax Module Connector. Parameters ---------- message : str - 例外メッセージ + Exception message status_code : int - エラーとなったHTTPステータスコード + The HTTP status code that caused the error Attributes ---------- status_code : int - エラーとなったHTTPステータスコード + The HTTP status code that caused the error """ def __init__(self, message: str, status_code: int) -> None: @@ -126,22 +127,23 @@ def __init__(self, message: str, status_code: int) -> None: class WikidotStatusCodeException(AjaxModuleConnectorException): """ - AMCからのレスポンスのステータスが「ok」でなかった場合に送出される例外 + Exception raised when the response status from AMC is not "ok" - HTTP通信自体は成功したが、Wikidot側で処理エラーが発生した場合に使用される。 - HTTPステータスが200以外の場合は代わりにAMCHttpStatusCodeExceptionが使用される。 + Used when HTTP communication itself succeeds but a processing error + occurs on the Wikidot side. + AMCHttpStatusCodeException is used instead when the HTTP status is not 200. Parameters ---------- message : str - 例外メッセージ + Exception message status_code : str - Wikidotから返されたエラーステータスコード + Error status code returned by Wikidot Attributes ---------- status_code : str - Wikidotから返されたエラーステータスコード + Error status code returned by Wikidot """ def __init__(self, message: str, status_code: str) -> None: @@ -151,14 +153,14 @@ def __init__(self, message: str, status_code: str) -> None: class ResponseDataException(AjaxModuleConnectorException): """ - AMCからのレスポンスデータが不正だった場合に送出される例外 + Exception raised when response data from AMC is invalid - レスポンスのパース失敗や、期待された形式と異なるデータが返された場合に使用される。 + Used when response parsing fails or data in an unexpected format is returned. Parameters ---------- message : str - 例外メッセージ + Exception message """ def __init__(self, message: str) -> None: @@ -166,21 +168,21 @@ def __init__(self, message: str) -> None: # --- -# ターゲットエラー関連 +# Target error related # --- class NotFoundException(WikidotException): """ - 要求されたリソースが見つからない場合に送出される例外 + Exception raised when the requested resource is not found - サイト、ページ、ユーザー、リビジョンなど、指定されたリソースが - Wikidot上に存在しない場合に使用される。 + Used when the specified resource such as site, page, user, or revision + does not exist on Wikidot. Parameters ---------- message : str - 例外メッセージ + Exception message """ def __init__(self, message: str) -> None: @@ -189,14 +191,14 @@ def __init__(self, message: str) -> None: class TargetExistsException(WikidotException): """ - 既に存在するリソースを作成しようとした場合に送出される例外 + Exception raised when attempting to create a resource that already exists - 新規作成操作が既存のリソースと衝突する場合に使用される。 + Used when a creation operation conflicts with an existing resource. Parameters ---------- message : str - 例外メッセージ + Exception message """ def __init__(self, message: str) -> None: @@ -205,15 +207,15 @@ def __init__(self, message: str) -> None: class TargetErrorException(WikidotException): """ - 対象オブジェクトに操作を適用できない場合に送出される例外 + Exception raised when an operation cannot be applied to the target object - リソースは存在するが、現在の状態では要求された操作を - 実行できない場合に使用される(例:ロック中のページを編集しようとする)。 + Used when the resource exists but the requested operation cannot be + executed in its current state (e.g., trying to edit a locked page). Parameters ---------- message : str - 例外メッセージ + Exception message """ def __init__(self, message: str) -> None: @@ -222,15 +224,15 @@ def __init__(self, message: str) -> None: class ForbiddenException(WikidotException): """ - 権限不足により操作が拒否された場合に送出される例外 + Exception raised when an operation is denied due to insufficient permissions - ユーザーが操作に必要な権限を持っていない場合や、 - プライベートサイトへのアクセスが拒否された場合などに使用される。 + Used when the user does not have the required permissions for an operation, + or when access to a private site is denied. Parameters ---------- message : str - 例外メッセージ + Exception message """ def __init__(self, message: str) -> None: @@ -238,21 +240,21 @@ def __init__(self, message: str) -> None: # --- -# 処理エラー関連 +# Processing error related # --- class NoElementException(WikidotException): """ - 必要な要素が見つからない場合に送出される例外 + Exception raised when a required element is not found - HTML解析時に期待された要素が見つからない場合など、 - 処理中に必要なデータが欠落している場合に使用される。 + Used when expected elements are not found during HTML parsing, + or when required data is missing during processing. Parameters ---------- message : str - 例外メッセージ + Exception message """ def __init__(self, message: str) -> None: diff --git a/src/wikidot/common/logger.py b/src/wikidot/common/logger.py index 03a7d96..dc187ca 100644 --- a/src/wikidot/common/logger.py +++ b/src/wikidot/common/logger.py @@ -1,8 +1,8 @@ """ -ロギング機能を提供するモジュール +Module providing logging functionality -このモジュールは、ライブラリ全体で使用されるロガーを設定し、提供する。 -NullHandlerを使用してアプリケーション側でのログ制御を可能にする。 +This module configures and provides loggers used throughout the library. +It uses NullHandler to enable log control on the application side. """ import logging @@ -10,17 +10,17 @@ def get_logger(name: str = "wikidot") -> logging.Logger: """ - ライブラリ用ロガーを取得 + Get the library logger Parameters ---------- name : str, default "wikidot" - ロガーの名前 + Logger name Returns ------- logging.Logger - ロガーインスタンス + Logger instance """ _logger = logging.getLogger(name) @@ -32,27 +32,27 @@ def get_logger(name: str = "wikidot") -> logging.Logger: def setup_console_handler(logger: logging.Logger, level: str | int = logging.WARNING) -> None: """ - コンソール出力用ハンドラを設定 + Configure console output handler Parameters ---------- logger : logging.Logger - 設定するロガー + Logger to configure level : str | int, default logging.WARNING - ログレベル + Log level """ - # 既存のStreamHandlerを削除(重複回避) + # Remove existing StreamHandler (to avoid duplicates) for handler in logger.handlers[:]: if isinstance(handler, logging.StreamHandler) and not isinstance(handler, logging.NullHandler): logger.removeHandler(handler) - # 新しいStreamHandlerを追加 + # Add new StreamHandler formatter = logging.Formatter("%(asctime)s [%(name)s/%(levelname)s] %(message)s") stream_handler = logging.StreamHandler() stream_handler.setFormatter(formatter) logger.addHandler(stream_handler) - # ログレベルを設定(文字列の場合は変換) + # Set log level (convert if string) if isinstance(level, str): level_attr = level.upper() level_value = getattr(logging, level_attr, None) @@ -62,5 +62,5 @@ def setup_console_handler(logger: logging.Logger, level: str | int = logging.WAR logger.setLevel(level) -# パッケージ全体で使用されるデフォルトロガー +# Default logger used throughout the package logger = get_logger() diff --git a/src/wikidot/connector/__init__.py b/src/wikidot/connector/__init__.py index ab5b853..e75f27b 100644 --- a/src/wikidot/connector/__init__.py +++ b/src/wikidot/connector/__init__.py @@ -1,7 +1,7 @@ """ -Wikidotサイトとの通信を担当するコネクタモジュール +Connector module responsible for communication with Wikidot sites -このパッケージは、Wikidot APIおよびAjax機能との通信を行う -低レベルなクライアントを提供する。モジュールパッケージのクラスは、 -これらのコネクタを介してWikidotサイトとの通信を行う。 +This package provides low-level clients for communicating with +the Wikidot API and Ajax functionality. Classes in the module package +communicate with Wikidot sites through these connectors. """ diff --git a/src/wikidot/connector/ajax.py b/src/wikidot/connector/ajax.py index 0b3288a..32a1a35 100644 --- a/src/wikidot/connector/ajax.py +++ b/src/wikidot/connector/ajax.py @@ -1,8 +1,9 @@ """ -WikidotのAjax Module Connectorとの通信を担当するモジュール +Module responsible for communication with Wikidot's Ajax Module Connector -このモジュールは、Wikidotサイトのajax-module-connector.phpとの通信を行うための -クラスやユーティリティを提供する。非同期通信、エラーハンドリング、リトライ機能を備えている。 +This module provides classes and utilities for communicating with +Wikidot site's ajax-module-connector.php. It features async communication, +error handling, and retry functionality. """ import asyncio @@ -26,10 +27,10 @@ class AjaxRequestHeader: """ - Ajax Module Connector通信時に使用するリクエストヘッダを管理するクラス + Class for managing request headers used in Ajax Module Connector communication - Content-Type、User-Agent、Referer、Cookieなどを管理し、 - 適切なHTTPヘッダを生成する機能を提供する。 + Manages Content-Type, User-Agent, Referer, Cookie, etc., + and provides functionality to generate appropriate HTTP headers. """ def __init__( @@ -40,18 +41,18 @@ def __init__( cookie: dict | None = None, ): """ - AjaxRequestHeaderの初期化 + Initialize AjaxRequestHeader Parameters ---------- content_type : str | None, default None - 設定するContent-Type。Noneの場合はデフォルト値が使用される + Content-Type to set. Default value is used if None user_agent : str | None, default None - 設定するUser-Agent。Noneの場合はデフォルト値が使用される + User-Agent to set. Default value is used if None referer : str | None, default None - 設定するReferer。Noneの場合はデフォルト値が使用される + Referer to set. Default value is used if None cookie : dict | None, default None - 設定するCookie。Noneの場合は空の辞書が使用される + Cookie to set. Empty dict is used if None """ self.content_type: str = ( "application/x-www-form-urlencoded; charset=UTF-8" if content_type is None else content_type @@ -65,38 +66,38 @@ def __init__( def set_cookie(self, name: str, value: Any) -> None: """ - Cookieを設定する + Set a cookie Parameters ---------- name : str - 設定するCookieの名前 + Name of the cookie to set value : str - 設定するCookieの値 + Value of the cookie to set """ self.cookie[name] = value return def delete_cookie(self, name: str) -> None: """ - Cookieを削除する + Delete a cookie Parameters ---------- name : str - 削除するCookieの名前 + Name of the cookie to delete """ del self.cookie[name] return def get_header(self) -> dict: """ - 構築されたHTTPヘッダを取得する + Get the constructed HTTP headers Returns ------- dict - HTTPリクエスト用のヘッダ辞書 + Header dictionary for HTTP requests """ return { "Content-Type": self.content_type, @@ -109,25 +110,24 @@ def get_header(self) -> dict: @dataclass class AjaxModuleConnectorConfig: """ - Ajax Module Connector通信の設定を保持するデータクラス + Data class holding Ajax Module Connector communication settings - リクエストのタイムアウト、リトライ回数、並行通信数などの - 設定を管理する。 + Manages settings such as request timeout, retry count, and concurrent connections. Attributes ---------- request_timeout : int, default 20 - リクエストのタイムアウト秒数 + Request timeout in seconds attempt_limit : int, default 3 - エラー発生時のリトライ上限回数 + Maximum number of retries on error retry_interval : float, default 1.0 - リトライの基本間隔(秒)。指数バックオフの基準値 + Base retry interval in seconds. Used as the basis for exponential backoff max_backoff : float, default 60.0 - リトライ間隔の最大値(秒) + Maximum retry interval in seconds backoff_factor : float, default 2.0 - 指数バックオフの係数(各リトライごとに間隔がこの係数倍される) + Exponential backoff factor (interval is multiplied by this factor for each retry) semaphore_limit : int, default 10 - 非同期リクエストの最大並行数 + Maximum number of concurrent async requests """ request_timeout: int = 20 @@ -140,17 +140,17 @@ class AjaxModuleConnectorConfig: def _mask_sensitive_data(body: dict[str, Any]) -> dict[str, Any]: """ - ログ出力用に機密情報をマスクする + Mask sensitive information for log output Parameters ---------- body : dict[str, Any] - マスク対象のリクエストボディ + Request body to mask Returns ------- dict[str, Any] - 機密情報がマスクされた辞書 + Dictionary with sensitive information masked """ masked = body.copy() sensitive_keys = {"password", "login", "WIKIDOT_SESSION_ID", "wikidot_token7"} @@ -167,37 +167,37 @@ def _calculate_backoff( max_backoff: float, ) -> float: """ - 指数バックオフ間隔を計算する(ジッター付き) + Calculate exponential backoff interval (with jitter) Parameters ---------- retry_count : int - 現在のリトライ回数(1から開始) + Current retry count (starting from 1) base_interval : float - 基本間隔(秒) + Base interval in seconds backoff_factor : float - バックオフ係数(各リトライごとに間隔がこの係数倍される) + Backoff factor (interval is multiplied by this factor for each retry) max_backoff : float - 最大バックオフ間隔(秒) + Maximum backoff interval in seconds Returns ------- float - 計算されたバックオフ間隔(秒) + Calculated backoff interval in seconds """ # backoff_factor^(retry_count-1) * base_interval backoff = (backoff_factor ** (retry_count - 1)) * base_interval - # 10%のジッターを追加 + # Add 10% jitter jitter = random.uniform(0, backoff * 0.1) return min(backoff + jitter, max_backoff) class AjaxModuleConnectorClient: """ - WikidotのAjax Module Connectorと通信するクライアントクラス + Client class for communicating with Wikidot's Ajax Module Connector - ajax-module-connector.phpへのHTTPリクエストを行い、レスポンスを処理する。 - 非同期通信、リトライ処理、エラーハンドリングなどの機能を備えている。 + Performs HTTP requests to ajax-module-connector.php and processes responses. + Features async communication, retry processing, and error handling. """ def __init__( @@ -206,53 +206,53 @@ def __init__( config: AjaxModuleConnectorConfig | None = None, ): """ - AjaxModuleConnectorClientの初期化 + Initialize AjaxModuleConnectorClient Parameters ---------- site_name : str | None, default None - 接続先のWikidotサイト名。Noneの場合は"www"が使用される + Wikidot site name to connect to. "www" is used if None config : AjaxModuleConnectorConfig | None, default None - 通信設定。Noneの場合はデフォルト値が使用される + Communication settings. Default values are used if None """ self.site_name: str = site_name if site_name is not None else "www" self.config: AjaxModuleConnectorConfig = config if config is not None else AjaxModuleConnectorConfig() - # ssl対応チェック + # Check SSL support self.ssl_supported: bool = self._check_existence_and_ssl() - # ヘッダの初期化 + # Initialize headers self.header: AjaxRequestHeader = AjaxRequestHeader() def _check_existence_and_ssl(self) -> bool: """ - サイトの存在とSSL対応状況を確認する + Check site existence and SSL support status - 実際にHTTPリクエストを送信し、サイトの存在を確認するとともに、 - HTTPSにリダイレクトされるかどうかでSSL対応状況を判断する。 + Sends an actual HTTP request to verify site existence and + determines SSL support status by checking if redirected to HTTPS. Returns ------- bool - サイトがSSL対応している場合はTrue、そうでない場合はFalse + True if the site supports SSL, False otherwise Raises ------ NotFoundException - 指定されたサイトが存在しない場合 + If the specified site does not exist """ - # wwwは常にSSL対応 + # www always supports SSL if self.site_name == "www": return True - # それ以外のサイトはhttpsにリダイレクトされるかどうかで判断 + # For other sites, determine by checking if redirected to https response = httpx.get(f"http://{self.site_name}.wikidot.com") - # 存在しなければ例外送出 + # Raise exception if not found if response.status_code == httpx.codes.NOT_FOUND: raise NotFoundException(f"Site is not found: {self.site_name}.wikidot.com") - # httpsにリダイレクトされているかどうかで判断 + # Determine by checking if redirected to https return ( response.status_code == httpx.codes.MOVED_PERMANENTLY and "Location" in response.headers @@ -285,34 +285,34 @@ def request( site_ssl_supported: bool | None = None, ) -> tuple[httpx.Response, ...] | tuple[httpx.Response | Exception, ...]: """ - Ajax Module Connectorにリクエストを送信し、レスポンスを取得する + Send request to Ajax Module Connector and get response - 複数のリクエストを非同期で並行処理し、エラー発生時には自動的にリトライを行う。 + Processes multiple requests asynchronously in parallel and automatically retries on error. Parameters ---------- bodies : list[dict[str, Any]] - 送信するリクエストボディのリスト + List of request bodies to send return_exceptions : bool, default False - 例外を返すか送出するか (True: 返す, False: 送出する) + Whether to return or raise exceptions (True: return, False: raise) site_name : str | None, default None - 接続先サイト名。Noneの場合は初期化時に指定したサイト名が使用される + Target site name. Uses the site name specified at initialization if None site_ssl_supported : bool | None, default None - サイトのSSL対応状況。Noneの場合は初期化時に確認した結果が使用される + Site's SSL support status. Uses the result confirmed at initialization if None Returns ------- tuple[httpx.Response, ...] | tuple[httpx.Response | Exception, ...] - レスポンスまたは例外のタプル(リクエストと同じ順序) + Tuple of responses or exceptions (in same order as requests) Raises ------ AMCHttpStatusCodeException - HTTPステータスコードが200以外の場合(return_exceptionsがFalseの場合) + If HTTP status code is not 200 (when return_exceptions is False) WikidotStatusCodeException - レスポンスのステータスが"ok"でない場合(return_exceptionsがFalseの場合) + If response status is not "ok" (when return_exceptions is False) ResponseDataException - レスポンスが不正なJSON形式または空の場合(return_exceptionsがFalseの場合) + If response is invalid JSON format or empty (when return_exceptions is False) """ semaphore_instance = asyncio.Semaphore(self.config.semaphore_limit) @@ -324,9 +324,9 @@ async def _request(_body: dict[str, Any]) -> httpx.Response: response: httpx.Response | None = None while True: - # リクエスト実行 + # Execute request try: - # Semaphoreで同時実行数制御 + # Control concurrent execution with Semaphore async with semaphore_instance, httpx.AsyncClient() as client: url = ( f"http{'s' if site_ssl_supported else ''}://{site_name}.wikidot.com/" @@ -342,10 +342,10 @@ async def _request(_body: dict[str, Any]) -> httpx.Response: ) response.raise_for_status() except (httpx.HTTPStatusError, httpx.TimeoutException) as e: - # HTTPステータスエラーまたはタイムアウトの場合はリトライ + # Retry on HTTP status error or timeout retry_count += 1 - # リトライ回数上限に達した場合は例外送出 + # Raise exception if retry limit reached if retry_count >= self.config.attempt_limit: wd_logger.error( f"AMC is respond HTTP error code: " @@ -358,7 +358,7 @@ async def _request(_body: dict[str, Any]) -> httpx.Response: response.status_code if response is not None else 999, ) from e - # 指数バックオフで間隔を空けてリトライ + # Retry with exponential backoff interval backoff = _calculate_backoff( retry_count, self.config.retry_interval, @@ -372,29 +372,29 @@ async def _request(_body: dict[str, Any]) -> httpx.Response: await asyncio.sleep(backoff) continue - # bodyをJSONデータとしてパース + # Parse body as JSON data try: _response_body = response.json() except json.decoder.JSONDecodeError as e: - # パースできなかったらエラーとして扱う + # Treat as error if parsing fails wd_logger.error(f'AMC is respond non-json data: "{response.text}" -> {_mask_sensitive_data(_body)}') raise ResponseDataException(f'AMC is respond non-json data: "{response.text}"') from e - # レスポンスが空だったらエラーとして扱う + # Treat as error if response is empty if _response_body is None or len(_response_body) == 0: wd_logger.error(f"AMC is respond empty data -> {_mask_sensitive_data(_body)}") raise ResponseDataException("AMC is respond empty data") - # 中身のstatusがokでなかったらエラーとして扱う + # Treat as error if status is not ok if "status" in _response_body: - # statusがtry_againの場合はリトライ + # Retry if status is try_again if _response_body["status"] == "try_again": retry_count += 1 if retry_count >= self.config.attempt_limit: wd_logger.error(f'AMC is respond status: "try_again" -> {_mask_sensitive_data(_body)}') raise WikidotStatusCodeException('AMC is respond status: "try_again"', "try_again") - # 指数バックオフで間隔を空けてリトライ + # Retry with exponential backoff interval backoff = _calculate_backoff( retry_count, self.config.retry_interval, @@ -415,7 +415,7 @@ async def _request(_body: dict[str, Any]) -> httpx.Response: target_str = f"action: {_body['action']}/{_body['event'] if 'event' in _body else ''}" raise ForbiddenException(f"Your account has no permission to perform this action: {target_str}") - # それ以外でstatusがokでない場合はエラーとして扱う + # Treat as error if status is not ok for other cases elif _response_body["status"] != "ok": wd_logger.error( f'AMC is respond error status: "{_response_body["status"]}" -> ' @@ -426,7 +426,7 @@ async def _request(_body: dict[str, Any]) -> httpx.Response: _response_body["status"], ) - # レスポンスを返す + # Return response return response async def _execute_requests() -> list[httpx.Response | BaseException]: @@ -435,7 +435,7 @@ async def _execute_requests() -> list[httpx.Response | BaseException]: return_exceptions=return_exceptions, ) - # 処理を実行(既存のループがある環境でも安全に動作) + # Execute processing (works safely even in existing loop environments) results: list[httpx.Response | BaseException] = run_coroutine(_execute_requests()) return tuple( r if isinstance(r, httpx.Response) else r if isinstance(r, Exception) else Exception(str(r)) diff --git a/src/wikidot/module/__init__.py b/src/wikidot/module/__init__.py index 6033d67..a2a1fa4 100644 --- a/src/wikidot/module/__init__.py +++ b/src/wikidot/module/__init__.py @@ -1,7 +1,7 @@ """ -Wikidotサイトのオブジェクトと機能を表現するモジュールパッケージ +Module package representing Wikidot site objects and functionality -このパッケージはWikidotの主要機能とオブジェクトのクラスを提供する。 -ユーザー、サイト、ページ、フォーラム等のWikidotの主要コンポーネントを -抽象化したクラスとそれらを操作するためのインターフェースを含む。 +This package provides classes for Wikidot's main features and objects. +It includes abstracted classes for Wikidot's main components such as +users, sites, pages, and forums, along with interfaces to operate them. """ diff --git a/src/wikidot/module/auth.py b/src/wikidot/module/auth.py index 69ce60f..90ac971 100644 --- a/src/wikidot/module/auth.py +++ b/src/wikidot/module/auth.py @@ -11,9 +11,9 @@ class HTTPAuthentication: """ - WikidotへのHTTP認証を提供するクラス + Class that provides HTTP authentication for Wikidot - ログインおよびログアウト処理を管理するための静的メソッドを提供する。 + Provides static methods for managing login and logout processing. """ @staticmethod @@ -23,23 +23,23 @@ def login( password: str, ) -> None: """ - ユーザー名とパスワードでWikidotにログインする + Log in to Wikidot with username and password Parameters ---------- client : Client - 接続するクライアントインスタンス + The client instance to connect username : str - ログインするユーザー名 + The username to log in with password : str - ユーザーのパスワード + The user's password Raises ------ SessionCreateException - ログイン試行が失敗した場合(HTTP応答コードエラー、認証情報不一致、Cookieの問題等) + If the login attempt fails (HTTP response code error, credential mismatch, cookie issues, etc.) """ - # ログインリクエスト実行 + # Execute login request response = httpx.post( url="https://www.wikidot.com/default--flow/login__LoginPopupScreen", data={ @@ -72,16 +72,16 @@ def login( @staticmethod def logout(client: "Client") -> None: """ - Wikidotからログアウトする + Log out from Wikidot Parameters ---------- client : Client - ログアウトするクライアントインスタンス + The client instance to log out Notes ----- - ログアウト処理でエラーが発生しても無視され、Cookieの削除は常に行われる。 + Errors during the logout process are ignored, and cookie deletion is always performed. """ with contextlib.suppress(Exception): client.amc_client.request([{"action": "Login2Action", "event": "logout", "moduleName": "Empty"}]) diff --git a/src/wikidot/module/client.py b/src/wikidot/module/client.py index 608066d..fd6fe24 100644 --- a/src/wikidot/module/client.py +++ b/src/wikidot/module/client.py @@ -17,195 +17,195 @@ class ClientUserAccessor: """ - ユーザー関連の操作を提供するクラス + A class that provides user-related operations - クライアントインスタンスに関連付けられ、Wikidotユーザーの取得や操作を行うメソッドを提供する。 - Client.userプロパティを通じてアクセスする。 + Associated with a client instance, provides methods for retrieving and manipulating Wikidot users. + Access through the Client.user property. """ def __init__(self, client: "Client"): """ - 初期化メソッド + Initialize method Parameters ---------- client : Client - 親クライアントインスタンス + Parent client instance """ self.client = client def get(self, name: str, raise_when_not_found: bool = False) -> Optional["AbstractUser"]: """ - ユーザー名からユーザーオブジェクトを取得する + Get a user object from a username Parameters ---------- name : str - ユーザー名 + Username raise_when_not_found : bool, default False - ユーザーが見つからない場合に例外を送出するかどうか (True: 送出する, False: 送出しない) - デフォルトでは送出せずにNoneを返す + Whether to raise an exception when a user is not found (True: raise, False: do not raise) + By default, returns None without raising Returns ------- AbstractUser - ユーザーオブジェクト + User object """ return User.from_name(self.client, name, raise_when_not_found) def get_bulk(self, names: list[str], raise_when_not_found: bool = False) -> UserCollection: """ - 複数のユーザー名からユーザーオブジェクトのコレクションを取得する + Get a collection of user objects from multiple usernames Parameters ---------- names : list[str] - ユーザー名のリスト + List of usernames raise_when_not_found : bool, default False - ユーザーが見つからない場合に例外を送出するかどうか (True: 送出する, False: 送出しない) - デフォルトでは送出せずにNoneを返す + Whether to raise an exception when a user is not found (True: raise, False: do not raise) + By default, returns None without raising Returns ------- UserCollection - ユーザーオブジェクトのコレクション + Collection of user objects """ return UserCollection.from_names(self.client, names, raise_when_not_found) class ClientPrivateMessageAccessor: """ - プライベートメッセージ関連の操作を提供するクラス + A class that provides private message-related operations - クライアントインスタンスに関連付けられ、Wikidotプライベートメッセージの送信や取得を行うメソッドを提供する。 - Client.private_messageプロパティを通じてアクセスする。 + Associated with a client instance, provides methods for sending and retrieving Wikidot private messages. + Access through the Client.private_message property. """ def __init__(self, client: "Client"): """ - 初期化メソッド + Initialize method Parameters ---------- client : Client - 親クライアントインスタンス + Parent client instance """ self.client = client def send(self, recipient: User, subject: str, body: str) -> None: """ - プライベートメッセージを送信する + Send a private message Parameters ---------- recipient : User - 受信者 + Recipient subject : str - 件名 + Subject body : str - 本文 + Message body """ PrivateMessage.send(self.client, recipient, subject, body) @property def inbox(self) -> PrivateMessageInbox: """ - 受信箱を取得する + Get the inbox Returns ------- PrivateMessageInbox - 受信箱オブジェクト + Inbox object """ return PrivateMessageInbox.acquire(self.client) @property def sentbox(self) -> PrivateMessageSentBox: """ - 送信箱を取得する + Get the sent box Returns ------- PrivateMessageSentBox - 送信箱オブジェクト + Sent box object """ return PrivateMessageSentBox.acquire(self.client) def get_messages(self, message_ids: list[int]) -> PrivateMessageCollection: """ - 複数のメッセージIDからメッセージのコレクションを取得する + Get a collection of messages from multiple message IDs Parameters ---------- message_ids : list[int] - メッセージIDのリスト + List of message IDs Returns ------- PrivateMessageCollection - メッセージのコレクション + Collection of messages """ return PrivateMessageCollection.from_ids(self.client, message_ids) def get_message(self, message_id: int) -> PrivateMessage: """ - メッセージIDからメッセージを取得する + Get a message from a message ID Parameters ---------- message_id : int - メッセージID + Message ID Returns ------- PrivateMessage - メッセージオブジェクト + Message object """ return PrivateMessage.from_id(self.client, message_id) class ClientSiteAccessor: """ - サイト関連の操作を提供するクラス + A class that provides site-related operations - クライアントインスタンスに関連付けられ、Wikidotサイトの取得や操作を行うメソッドを提供する。 - Client.siteプロパティを通じてアクセスする。 + Associated with a client instance, provides methods for retrieving and manipulating Wikidot sites. + Access through the Client.site property. """ def __init__(self, client: "Client"): """ - 初期化メソッド + Initialize method Parameters ---------- client : Client - 親クライアントインスタンス + Parent client instance """ self.client = client def get(self, unix_name: str) -> "Site": """ - UNIX名からサイトオブジェクトを取得する + Get a site object from a UNIX name Parameters ---------- unix_name : str - サイトのUNIX名(例: 'fondation') + UNIX name of the site (e.g., 'fondation') Returns ------- Site - サイトオブジェクト + Site object """ return Site.from_unix_name(self.client, unix_name) class Client: """ - Wikidot APIへの接続とインタラクションを管理する基幹クライアント + Core client for managing connections and interactions with the Wikidot API - このクラスは、Wikidot APIとの全てのインタラクションの基盤となる。 - ユーザー認証、サイト操作、ページ管理などすべての機能はこのクライアントを通じて提供される。 + This class serves as the foundation for all interactions with the Wikidot API. + All functionality such as user authentication, site operations, and page management is provided through this client. """ # Accessor属性 @@ -227,18 +227,18 @@ def __init__( logging_level: str = "WARNING", ): """ - クライアントの初期化とオプションでの認証を行う + Initialize the client and optionally perform authentication Parameters ---------- username : str | None, default None - ユーザー名。設定すると認証試行を行う + Username. If provided, authentication will be attempted password : str | None, default None - パスワード。設定すると認証試行を行う + Password. If provided, authentication will be attempted amc_config : AjaxModuleConnectorConfig | None, default None - AjaxModuleConnectorの設定 + AjaxModuleConnector configuration logging_level : str, default "WARNING" - ロギングレベル + Logging level """ # ロギング設定を行う from wikidot.common.logger import setup_console_handler @@ -274,14 +274,14 @@ def __init__( def __enter__(self) -> "Client": """ - コンテキストマネージャプロトコルのエントリーポイント + Context manager protocol entry point - with文でクライアントを使用する際に呼び出される。 + Called when using the client with a with statement. Returns ------- Client - 自身のインスタンス + Self instance """ return self @@ -292,18 +292,18 @@ def __exit__( traceback: TracebackType | None, ) -> None: """ - コンテキストマネージャプロトコルの終了処理 + Context manager protocol exit processing - with文の終了時に呼び出され、自動的にログアウト処理を行う。 + Called at the end of a with statement and automatically performs logout processing. Parameters ---------- exc_type : type - 発生した例外の型 + Type of exception that occurred exc_value : Exception - 発生した例外 + Exception that occurred traceback : traceback - 例外のトレースバック + Exception traceback """ if self.is_logged_in: try: @@ -317,26 +317,26 @@ def __exit__( def __str__(self) -> str: """ - オブジェクトの文字列表現 + String representation of the object Returns ------- str - クライアントの文字列表現 + String representation of the client """ return f"Client(username={self.username}, is_logged_in={self.is_logged_in})" def login_check(self) -> None: """ - ログイン状態の確認 + Check login status - ログインが必要な操作を実行する前に呼び出される。 - ログインしていない場合は例外を送出する。 + Called before executing operations that require login. + Raises an exception if not logged in. Raises ------ LoginRequiredException - ログインしていない場合 + When not logged in """ if not self.is_logged_in: raise LoginRequiredException("Login is required to execute this function") @@ -344,16 +344,16 @@ def login_check(self) -> None: def close(self) -> None: """ - クライアントのリソースを明示的に解放 + Explicitly release client resources - ログイン中であればログアウト処理を行い、関連するリソースをクリーンアップする。 - with文を使用しない場合は、このメソッドを明示的に呼び出してリソースを解放すること。 + Performs logout processing if logged in and cleans up associated resources. + If not using a with statement, explicitly call this method to release resources. Examples -------- >>> client = Client(username="user", password="pass") >>> try: - ... # 何か処理 + ... # Some processing ... pass ... finally: ... client.close() diff --git a/src/wikidot/module/forum_category.py b/src/wikidot/module/forum_category.py index 7214719..d248049 100644 --- a/src/wikidot/module/forum_category.py +++ b/src/wikidot/module/forum_category.py @@ -1,8 +1,8 @@ """ -Wikidotフォーラムのカテゴリを扱うモジュール +Module for handling Wikidot forum categories -このモジュールは、Wikidotサイトのフォーラムカテゴリに関連するクラスや機能を提供する。 -フォーラムカテゴリの情報取得やスレッド一覧の取得などの操作が可能。 +This module provides classes and functionality related to Wikidot forum categories. +It enables operations such as retrieving category information and thread lists. """ import re @@ -21,9 +21,9 @@ class ForumCategoryCollection(list["ForumCategory"]): """ - フォーラムカテゴリのコレクションを表すクラス + Class representing a collection of forum categories - 複数のフォーラムカテゴリを格納し、一括して操作するためのリスト拡張クラス。 + A list extension class for storing multiple forum categories and performing batch operations. """ site: "Site" @@ -34,14 +34,14 @@ def __init__( categories: list["ForumCategory"] | None = None, ): """ - 初期化メソッド + Initialization method Parameters ---------- site : Site | None, default None - カテゴリが属するサイト。Noneの場合は最初のカテゴリから推測する + The site the categories belong to。If None, inferred from the first category categories : list[ForumCategory] | None, default None - 格納するカテゴリのリスト + List of categories to store """ super().__init__(categories or []) @@ -52,30 +52,30 @@ def __init__( def __iter__(self) -> Iterator["ForumCategory"]: """ - コレクション内のカテゴリを順に返すイテレータ + Iterator that returns categories in the collection sequentially Returns ------- Iterator[ForumCategory] - カテゴリオブジェクトのイテレータ + Iterator of category objects """ return super().__iter__() def find(self, id: int) -> Optional["ForumCategory"]: """ - カテゴリIDでカテゴリを検索する + Search for a category by category ID - 指定されたIDのカテゴリが存在する場合はそのカテゴリオブジェクトを返す。 + Returns the category object if a category with the specified ID exists。 Parameters ---------- id : int - 検索するカテゴリのID + Category ID to search for Returns ------- ForumCategory | None - 検索結果のカテゴリオブジェクト。見つからない場合はNone + Category object if found, None otherwise """ for category in self: if category.id == id: @@ -85,25 +85,25 @@ def find(self, id: int) -> Optional["ForumCategory"]: @staticmethod def acquire_all(site: "Site") -> "ForumCategoryCollection": """ - サイトのすべてのフォーラムカテゴリを取得する + Retrieve all forum categories of a site - 指定されたサイトのフォーラムページにアクセスし、 - 利用可能なすべてのカテゴリ情報を取得する。 + Accesses the forum page of the specified site and retrieves + information about all available categories。 Parameters ---------- site : Site - カテゴリを取得するサイト + The site to retrieve categories from Returns ------- ForumCategoryCollection - 取得したフォーラムカテゴリのコレクション + Collection of retrieved forum categories Raises ------ NoElementException - 必要なHTML要素が見つからない場合 + If required HTML elements are not found """ categories = [] @@ -156,26 +156,26 @@ def acquire_all(site: "Site") -> "ForumCategoryCollection": @dataclass class ForumCategory: """ - Wikidotフォーラムのカテゴリを表すクラス + Class representing a Wikidot forum category - フォーラムカテゴリの基本情報とスレッド一覧へのアクセス機能を提供する。 + Provides basic forum category information and access to thread lists。 Attributes ---------- site : Site - カテゴリが属するサイト + The site the categories belong to id : int - カテゴリID + Category ID title : str - カテゴリのタイトル + Category title description : str - カテゴリの説明文 + Category description threads_count : int - カテゴリ内のスレッド数 + Number of threads in the category posts_count : int - カテゴリ内の投稿数 + Number of posts in the category _threads : ForumThreadCollection | None - カテゴリ内のスレッドコレクション(内部キャッシュ用) + Thread collection in the category (for internal caching) """ site: "Site" @@ -188,12 +188,12 @@ class ForumCategory: def __str__(self) -> str: """ - オブジェクトの文字列表現 + String representation of the object Returns ------- str - カテゴリの文字列表現 + String representation of the category """ return ( f"ForumCategory(id={self.id}, " @@ -204,14 +204,14 @@ def __str__(self) -> str: @property def threads(self) -> ForumThreadCollection: """ - カテゴリ内のスレッド一覧を取得する + Retrieve the list of threads in the category - スレッドリストが未取得の場合は自動的に取得処理を行う。 + Automatically retrieves if the thread list has not been fetched。 Returns ------- ForumThreadCollection - カテゴリ内のスレッドコレクション + Thread collection in the category """ if self._threads is None: self._threads = ForumThreadCollection.acquire_all_in_category(self) @@ -220,46 +220,46 @@ def threads(self) -> ForumThreadCollection: @threads.setter def threads(self, value: ForumThreadCollection) -> None: """ - カテゴリ内のスレッド一覧を設定する + Set the list of threads in the category Parameters ---------- value : ForumThreadCollection - 設定するスレッドコレクション + Thread collection to set """ self._threads = value def reload_threads(self) -> ForumThreadCollection: """ - カテゴリ内のスレッド一覧を再取得する + Re-retrieve the list of threads in the category - キャッシュを無視して最新のスレッド一覧を取得する。 + Retrieves the latest thread list ignoring the cache。 Returns ------- ForumThreadCollection - 最新のスレッドコレクション + Latest thread collection """ self._threads = ForumThreadCollection.acquire_all_in_category(self) return self._threads def create_thread(self, title: str, description: str, source: str) -> ForumThread: """ - カテゴリ内に新しいスレッドを作成する + Create a new thread in the category Parameters ---------- title : str - スレッドのタイトル + Thread title description : str - スレッドの説明文 + Thread description source : str - スレッドの本文(Wikidot記法) + Thread body (Wikidot syntax) Returns ------- ForumThread - 作成したスレッドオブジェクト + Created thread object """ self.site.client.login_check() diff --git a/src/wikidot/module/forum_post.py b/src/wikidot/module/forum_post.py index b2fa4c2..25a7bc7 100644 --- a/src/wikidot/module/forum_post.py +++ b/src/wikidot/module/forum_post.py @@ -1,8 +1,8 @@ """ -Wikidotフォーラムの投稿を扱うモジュール +Module for handling Wikidot forum posts -このモジュールは、Wikidotサイトのフォーラム投稿(スレッド内の各メッセージ)に関連する -クラスや機能を提供する。投稿の情報取得や表示などの操作が可能。 +This module provides classes and functionality related to Wikidot forum posts (individual messages within threads). +It enables operations such as retrieving post information and display. """ from collections.abc import Iterator @@ -23,9 +23,9 @@ class ForumPostCollection(list["ForumPost"]): """ - フォーラム投稿のコレクションを表すクラス + Class representing a collection of forum posts - フォーラムスレッド内の複数の投稿を格納し、一括して操作するためのリスト拡張クラス。 + A list extension class for storing multiple posts within a forum thread and performing batch operations。 """ thread: "ForumThread" @@ -36,14 +36,14 @@ def __init__( posts: list["ForumPost"] | None = None, ): """ - 初期化メソッド + Initialization method Parameters ---------- thread : ForumThread | None, default None - 投稿が属するスレッド。Noneの場合は最初の投稿から推測する + The thread the posts belong to。If None, inferred from the first post posts : list[ForumPost] | None, default None - 格納する投稿のリスト + List of posts to store """ super().__init__(posts or []) @@ -54,28 +54,28 @@ def __init__( def __iter__(self) -> Iterator["ForumPost"]: """ - コレクション内の投稿を順に返すイテレータ + Iterator that returns posts in the collection sequentially Returns ------- Iterator[ForumPost] - 投稿オブジェクトのイテレータ + Iterator of post objects """ return super().__iter__() def find(self, id: int) -> Optional["ForumPost"]: """ - 指定したIDの投稿を取得する + Retrieve a post with the specified ID Parameters ---------- id : int - 取得する投稿のID + Post ID to retrieve Returns ------- ForumPost | None - 指定したIDの投稿。存在しない場合はNone + Post with the specified ID, or None if it does not exist """ for post in self: if post.id == id: @@ -85,24 +85,24 @@ def find(self, id: int) -> Optional["ForumPost"]: @staticmethod def _parse(thread: "ForumThread", html: BeautifulSoup) -> list["ForumPost"]: """ - HTMLから投稿リストをパースする + Parse post list from HTML Parameters ---------- thread : ForumThread - 投稿が属するスレッド + The thread the posts belong to html : BeautifulSoup - パース対象のHTML + HTML to parse Returns ------- list[ForumPost] - パースされた投稿のリスト + List of parsed posts Raises ------ NoElementException - 必要な要素が見つからない場合 + If required elements are not found """ posts: list[ForumPost] = [] post_elements = html.select("div.post") @@ -113,7 +113,7 @@ def _parse(thread: "ForumThread", html: BeautifulSoup) -> list["ForumPost"]: raise NoElementException("Post ID attribute is not found.") post_id = int(str(post_id_attr).removeprefix("post-")) - # 親投稿IDの取得 + # 親Post IDの取得 parent_id: int | None = None parent_container = post_elem.parent if parent_container is not None: @@ -191,25 +191,25 @@ def _parse(thread: "ForumThread", html: BeautifulSoup) -> list["ForumPost"]: @staticmethod def acquire_all_in_thread(thread: "ForumThread") -> "ForumPostCollection": """ - スレッド内の全投稿を取得する + Retrieve all posts in a thread - 指定されたスレッド内のすべての投稿を取得する。 - ページネーションが存在する場合は、すべてのページを巡回する。 + Retrieves all posts in the specified thread。 + Traverses all pages if pagination exists。 Parameters ---------- thread : ForumThread - 投稿を取得するスレッド + Thread to retrieve posts from Returns ------- ForumPostCollection - スレッド内のすべての投稿を含むコレクション + Collection containing all posts in the thread Raises ------ NoElementException - HTML要素の解析に失敗した場合 + If HTML element parsing fails """ posts: list[ForumPost] = [] @@ -264,35 +264,35 @@ def acquire_all_in_thread(thread: "ForumThread") -> "ForumPostCollection": @dataclass class ForumPost: """ - Wikidotフォーラムの投稿を表すクラス + Class representing a Wikidot forum post - フォーラムスレッド内の個別の投稿(メッセージ)に関する情報を保持する。 - 投稿のタイトル、本文、作成者、作成日時などの情報を提供する。 + Holds information about individual posts (messages) within a forum thread. + Provides information such as post title, body, author, and creation date. Attributes ---------- thread : ForumThread - 投稿が属するスレッド + The thread the post belongs to id : int - 投稿ID + Post ID title : str - 投稿のタイトル + Post title text : str - 投稿の本文(HTMLテキスト) + Post body (HTML text) element : Tag - 投稿のHTML要素(解析用) + HTML element of the post (for parsing) created_by : AbstractUser - 投稿の作成者 + Post creator created_at : datetime - 投稿の作成日時 + Post creation date and time edited_by : AbstractUser | None, default None - 投稿の編集者(編集されていない場合はNone) + Post editor (None if not edited) edited_at : datetime | None, default None - 投稿の編集日時(編集されていない場合はNone) + Post edit date and time (None if not edited) _parent_id : int | None, default None - 親投稿のID(返信元の投稿ID) + Parent post ID (ID of the post being replied to) _source : str | None, default None - 投稿のソース(Wikidot記法) + Post source (Wikidot syntax) """ thread: "ForumThread" @@ -309,12 +309,12 @@ class ForumPost: def __str__(self) -> str: """ - オブジェクトの文字列表現 + String representation of the object Returns ------- str - 投稿の文字列表現 + String representation of the post """ return ( f"ForumPost(thread={self.thread}, id={self.id}, title={self.title}, " @@ -325,31 +325,31 @@ def __str__(self) -> str: @property def parent_id(self) -> int | None: """ - 親投稿のIDを取得する + Retrieve the parent post ID Returns ------- int | None - 親投稿のID。親がない場合はNone + Parent post ID, or None if no parent """ return self._parent_id @property def source(self) -> str: """ - 投稿のソース(Wikidot記法)を取得する + Retrieve the post source (Wikidot syntax) - ソースが未取得の場合は自動的に取得処理を行う。 + Automatically retrieves if source has not been fetched. Returns ------- str - 投稿のソース(Wikidot記法) + Post source (Wikidot syntax) Raises ------ NoElementException - ソース要素が見つからない場合 + If source element is not found """ if self._source is None: response = self.thread.site.amc_request( @@ -374,30 +374,30 @@ def source(self) -> str: def edit(self, source: str, title: str | None = None) -> "ForumPost": """ - 投稿を編集する + Edit the post - 投稿の内容を更新する。タイトルを指定しない場合は現在のタイトルを維持する。 + Updates the post content. Maintains the current title if not specified。 Parameters ---------- source : str - 新しいソース(Wikidot記法) + New source (Wikidot syntax) title : str | None, default None - 新しいタイトル(Noneの場合は現在のタイトルを維持) + New title (maintains current title if None) Returns ------- ForumPost - 自身(メソッドチェーン用) + Self (for method chaining) Raises ------ LoginRequiredException - ログインしていない場合 + If not logged in WikidotStatusCodeException - 編集に失敗した場合 + If editing fails NoElementException - リビジョンID要素が見つからない場合 + If revision ID element is not found """ self.thread.site.client.login_check() diff --git a/src/wikidot/module/forum_thread.py b/src/wikidot/module/forum_thread.py index 8e6759e..caba4a0 100644 --- a/src/wikidot/module/forum_thread.py +++ b/src/wikidot/module/forum_thread.py @@ -1,8 +1,8 @@ """ -Wikidotフォーラムのスレッドを扱うモジュール +Module for handling Wikidot forum threads -このモジュールは、Wikidotサイトのフォーラムスレッドに関連するクラスや機能を提供する。 -スレッドの情報取得や閲覧などの操作が可能。 +This module provides classes and functionality related to Wikidot forum threads. +It enables operations such as retrieving thread information and viewing. """ import re @@ -26,10 +26,10 @@ class ForumThreadCollection(list["ForumThread"]): """ - フォーラムスレッドのコレクションを表すクラス + Class representing a collection of forum threads - 複数のフォーラムスレッドを格納し、一括して操作するためのリスト拡張クラス。 - 特定のカテゴリ内のスレッド一覧を取得する機能などを提供する。 + A list extension class for storing multiple forum threads and performing batch operations. + Provides functionality such as retrieving thread lists within specific categories。 """ site: "Site" @@ -40,14 +40,14 @@ def __init__( threads: list["ForumThread"] | None = None, ): """ - 初期化メソッド + Initialization method Parameters ---------- site : Site | None, default None - スレッドが属するサイト。Noneの場合は最初のスレッドから推測する + The site the threads belong to。If None, inferred from the first thread threads : list[ForumThread] | None, default None - 格納するスレッドのリスト + List of threads to store """ super().__init__(threads or []) @@ -58,28 +58,28 @@ def __init__( def __iter__(self) -> Iterator["ForumThread"]: """ - コレクション内のスレッドを順に返すイテレータ + Iterator that returns threads in the collection sequentially Returns ------- Iterator[ForumThread] - スレッドオブジェクトのイテレータ + Iterator of thread objects """ return super().__iter__() def find(self, id: int) -> Optional["ForumThread"]: """ - 指定したIDのスレッドを取得する + Retrieve a thread with the specified ID Parameters ---------- id : int - 取得するスレッドのID + Thread ID to retrieve Returns ------- ForumThread | None - 指定したIDのスレッド。存在しない場合はNone + Thread with the specified ID, or None if it does not exist """ for thread in self: if thread.id == id: @@ -91,29 +91,29 @@ def _parse_list_in_category( site: "Site", html: BeautifulSoup, category: Optional["ForumCategory"] = None ) -> "ForumThreadCollection": """ - フォーラムページのHTMLからスレッド情報を抽出する内部メソッド + Internal method to extract thread information from forum page HTML - HTMLからスレッドのタイトル、説明、作成者、作成日時などの情報を抽出し、 - ForumThreadオブジェクトのリストを生成する。 + Extracts information such as thread title, description, author, creation date from HTML + and generates a list of ForumThread objects。 Parameters ---------- site : Site - スレッドが属するサイト + The site the threads belong to html : BeautifulSoup - パース対象のHTML + HTML to parse category : ForumCategory | None, default None - スレッドが属するカテゴリ(オプション) + Category the thread belongs to (optional) Returns ------- list[ForumThread] - 抽出されたスレッドオブジェクトのリスト + List of extracted thread objects Raises ------ NoElementException - 必要なHTML要素が見つからない場合 + If required HTML elements are not found """ threads = [] for info in html.select("table.table tr.head~tr"): @@ -165,29 +165,29 @@ def _parse_thread_page( site: "Site", html: BeautifulSoup, category: Optional["ForumCategory"] = None ) -> "ForumThread": """ - スレッドページのHTMLからスレッド情報を抽出する内部メソッド + Internal method to extract thread information from thread page HTML - HTMLからスレッドのタイトル、説明、作成者、作成日時などの情報を抽出し、 - ForumThreadオブジェクトを生成する。 + Extracts information such as thread title, description, author, creation date from HTML, + and generates a ForumThread object. Parameters ---------- site : Site - スレッドが属するサイト + The site the threads belong to html : BeautifulSoup - パース対象のHTML + HTML to parse category : ForumCategory | None, default None - スレッドが属するカテゴリ(オプション) + Category the thread belongs to (optional) Returns ------- ForumThread - 抽出されたスレッドオブジェクト + Extracted thread object Raises ------ NoElementException - 必要なHTML要素が見つからない場合 + If required HTML elements are not found """ # title取得処理 # forum-breadcrumbsの最後のNavigableStringを取得 @@ -259,25 +259,25 @@ def _parse_thread_page( @staticmethod def acquire_all_in_category(category: "ForumCategory") -> "ForumThreadCollection": """ - 特定のカテゴリ内のすべてのスレッドを取得する + Retrieve all threads within a specific category - カテゴリページの各ページにアクセスし、すべてのスレッド情報を収集する。 - ページネーションが存在する場合は、すべてのページを巡回する。 + Accesses each page of the category page and collects all thread information。 + Traverses all pages if pagination exists。 Parameters ---------- category : ForumCategory - スレッドを取得するカテゴリ + Category to retrieve threads from Returns ------- ForumThreadCollection - カテゴリ内のすべてのスレッドを含むコレクション + Collection containing all threads in the category Raises ------ NoElementException - HTML要素の解析に失敗した場合 + If HTML element parsing fails """ threads: list[ForumThread] = [] @@ -328,23 +328,23 @@ def acquire_from_thread_ids( site: "Site", thread_ids: list[int], category: Optional["ForumCategory"] = None ) -> "ForumThreadCollection": """ - 指定されたスレッドIDのスレッド情報を取得する + Retrieve thread information for the specified thread IDs - 指定されたスレッドIDのスレッド情報を取得し、コレクションとして返す。 + Retrieves thread information for the specified thread IDs and returns them as a collection. Parameters ---------- site : Site - スレッドが属するサイト + The site the threads belong to thread_ids : list[int] - 取得するスレッドのIDリスト + List of thread IDs to retrieve category : ForumCategory | None, default None - スレッドが属するカテゴリ(オプション) + Category the thread belongs to (optional) Returns ------- ForumThreadCollection - 取得したスレッド情報のコレクション + Collection of retrieved thread information """ responses = site.amc_request( [ @@ -373,31 +373,31 @@ def acquire_from_thread_ids( @dataclass class ForumThread: """ - Wikidotフォーラムのスレッドを表すクラス + Class representing a Wikidot forum thread - フォーラムスレッドの基本情報を保持する。スレッドのタイトル、説明、 - 作成者、作成日時、投稿数などの情報を提供する。 + Holds basic forum thread information. Provides information such as thread title, + description, author, creation date, and post count. Attributes ---------- site : Site - スレッドが属するサイト + The site the thread belongs to id : int - スレッドID + Thread ID title : str - スレッドのタイトル + Thread title description : str - スレッドの説明または抜粋 + Thread description or excerpt created_by : AbstractUser - スレッドの作成者 + Thread creator created_at : datetime - スレッドの作成日時 + Thread creation date and time post_count : int - スレッド内の投稿数 + Number of posts in the thread category : ForumCategory | None, default None - スレッドが属するフォーラムカテゴリ + Forum category the thread belongs to _posts : ForumPostCollection | None, default None - スレッド内の投稿コレクション(遅延取得) + Post collection in the thread (lazy loading) """ site: "Site" @@ -412,12 +412,12 @@ class ForumThread: def __str__(self) -> str: """ - オブジェクトの文字列表現 + String representation of the object Returns ------- str - スレッドの文字列表現 + String representation of the thread """ return ( f"ForumThread(id={self.id}, " @@ -430,26 +430,26 @@ def __str__(self) -> str: @property def url(self) -> str: """ - スレッドのURLを取得する + Retrieve the thread URL Returns ------- str - スレッドのURL + Thread URL """ return f"{self.site.url}/forum/t-{self.id}/" @property def posts(self) -> "ForumPostCollection": """ - スレッド内の全投稿を取得する + Retrieve all posts in a thread - 投稿が未取得の場合は自動的に取得処理を行う。 + Automatically retrieves if posts have not been fetched。 Returns ------- ForumPostCollection - スレッド内のすべての投稿を含むコレクション + Collection containing all posts in the thread """ if self._posts is None: from .forum_post import ForumPostCollection @@ -459,31 +459,31 @@ def posts(self) -> "ForumPostCollection": def reply(self, source: str, title: str = "", parent_post_id: int | None = None) -> "ForumThread": """ - スレッドに返信を投稿する + Post a reply to the thread - スレッドに新しい投稿を追加する。親投稿IDを指定すると、 - その投稿への返信として投稿される。 + Adds a new post to the thread. If a parent post ID is specified, + it is posted as a reply to that post。 Parameters ---------- source : str - 投稿の本文(Wikidot記法) + Post body (Wikidot syntax) title : str, default "" - 投稿のタイトル + Post title parent_post_id : int | None, default None - 返信先の投稿ID(スレッドへの直接返信の場合はNone) + Post ID to reply to (None for direct replies to thread) Returns ------- ForumThread - 自身(メソッドチェーン用) + Self (for method chaining) Raises ------ LoginRequiredException - ログインしていない場合 + If not logged in WikidotStatusCodeException - 投稿に失敗した場合 + If posting fails """ self.site.client.login_check() self.site.amc_request( @@ -507,20 +507,20 @@ def reply(self, source: str, title: str = "", parent_post_id: int | None = None) @staticmethod def get_from_id(site: "Site", thread_id: int, category: Optional["ForumCategory"] = None) -> "ForumThread": """ - スレッドIDからスレッド情報を取得する + Retrieve thread information from thread ID Parameters ---------- site : Site - スレッドが属するサイト + The site the thread belongs to thread_id : int - 取得するスレッドのID + Thread ID to retrieve category : ForumCategory | None, default None - スレッドが属するカテゴリ(オプション) + Category the thread belongs to (optional) Returns ------- ForumThread - 取得したスレッド情報 + Retrieved thread information """ return ForumThreadCollection.acquire_from_thread_ids(site, [thread_id], category)[0] diff --git a/src/wikidot/module/page.py b/src/wikidot/module/page.py index 061951c..eb1e5de 100644 --- a/src/wikidot/module/page.py +++ b/src/wikidot/module/page.py @@ -30,12 +30,12 @@ class PageConstants: """ - ページモジュールで使用される定数を一元管理するクラス + A class for centrally managing constants used in the page module Attributes ---------- DEFAULT_PER_PAGE : int - ListPagesModuleのデフォルト1ページあたり件数 + Default number of items per page for ListPagesModule """ DEFAULT_PER_PAGE: int = 250 @@ -67,51 +67,51 @@ class PageConstants: class SearchPagesQueryParams(TypedDict, total=False): """ - ページ検索クエリのパラメータを定義するTypedDict + A TypedDict defining page search query parameters - SitePagesAccessor.search()およびSearchPagesQuery.__init__()の - キーワード引数の型定義に使用する。IDEのオートコンプリートと型チェックを有効にする。 + Used for type definition of keyword arguments in SitePagesAccessor.search() + and SearchPagesQuery.__init__(). Enables IDE autocomplete and type checking. Attributes ---------- pagetype : str - ページタイプ(例: "normal", "admin"等)。デフォルト: "*" + Page type (e.g., "normal", "admin", etc.). Default: "*" category : str - カテゴリ名。デフォルト: "*" + Category name. Default: "*" tags : str | list[str] - 検索対象のタグ(文字列または文字列のリスト) + Tags to search for (string or list of strings) parent : str - 親ページ名 + Parent page name link_to : str - リンク先ページ名 + Linked page name created_at : str - 作成日時の条件(例: "> -86400 86400") + Creation date condition (e.g., "> -86400 86400") updated_at : str - 更新日時の条件 + Update date condition created_by : User | str - 作成者による絞り込み + Filter by creator rating : str - 評価値による絞り込み + Filter by rating value votes : str - 投票数による絞り込み + Filter by vote count name : str - ページ名による絞り込み + Filter by page name fullname : str - フルネームによる絞り込み(完全一致) + Filter by fullname (exact match) range : str - 範囲指定 + Range specification order : str - ソート順(例: "created_at desc", "title asc")。デフォルト: "created_at desc" + Sort order (e.g., "created_at desc", "title asc"). Default: "created_at desc" offset : int - 取得開始位置。デフォルト: 0 + Starting position for retrieval. Default: 0 limit : int - 取得件数制限 + Limit on number of items to retrieve perPage : int - 1ページあたりの表示件数。デフォルト: 250 + Number of items displayed per page. Default: 250 separate : str - 個別表示するかどうか。デフォルト: "no" + Whether to display separately. Default: "no" wrapper : str - ラッパー要素を表示するかどうか。デフォルト: "no" + Whether to display wrapper element. Default: "no" """ pagetype: str @@ -137,56 +137,56 @@ class SearchPagesQueryParams(TypedDict, total=False): class SearchPagesQuery: """ - ページ検索クエリを表すクラス + A class representing a page search query - Wikidotのページ検索に使用される各種検索条件を定義する。 - ListPagesModuleに渡すためのクエリパラメータをカプセル化している。 + Defines various search conditions used for Wikidot page searches. + Encapsulates query parameters to pass to ListPagesModule. Attributes ---------- pagetype : str, default "*" - ページタイプ(例: "normal", "admin"等) + Page type (e.g., "normal", "admin", etc.) category : str, default "*" - カテゴリ名 + Category name tags : str | list[str] | None, default None - 検索対象のタグ(文字列または文字列のリスト) + Tags to search for (string or list of strings) parent : str | None, default None - 親ページ名 + Parent page name link_to : str | None, default None - リンク先ページ名 + Linked page name created_at : str | None, default None - 作成日時の条件 + Creation date condition updated_at : str | None, default None - 更新日時の条件 + Update date condition created_by : User | str | None, default None - 作成者による絞り込み + Filter by creator rating : str | None, default None - 評価値による絞り込み + Filter by rating value votes : str | None, default None - 投票数による絞り込み + Filter by vote count name : str | None, default None - ページ名による絞り込み + Filter by page name fullname : str | None, default None - フルネームによる絞り込み(完全一致) + Filter by fullname (exact match) range : str | None, default None - 範囲指定 + Range specification order : str, default "created_at desc" - ソート順(例: "created_at desc", "title asc"等) + Sort order (e.g., "created_at desc", "title asc", etc.) offset : int, default 0 - 取得開始位置 + Starting position for retrieval limit : int | None, default None - 取得件数制限 + Limit on number of items to retrieve perPage : int, default 250 - 1ページあたりの表示件数 + Number of items displayed per page separate : str, default "no" - 個別表示するかどうか + Whether to display separately wrapper : str, default "no" - ラッパー要素を表示するかどうか + Whether to display wrapper element Raises ------ ValueError - 無効なキーワード引数が渡された場合 + When invalid keyword arguments are passed """ # 有効なフィールド名のセット @@ -214,17 +214,17 @@ class SearchPagesQuery: def __init__(self, **kwargs: Unpack[SearchPagesQueryParams]) -> None: """ - SearchPagesQueryの初期化 + Initialize SearchPagesQuery Parameters ---------- **kwargs : Unpack[SearchPagesQueryParams] - 検索条件のキーワード引数。詳細はSearchPagesQueryParamsを参照。 + Search condition keyword arguments. See SearchPagesQueryParams for details. Raises ------ ValueError - 無効なキーワード引数が含まれている場合 + When invalid keyword arguments are included """ # 無効なキーのチェック invalid_keys = set(kwargs.keys()) - self._VALID_FIELDS @@ -263,14 +263,14 @@ def __init__(self, **kwargs: Unpack[SearchPagesQueryParams]) -> None: def as_dict(self) -> dict[str, Any]: """ - クエリパラメータを辞書形式に変換する + Convert query parameters to dictionary format - タグがリスト形式の場合は空白区切りの文字列に変換する。 + If tags are in list format, converts them to a space-separated string. Returns ------- dict[str, Any] - APIリクエスト用の辞書形式パラメータ + Dictionary format parameters for API requests """ res = {k: v for k, v in self.__dict__.items() if v is not None and k in self._VALID_FIELDS} @@ -281,24 +281,24 @@ def as_dict(self) -> dict[str, Any]: class PageCollection(list["Page"]): """ - ページオブジェクトのコレクションを表すクラス + A class representing a collection of page objects - 複数のページオブジェクトを格納し、一括して操作するための機能を提供する。 - ページの検索、一括取得、一括操作などの機能を集約している。 + Stores multiple page objects and provides functionality for batch operations. + Consolidates features such as page search, batch retrieval, and batch operations. """ site: "Site" def __init__(self, site: Optional["Site"] = None, pages: list["Page"] | None = None): """ - 初期化メソッド + Initialize method Parameters ---------- site : Site | None, default None - ページが属するサイト。Noneの場合は最初のページから推測する + Site to which pages belong. If None, inferred from the first page pages : list[Page] | None, default None - 格納するページのリスト + List of pages to store """ super().__init__(pages or []) @@ -309,28 +309,28 @@ def __init__(self, site: Optional["Site"] = None, pages: list["Page"] | None = N def __iter__(self) -> Iterator["Page"]: """ - コレクション内のページを順に返すイテレータ + An iterator that returns pages in the collection sequentially Returns ------- Iterator[Page] - ページオブジェクトのイテレータ + Iterator of page objects """ return super().__iter__() def find(self, fullname: str) -> Optional["Page"]: """ - 指定したフルネームのページを取得する + Get a page with the specified fullname Parameters ---------- fullname : str - 取得するページのフルネーム + Fullname of the page to retrieve Returns ------- Page | None - 指定したフルネームのページ。存在しない場合はNone + Page with the specified fullname. None if it does not exist """ for page in self: if page.fullname == fullname: @@ -340,24 +340,24 @@ def find(self, fullname: str) -> Optional["Page"]: @staticmethod def _parse(site: "Site", html_body: BeautifulSoup) -> "PageCollection": """ - ListPagesModuleのレスポンスをパースしてページオブジェクトのリストを生成する + Parse ListPagesModule responses and generate a list of page objects Parameters ---------- site : Site - ページが属するサイト + Site to which pages belong html_body : BeautifulSoup - パース対象のHTML + HTML to parse Returns ------- PageCollection - パース結果のページコレクション + Page collection from parsing results Raises ------ NoElementException - 必要な要素が見つからない場合 + When required elements are not found """ pages = [] @@ -444,31 +444,31 @@ def _parse(site: "Site", html_body: BeautifulSoup) -> "PageCollection": @staticmethod def search_pages(site: "Site", query: SearchPagesQuery | None = None) -> "PageCollection": """ - サイト内のページを検索する + Search for pages within a site - 指定されたクエリに基づいてサイト内のページを検索し、結果を返す。 - Wikidotの「ListPagesModule」を使用して検索を実行する。 + Searches for pages within a site based on the specified query and returns the results. + Executes the search using Wikidot's "ListPagesModule". Parameters ---------- site : Site - 検索対象のサイト + Site to search query : SearchPagesQuery | None, default None - 検索条件。Noneの場合はデフォルトの検索条件を使用する。 + Search conditions. If None, default search conditions are used. Returns ------- PageCollection - 検索結果のページコレクション + Page collection of search results Raises ------ ForbiddenException - プライベートサイトでアクセスが拒否された場合 + When access is denied on a private site WikidotStatusCodeException - その他のAPIエラーが発生した場合 + When other API errors occur NoElementException - レスポンスからページ情報を抽出できない場合 + When page information cannot be extracted from the response """ if query is None: query = SearchPagesQuery() @@ -530,27 +530,27 @@ def search_pages(site: "Site", query: SearchPagesQuery | None = None) -> "PageCo @staticmethod def _acquire_page_ids(site: "Site", pages: list["Page"]) -> list["Page"]: """ - ページIDを取得する内部メソッド + Internal method to retrieve page IDs - 未取得のページIDを一括で取得する。norender/noredirectオプション付きで - ページにアクセスし、ページソースからIDを抽出する。 + Batch retrieves unacquired page IDs. Accesses pages with norender/noredirect options + and extracts IDs from page source. Parameters ---------- site : Site - ページが属するサイト + Site to which pages belong pages : list[Page] - 対象ページのリスト + List of target pages Returns ------- list[Page] - ID情報が更新されたページのリスト + List of pages with updated ID information Raises ------ UnexpectedException - ページIDが見つからない場合や、予期しないレスポンスタイプの場合 + When page ID is not found or response type is unexpected """ # pagesからidが設定されていないものを抽出 target_pages = [page for page in pages if not page.is_id_acquired()] @@ -581,14 +581,14 @@ def _acquire_page_ids(site: "Site", pages: list["Page"]) -> list["Page"]: def get_page_ids(self) -> "PageCollection": """ - コレクション内の全ページのIDを取得する + Get IDs for all pages in the collection - IDが設定されていないページについて、一括でIDを取得する。 + Batch retrieves IDs for pages that do not have IDs set. Returns ------- PageCollection - 自身(メソッドチェーン用) + Self (for method chaining) """ PageCollection._acquire_page_ids(self.site, self) return self @@ -596,26 +596,26 @@ def get_page_ids(self) -> "PageCollection": @staticmethod def _acquire_page_sources(site: "Site", pages: list["Page"]) -> list["Page"]: """ - ページソースを取得する内部メソッド + Internal method to retrieve page sources - 指定されたページのソースコード(Wikidot記法)を一括で取得する。 + Batch retrieves source code (Wikidot markup) for specified pages. Parameters ---------- site : Site - ページが属するサイト + Site to which pages belong pages : list[Page] - 対象ページのリスト + List of target pages Returns ------- list[Page] - ソース情報が更新されたページのリスト + List of pages with updated source information Raises ------ NoElementException - ソース要素が見つからない場合 + When source elements are not found """ if len(pages) == 0: return pages @@ -640,14 +640,14 @@ def _acquire_page_sources(site: "Site", pages: list["Page"]) -> list["Page"]: def get_page_sources(self) -> "PageCollection": """ - コレクション内の全ページのソースコードを取得する + Get source code for all pages in the collection - ページのソースコード(Wikidot記法)を一括で取得し、各ページのsourceプロパティに設定する。 + Batch retrieves source code (Wikidot markup) for pages and sets the source property for each page. Returns ------- PageCollection - 自身(メソッドチェーン用) + Self (for method chaining) """ PageCollection._acquire_page_sources(self.site, self) return self @@ -655,26 +655,26 @@ def get_page_sources(self) -> "PageCollection": @staticmethod def _acquire_page_revisions(site: "Site", pages: list["Page"]) -> list["Page"]: """ - ページリビジョン履歴を取得する内部メソッド + Internal method to retrieve page revision history - 指定されたページのリビジョン(編集履歴)を一括で取得する。 + Batch retrieves revisions (edit history) for specified pages. Parameters ---------- site : Site - ページが属するサイト + Site to which pages belong pages : list[Page] - 対象ページのリスト + List of target pages Returns ------- list[Page] - リビジョン情報が更新されたページのリスト + List of pages with updated revision information Raises ------ NoElementException - 必要な要素が見つからない場合 + When required elements are not found """ if len(pages) == 0: return pages @@ -732,14 +732,14 @@ def _acquire_page_revisions(site: "Site", pages: list["Page"]) -> list["Page"]: def get_page_revisions(self) -> "PageCollection": """ - コレクション内の全ページのリビジョン履歴を取得する + Get revision history for all pages in the collection - ページのリビジョン(編集履歴)を一括で取得し、各ページのrevisionsプロパティに設定する。 + Batch retrieves revisions (edit history) for pages and sets the revisions property for each page. Returns ------- PageCollection - 自身(メソッドチェーン用) + Self (for method chaining) """ PageCollection._acquire_page_revisions(self.site, self) return self @@ -747,26 +747,26 @@ def get_page_revisions(self) -> "PageCollection": @staticmethod def _acquire_page_votes(site: "Site", pages: list["Page"]) -> list["Page"]: """ - ページへの投票情報を取得する内部メソッド + Internal method to retrieve vote information for pages - 指定されたページへの投票(レーティング)情報を一括で取得する。 + Batch retrieves vote (rating) information for specified pages. Parameters ---------- site : Site - ページが属するサイト + Site to which pages belong pages : list[Page] - 対象ページのリスト + List of target pages Returns ------- list[Page] - 投票情報が更新されたページのリスト + List of pages with updated vote information Raises ------ UnexpectedException - ユーザー要素と投票値要素の数が一致しない場合 + When the number of user elements and vote value elements do not match """ if len(pages) == 0: return pages @@ -802,14 +802,14 @@ def _acquire_page_votes(site: "Site", pages: list["Page"]) -> list["Page"]: def get_page_votes(self) -> "PageCollection": """ - コレクション内の全ページの投票情報を取得する + Get vote information for all pages in the collection - ページへの投票(レーティング)情報を一括で取得し、各ページのvotesプロパティに設定する。 + Batch retrieves vote (rating) information for pages and sets the votes property for each page. Returns ------- PageCollection - 自身(メソッドチェーン用) + Self (for method chaining) """ PageCollection._acquire_page_votes(self.site, self) return self @@ -818,63 +818,63 @@ def get_page_votes(self) -> "PageCollection": @dataclass class Page: """ - Wikidotページを表すクラス + A class representing a Wikidot page - Wikidotサイト内の単一ページに関する情報と操作機能を提供する。 - ページの基本情報、メタデータ、履歴、評価などを管理する。 + Provides information and operation functions for a single page within a Wikidot site. + Manages page basic information, metadata, history, ratings, etc. Attributes ---------- site : Site - ページが存在するサイト + Site where the page exists fullname : str - ページのフルネーム(例: "コンポーネント:scp-173") + Fullname of the page (e.g., "component:scp-173") name : str - ページ名(例: "scp-173") + Page name (e.g., "scp-173") category : str - カテゴリ(例: "コンポーネント") + Category (e.g., "component") title : str - ページのタイトル + Title of the page children_count : int - 子ページの数 + Number of child pages comments_count : int - コメント数 + Number of comments size : int - ページのサイズ(バイト数) + Size of the page (in bytes) rating : int | float - レーティング(+/-評価の場合はint、5つ星評価の場合はfloat) + Rating (int for +/- rating, float for 5-star rating) votes_count : int - 投票数 + Number of votes rating_percent : float - 5つ星評価システムにおけるパーセンテージ値(0.0~1.0) + Percentage value in 5-star rating system (0.0 to 1.0) revisions_count : int - リビジョン(編集履歴)の数 + Number of revisions (edit history) parent_fullname : str | None - 親ページのフルネーム(親がない場合はNone) + Fullname of parent page (None if no parent) tags : list[str] - 付けられたタグのリスト + List of tags attached created_by : User - ページの作成者 + Creator of the page created_at : datetime - ページの作成日時 + Date and time the page was created updated_by : User - 最終更新者 + Last updater updated_at : datetime - 最終更新日時 + Last update date and time commented_by : User | None - 最後にコメントしたユーザー(コメントがない場合はNone) + User who last commented (None if no comments) commented_at : datetime | None - 最後のコメント日時(コメントがない場合はNone) + Date and time of last comment (None if no comments) _id : int | None - ページのID(内部識別子) + Page ID (internal identifier) _source : PageSource | None - ページのソースコード(要求時に取得) + Source code of the page (retrieved on request) _revisions : PageRevisionCollection | None - ページのリビジョン履歴(要求時に取得) + Revision history of the page (retrieved on request) _votes : PageVoteCollection | None - ページへの投票情報(要求時に取得) + Vote information for the page (retrieved on request) _metas : dict[str, str] | None - ページのメタタグ情報(要求時に取得) + Meta tag information for the page (retrieved on request) """ site: "Site" @@ -908,33 +908,33 @@ class Page: def get_url(self) -> str: """ - ページの完全なURLを取得する + Get the full URL of the page - サイトのURLとページ名から完全なページURLを生成する。 + Generates the full page URL from the site URL and page name. Returns ------- str - ページの完全なURL + Full URL of the page """ return f"{self.site.url}/{self.fullname}" @property def id(self) -> int: """ - ページIDを取得する + Get the page ID - IDが未取得の場合は自動的に取得処理を行う。 + Automatically performs retrieval processing if the ID has not been acquired. Returns ------- int - ページID + Page ID Raises ------ NotFoundException - ページIDが見つからない場合 + When the page ID is not found """ if not self.is_id_acquired(): PageCollection(self.site, [self]).get_page_ids() @@ -947,42 +947,42 @@ def id(self) -> int: @id.setter def id(self, value: int) -> None: """ - ページIDを設定する + Set the page ID Parameters ---------- value : int - 設定するページID + Page ID to set """ self._id = value def is_id_acquired(self) -> bool: """ - ページIDが既に取得済みかどうかを確認する + Check whether the page ID has already been acquired Returns ------- bool - IDが取得済みの場合はTrue、未取得の場合はFalse + True if the ID has been acquired, False if not acquired """ return self._id is not None @property def source(self) -> PageSource: """ - ページのソースコードを取得する + Get the source code of the page - ソースコードが未取得の場合は自動的に取得処理を行う。 + Automatically performs retrieval processing if the source code has not been acquired. Returns ------- PageSource - ページのソースコードオブジェクト + Source code object of the page Raises ------ NotFoundException - ページソースが見つからない場合 + When the page source is not found """ if self._source is None: PageCollection(self.site, [self]).get_page_sources() @@ -995,31 +995,31 @@ def source(self) -> PageSource: @source.setter def source(self, value: PageSource) -> None: """ - ページのソースコードを設定する + Set the source code of the page Parameters ---------- value : PageSource - 設定するソースコードオブジェクト + Source code object to set """ self._source = value @property def revisions(self) -> PageRevisionCollection: """ - ページのリビジョン履歴を取得する + Get the revision history of the page - リビジョン履歴が未取得の場合は自動的に取得処理を行う。 + Automatically performs retrieval processing if the revision history has not been acquired. Returns ------- PageRevisionCollection - ページのリビジョン履歴コレクション + Revision history collection of the page Raises ------ NotFoundException - リビジョン履歴が見つからない場合 + When the revision history is not found """ if self._revisions is None: PageCollection(self.site, [self]).get_page_revisions() @@ -1028,12 +1028,12 @@ def revisions(self) -> PageRevisionCollection: @revisions.setter def revisions(self, value: list["PageRevision"] | PageRevisionCollection) -> None: """ - ページのリビジョン履歴を設定する + Set the revision history of the page Parameters ---------- value : list[PageRevision] | PageRevisionCollection - 設定するリビジョンのリストまたはコレクション + List or collection of revisions to set """ if isinstance(value, list): self._revisions = PageRevisionCollection(self, value) @@ -1043,19 +1043,19 @@ def revisions(self, value: list["PageRevision"] | PageRevisionCollection) -> Non @property def latest_revision(self) -> PageRevision: """ - ページの最新リビジョンを取得する + Get the latest revision of the page - revision_countとrev_noが一致するリビジョンを最新として返す。 + Returns the revision where revision_count and rev_no match as the latest. Returns ------- PageRevision - 最新のリビジョンオブジェクト + Latest revision object Raises ------ NotFoundException - 最新リビジョンが見つからない場合 + When the latest revision is not found """ # revision_countとrev_noが一致するものを取得 for revision in self.revisions: @@ -1067,19 +1067,19 @@ def latest_revision(self) -> PageRevision: @property def votes(self) -> PageVoteCollection: """ - ページへの投票情報を取得する + Get vote information for the page - 投票情報が未取得の場合は自動的に取得処理を行う。 + Automatically performs retrieval processing if the vote information has not been acquired. Returns ------- PageVoteCollection - ページへの投票情報コレクション + Vote information collection for the page Raises ------ NotFoundException - 投票情報が見つからない場合 + When the vote information is not found """ if self._votes is None: PageCollection(self.site, [self]).get_page_votes() @@ -1092,27 +1092,27 @@ def votes(self) -> PageVoteCollection: @votes.setter def votes(self, value: PageVoteCollection) -> None: """ - ページへの投票情報を設定する + Set vote information for the page Parameters ---------- value : PageVoteCollection - 設定する投票情報コレクション + Vote information collection to set """ self._votes = value @property def discussion(self) -> Optional["ForumThread"]: """ - ページのディスカッションスレッドを取得する + Get the discussion thread for the page - ページに関連付けられたフォーラムスレッド(コメント欄)を取得する。 - ディスカッションが存在しない場合はNoneを返す。 + Retrieves the forum thread (comments section) associated with the page. + Returns None if the discussion does not exist. Returns ------- ForumThread | None - ディスカッションスレッド。存在しない場合はNone + Discussion thread. None if it does not exist """ if not self._discussion_checked: response = self.site.amc_request( @@ -1138,14 +1138,14 @@ def discussion(self) -> Optional["ForumThread"]: @property def files(self) -> "PageFileCollection": """ - ページに添付されたファイル一覧を取得する + Get a list of files attached to the page - ファイル一覧が未取得の場合は自動的に取得処理を行う。 + Automatically performs retrieval processing if the file list has not been acquired. Returns ------- PageFileCollection - ページに添付されたファイルのコレクション + Collection of files attached to the page """ if self._files is None: from .page_file import PageFileCollection @@ -1155,16 +1155,16 @@ def files(self) -> "PageFileCollection": def destroy(self) -> None: """ - ページを削除する + Delete the page - ログイン状態でのみ実行可能。ページの完全削除を行う。 + Can only be executed while logged in. Performs complete deletion of the page. Raises ------ LoginRequiredException - ログインしていない場合 + When not logged in WikidotStatusCodeException - 削除に失敗した場合 + When deletion fails """ self.site.client.login_check() self.site.amc_request( @@ -1181,14 +1181,14 @@ def destroy(self) -> None: @property def metas(self) -> dict[str, str]: """ - ページのメタタグ情報を取得する + Get meta tag information for the page - メタタグ情報が未取得の場合は自動的に取得処理を行う。 + Automatically performs retrieval processing if the meta tag information has not been acquired. Returns ------- dict[str, str] - メタタグ名とその内容の辞書 + Dictionary of meta tag names and their contents """ if self._metas is None: response = self.site.amc_request( @@ -1215,21 +1215,21 @@ def metas(self) -> dict[str, str]: @metas.setter def metas(self, value: dict[str, str]) -> None: """ - ページのメタタグ情報を設定する + Set meta tag information for the page - 現在のメタタグと比較し、削除されたものは削除、追加・更新されたものは保存する。 + Compares with current meta tags, deletes removed ones, and saves added/updated ones. Parameters ---------- value : dict[str, str] - 設定するメタタグ名とその内容の辞書 + Dictionary of meta tag names and their contents to set Raises ------ LoginRequiredException - ログインしていない場合 + When not logged in WikidotStatusCodeException - メタタグの設定に失敗した場合 + When setting meta tags fails """ self.site.client.login_check() current_metas = self.metas @@ -1292,49 +1292,49 @@ def create_or_edit( raise_on_exists: bool = False, ) -> "Page": """ - ページを作成または編集する + Create or edit a page - 新規ページの作成または既存ページの編集を行う。 - 編集の場合はページロックの取得とページ保存の処理を行う。 + Creates a new page or edits an existing page. + For editing, acquires page lock and performs page save processing. Parameters ---------- site : Site - ページが属するサイト + Site to which the page belongs fullname : str - ページのフルネーム + Fullname of the page page_id : int | None, default None - 編集する場合のページID(新規作成時はNone) + Page ID when editing (None when creating new) title : str, default "" - ページのタイトル + Title of the page source : str, default "" - ページのソースコード(Wikidot記法) + Source code of the page (Wikidot markup) comment : str, default "" - 編集コメント + Edit comment force_edit : bool, default False - 他のユーザーによるロックを強制的に解除するかどうか + Whether to forcibly release locks by other users raise_on_exists : bool, default False - ページが既に存在する場合に例外を送出するかどうか + Whether to raise an exception if the page already exists Returns ------- Page - 作成または編集されたページオブジェクト + Created or edited page object Raises ------ LoginRequiredException - ログインしていない場合 + When not logged in TargetErrorException - ページがロックされている場合 + When the page is locked TargetExistsException - ページが既に存在し、raise_on_existsがTrueの場合 + When the page already exists and raise_on_exists is True ValueError - 既存ページの編集時にpage_idが指定されていない場合 + When page_id is not specified when editing an existing page WikidotStatusCodeException - ページの保存に失敗した場合 + When saving the page fails NotFoundException - ページの作成後に検索できない場合 + When the page cannot be found after creation """ site.client.login_check() @@ -1405,29 +1405,29 @@ def edit( force_edit: bool = False, ) -> "Page": """ - このページを編集する + Edit this page - 既存ページの内容を更新する。指定されていないパラメータは現在の値を維持する。 + Updates the contents of an existing page. Parameters not specified maintain their current values. Parameters ---------- title : str | None, default None - 新しいタイトル(Noneの場合は現在のタイトルを維持) + New title (maintains current title if None) source : str | None, default None - 新しいソースコード(Noneの場合は現在のソースを維持) + New source code (maintains current source if None) comment : str | None, default None - 編集コメント + Edit comment force_edit : bool, default False - 他のユーザーによるロックを強制的に解除するかどうか + Whether to forcibly release locks by other users Returns ------- Page - 編集後のページオブジェクト + Edited page object Raises ------ - 同上(create_or_editメソッドと同様) + Same as above (same as create_or_edit method) """ # Noneならそのままにする title = title or self.title @@ -1446,21 +1446,21 @@ def edit( def commit_tags(self) -> "Page": """ - ページのタグ情報を保存する + Save tag information for the page - 現在のtagsプロパティの内容をWikidotに保存する。 + Saves the contents of the current tags property to Wikidot. Returns ------- Page - 自身(メソッドチェーン用) + Self (for method chaining) Raises ------ LoginRequiredException - ログインしていない場合 + When not logged in WikidotStatusCodeException - タグの保存に失敗した場合 + When saving tags fails """ self.site.client.login_check() self.site.amc_request( @@ -1478,27 +1478,27 @@ def commit_tags(self) -> "Page": def set_parent(self, parent_fullname: str | None) -> "Page": """ - 親ページを設定する + Set the parent page - 指定した親ページをこのページの親として設定する。 - Noneまたは空文字列を指定すると親ページの設定を解除する。 + Sets the specified parent page as the parent of this page. + Specifying None or an empty string removes the parent page setting. Parameters ---------- parent_fullname : str | None - 親ページのフルネーム。Noneまたは空文字列で親を解除 + Fullname of the parent page. None or empty string removes the parent Returns ------- Page - 自身(メソッドチェーン用) + Self (for method chaining) Raises ------ LoginRequiredException - ログインしていない場合 + When not logged in WikidotStatusCodeException - 親ページの設定に失敗した場合 + When setting the parent page fails """ self.site.client.login_check() self.site.amc_request( @@ -1517,27 +1517,27 @@ def set_parent(self, parent_fullname: str | None) -> "Page": def rename(self, new_fullname: str) -> "Page": """ - ページ名を変更する + Rename the page - ページのフルネームを新しい名前に変更する。 - カテゴリも含めた完全なフルネームを指定する必要がある。 + Changes the page's fullname to a new name. + Must specify the complete fullname including category. Parameters ---------- new_fullname : str - 新しいフルネーム(例: "component:new-name") + New fullname (e.g., "component:new-name") Returns ------- Page - 自身(メソッドチェーン用) + Self (for method chaining) Raises ------ LoginRequiredException - ログインしていない場合 + When not logged in WikidotStatusCodeException - ページ名の変更に失敗した場合(同名ページが存在する場合など) + When renaming the page fails (e.g., when a page with the same name exists) """ self.site.client.login_check() self.site.amc_request( @@ -1561,27 +1561,27 @@ def rename(self, new_fullname: str) -> "Page": def vote(self, value: int) -> int: """ - ページに投票する + Vote on the page - ページに対して+1または-1の投票を行う。 - 既に投票している場合は上書きされる。 + Casts a +1 or -1 vote on the page. + Overwrites if already voted. Parameters ---------- value : int - 投票値(1または-1) + Vote value (1 or -1) Returns ------- int - 投票後の新しいレーティング値 + New rating value after voting Raises ------ LoginRequiredException - ログインしていない場合 + When not logged in WikidotStatusCodeException - 投票に失敗した場合 + When voting fails """ self.site.client.login_check() response = self.site.amc_request( @@ -1602,21 +1602,21 @@ def vote(self, value: int) -> int: def cancel_vote(self) -> int: """ - 投票をキャンセルする + Cancel the vote - このページに対する自分の投票を取り消す。 + Cancels your vote on this page. Returns ------- int - キャンセル後の新しいレーティング値 + New rating value after cancellation Raises ------ LoginRequiredException - ログインしていない場合 + When not logged in WikidotStatusCodeException - 投票キャンセルに失敗した場合 + When vote cancellation fails """ self.site.client.login_check() response = self.site.amc_request( diff --git a/src/wikidot/module/page_file.py b/src/wikidot/module/page_file.py index 1807978..080b776 100644 --- a/src/wikidot/module/page_file.py +++ b/src/wikidot/module/page_file.py @@ -1,8 +1,8 @@ """ -Wikidotページのファイル添付を扱うモジュール +Module for handling Wikidot page file attachments -このモジュールは、Wikidotサイトのページに添付されたファイルに関連する -クラスや機能を提供する。ファイルの情報取得などの操作が可能。 +This module provides classes and functions related to files attached +to Wikidot site pages. It enables operations such as retrieving file information. """ from collections.abc import Iterator @@ -17,9 +17,10 @@ class PageFileCollection(list["PageFile"]): """ - ページファイルのコレクションを表すクラス + Class representing a collection of page files - ページに添付された複数のファイルを格納し、一括して操作するためのリスト拡張クラス。 + A list extension class for storing and operating on multiple files + attached to a page in bulk. """ page: "Page" @@ -30,14 +31,14 @@ def __init__( files: list["PageFile"] | None = None, ): """ - 初期化メソッド + Initialize the collection Parameters ---------- page : Page | None, default None - ファイルが属するページ。Noneの場合は最初のファイルから推測する + The page the files belong to. If None, inferred from the first file files : list[PageFile] | None, default None - 格納するファイルのリスト + List of files to store """ super().__init__(files or []) @@ -48,28 +49,28 @@ def __init__( def __iter__(self) -> Iterator["PageFile"]: """ - コレクション内のファイルを順に返すイテレータ + Return an iterator over the files in the collection Returns ------- Iterator[PageFile] - ファイルオブジェクトのイテレータ + Iterator of file objects """ return super().__iter__() def find(self, id: int) -> Optional["PageFile"]: """ - 指定したIDのファイルを取得する + Get the file with the specified ID Parameters ---------- id : int - 取得するファイルのID + The ID of the file to retrieve Returns ------- PageFile | None - 指定したIDのファイル。存在しない場合はNone + The file with the specified ID, or None if not found """ for file in self: if file.id == id: @@ -78,17 +79,17 @@ def find(self, id: int) -> Optional["PageFile"]: def find_by_name(self, name: str) -> Optional["PageFile"]: """ - 指定した名前のファイルを取得する + Get the file with the specified name Parameters ---------- name : str - 取得するファイルの名前 + The name of the file to retrieve Returns ------- PageFile | None - 指定した名前のファイル。存在しない場合はNone + The file with the specified name, or None if not found """ for file in self: if file.name == name: @@ -98,17 +99,17 @@ def find_by_name(self, name: str) -> Optional["PageFile"]: @staticmethod def _parse_size(size_text: str) -> int: """ - ファイルサイズ文字列をバイト数に変換する + Convert file size string to bytes Parameters ---------- size_text : str - サイズ文字列(例: "1.5 kB", "2 MB", "500 Bytes") + Size string (e.g., "1.5 kB", "2 MB", "500 Bytes") Returns ------- int - バイト数 + Size in bytes """ size_text = size_text.strip() if "Bytes" in size_text: @@ -124,17 +125,17 @@ def _parse_size(size_text: str) -> int: @staticmethod def acquire(page: "Page") -> "PageFileCollection": """ - ページに添付されたファイル一覧を取得する + Get the list of files attached to a page Parameters ---------- page : Page - ファイルを取得するページ + The page to retrieve files from Returns ------- PageFileCollection - ページに添付されたファイルのコレクション + Collection of files attached to the page """ response = page.site.amc_request( [ @@ -193,24 +194,24 @@ def acquire(page: "Page") -> "PageFileCollection": @dataclass class PageFile: """ - Wikidotページの添付ファイルを表すクラス + Class representing a Wikidot page attachment file - ページに添付された個別のファイルに関する情報を保持する。 + Holds information about an individual file attached to a page. Attributes ---------- page : Page - ファイルが添付されているページ + The page the file is attached to id : int - ファイルID + File ID name : str - ファイル名 + File name url : str - ファイルのダウンロードURL + File download URL mime_type : str - ファイルのMIMEタイプ + File MIME type size : int - ファイルサイズ(バイト) + File size in bytes """ page: "Page" @@ -222,11 +223,11 @@ class PageFile: def __str__(self) -> str: """ - オブジェクトの文字列表現 + String representation of the object Returns ------- str - ファイルの文字列表現 + String representation of the file """ return f"PageFile(id={self.id}, name={self.name}, url={self.url}, mime_type={self.mime_type}, size={self.size})" diff --git a/src/wikidot/module/page_revision.py b/src/wikidot/module/page_revision.py index dc8eb80..ae98a40 100644 --- a/src/wikidot/module/page_revision.py +++ b/src/wikidot/module/page_revision.py @@ -1,8 +1,8 @@ """ -Wikidotページの編集履歴(リビジョン)を扱うモジュール +Module for handling Wikidot page edit history (revisions) -このモジュールは、Wikidotページの編集履歴(リビジョン)に関連するクラスや機能を提供する。 -リビジョンの取得、ソースの取得、HTML表示などの操作が可能。 +This module provides classes and functions related to Wikidot page edit history (revisions). +It enables operations such as retrieving revisions, getting source code, and displaying HTML. """ from collections.abc import Callable, Iterator @@ -23,10 +23,11 @@ class PageRevisionCollection(list["PageRevision"]): """ - ページリビジョンのコレクションを表すクラス + Class representing a collection of page revisions - ページの編集履歴(リビジョン)の複数バージョンを格納し、一括して操作するための - リスト拡張クラス。ソースコードやHTMLの一括取得など、便利な機能を提供する。 + A list extension class for storing and operating on multiple versions of a page's + edit history (revisions) in bulk. Provides convenient functions such as + batch retrieval of source code and HTML. """ page: "Page | None" @@ -37,42 +38,42 @@ def __init__( revisions: list["PageRevision"] | None = None, ): """ - 初期化メソッド + Initialize the collection Parameters ---------- page : Page | None, default None - リビジョンが属するページ。Noneの場合は最初のリビジョンから推測する + The page the revisions belong to. If None, inferred from the first revision revisions : list[PageRevision] | None, default None - 格納するリビジョンのリスト + List of revisions to store """ super().__init__(revisions or []) self.page = page or self[0].page if len(self) > 0 else None def __iter__(self) -> Iterator["PageRevision"]: """ - コレクション内のリビジョンを順に返すイテレータ + Return an iterator over the revisions in the collection Returns ------- Iterator[PageRevision] - リビジョンオブジェクトのイテレータ + Iterator of revision objects """ return super().__iter__() def find(self, id: int) -> Optional["PageRevision"]: """ - 指定したリビジョンIDのリビジョンを取得する + Get the revision with the specified ID Parameters ---------- id : int - 取得するリビジョンのID + The ID of the revision to retrieve Returns ------- PageRevision | None - 指定したIDのリビジョン。見つからない場合はNone + The revision with the specified ID, or None if not found """ for revision in self: if revision.id == id: @@ -88,25 +89,25 @@ def _generic_acquire( process_response_func: Callable[["PageRevision", httpx.Response, "Page"], None], ) -> list["PageRevision"]: """ - リビジョンデータを一括取得する汎用メソッド + Generic method for batch retrieval of revision data Parameters ---------- page : Page - リビジョンが属するページ + The page the revisions belong to revisions : list[PageRevision] - データを取得するリビジョンのリスト + List of revisions to retrieve data for check_acquired_func : callable - データが既に取得済みかチェックする関数 + Function to check if data is already acquired module_name : str - AMCリクエストで使用するモジュール名 + Module name to use in AMC request process_response_func : callable - レスポンスを処理する関数 (revision, response, page) -> None + Function to process the response (revision, response, page) -> None Returns ------- list[PageRevision] - データが更新されたリビジョンのリスト + List of revisions with updated data """ target_revisions = [revision for revision in revisions if not check_acquired_func(revision)] @@ -125,31 +126,31 @@ def _generic_acquire( @staticmethod def _acquire_sources(page: "Page", revisions: list["PageRevision"]) -> list["PageRevision"]: """ - 複数のリビジョンのソースコードを一括取得する内部メソッド + Internal method to batch retrieve source code for multiple revisions - 未取得のリビジョンソースコードを一括でリクエストし、取得する。 + Requests and retrieves source code for revisions that haven't been fetched yet. Parameters ---------- page : Page - リビジョンが属するページ + The page the revisions belong to revisions : list[PageRevision] - ソースコードを取得するリビジョンのリスト + List of revisions to retrieve source code for Returns ------- list[PageRevision] - ソースコード情報が更新されたリビジョンのリスト + List of revisions with updated source code information Raises ------ NoElementException - ソース要素が見つからない場合 + If source element is not found """ def process_source_response(revision: "PageRevision", response: httpx.Response, page: "Page") -> None: body = response.json()["body"] - # nbspをスペースに置換 + # Replace nbsp with space body = body.replace(" ", " ") body_html = BeautifulSoup(body, "lxml") wiki_text_elem = body_html.select_one("div.page-source") @@ -170,12 +171,12 @@ def process_source_response(revision: "PageRevision", response: httpx.Response, def get_sources(self) -> "PageRevisionCollection": """ - コレクション内のすべてのリビジョンのソースコードを取得する + Get source code for all revisions in the collection Returns ------- PageRevisionCollection - 自身(メソッドチェーン用) + Self (for method chaining) """ if self.page is None: raise ValueError("Page is not set for this collection") @@ -185,21 +186,21 @@ def get_sources(self) -> "PageRevisionCollection": @staticmethod def _acquire_htmls(page: "Page", revisions: list["PageRevision"]) -> list["PageRevision"]: """ - 複数のリビジョンのHTML表示を一括取得する内部メソッド + Internal method to batch retrieve HTML display for multiple revisions - 未取得のリビジョンHTMLを一括でリクエストし、取得する。 + Requests and retrieves HTML for revisions that haven't been fetched yet. Parameters ---------- page : Page - リビジョンが属するページ + The page the revisions belong to revisions : list[PageRevision] - HTMLを取得するリビジョンのリスト + List of revisions to retrieve HTML for Returns ------- list[PageRevision] - HTML情報が更新されたリビジョンのリスト + List of revisions with updated HTML information """ def process_html_response(revision: "PageRevision", response: httpx.Response, page: "Page") -> None: @@ -223,12 +224,12 @@ def process_html_response(revision: "PageRevision", response: httpx.Response, pa def get_htmls(self) -> "PageRevisionCollection": """ - コレクション内のすべてのリビジョンのHTML表示を取得する + Get HTML display for all revisions in the collection Returns ------- PageRevisionCollection - 自身(メソッドチェーン用) + Self (for method chaining) """ if self.page is None: raise ValueError("Page is not set for this collection") @@ -239,29 +240,30 @@ def get_htmls(self) -> "PageRevisionCollection": @dataclass class PageRevision: """ - ページのリビジョン(編集履歴のバージョン)を表すクラス + Class representing a page revision (version in edit history) - ページの特定のバージョンに関する情報を保持する。リビジョン番号、作成者、作成日時、 - 編集コメントなどの基本情報に加え、ソースコードやHTML表示へのアクセス機能を提供する。 + Holds information about a specific version of a page. Provides basic information + such as revision number, creator, creation date, and edit comment, along with + access to source code and HTML display. Attributes ---------- page : Page - リビジョンが属するページ + The page this revision belongs to id : int - リビジョンID + Revision ID rev_no : int - リビジョン番号 + Revision number created_by : AbstractUser - リビジョンの作成者 + The creator of the revision created_at : datetime - リビジョンの作成日時 + The creation date and time of the revision comment : str - 編集コメント + Edit comment _source : PageSource | None, default None - リビジョンのソースコード(内部キャッシュ用) + The revision's source code (internal cache) _html : str | None, default None - リビジョンのHTML表示(内部キャッシュ用) + The revision's HTML display (internal cache) """ page: "Page" @@ -275,37 +277,37 @@ class PageRevision: def is_source_acquired(self) -> bool: """ - ソースコードが既に取得済みかどうかを確認する + Check if source code has already been acquired Returns ------- bool - ソースコードが取得済みの場合はTrue、そうでない場合はFalse + True if source code is acquired, False otherwise """ return self._source is not None def is_html_acquired(self) -> bool: """ - HTML表示が既に取得済みかどうかを確認する + Check if HTML display has already been acquired Returns ------- bool - HTML表示が取得済みの場合はTrue、そうでない場合はFalse + True if HTML display is acquired, False otherwise """ return self._html is not None @property def source(self) -> Optional["PageSource"]: """ - リビジョンのソースコードを取得する + Get the revision's source code - ソースコードが未取得の場合は自動的に取得処理を行う。 + Automatically fetches the source code if not yet acquired. Returns ------- PageSource | None - リビジョンのソースコード + The revision's source code """ if not self.is_source_acquired(): PageRevisionCollection(self.page, [self]).get_sources() @@ -314,26 +316,26 @@ def source(self) -> Optional["PageSource"]: @source.setter def source(self, value: "PageSource") -> None: """ - リビジョンのソースコードを設定する + Set the revision's source code Parameters ---------- value : PageSource - 設定するソースコード + The source code to set """ self._source = value @property def html(self) -> str | None: """ - リビジョンのHTML表示を取得する + Get the revision's HTML display - HTML表示が未取得の場合は自動的に取得処理を行う。 + Automatically fetches the HTML display if not yet acquired. Returns ------- str | None - リビジョンのHTML表示 + The revision's HTML display """ if not self.is_html_acquired(): PageRevisionCollection(self.page, [self]).get_htmls() @@ -342,11 +344,11 @@ def html(self) -> str | None: @html.setter def html(self, value: str) -> None: """ - リビジョンのHTML表示を設定する + Set the revision's HTML display Parameters ---------- value : str - 設定するHTML表示 + The HTML display to set """ self._html = value diff --git a/src/wikidot/module/page_source.py b/src/wikidot/module/page_source.py index da73f14..4683dd1 100644 --- a/src/wikidot/module/page_source.py +++ b/src/wikidot/module/page_source.py @@ -1,7 +1,7 @@ """ -Wikidotページのソースコードを扱うモジュール +Module for handling Wikidot page source code -このモジュールは、Wikidotページのソースコード(Wikidot記法)に関連するクラスや機能を提供する。 +This module provides classes and functions related to Wikidot page source code (Wikidot markup). """ from dataclasses import dataclass @@ -14,17 +14,17 @@ @dataclass class PageSource: """ - ページのソースコード(Wikidot記法)を表すクラス + Class representing a page's source code (Wikidot markup) - Wikidotページのソースコード(Wikidot記法)を保持し、基本的な操作を提供する。 - ページの現在または特定リビジョンのソースコードを表現する。 + Holds the source code (Wikidot markup) of a Wikidot page and provides basic operations. + Represents the source code of a page's current or specific revision. Attributes ---------- page : Page - ソースコードが属するページ + The page this source code belongs to wiki_text : str - ページのソースコード(Wikidot記法) + The page's source code (Wikidot markup) """ page: "Page" diff --git a/src/wikidot/module/page_votes.py b/src/wikidot/module/page_votes.py index 2dce22b..07b16e0 100644 --- a/src/wikidot/module/page_votes.py +++ b/src/wikidot/module/page_votes.py @@ -1,8 +1,8 @@ """ -Wikidotページの投票(レーティング)を扱うモジュール +Module for handling Wikidot page votes (ratings) -このモジュールは、Wikidotページの投票(レーティング)に関連するクラスや機能を提供する。 -ページへの投票情報の取得や表示などの操作が可能。 +This module provides classes and functions related to Wikidot page votes (ratings). +It enables operations such as retrieving and displaying vote information for pages. """ from collections.abc import Iterator @@ -16,52 +16,52 @@ class PageVoteCollection(list["PageVote"]): """ - ページ投票のコレクションを表すクラス + Class representing a collection of page votes - ページに対する複数の投票(レーティング)を格納し、一括して操作するための - リスト拡張クラス。 + A list extension class for storing and operating on multiple votes (ratings) + for a page in bulk. """ page: "Page" def __init__(self, page: "Page", votes: list["PageVote"]): """ - 初期化メソッド + Initialize the collection Parameters ---------- page : Page - 投票が属するページ + The page the votes belong to votes : list[PageVote] - 格納する投票のリスト + List of votes to store """ super().__init__(votes) self.page = page def __iter__(self) -> Iterator["PageVote"]: """ - コレクション内の投票を順に返すイテレータ + Return an iterator over the votes in the collection Returns ------- Iterator[PageVote] - 投票オブジェクトのイテレータ + Iterator of vote objects """ return super().__iter__() def find(self, user: "AbstractUser") -> "PageVote": """ - 指定ユーザーの投票を取得する + Get the vote by the specified user Parameters ---------- user : AbstractUser - 投票を行ったユーザー + The user who cast the vote Returns ------- PageVote - ユーザーの投票情報 + The user's vote information """ for vote in self: if vote.user.id == user.id: @@ -72,18 +72,18 @@ def find(self, user: "AbstractUser") -> "PageVote": @dataclass class PageVote: """ - ページへの投票(レーティング)を表すクラス + Class representing a vote (rating) for a page - ユーザーがページに対して行った投票(評価)の情報を保持する。 + Holds information about a vote (rating) cast by a user for a page. Attributes ---------- page : Page - 投票が属するページ + The page the vote belongs to user : AbstractUser - 投票を行ったユーザー + The user who cast the vote value : int - 投票値(+1/-1 または 数値) + The vote value (+1/-1 or numeric) """ page: "Page" diff --git a/src/wikidot/module/private_message.py b/src/wikidot/module/private_message.py index 459868a..57454a1 100644 --- a/src/wikidot/module/private_message.py +++ b/src/wikidot/module/private_message.py @@ -1,8 +1,8 @@ """ -Wikidotのプライベートメッセージを扱うモジュール +Module for handling Wikidot private messages -このモジュールは、Wikidotのプライベートメッセージ(PM)に関連するクラスや機能を提供する。 -メッセージの送信、受信箱・送信箱の取得、メッセージの閲覧などの操作が可能。 +This module provides classes and functionality related to Wikidot private messages (PM). +It enables operations such as sending messages, retrieving inbox/sent box, and viewing messages. """ from collections.abc import Iterator @@ -25,47 +25,47 @@ class PrivateMessageCollection(list["PrivateMessage"]): """ - プライベートメッセージのコレクションを表す基底クラス + Base class representing a collection of private messages - 複数のプライベートメッセージを格納し、一括して操作するためのリスト拡張クラス。 - 受信箱や送信箱など、特定のメッセージグループを表現するために継承される。 + A list extension class for storing multiple private messages and performing batch operations. + Inherited to represent specific message groups such as inbox or sent box. """ def __str__(self) -> str: """ - オブジェクトの文字列表現 + String representation of the object Returns ------- str - メッセージコレクションの文字列表現 + String representation of the message collection """ return f"{self.__class__.__name__}({len(self)} messages)" def __iter__(self) -> Iterator["PrivateMessage"]: """ - コレクション内のメッセージを順に返すイテレータ + Iterator that returns messages in the collection sequentially Returns ------- Iterator[PrivateMessage] - メッセージオブジェクトのイテレータ + Iterator of message objects """ return super().__iter__() def find(self, id: int) -> Optional["PrivateMessage"]: """ - 指定IDのメッセージを取得する + Retrieve a message with the specified ID Parameters ---------- id : int - 取得するメッセージのID + The ID of the message to retrieve Returns ------- PrivateMessage | None - 取得したメッセージオブジェクト。見つからない場合はNone + The retrieved message object, or None if not found """ for message in self: if message.id == id: @@ -77,28 +77,28 @@ def find(self, id: int) -> Optional["PrivateMessage"]: @login_required def from_ids(client: "Client", message_ids: list[int]) -> "PrivateMessageCollection": """ - メッセージIDのリストからメッセージオブジェクトのコレクションを取得する + Retrieve a collection of message objects from a list of message IDs - 指定されたIDのメッセージを一括で取得し、コレクションとして返す。 + Batch retrieves messages with the specified IDs and returns them as a collection. Parameters ---------- client : Client - クライアントインスタンス + Client instance message_ids : list[int] - 取得するメッセージIDのリスト + List of message IDs to retrieve Returns ------- PrivateMessageCollection - 取得したメッセージのコレクション + Collection of retrieved messages Raises ------ LoginRequiredException - ログインしていない場合 + If not logged in ForbiddenException - メッセージにアクセスする権限がない場合 + If no permission to access the message """ bodies = [] @@ -148,27 +148,27 @@ def from_ids(client: "Client", message_ids: list[int]) -> "PrivateMessageCollect @login_required def _acquire(client: "Client", module_name: str) -> "PrivateMessageCollection": """ - 特定のモジュールからプライベートメッセージを取得する内部メソッド + Internal method to retrieve private messages from a specific module - 受信箱や送信箱などのメッセージ一覧を取得するための共通メソッド。 - ページネーションが存在する場合は、すべてのページから取得する。 + Common method for retrieving message lists such as inbox or sent box. + If pagination exists, retrieves from all pages. Parameters ---------- client : Client - クライアントインスタンス + Client instance module_name : str - メッセージを取得するモジュール名 + Module name to retrieve messages from Returns ------- PrivateMessageCollection - 取得したメッセージのコレクション + Collection of retrieved messages Raises ------ LoginRequiredException - ログインしていない場合 + If not logged in """ # pager取得 response = client.amc_client.request([{"moduleName": module_name}])[0] @@ -198,143 +198,143 @@ def _acquire(client: "Client", module_name: str) -> "PrivateMessageCollection": @classmethod def _factory_from_ids(cls, client: "Client", message_ids: list[int]) -> Self: """ - メッセージIDのリストからメッセージコレクションを取得する汎用ファクトリメソッド + Generic factory method to retrieve message collection from a list of message IDs Parameters ---------- client : Client - クライアントインスタンス + Client instance message_ids : list[int] - 取得するメッセージIDのリスト + List of message IDs to retrieve Returns ------- cls - 呼び出し元のクラスのインスタンス + Instance of the calling class """ return cls(PrivateMessageCollection.from_ids(client, message_ids)) @classmethod def _factory_acquire(cls, client: "Client", module_name: str) -> Self: """ - 指定したモジュールからメッセージを取得する汎用ファクトリメソッド + Generic factory method to retrieve messages from a specified module Parameters ---------- client : Client - クライアントインスタンス + Client instance module_name : str - 取得に使用するモジュール名 + Module name to use for retrieval Returns ------- cls - 呼び出し元のクラスのインスタンス + Instance of the calling class Raises ------ LoginRequiredException - ログインしていない場合 + If not logged in """ return cls(PrivateMessageCollection._acquire(client, module_name)) class PrivateMessageInbox(PrivateMessageCollection): """ - 受信したプライベートメッセージのコレクションを表すクラス + Class representing a collection of received private messages - 受信箱内のプライベートメッセージを格納し、操作するための - PrivateMessageCollectionの特殊化クラス。 + A specialized class of PrivateMessageCollection for storing and operating + on private messages in the inbox. """ @classmethod def from_ids(cls, client: "Client", message_ids: list[int]) -> "PrivateMessageInbox": """ - メッセージIDのリストから受信箱のメッセージコレクションを取得する + Retrieve inbox message collection from a list of message IDs Parameters ---------- client : Client - クライアントインスタンス + Client instance message_ids : list[int] - 取得するメッセージIDのリスト + List of message IDs to retrieve Returns ------- PrivateMessageInbox - 受信箱メッセージのコレクション + Collection of inbox messages """ return cls._factory_from_ids(client, message_ids) @classmethod def acquire(cls, client: "Client") -> "PrivateMessageInbox": """ - ログイン中のユーザーの受信箱メッセージをすべて取得する + Retrieve all inbox messages for the logged-in user Parameters ---------- client : Client - クライアントインスタンス + Client instance Returns ------- PrivateMessageInbox - 受信箱メッセージのコレクション + Collection of inbox messages Raises ------ LoginRequiredException - ログインしていない場合 + If not logged in """ return cls._factory_acquire(client, "dashboard/messages/DMInboxModule") class PrivateMessageSentBox(PrivateMessageCollection): """ - 送信したプライベートメッセージのコレクションを表すクラス + Class representing a collection of sent private messages - 送信箱内のプライベートメッセージを格納し、操作するための - PrivateMessageCollectionの特殊化クラス。 + A specialized class of PrivateMessageCollection for storing and operating + on private messages in the sent box. """ @classmethod def from_ids(cls, client: "Client", message_ids: list[int]) -> "PrivateMessageSentBox": """ - メッセージIDのリストから送信箱のメッセージコレクションを取得する + Retrieve sent box message collection from a list of message IDs Parameters ---------- client : Client - クライアントインスタンス + Client instance message_ids : list[int] - 取得するメッセージIDのリスト + List of message IDs to retrieve Returns ------- PrivateMessageSentBox - 送信箱メッセージのコレクション + Collection of sent box messages """ return cls._factory_from_ids(client, message_ids) @classmethod def acquire(cls, client: "Client") -> "PrivateMessageSentBox": """ - ログイン中のユーザーの送信箱メッセージをすべて取得する + Retrieve all sent box messages for the logged-in user Parameters ---------- client : Client - クライアントインスタンス + Client instance Returns ------- PrivateMessageSentBox - 送信箱メッセージのコレクション + Collection of sent box messages Raises ------ LoginRequiredException - ログインしていない場合 + If not logged in """ return cls._factory_acquire(client, "dashboard/messages/DMSentModule") @@ -342,27 +342,27 @@ def acquire(cls, client: "Client") -> "PrivateMessageSentBox": @dataclass class PrivateMessage: """ - Wikidotプライベートメッセージを表すクラス + Class representing a Wikidot private message - ユーザー間でやりとりされるプライベートメッセージの情報を保持する。 - メッセージの送信者、受信者、件名、本文などの基本情報を提供する。 + Holds information about private messages exchanged between users. + Provides basic information such as sender, recipient, subject, and body. Attributes ---------- client : Client - クライアントインスタンス + Client instance id : int - メッセージID + Message ID sender : AbstractUser - メッセージの送信者 + Sender of the message recipient : AbstractUser - メッセージの受信者 + Recipient of the message subject : str - メッセージの件名 + Subject of the message body : str - メッセージの本文 + Body of the message created_at : datetime - メッセージの作成日時 + Creation date and time of the message """ client: "Client" @@ -375,40 +375,40 @@ class PrivateMessage: def __str__(self) -> str: """ - オブジェクトの文字列表現 + String representation of the object Returns ------- str - メッセージの文字列表現 + String representation of the message """ return f"PrivateMessage(id={self.id}, sender={self.sender}, recipient={self.recipient}, subject={self.subject})" @staticmethod def from_id(client: "Client", message_id: int) -> "PrivateMessage": """ - メッセージIDからメッセージオブジェクトを取得する + Retrieve a message object from a message ID Parameters ---------- client : Client - クライアントインスタンス + Client instance message_id : int - 取得するメッセージID + Message ID to retrieve Returns ------- PrivateMessage - 取得したメッセージオブジェクト + Retrieved message object Raises ------ LoginRequiredException - ログインしていない場合 + If not logged in ForbiddenException - メッセージにアクセスする権限がない場合 + If no permission to access the message IndexError - メッセージが見つからない場合 + If message not found """ return PrivateMessageCollection.from_ids(client, [message_id])[0] @@ -416,23 +416,23 @@ def from_id(client: "Client", message_id: int) -> "PrivateMessage": @login_required def send(client: "Client", recipient: "User", subject: str, body: str) -> None: """ - プライベートメッセージを送信する + Send a private message Parameters ---------- client : Client - クライアントインスタンス + Client instance recipient : User - メッセージの受信者 + Recipient of the message subject : str - メッセージの件名 + Subject of the message body : str - メッセージの本文 + Body of the message Raises ------ LoginRequiredException - ログインしていない場合 + If not logged in """ client.amc_client.request( [ diff --git a/src/wikidot/module/site.py b/src/wikidot/module/site.py index 2458bc0..6b57cff 100644 --- a/src/wikidot/module/site.py +++ b/src/wikidot/module/site.py @@ -30,38 +30,38 @@ class SitePagesAccessor: """ - サイト内のページコレクションに対する操作を提供するクラス + A class that provides operations on page collections within a site - ページの検索機能など、複数のページに対する操作を提供する。 - Site.pagesプロパティを通じてアクセスする。 + Provides operations on multiple pages such as page search functionality. + Access through the Site.pages property. """ def __init__(self, site: "Site"): """ - 初期化メソッド + Initialize method Parameters ---------- site : Site - 親サイトインスタンス + Parent site instance """ self.site = site def search(self, **kwargs: Unpack[SearchPagesQueryParams]) -> "PageCollection": """ - サイト内のページを検索する + Search for pages within a site - キーワード引数を受け取り、SearchPagesQueryオブジェクトに変換して検索を実行する。 + Receives keyword arguments, converts them to a SearchPagesQuery object, and executes the search. Parameters ---------- **kwargs : Unpack[SearchPagesQueryParams] - 検索条件のキーワード引数。詳細はSearchPagesQueryParamsを参照。 + Search condition keyword arguments. See SearchPagesQueryParams for details. Returns ------- PageCollection - 検索結果のページコレクション + Page collection of search results """ query = SearchPagesQuery(**kwargs) return PageCollection.search_pages(self.site, query) @@ -69,44 +69,44 @@ def search(self, **kwargs: Unpack[SearchPagesQueryParams]) -> "PageCollection": class SitePageAccessor: """ - サイト内の個別ページに対する操作を提供するクラス + A class that provides operations on individual pages within a site - ページの取得や作成などの個別ページ操作を提供する。 - Site.pageプロパティを通じてアクセスする。 + Provides individual page operations such as retrieving and creating pages. + Access through the Site.page property. """ def __init__(self, site: "Site"): """ - 初期化メソッド + Initialize method Parameters ---------- site : Site - 親サイトインスタンス + Parent site instance """ self.site = site def get(self, fullname: str, raise_when_not_found: bool = True) -> Optional["Page"]: """ - フルネームからページを取得する + Get a page from its fullname Parameters ---------- fullname : str - ページのフルネーム(例: "コンポーネント:scp-173") + Fullname of the page (e.g., "component:scp-173") raise_when_not_found : bool, default True - ページが見つからなかった場合に例外を発生させるかどうか - Falseの場合、ページが見つからなければNoneを返す + Whether to raise an exception if the page is not found + If False, returns None when the page is not found Returns ------- Page | None - ページオブジェクト、または見つからない場合はNone + Page object, or None if not found Raises ------ NotFoundException - raise_when_not_foundがTrueでページが見つからない場合 + When raise_when_not_found is True and the page is not found """ res = PageCollection.search_pages(self.site, SearchPagesQuery(fullname=fullname)) if len(res) == 0: @@ -124,30 +124,30 @@ def create( force_edit: bool = False, ) -> "Page": """ - ページを新規作成する + Create a new page Parameters ---------- fullname : str - ページのフルネーム(例: "scp-173") + Fullname of the page (e.g., "scp-173") title : str, default "" - ページのタイトル + Title of the page source : str, default "" - ページのソースコード(Wikidot記法) + Source code of the page (Wikidot markup) comment : str, default "" - 編集コメント + Edit comment force_edit : bool, default False - ページが既に存在する場合に上書きするかどうか + Whether to overwrite if the page already exists Returns ------- Page - 作成されたページオブジェクト + Created page object Raises ------ TargetErrorException - ページが既に存在し、force_editがFalseの場合 + When the page already exists and force_edit is False """ return Page.create_or_edit( site=self.site, @@ -162,32 +162,32 @@ def create( class SiteForumAccessor: """ - サイト内のフォーラム機能に対する操作を提供するクラス + A class that provides operations on forum functionality within a site - フォーラムカテゴリの取得などのフォーラム関連機能を提供する。 - Site.forumプロパティを通じてアクセスする。 + Provides forum-related functionality such as retrieving forum categories. + Access through the Site.forum property. """ def __init__(self, site: "Site"): """ - 初期化メソッド + Initialize method Parameters ---------- site : Site - 親サイトインスタンス + Parent site instance """ self.site = site @property def categories(self) -> "ForumCategoryCollection": """ - サイト内のフォーラムカテゴリ一覧を取得する + Get a list of forum categories within the site Returns ------- ForumCategoryCollection - フォーラムカテゴリのコレクション + Collection of forum categories """ return ForumCategoryCollection.acquire_all(self.site) @@ -195,28 +195,28 @@ def categories(self) -> "ForumCategoryCollection": @dataclass class SiteChange: """ - サイトの変更履歴の1件を表すクラス + A class representing a single change history entry for a site - サイト内のページに対する変更(作成、編集、削除など)の情報を保持する。 + Holds information about changes to pages within a site (creation, editing, deletion, etc.). Attributes ---------- site : Site - 変更が行われたサイト + Site where the change occurred page_fullname : str - 変更されたページのフルネーム + Fullname of the changed page page_title : str - 変更されたページのタイトル + Title of the changed page revision_no : int - リビジョン番号 + Revision number changed_by : AbstractUser - 変更を行ったユーザー + User who made the change changed_at : datetime - 変更日時 + Date and time of change flags : list[str] - 変更フラグ("N"=新規作成, "S"=ソース変更, "T"=タイトル変更, "R"=名前変更, "M"=移動, "F"=ファイル, "A"=削除) + Change flags ("N"=new, "S"=source change, "T"=title change, "R"=rename, "M"=move, "F"=file, "A"=delete) comment : str | None - 変更コメント + Change comment """ site: "Site" @@ -230,12 +230,12 @@ class SiteChange: def __str__(self) -> str: """ - オブジェクトの文字列表現 + String representation of the object Returns ------- str - 変更履歴の文字列表現 + String representation of the change history """ return ( f"SiteChange(page_fullname={self.page_fullname}, " @@ -247,25 +247,25 @@ def __str__(self) -> str: @dataclass class Site: """ - Wikidotサイトを表すクラス + A class representing a Wikidot site - サイトの基本情報とサイトに対する様々な操作機能を提供する。 - ページ、フォーラム、メンバー管理などの機能にアクセスするための起点となる。 + Provides basic site information and various operational functions for the site. + Serves as the entry point for accessing features such as pages, forums, and member management. Attributes ---------- client : Client - クライアントインスタンス + Client instance id : int - サイトID + Site ID title : str - サイトのタイトル + Title of the site unix_name : str - サイトのUNIX名(URLの一部として使用される) + UNIX name of the site (used as part of the URL) domain : str - サイトのドメイン(完全修飾ドメイン名) + Domain of the site (fully qualified domain name) ssl_supported : bool - サイトがSSL/HTTPS対応しているかどうか + Whether the site supports SSL/HTTPS """ client: "Client" @@ -288,9 +288,9 @@ class Site: def __post_init__(self) -> None: """ - 初期化後の処理 + Post-initialization processing - サイト関連の機能を提供する各サブクラスのインスタンスを初期化する。 + Initializes instances of each subclass that provides site-related functionality. """ self.pages = SitePagesAccessor(self) self.page = SitePageAccessor(self) @@ -298,40 +298,40 @@ def __post_init__(self) -> None: def __str__(self) -> str: """ - オブジェクトの文字列表現 + String representation of the object Returns ------- str - サイトオブジェクトの文字列表現 + String representation of the site object """ return f"Site(id={self.id}, title={self.title}, unix_name={self.unix_name})" @staticmethod def from_unix_name(client: "Client", unix_name: str) -> "Site": """ - UNIX名からサイトオブジェクトを取得する + Get a site object from a UNIX name - 指定されたUNIX名のサイトにアクセスし、サイト情報を解析してSiteオブジェクトを生成する。 + Accesses the site with the specified UNIX name, parses site information, and generates a Site object. Parameters ---------- client : Client - クライアントインスタンス + Client instance unix_name : str - サイトのUNIX名(例: "fondation") + UNIX name of the site (e.g., "fondation") Returns ------- Site - サイトオブジェクト + Site object Raises ------ NotFoundException - 指定されたUNIX名のサイトが存在しない場合 + When a site with the specified UNIX name does not exist UnexpectedException - サイト情報の解析中にエラーが発生した場合 + When an error occurs during site information parsing """ # サイト情報を取得 # リダイレクトには従う @@ -398,19 +398,19 @@ def amc_request( self, bodies: list[dict[str, Any]], return_exceptions: bool = False ) -> tuple[httpx.Response, ...] | tuple[httpx.Response | Exception, ...]: """ - このサイトに対してAjax Module Connectorリクエストを実行する + Execute an Ajax Module Connector request for this site Parameters ---------- bodies : list[dict] - リクエストボディのリスト + List of request bodies return_exceptions : bool, default False - 例外を返すか送出するか(True: 返す, False: 送出する) + Whether to return or raise exceptions (True: return, False: raise) Returns ------- list | Exception - レスポンスのリスト、またはreturn_exceptionsがTrueの場合は例外 + List of responses, or exceptions if return_exceptions is True """ if return_exceptions: return self.client.amc_client.request(bodies, True, self.unix_name, self.ssl_supported) @@ -420,35 +420,35 @@ def amc_request( @property def applications(self) -> list[SiteApplication]: """ - サイトへの未処理の参加申請を取得する + Get pending membership applications to the site Returns ------- list[SiteApplication] - 参加申請のリスト + List of membership applications """ return SiteApplication.acquire_all(self) @login_required def invite_user(self, user: "User", text: str) -> None: """ - ユーザーをサイトに招待する + Invite a user to the site Parameters ---------- user : User - 招待するユーザー + User to invite text : str - 招待メッセージ + Invitation message Raises ------ TargetErrorException - ユーザーが既に招待済み、または既にメンバーの場合 + When the user is already invited or already a member WikidotStatusCodeException - その他のWikidot APIエラーが発生した場合 + When other Wikidot API errors occur LoginRequiredException - ログインしていない場合(@login_required装飾子による) + When not logged in (by @login_required decorator) """ try: self.amc_request( @@ -477,24 +477,24 @@ def invite_user(self, user: "User", text: str) -> None: @property def url(self) -> str: """ - サイトのURLを取得する + Get the URL of the site Returns ------- str - サイトの完全なURL + Full URL of the site """ return f"http{'s' if self.ssl_supported else ''}://{self.domain}" @property def members(self) -> list[SiteMember]: """ - サイトのメンバー一覧を取得する + Get a list of site members Returns ------- list[SiteMember] - サイトメンバーのリスト + List of site members """ if self._members is None: self._members = SiteMember.get(self) @@ -503,12 +503,12 @@ def members(self) -> list[SiteMember]: @property def moderators(self) -> list[SiteMember]: """ - サイトのモデレーター一覧を取得する + Get a list of site moderators Returns ------- list[SiteMember] - サイトモデレーターのリスト + List of site moderators """ if self._moderators is None: self._moderators = SiteMember.get(self, "moderators") @@ -517,12 +517,12 @@ def moderators(self) -> list[SiteMember]: @property def admins(self) -> list[SiteMember]: """ - サイトの管理者一覧を取得する + Get a list of site administrators Returns ------- list[SiteMember] - サイト管理者のリスト + List of site administrators """ if self._admins is None: self._admins = SiteMember.get(self, "admins") @@ -530,19 +530,19 @@ def admins(self) -> list[SiteMember]: def member_lookup(self, user_name: str, user_id: int | None = None) -> bool: """ - 指定されたユーザーがサイトのメンバーかどうかを確認する + Check whether a specified user is a member of the site Parameters ---------- user_name : str - 確認するユーザー名 + Username to check user_id : int | None, default None - 確認するユーザーID(指定した場合はIDも一致する必要がある) + User ID to check (if specified, the ID must also match) Returns ------- bool - ユーザーがサイトメンバーである場合はTrue、そうでない場合はFalse + True if the user is a site member, False otherwise """ users: list[QMCUser] = QuickModule.member_lookup(self.id, user_name) @@ -557,56 +557,56 @@ def member_lookup(self, user_name: str, user_id: int | None = None) -> bool: def get_thread(self, thread_id: int) -> ForumThread: """ - スレッドを取得する + Get a thread Parameters ---------- thread_id : int - スレッドID + Thread ID Returns ------- ForumThread - スレッドオブジェクト + Thread object """ return ForumThread.get_from_id(self, thread_id) def get_threads(self, thread_ids: list[int]) -> ForumThreadCollection: """ - 複数のスレッドを取得する + Get multiple threads Parameters ---------- thread_ids : list[int] - スレッドIDのリスト + List of thread IDs Returns ------- list[ForumThread] - スレッドオブジェクトのリスト + List of thread objects """ return ForumThreadCollection.acquire_from_thread_ids(self, thread_ids) def get_recent_changes(self, limit: int | None = None) -> list["SiteChange"]: """ - サイトの最近の変更履歴を取得する + Get recent change history of the site - サイト内のページに対する最近の変更(作成、編集、削除など)を取得する。 + Retrieves recent changes to pages within the site (creation, editing, deletion, etc.). Parameters ---------- limit : int | None, default None - 取得する最大件数。Noneの場合は最初のページ(デフォルト件数)のみ取得 + Maximum number of entries to retrieve. If None, retrieves only the first page (default count) Returns ------- list[SiteChange] - 変更履歴のリスト(新しい順) + List of change history (in descending order by date) Raises ------ NoElementException - HTML要素の解析に失敗した場合 + When HTML element parsing fails """ from ..common.exceptions import NoElementException diff --git a/src/wikidot/module/site_application.py b/src/wikidot/module/site_application.py index 1d799f9..bec7882 100644 --- a/src/wikidot/module/site_application.py +++ b/src/wikidot/module/site_application.py @@ -1,8 +1,8 @@ """ -Wikidotサイトへの参加申請を扱うモジュール +Module for handling site join applications on Wikidot -このモジュールは、Wikidotサイトへの参加申請に関連するクラスや機能を提供する。 -申請の取得、承認、拒否などの操作が可能。 +This module provides classes and functionality related to site join applications on Wikidot. +It enables operations such as retrieving, accepting, and declining applications. """ from dataclasses import dataclass @@ -22,19 +22,19 @@ @dataclass class SiteApplication: """ - Wikidotサイトへの参加申請を表すクラス + Class representing a site join application on Wikidot - ユーザーからサイトへの参加申請情報を保持し、申請の承認や拒否などの - 処理機能を提供する。 + Holds site join application information from users and provides + functionality for processing such as accepting or declining applications. Attributes ---------- site : Site - 申請先のサイト + The site being applied to user : AbstractUser - 申請者 + The applicant text : str - 申請メッセージ + Application message """ site: "Site" @@ -43,12 +43,12 @@ class SiteApplication: def __str__(self) -> str: """ - オブジェクトの文字列表現 + String representation of the object Returns ------- str - 申請の文字列表現 + String representation of the application """ return f"SiteApplication(user={self.user}, site={self.site}, text={self.text})" @@ -56,26 +56,26 @@ def __str__(self) -> str: @login_required def acquire_all(site: "Site") -> list["SiteApplication"]: """ - サイトへの未処理の参加申請をすべて取得する + Retrieve all pending site join applications Parameters ---------- site : Site - 参加申請を取得するサイト + The site to retrieve applications from Returns ------- list[SiteApplication] - 参加申請のリスト + List of site applications Raises ------ LoginRequiredException - ログインしていない場合 + If not logged in ForbiddenException - サイトの参加申請を管理する権限がない場合 + If no permission to manage site applications UnexpectedException - 応答の解析に失敗した場合 + If response parsing fails """ response = site.amc_request([{"moduleName": "managesite/ManageSiteMembersApplicationsModule"}])[0] @@ -108,25 +108,25 @@ def acquire_all(site: "Site") -> list["SiteApplication"]: @login_required def _process(self, action: str) -> None: """ - 参加申請を処理する内部メソッド + Internal method to process a site join application - 承認または拒否の処理を行う共通メソッド。 + Common method for processing acceptance or decline. Parameters ---------- action : str - 処理の種類 ("accept" または "decline") + Type of action ("accept" or "decline") Raises ------ LoginRequiredException - ログインしていない場合 + If not logged in ValueError - 無効なアクションが指定された場合 + If an invalid action is specified NotFoundException - 指定された申請が見つからない場合 + If the specified application is not found WikidotStatusCodeException - その他のエラーが発生した場合 + If other errors occur """ if action not in ["accept", "decline"]: raise ValueError(f"Invalid action: {action}") @@ -152,34 +152,34 @@ def _process(self, action: str) -> None: def accept(self) -> None: """ - 参加申請を承認する + Accept the site join application - 申請者をサイトのメンバーとして追加する。 + Adds the applicant as a member of the site. Raises ------ LoginRequiredException - ログインしていない場合 + If not logged in NotFoundException - 指定された申請が見つからない場合 + If the specified application is not found WikidotStatusCodeException - その他のエラーが発生した場合 + If other errors occur """ self._process("accept") def decline(self) -> None: """ - 参加申請を拒否する + Decline the site join application - 申請者の参加を拒否し、申請を削除する。 + Rejects the applicant's join request and deletes the application. Raises ------ LoginRequiredException - ログインしていない場合 + If not logged in NotFoundException - 指定された申請が見つからない場合 + If the specified application is not found WikidotStatusCodeException - その他のエラーが発生した場合 + If other errors occur """ self._process("decline") diff --git a/src/wikidot/module/site_member.py b/src/wikidot/module/site_member.py index 19c5365..8aabb7d 100644 --- a/src/wikidot/module/site_member.py +++ b/src/wikidot/module/site_member.py @@ -1,8 +1,8 @@ """ -Wikidotサイトのメンバーを扱うモジュール +Module for handling Wikidot site members -このモジュールは、Wikidotサイトのメンバーに関連するクラスや機能を提供する。 -メンバーの情報取得や権限変更などの操作が可能。 +This module provides classes and functionality related to Wikidot site members. +It enables operations such as retrieving member information and changing permissions. """ from dataclasses import dataclass @@ -26,18 +26,18 @@ @dataclass class SiteMember: """ - Wikidotサイトのメンバーを表すクラス + Class representing a member of a Wikidot site - サイトのメンバー情報を保持し、権限変更などの操作機能を提供する。 + Holds site member information and provides functionality for operations such as permission changes. Attributes ---------- site : Site - メンバーが所属するサイト + The site the member belongs to user : AbstractUser - メンバーユーザー + The member user joined_at : datetime | None - サイトへの参加日時(取得できない場合はNone) + Date and time the member joined the site (None if unavailable) """ site: "Site" @@ -47,19 +47,19 @@ class SiteMember: @staticmethod def _parse(site: "Site", html: BeautifulSoup) -> list["SiteMember"]: """ - メンバーリストページのHTMLからメンバー情報を抽出する内部メソッド + Internal method to extract member information from member list page HTML Parameters ---------- site : Site - メンバーが所属するサイト + The site the members belong to html : BeautifulSoup - 解析対象のHTML + HTML to parse Returns ------- list[SiteMember] - 抽出されたメンバーのリスト + List of extracted members """ members: list[SiteMember] = [] @@ -89,26 +89,26 @@ def _parse(site: "Site", html: BeautifulSoup) -> list["SiteMember"]: @staticmethod def get(site: "Site", group: str | None = None) -> list["SiteMember"]: """ - サイトのメンバーリストを取得する + Retrieve the member list of a site - 指定したグループ(管理者、モデレーターなど)のメンバー一覧を取得する。 + Retrieves a list of members of the specified group (admins, moderators, etc.). Parameters ---------- site : Site - メンバーリストを取得するサイト + The site to retrieve members from group : str | None, default None - 取得するメンバーのグループ("admins", "moderators", または "" で全メンバー) + Group of members to retrieve ("admins", "moderators", or "" for all members) Returns ------- list[SiteMember] - メンバーのリスト + List of members Raises ------ ValueError - 無効なグループが指定された場合 + If an invalid group is specified """ if group is None: group = "" @@ -161,25 +161,25 @@ def get(site: "Site", group: str | None = None) -> list["SiteMember"]: def _change_group(self, event: str) -> None: """ - メンバーのグループ(権限)を変更する内部メソッド + Internal method to change a member's group (permissions) - モデレーターや管理者への昇格、または降格を行う共通メソッド。 + Common method for promoting to or demoting from moderator or admin. Parameters ---------- event : str - 変更イベント("toModerators", "removeModerator", "toAdmins", "removeAdmin") + Change event ("toModerators", "removeModerator", "toAdmins", "removeAdmin") Raises ------ ValueError - 無効なイベントが指定された場合 + If an invalid event is specified ForbiddenException - 権限不足の場合 + If insufficient permissions TargetErrorException - ユーザーが既に指定された権限を持っている、または持っていない場合 + If the user already has or doesn't have the specified permission WikidotStatusCodeException - その他のエラーが発生した場合 + If other errors occur """ if event not in [ "toModerators", @@ -213,60 +213,60 @@ def _change_group(self, event: str) -> None: def to_moderator(self) -> None: """ - メンバーをモデレーターに昇格させる + Promote a member to moderator Raises ------ ForbiddenException - 権限不足の場合 + If insufficient permissions TargetErrorException - ユーザーが既にモデレーターである場合 + If the user is already a moderator WikidotStatusCodeException - その他のエラーが発生した場合 + If other errors occur """ self._change_group("toModerators") def remove_moderator(self) -> None: """ - メンバーのモデレーター権限を削除する + Remove moderator permissions from a member Raises ------ ForbiddenException - 権限不足の場合 + If insufficient permissions TargetErrorException - ユーザーがモデレーターでない場合 + If the user is not a moderator WikidotStatusCodeException - その他のエラーが発生した場合 + If other errors occur """ self._change_group("removeModerator") def to_admin(self) -> None: """ - メンバーを管理者に昇格させる + Promote a member to admin Raises ------ ForbiddenException - 権限不足の場合 + If insufficient permissions TargetErrorException - ユーザーが既に管理者である場合 + If the user is already an admin WikidotStatusCodeException - その他のエラーが発生した場合 + If other errors occur """ self._change_group("toAdmins") def remove_admin(self) -> None: """ - メンバーの管理者権限を削除する + Remove admin permissions from a member Raises ------ ForbiddenException - 権限不足の場合 + If insufficient permissions TargetErrorException - ユーザーが管理者でない場合 + If the user is not an admin WikidotStatusCodeException - その他のエラーが発生した場合 + If other errors occur """ self._change_group("removeAdmin") diff --git a/src/wikidot/module/user.py b/src/wikidot/module/user.py index e5ddb96..ebbd509 100644 --- a/src/wikidot/module/user.py +++ b/src/wikidot/module/user.py @@ -14,49 +14,49 @@ class UserCollection(list["AbstractUser"]): """ - ユーザーオブジェクトのコレクションを表すクラス + A class representing a collection of user objects - 複数のユーザーオブジェクトを格納・操作するためのリスト拡張クラス。 - イテレーション操作やユーザー名からの一括取得などの機能を提供する。 + A list extension class for storing and manipulating multiple user objects. + Provides functionality for iteration operations and bulk retrieval from usernames. """ def __iter__(self) -> Iterator["AbstractUser"]: """ - コレクション内のユーザーオブジェクトを順に返すイテレータ + An iterator that returns user objects in the collection sequentially Returns ------- Iterator[AbstractUser] - ユーザーオブジェクトのイテレータ + Iterator of user objects """ return super().__iter__() @staticmethod def from_names(client: "Client", names: list[str], raise_when_not_found: bool = False) -> "UserCollection": """ - ユーザー名のリストからユーザーオブジェクトのコレクションを取得する + Get a collection of user objects from a list of usernames Parameters ---------- client : Client - クライアントインスタンス + Client instance names : list[str] - 検索対象のユーザー名リスト + List of usernames to search for raise_when_not_found : bool, default False - ユーザーが見つからない場合に例外を送出するかどうか (True: 送出する, False: 送出しない) - デフォルトでは送出せず、該当ユーザーは結果に含めない + Whether to raise an exception when a user is not found (True: raise, False: do not raise) + By default, does not raise and excludes the user from results Returns ------- UserCollection - ユーザーオブジェクトのコレクション + Collection of user objects Raises ------ NotFoundException - raise_when_not_foundがTrueで、ユーザーが見つからない場合 + When raise_when_not_found is True and a user is not found NoElementException - ユーザーページの解析中に必要な要素が見つからない場合 + When required elements are not found during user page parsing """ responses = RequestUtil.request( client, @@ -110,25 +110,25 @@ def from_names(client: "Client", names: list[str], raise_when_not_found: bool = @dataclass class AbstractUser: """ - ユーザーオブジェクトの抽象基底クラス + Abstract base class for user objects - すべてのユーザータイプの共通属性と機能を定義する。 - このクラスを直接インスタンス化せず、派生クラスを使用する。 + Defines common attributes and functionality for all user types. + Do not instantiate this class directly; use derived classes instead. Attributes ---------- client : Client - クライアントインスタンス + Client instance id : int | None - ユーザーID + User ID name : str | None - ユーザー名 + Username unix_name : str | None - ユーザーのURLで使用されるUNIX形式の名前 + UNIX-formatted name used in user URLs avatar_url : str | None - ユーザーアバター画像のURL + URL of the user's avatar image ip : str | None - ユーザーのIPアドレス(匿名ユーザーの場合のみ設定される) + User's IP address (only set for anonymous users) """ client: "Client" @@ -140,12 +140,12 @@ class AbstractUser: def __str__(self) -> str: """ - オブジェクトの文字列表現 + String representation of the object Returns ------- str - ユーザーオブジェクトの文字列表現 + String representation of the user object """ return f"{self.__class__.__name__}(id={self.id}, name={self.name}, unix_name={self.unix_name})" @@ -153,24 +153,24 @@ def __str__(self) -> str: @dataclass class User(AbstractUser): """ - 一般のWikidotユーザーを表すクラス + A class representing a regular Wikidot user - 登録済みの通常Wikidotユーザーを表現する。ユーザーIDやユーザー名などの基本情報を保持する。 + Represents a registered normal Wikidot user. Holds basic information such as user ID and username. Attributes ---------- client : Client - クライアントインスタンス + Client instance id : int | None - ユーザーID + User ID name : str | None - ユーザー名 + Username unix_name : str | None - ユーザーのURLで使用されるUNIX形式の名前 + UNIX-formatted name used in user URLs avatar_url : str | None - ユーザーアバター画像のURL + URL of the user's avatar image ip : None - ユーザーのIPアドレス(通常ユーザーでは取得できないためNone) + User's IP address (None for regular users as it cannot be obtained) """ # client: 'Client' @@ -183,31 +183,31 @@ class User(AbstractUser): @staticmethod def from_name(client: "Client", name: str, raise_when_not_found: bool = False) -> Optional["AbstractUser"]: """ - ユーザー名からユーザーオブジェクトを取得する + Get a user object from a username Parameters ---------- client : Client - クライアントインスタンス + Client instance name : str - 検索対象のユーザー名 + Username to search for raise_when_not_found : bool, default False - ユーザーが見つからない場合に例外を送出するかどうか (True: 送出する, False: 送出しない) - デフォルトでは送出せずにNoneを返す + Whether to raise an exception when a user is not found (True: raise, False: do not raise) + By default, returns None without raising Returns ------- AbstractUser - ユーザーオブジェクト + User object Raises ------ NotFoundException - raise_when_not_foundがTrueで、ユーザーが見つからない場合 + When raise_when_not_found is True and the user is not found NoElementException - ユーザーページの解析中に必要な要素が見つからない場合 + When required elements are not found during user page parsing IndexError - ユーザーが見つからない場合(raise_when_not_foundがFalseの場合) + When the user is not found (when raise_when_not_found is False) """ result = UserCollection.from_names(client, [name], raise_when_not_found) if len(result) == 0: @@ -222,25 +222,25 @@ def from_name(client: "Client", name: str, raise_when_not_found: bool = False) - @dataclass class DeletedUser(AbstractUser): """ - 削除されたWikidotユーザーを表すクラス + A class representing a deleted Wikidot user - すでに削除されたユーザーアカウントを表現する。 - 削除されたユーザーには固定の「account deleted」という名前が割り当てられる。 + Represents a user account that has been deleted. + Deleted users are assigned a fixed name of "account deleted". Attributes ---------- client : Client - クライアントインスタンス + Client instance id : int | None - ユーザーID + User ID name : str - ユーザー名(削除されたため"account deleted"固定) + Username (fixed as "account deleted" because the account is deleted) unix_name : str - ユーザーのUNIX名(削除されたため"account_deleted"固定) + UNIX name of the user (fixed as "account_deleted" because the account is deleted) avatar_url : None - ユーザーアバターのURL(削除されたユーザーのためNone) + URL of the user's avatar (None for deleted users) ip : None - ユーザーのIPアドレス(取得できないためNone) + User's IP address (None as it cannot be obtained) """ id: int | None = None @@ -253,25 +253,25 @@ class DeletedUser(AbstractUser): @dataclass class AnonymousUser(AbstractUser): """ - 匿名(非登録)のWikidotユーザーを表すクラス + A class representing an anonymous (unregistered) Wikidot user - 登録せずに投稿した匿名ユーザーを表現する。 - IPアドレスのみを識別情報として持つ。 + Represents an anonymous user who posted without registering. + Has only an IP address as identification information. Attributes ---------- client : Client - クライアントインスタンス + Client instance id : None - ユーザーID(匿名ユーザーのためNone) + User ID (None for anonymous users) name : str - ユーザー名(匿名ユーザーのため"Anonymous"固定) + Username (fixed as "Anonymous" for anonymous users) unix_name : str - ユーザーのUNIX名(匿名ユーザーのため"anonymous"固定) + UNIX name of the user (fixed as "anonymous" for anonymous users) avatar_url : None - ユーザーアバターのURL(匿名ユーザーのためNone) + URL of the user's avatar (None for anonymous users) ip : str - ユーザーのIPアドレス + User's IP address """ id: int | None = None @@ -284,25 +284,25 @@ class AnonymousUser(AbstractUser): @dataclass class GuestUser(AbstractUser): """ - ゲスト投稿したWikidotユーザーを表すクラス + A class representing a guest Wikidot user who posted as a guest - 名前とメールアドレスのみを入力して投稿したゲストユーザーを表現する。 - ユーザー名は任意だが、IDやUNIX名は持たない。 + Represents a guest user who posted by entering only a name and email address. + The username is optional but does not have an ID or UNIX name. Attributes ---------- client : Client - クライアントインスタンス + Client instance id : None - ユーザーID(ゲストユーザーのためNone) + User ID (None for guest users) name : str | None - ユーザー名(ゲスト投稿時に指定した名前) + Username (name specified when posting as a guest) unix_name : None - ユーザーのUNIX名(ゲストユーザーのためNone) + UNIX name of the user (None for guest users) avatar_url : str | None - ユーザーアバターのURL(Gravatarの場合あり) + URL of the user's avatar (may be from Gravatar) ip : None - ユーザーのIPアドレス(取得できないためNone) + User's IP address (None as it cannot be obtained) """ id: int | None = None @@ -315,25 +315,25 @@ class GuestUser(AbstractUser): @dataclass class WikidotUser(AbstractUser): """ - Wikidotシステムユーザーを表すクラス + A class representing the Wikidot system user - Wikidotシステムによる自動投稿や通知を表現するための特殊ユーザー。 - "Wikidot"という固定の名前を持つ。 + A special user for representing automatic posts and notifications by the Wikidot system. + Has a fixed name of "Wikidot". Attributes ---------- client : Client - クライアントインスタンス + Client instance id : None - ユーザーID(システムユーザーのためNone) + User ID (None for system users) name : str - ユーザー名(システムユーザーのため"Wikidot"固定) + Username (fixed as "Wikidot" for system users) unix_name : str - ユーザーのUNIX名(システムユーザーのため"wikidot"固定) + UNIX name of the user (fixed as "wikidot" for system users) avatar_url : None - ユーザーアバターのURL(システムユーザーのためNone) + URL of the user's avatar (None for system users) ip : None - ユーザーのIPアドレス(取得できないためNone) + User's IP address (None as it cannot be obtained) """ id: int | None = None diff --git a/src/wikidot/util/__init__.py b/src/wikidot/util/__init__.py index 1d1f212..11780e4 100644 --- a/src/wikidot/util/__init__.py +++ b/src/wikidot/util/__init__.py @@ -1,7 +1,7 @@ """ -Wikidotサイトを操作するための汎用ユーティリティモジュール +General utility module for operating Wikidot sites -このパッケージには、Wikidotサイトとの通信や操作を効率的に行うための -様々なユーティリティクラスや関数が含まれている。 -文字列処理、リクエスト処理、パース処理などの機能を提供する。 +This package contains various utility classes and functions for +efficiently communicating with and operating Wikidot sites. +It provides functionality for string processing, request processing, parsing, and more. """ diff --git a/src/wikidot/util/async_helper.py b/src/wikidot/util/async_helper.py index e98ae1d..241c618 100644 --- a/src/wikidot/util/async_helper.py +++ b/src/wikidot/util/async_helper.py @@ -1,7 +1,7 @@ -"""非同期実行のヘルパーモジュール +"""Async execution helper module -既存のイベントループ環境でも安全に非同期処理を実行するためのユーティリティを提供する。 -Jupyter NotebookやFastAPI等、イベントループが既に実行中の環境でも動作する。 +Provides utilities for safely executing async operations even in existing event loop environments. +Works in environments where an event loop is already running, such as Jupyter Notebook or FastAPI. """ import asyncio @@ -13,20 +13,20 @@ def run_coroutine(coro: Coroutine[None, None, T]) -> T: - """既存のイベントループ環境でも安全に非同期処理を実行する + """Safely execute async operations even in existing event loop environments - イベントループが既に実行中の場合は別スレッドで実行し、 - そうでない場合は新しいイベントループを作成して実行する。 + If an event loop is already running, execute in a separate thread. + Otherwise, create a new event loop and execute. Parameters ---------- coro : Coroutine - 実行する非同期コルーチン + Async coroutine to execute Returns ------- T - コルーチンの戻り値 + Return value of the coroutine Examples -------- @@ -36,18 +36,18 @@ def run_coroutine(coro: Coroutine[None, None, T]) -> T: >>> result 42 """ - # 既存のイベントループが実行中かチェック + # Check if an existing event loop is running try: asyncio.get_running_loop() except RuntimeError: - # 実行中のループがない場合は新しいループを作成 + # If no running loop, create a new loop loop = asyncio.new_event_loop() try: return loop.run_until_complete(coro) finally: loop.close() else: - # 実行中のループがある場合は別スレッドで実行 + # If there is a running loop, execute in a separate thread def _run_in_thread() -> T: new_loop = asyncio.new_event_loop() asyncio.set_event_loop(new_loop) diff --git a/src/wikidot/util/parser/__init__.py b/src/wikidot/util/parser/__init__.py index 567baf1..f765189 100644 --- a/src/wikidot/util/parser/__init__.py +++ b/src/wikidot/util/parser/__init__.py @@ -1,8 +1,8 @@ """ -Wikidotサイトの各種要素をパースするためのユーティリティモジュール +Utility module for parsing various elements of Wikidot sites -このパッケージには、Wikidotサイトから取得したHTMLや特定の形式の要素を -パースするためのユーティリティ関数が含まれている。 +This package contains utility functions for parsing HTML and specific format elements +retrieved from Wikidot sites. """ from .odate import odate_parse as odate diff --git a/src/wikidot/util/parser/odate.py b/src/wikidot/util/parser/odate.py index 0083291..c2b9002 100644 --- a/src/wikidot/util/parser/odate.py +++ b/src/wikidot/util/parser/odate.py @@ -4,22 +4,22 @@ def odate_parse(odate_element: bs4.Tag) -> datetime: - """odate要素を解析し、datetimeオブジェクトを返す + """Parse an odate element and return a datetime object Parameters ---------- odate_element: bs4.Tag - odate要素 + odate element Returns ------- datetime - odate要素が表す日時 + Date and time represented by the odate element Raises ------ ValueError - odate要素が有効なunix timeを含んでいない場合 + If the odate element does not contain a valid unix time """ _odate_classes = odate_element["class"] diff --git a/src/wikidot/util/parser/user.py b/src/wikidot/util/parser/user.py index 248dc0e..4d47689 100644 --- a/src/wikidot/util/parser/user.py +++ b/src/wikidot/util/parser/user.py @@ -9,20 +9,20 @@ def user_parse(client: "Client", elem: bs4.Tag) -> user.AbstractUser: - """printuser要素をパースし、ユーザーオブジェクトを返す + """Parse a printuser element and return a user object Parameters ---------- elem: bs4.Tag - パース対象の要素(printuserクラスがついた要素) + Element to parse (element with printuser class) client: Client - クライアント + Client Returns ------- user.AbstractUser - パースされて得られたユーザーオブジェクト - User | DeletedUser | AnonymousUser | GuestUser | WikidotUser のいずれか + Parsed user object + One of User | DeletedUser | AnonymousUser | GuestUser | WikidotUser """ if ("class" in elem.attrs and "deleted" in elem["class"]) or ( diff --git a/src/wikidot/util/quick_module.py b/src/wikidot/util/quick_module.py index 41b0052..9445b58 100644 --- a/src/wikidot/util/quick_module.py +++ b/src/wikidot/util/quick_module.py @@ -7,14 +7,14 @@ @dataclass class QMCUser: - """QuickModuleから返されるユーザー情報を格納するクラス + """Class to store user information returned from QuickModule Attributes ---------- id: int - ユーザーID + User ID name: str - ユーザー名 + User name """ id: int @@ -23,14 +23,14 @@ class QMCUser: @dataclass class QMCPage: - """QuickModuleから返されるページ情報を格納するクラス + """Class to store page information returned from QuickModule Attributes ---------- title: str - ページタイトル + Page title unix_name: str - ページのUNIX名 + UNIX name of the page """ title: str @@ -47,16 +47,16 @@ def _request( site_id: int, query: str, ) -> dict[str, Any]: - """リクエストを送信する + """Send a request Parameters ---------- module_name: str - モジュール名 + Module name site_id: int - サイトID + Site ID query: str - クエリ + Query """ if module_name not in [ @@ -82,27 +82,27 @@ def _generic_lookup( item_mapping: Callable[[type[T], dict[str, Any]], T], ) -> list[T]: """ - 汎用的な検索メソッド + Generic lookup method Parameters ---------- module_name: str - モジュール名 + Module name site_id: int - サイトID + Site ID query: str - クエリ + Query response_key: str - レスポンスから取得するキー + Key to retrieve from response item_class: type - 返すアイテムのクラス + Class of items to return item_mapping: callable - レスポンスアイテムからクラスインスタンスへの変換関数 + Conversion function from response items to class instances Returns ------- list - アイテムのリスト + List of items """ items = QuickModule._request(module_name, site_id, query)[response_key] # member_lookupの特殊ケースを処理 @@ -112,19 +112,19 @@ def _generic_lookup( @staticmethod def member_lookup(site_id: int, query: str) -> list[QMCUser]: - """メンバーを検索する + """Search for members Parameters ---------- site_id: int - サイトID + Site ID query: str - クエリ + Query Returns ------- list[QMCUser] - ユーザーのリスト + List of users """ return QuickModule._generic_lookup( "MemberLookupQModule", @@ -137,19 +137,19 @@ def member_lookup(site_id: int, query: str) -> list[QMCUser]: @staticmethod def user_lookup(site_id: int, query: str) -> list[QMCUser]: - """ユーザーを検索する + """Search for users Parameters ---------- site_id: int - サイトID + Site ID query: str - クエリ + Query Returns ------- list[QMCUser] - ユーザーのリスト + List of users """ return QuickModule._generic_lookup( "UserLookupQModule", @@ -162,19 +162,19 @@ def user_lookup(site_id: int, query: str) -> list[QMCUser]: @staticmethod def page_lookup(site_id: int, query: str) -> list[QMCPage]: - """ページを検索する + """Search for pages Parameters ---------- site_id: int - サイトID + Site ID query: str - クエリ + Query Returns ------- list[QMCPage] - ページのリスト + List of pages """ return QuickModule._generic_lookup( "PageLookupQModule", diff --git a/src/wikidot/util/requestutil.py b/src/wikidot/util/requestutil.py index 89f5fc7..a65d276 100644 --- a/src/wikidot/util/requestutil.py +++ b/src/wikidot/util/requestutil.py @@ -14,24 +14,24 @@ class RequestUtil: def request( client: "Client", method: str, urls: list[str], return_exceptions: bool = False ) -> list[httpx.Response | Exception]: - """GETリクエストを送信する + """Send GET request Parameters ---------- client: Client - クライアント + Client instance method: str - リクエストメソッド + Request method urls: list[str] - URLのリスト + List of URLs return_exceptions: bool - 例外を返すかどうか (True: 返す, False: 例外を送出) - デフォルトでは例外を送出 + Whether to return exceptions (True: return, False: raise) + Default is to raise exceptions Returns ------- list[httpx.Response | Exception] - レスポンスのリスト + List of responses """ config = client.amc_client.config semaphore = asyncio.Semaphore(config.semaphore_limit) diff --git a/src/wikidot/util/stringutil.py b/src/wikidot/util/stringutil.py index 7f6bed0..8c34921 100644 --- a/src/wikidot/util/stringutil.py +++ b/src/wikidot/util/stringutil.py @@ -6,17 +6,17 @@ class StringUtil: @staticmethod def to_unix(target_str: str) -> str: - """Unix形式に文字列を変換する + """Convert a string to Unix format Parameters ---------- target_str: str - 変換対象の文字列 + String to convert Returns ------- str - 変換された文字列 + Converted string """ # MEMO: legacy wikidotの実装に合わせている diff --git a/src/wikidot/util/table/__init__.py b/src/wikidot/util/table/__init__.py index 126d6e0..90be41c 100644 --- a/src/wikidot/util/table/__init__.py +++ b/src/wikidot/util/table/__init__.py @@ -1,6 +1,6 @@ """ -文字変換テーブルを含むモジュール +Module containing character conversion tables -このパッケージには、特殊文字や非ASCII文字の変換に使用されるマッピングテーブルが含まれている。 -主にURL生成やunix名変換のための文字変換処理で使用される。 +This package contains mapping tables used for converting special characters and non-ASCII characters. +Primarily used for character conversion processing in URL generation and unix name conversion. """ diff --git a/src/wikidot/util/table/char_table.py b/src/wikidot/util/table/char_table.py index 02d529b..486827f 100644 --- a/src/wikidot/util/table/char_table.py +++ b/src/wikidot/util/table/char_table.py @@ -1,16 +1,16 @@ """ -特殊記号・非英語アルファベットを英語アルファベットに変換するためのマッピングテーブル +Mapping table for converting special symbols and non-English alphabets to English alphabets -このモジュールは、非ASCII文字を対応するASCII文字に変換するためのマッピングを提供する。 -主にURL生成やページ名のunix形式への変換時に使用される。 +This module provides mappings for converting non-ASCII characters to their corresponding ASCII characters. +Primarily used for URL generation and converting page names to unix format. Attributes ---------- special_char_map: dict[str, str] - 特殊文字からASCII文字への変換マッピング辞書 + Dictionary mapping special characters to ASCII characters """ -# 特殊記号・非英語アルファベットを英語アルファベットに変換する +# Convert special symbols and non-English alphabets to English alphabets special_char_map = { "À": "a", "Á": "a",