fix(ci): fix black/ruff failures, add CoC and PR template

- Fix Python formatting (sync no longer strips blank lines from .py files)
- Remove test_community_build.py (tests private sync module)
- Fix ruff warnings in test files
- Add CODE_OF_CONDUCT.md
- Add .github/PULL_REQUEST_TEMPLATE.md

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
airano
2026-02-17 18:19:39 +03:30
parent c9083d86b1
commit c73e39f6e4
135 changed files with 1185 additions and 317 deletions

View File

@@ -12,16 +12,19 @@ from typing import Any
import aiohttp
class ConfigurationError(Exception):
"""Raised when site configuration is invalid or incomplete."""
pass
class AuthenticationError(Exception):
"""Raised when authentication fails (401/403)."""
pass
class WordPressClient:
"""
WordPress REST API client for HTTP communication.

View File

@@ -5,6 +5,7 @@ from typing import Any
from plugins.wordpress.client import WordPressClient
def get_tool_specifications() -> list[dict[str, Any]]:
"""Return tool specifications for ToolGenerator"""
return [
@@ -154,6 +155,7 @@ def get_tool_specifications() -> list[dict[str, Any]]:
},
]
class CommentsHandler:
"""Handle comment-related operations for WordPress"""

View File

@@ -5,6 +5,7 @@ from typing import Any
from plugins.wordpress.client import WordPressClient
def get_tool_specifications() -> list[dict[str, Any]]:
"""Return tool specifications for ToolGenerator"""
return [
@@ -219,6 +220,7 @@ def get_tool_specifications() -> list[dict[str, Any]]:
},
]
class CouponsHandler:
"""Handle coupon-related operations for WooCommerce"""

View File

@@ -5,6 +5,7 @@ from typing import Any
from plugins.wordpress.client import WordPressClient
def get_tool_specifications() -> list[dict[str, Any]]:
"""Return tool specifications for ToolGenerator"""
return [
@@ -141,6 +142,7 @@ def get_tool_specifications() -> list[dict[str, Any]]:
},
]
class CustomersHandler:
"""Handle WooCommerce customer operations"""

View File

@@ -7,6 +7,7 @@ import aiohttp
from plugins.wordpress.client import WordPressClient
def get_tool_specifications() -> list[dict[str, Any]]:
"""Return tool specifications for ToolGenerator"""
return [
@@ -155,6 +156,7 @@ def get_tool_specifications() -> list[dict[str, Any]]:
},
]
class MediaHandler:
"""Handle media-related operations for WordPress"""

View File

@@ -5,6 +5,7 @@ from typing import Any
from plugins.wordpress.client import WordPressClient
def get_tool_specifications() -> list[dict[str, Any]]:
"""Return tool specifications for ToolGenerator"""
return [
@@ -148,6 +149,7 @@ def get_tool_specifications() -> list[dict[str, Any]]:
},
]
class MenusHandler:
"""Handle menu-related operations for WordPress"""

View File

@@ -5,6 +5,7 @@ from typing import Any
from plugins.wordpress.client import WordPressClient
def get_tool_specifications() -> list[dict[str, Any]]:
"""Return tool specifications for ToolGenerator"""
return [
@@ -196,6 +197,7 @@ def get_tool_specifications() -> list[dict[str, Any]]:
},
]
class OrdersHandler:
"""Handle WooCommerce order-related operations"""

View File

@@ -7,12 +7,14 @@ from typing import Any
from plugins.wordpress.client import WordPressClient
def _count_words(html_content: str) -> int:
"""Strip HTML tags and count words."""
text = re.sub(r"<[^>]+>", " ", html_content)
text = re.sub(r"\s+", " ", text).strip()
return len(text.split()) if text else 0
def _strip_html(html_content: str, max_chars: int = 500) -> str:
"""Strip HTML tags and return first max_chars characters."""
text = re.sub(r"<[^>]+>", " ", html_content)
@@ -21,6 +23,7 @@ def _strip_html(html_content: str, max_chars: int = 500) -> str:
return text[:max_chars] + "..."
return text
def get_tool_specifications() -> list[dict[str, Any]]:
"""Return tool specifications for ToolGenerator"""
return [
@@ -454,6 +457,7 @@ def get_tool_specifications() -> list[dict[str, Any]]:
},
]
class PostsHandler:
"""Handle post-related operations for WordPress"""

View File

@@ -7,12 +7,14 @@ from typing import Any
from plugins.wordpress.client import WordPressClient
def _count_words(html_content: str) -> int:
"""Strip HTML tags and count words."""
text = re.sub(r"<[^>]+>", " ", html_content)
text = re.sub(r"\s+", " ", text).strip()
return len(text.split()) if text else 0
def _strip_html(html_content: str, max_chars: int = 500) -> str:
"""Strip HTML tags and return first max_chars characters."""
text = re.sub(r"<[^>]+>", " ", html_content)
@@ -21,6 +23,7 @@ def _strip_html(html_content: str, max_chars: int = 500) -> str:
return text[:max_chars] + "..."
return text
def normalize_id_list(value: Any, field_name: str = "item") -> list[dict[str, Any]]:
"""
Convert various formats of category/tag IDs to WooCommerce API format.
@@ -100,6 +103,7 @@ def normalize_id_list(value: Any, field_name: str = "item") -> list[dict[str, An
return result
def get_tool_specifications() -> list[dict[str, Any]]:
"""Return tool specifications for ToolGenerator"""
return [
@@ -589,6 +593,7 @@ def get_tool_specifications() -> list[dict[str, Any]]:
},
]
class ProductsHandler:
"""Handle WooCommerce product-related operations"""

View File

@@ -5,6 +5,7 @@ from typing import Any
from plugins.wordpress.client import WordPressClient
def get_tool_specifications() -> list[dict[str, Any]]:
"""Return tool specifications for ToolGenerator"""
return [
@@ -86,6 +87,7 @@ def get_tool_specifications() -> list[dict[str, Any]]:
},
]
class ReportsHandler:
"""Handle WooCommerce reporting operations"""

View File

@@ -5,6 +5,7 @@ from typing import Any
from plugins.wordpress.client import WordPressClient
def get_tool_specifications() -> list[dict[str, Any]]:
"""Return tool specifications for ToolGenerator"""
return [
@@ -163,6 +164,7 @@ def get_tool_specifications() -> list[dict[str, Any]]:
},
]
class SEOHandler:
"""Handle SEO-related operations for WordPress (Yoast SEO and RankMath)"""

View File

@@ -5,6 +5,7 @@ from typing import Any
from plugins.wordpress.client import WordPressClient
def get_tool_specifications() -> list[dict[str, Any]]:
"""Return tool specifications for ToolGenerator"""
return [
@@ -69,6 +70,7 @@ def get_tool_specifications() -> list[dict[str, Any]]:
},
]
class SiteHandler:
"""Handle site management operations for WordPress"""

View File

@@ -5,6 +5,7 @@ from typing import Any
from plugins.wordpress.client import WordPressClient
def get_tool_specifications() -> list[dict[str, Any]]:
"""Return tool specifications for ToolGenerator"""
return [
@@ -269,6 +270,7 @@ def get_tool_specifications() -> list[dict[str, Any]]:
},
]
class TaxonomyHandler:
"""Handle taxonomy-related operations for WordPress"""

View File

@@ -5,6 +5,7 @@ from typing import Any
from plugins.wordpress.client import WordPressClient
def get_tool_specifications() -> list[dict[str, Any]]:
"""Return tool specifications for ToolGenerator"""
return [
@@ -46,6 +47,7 @@ def get_tool_specifications() -> list[dict[str, Any]]:
},
]
class UsersHandler:
"""Handle user-related operations for WordPress"""

View File

@@ -5,6 +5,7 @@ from typing import Any
from plugins.wordpress.wp_cli import WPCLIManager
def get_tool_specifications() -> list[dict[str, Any]]:
"""Return tool specifications for ToolGenerator"""
return [
@@ -183,6 +184,7 @@ def get_tool_specifications() -> list[dict[str, Any]]:
},
]
class WPCLIHandler:
"""Handle WP-CLI operations for WordPress"""

View File

@@ -13,6 +13,7 @@ from plugins.base import BasePlugin
from plugins.wordpress import handlers
from plugins.wordpress.client import WordPressClient
class WordPressPlugin(BasePlugin):
"""
WordPress project plugin - Option B architecture.

View File

@@ -14,6 +14,7 @@ import aiohttp
from plugins.base import BasePlugin
from plugins.wordpress.wp_cli import WPCLIManager
class WordPressPlugin(BasePlugin):
"""
WordPress project plugin.

View File

@@ -8,6 +8,7 @@ from typing import Any
from pydantic import BaseModel, ConfigDict, Field, field_validator
class PaginationParams(BaseModel):
"""Pagination parameters for list endpoints"""
@@ -16,6 +17,7 @@ class PaginationParams(BaseModel):
model_config = ConfigDict(extra="forbid")
class StatusFilter(BaseModel):
"""Status filter for posts/pages/products"""
@@ -29,6 +31,7 @@ class StatusFilter(BaseModel):
raise ValueError(f"Status must be one of: {', '.join(allowed)}")
return v
class ErrorResponse(BaseModel):
"""Standard error response"""
@@ -37,6 +40,7 @@ class ErrorResponse(BaseModel):
code: str | None = Field(None, description="Error code")
details: dict[str, Any] | None = Field(None, description="Additional error details")
class SuccessResponse(BaseModel):
"""Standard success response"""

View File

@@ -6,6 +6,7 @@ Validation schemas for WordPress media library operations.
from pydantic import BaseModel, ConfigDict, Field, HttpUrl, field_validator
class MediaBase(BaseModel):
"""Base media schema"""
@@ -16,6 +17,7 @@ class MediaBase(BaseModel):
caption: str | None = Field(None, description="Media caption")
description: str | None = Field(None, description="Media description")
class MediaUpload(MediaBase):
"""Schema for uploading media from URL"""
@@ -33,12 +35,14 @@ class MediaUpload(MediaBase):
raise ValueError("Filename too long (max 255 characters)")
return v
class MediaUpdate(MediaBase):
"""Schema for updating media metadata"""
# All fields optional for updates
pass
class MediaResponse(BaseModel):
"""Schema for media response data"""

View File

@@ -8,6 +8,7 @@ from typing import Any
from pydantic import BaseModel, ConfigDict, EmailStr, Field, field_validator
class OrderLineItem(BaseModel):
"""Schema for order line item"""
@@ -19,6 +20,7 @@ class OrderLineItem(BaseModel):
subtotal: str | None = Field(None, description="Line subtotal")
total: str | None = Field(None, description="Line total")
class ShippingAddress(BaseModel):
"""Schema for shipping address"""
@@ -34,12 +36,14 @@ class ShippingAddress(BaseModel):
postcode: str | None = Field(None, description="Postal code")
country: str | None = Field(None, description="Country code (ISO 3166-1 alpha-2)")
class BillingAddress(ShippingAddress):
"""Schema for billing address (extends shipping)"""
email: EmailStr | None = Field(None, description="Email address")
phone: str | None = Field(None, description="Phone number")
class OrderBase(BaseModel):
"""Base order schema"""
@@ -76,6 +80,7 @@ class OrderBase(BaseModel):
raise ValueError(f"Status must be one of: {', '.join(allowed)}")
return v
class OrderCreate(OrderBase):
"""Schema for creating a new order"""
@@ -85,12 +90,14 @@ class OrderCreate(OrderBase):
model_config = ConfigDict(extra="allow")
class OrderUpdate(OrderBase):
"""Schema for updating an existing order"""
# All fields optional for updates
pass
class OrderStatusUpdate(BaseModel):
"""Schema for updating order status"""
@@ -112,6 +119,7 @@ class OrderStatusUpdate(BaseModel):
raise ValueError(f"Status must be one of: {', '.join(allowed)}")
return v
class OrderResponse(BaseModel):
"""Schema for order response data"""
@@ -126,6 +134,7 @@ class OrderResponse(BaseModel):
shipping: dict[str, Any]
line_items: list[dict[str, Any]]
class CustomerBase(BaseModel):
"""Base customer schema"""
@@ -138,6 +147,7 @@ class CustomerBase(BaseModel):
billing: BillingAddress | None = Field(None, description="Billing address")
shipping: ShippingAddress | None = Field(None, description="Shipping address")
class CustomerCreate(CustomerBase):
"""Schema for creating a new customer"""
@@ -145,6 +155,7 @@ class CustomerCreate(CustomerBase):
model_config = ConfigDict(extra="allow")
class CustomerUpdate(CustomerBase):
"""Schema for updating an existing customer"""

View File

@@ -6,6 +6,7 @@ Validation schemas for WordPress posts, pages, and custom post types.
from pydantic import BaseModel, ConfigDict, Field, field_validator
class PostBase(BaseModel):
"""Base post schema with common fields"""
@@ -44,6 +45,7 @@ class PostBase(BaseModel):
raise ValueError("Status must be 'open' or 'closed'")
return v
class PostCreate(PostBase):
"""Schema for creating a new post"""
@@ -52,12 +54,14 @@ class PostCreate(PostBase):
model_config = ConfigDict(extra="allow")
class PostUpdate(PostBase):
"""Schema for updating an existing post"""
# All fields optional for updates
pass
class PostResponse(BaseModel):
"""Schema for post response data"""
@@ -77,6 +81,7 @@ class PostResponse(BaseModel):
categories: list[int]
tags: list[int]
class PageCreate(PostCreate):
"""Schema for creating a new page"""
@@ -84,6 +89,7 @@ class PageCreate(PostCreate):
menu_order: int | None = Field(None, description="Menu order")
template: str | None = Field(None, description="Page template")
class PageUpdate(PostUpdate):
"""Schema for updating an existing page"""
@@ -91,11 +97,13 @@ class PageUpdate(PostUpdate):
menu_order: int | None = Field(None, description="Menu order")
template: str | None = Field(None, description="Page template")
class CustomPostCreate(PostCreate):
"""Schema for creating custom post types"""
post_type: str = Field(..., description="Custom post type")
class CustomPostUpdate(PostUpdate):
"""Schema for updating custom post types"""

View File

@@ -8,6 +8,7 @@ from typing import Any
from pydantic import BaseModel, ConfigDict, Field, field_validator
class ProductBase(BaseModel):
"""Base product schema"""
@@ -71,18 +72,21 @@ class ProductBase(BaseModel):
raise ValueError(f"Stock status must be one of: {', '.join(allowed)}")
return v
class ProductCreate(ProductBase):
"""Schema for creating a new product"""
name: str = Field(..., min_length=1, description="Product name (required)")
type: str = Field("simple", description="Product type")
class ProductUpdate(ProductBase):
"""Schema for updating an existing product"""
# All fields optional for updates
pass
class ProductResponse(BaseModel):
"""Schema for product response data"""
@@ -100,6 +104,7 @@ class ProductResponse(BaseModel):
stock_status: str
permalink: str
class ProductCategory(BaseModel):
"""Schema for product category"""
@@ -112,6 +117,7 @@ class ProductCategory(BaseModel):
display: str | None = Field("default", description="Display type")
image: dict[str, Any] | None = Field(None, description="Category image")
class ProductVariation(BaseModel):
"""Schema for product variation"""
@@ -128,6 +134,7 @@ class ProductVariation(BaseModel):
attributes: list[dict[str, Any]] | None = Field(None, description="Variation attributes")
image: dict[str, Any] | None = Field(None, description="Variation image")
class ProductAttribute(BaseModel):
"""Schema for product attribute"""

View File

@@ -6,6 +6,7 @@ Validation schemas for SEO plugin data (Yoast, RankMath, etc.).
from pydantic import BaseModel, ConfigDict, Field, field_validator
class SEOData(BaseModel):
"""Schema for SEO data (read)"""
@@ -23,6 +24,7 @@ class SEOData(BaseModel):
twitter_image: str | None = Field(None, description="Twitter card image URL")
robots: list[str] | None = Field(None, description="Robots meta tags")
class SEOUpdate(BaseModel):
"""Schema for SEO data updates"""
@@ -61,6 +63,7 @@ class SEOUpdate(BaseModel):
pass
return v
class YoastSEO(SEOData):
"""Yoast SEO specific data"""
@@ -70,6 +73,7 @@ class YoastSEO(SEOData):
yoast_wpseo_metadesc: str | None = Field(None, description="Yoast meta description")
yoast_wpseo_title: str | None = Field(None, description="Yoast SEO title")
class RankMathSEO(SEOData):
"""RankMath SEO specific data"""

View File

@@ -20,6 +20,7 @@ import json
import logging
from typing import Any
class WPCLIManager:
"""
Manages WP-CLI command execution for WordPress containers.