From 0401a2e075bf2d9052d78256cba7c38d868c6140 Mon Sep 17 00:00:00 2001 From: Nick Moreton Date: Wed, 21 May 2025 21:46:35 +0100 Subject: [PATCH 1/3] Remove click cli.py and replace with Makefile --- Makefile | 218 +++++++++++++++++++++++++++++++++ commands/cli.py | 315 ------------------------------------------------ 2 files changed, 218 insertions(+), 315 deletions(-) create mode 100644 Makefile delete mode 100644 commands/cli.py diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..9de6fa2 --- /dev/null +++ b/Makefile @@ -0,0 +1,218 @@ +# Makefile for Wagtail-WordPress Connector + +# Constants +WORDPRESS_ROOT = wordpress.docker +WORDPRESS_URL = http://localhost:8888 +WORDPRESS_API = wp-json/wp/v2 +DC = docker-compose + +# Help command +.PHONY: help +help: + @echo "Wagtail-WordPress Connector Commands" + @echo "" + @echo "WordPress Container Commands:" + @echo " make wp-build - Wordpress: initial setup" + @echo " make wp-up - Wordpress: start the container" + @echo " make wp-load - Wordpress: import the demo data" + @echo " make wp-down - Wordpress: stop the container" + @echo " make wp-destroy - Wordpress: destroy the container" + @echo "" + @echo "Wagtail Virtual Environment Commands:" + @echo " make wt-migrate - Wagtail: run migrations" + @echo " make wt-superuser - Wagtail: create superuser" + @echo " make wt-run - Wagtail: run the server" + @echo " make wt-fixtree - Wagtail: fix the tree" + @echo "" + @echo "Django Import Commands:" + @echo " make import-authors - Django: import authors from wordpress" + @echo " make import-categories - Django: import categories from wordpress" + @echo " make import-tags - Django: import tags from wordpress" + @echo " make import-pages - Django: import pages from wordpress" + @echo " make import-posts - Django: import posts from wordpress" + @echo " make import-media - Django: import media from wordpress" + @echo " make import-comments - Django: import comments from wordpress" + @echo " make import-all - Django: import all data from wordpress" + @echo "" + @echo "Node.js Commands:" + @echo " make node-setup - Install Node.js dependencies" + @echo " make node-build - Build all frontend assets for production" + @echo " make node-start - Start the frontend development server" + @echo " make node-styles - Compile CSS styles" + @echo " make node-styles-watch - Watch and compile CSS styles" + @echo " make node-scripts - Compile JavaScript" + @echo " make node-scripts-watch - Watch and compile JavaScript" + @echo "" + @echo "Convenience Commands:" + @echo " make devstart - Run all commands to set up and start the development environment" + @echo " make devstop - Stop all running services" + @echo " make devdestroy - Destroy and cleanup wordpress and wagtail" + +# WordPress Commands +.PHONY: wp-build +wp-build: + @echo "WordPress: initial setup" + @if [ ! -f "$(WORDPRESS_ROOT)/.env" ]; then \ + cp $(WORDPRESS_ROOT)/.env.example $(WORDPRESS_ROOT)/.env; \ + fi + @mkdir -p $(WORDPRESS_ROOT)/wp-content/plugins + @cd $(WORDPRESS_ROOT)/wp-content/plugins && \ + if [ ! -d "wp-graphql-offset-pagination" ]; then \ + git clone https://github.com/valu-digital/wp-graphql-offset-pagination.git; \ + else \ + echo "Plugin wp-graphql-offset-pagination already exists"; \ + fi + +.PHONY: wp-up +wp-up: + @echo "WordPress: start the container" + @cd $(WORDPRESS_ROOT) && $(DC) up -d + +.PHONY: wp-down +wp-down: + @echo "WordPress: stop the container" + @cd $(WORDPRESS_ROOT) && $(DC) down + +.PHONY: wp-destroy +wp-destroy: + @echo "WordPress: destroy the container" + @cd $(WORDPRESS_ROOT) && $(DC) down --volumes + @echo "Do you want to clean up the files? (y/n)" + @read cleanup; \ + if [ "$$cleanup" = "y" ]; then \ + if [ -f "$(WORDPRESS_ROOT)/.env" ]; then \ + rm $(WORDPRESS_ROOT)/.env; \ + echo "Removed .env file"; \ + fi; \ + if [ -d "$(WORDPRESS_ROOT)/wp-content" ]; then \ + rm -rf $(WORDPRESS_ROOT)/wp-content; \ + echo "Removed wp-content directory"; \ + fi; \ + if [ -d "$(WORDPRESS_ROOT)/xml" ]; then \ + rm -rf $(WORDPRESS_ROOT)/xml; \ + echo "Removed xml directory"; \ + fi; \ + if [ -f "db.sqlite3" ]; then \ + rm -rf db.sqlite3; \ + echo "Removed wagtail database"; \ + fi; \ + fi + +.PHONY: wp-load +wp-load: + @echo "WordPress: import the demo data" + @if [ -z "$$(cd $(WORDPRESS_ROOT) && $(DC) ps | grep wordpress)" ]; then \ + $(MAKE) wp-up; \ + fi + @cd $(WORDPRESS_ROOT) && $(DC) exec -T wordpress bin/init.sh + +# Wagtail/Django Commands +.PHONY: wt-migrate +wt-migrate: + @echo "Wagtail: run migrations" + uv run manage.py migrate + +.PHONY: wt-superuser +wt-superuser: + @echo "Wagtail: create superuser" + uv run manage.py createsuperuser + +.PHONY: wt-run +wt-run: + @echo "Wagtail: run the server" + uv run manage.py runserver + +.PHONY: wt-fixtree +wt-fixtree: + @echo "Wagtail: fix the tree" + uv run manage.py fixtree + +# Import Commands +.PHONY: import-authors +import-authors: + @echo "Django: import authors from wordpress" + uv run manage.py import $(WORDPRESS_URL)/$(WORDPRESS_API)/users WPAuthor + +.PHONY: import-categories +import-categories: + @echo "Django: import categories from wordpress" + uv run manage.py import $(WORDPRESS_URL)/$(WORDPRESS_API)/categories WPCategory + +.PHONY: import-tags +import-tags: + @echo "Django: import tags from wordpress" + uv run manage.py import $(WORDPRESS_URL)/$(WORDPRESS_API)/tags WPTag + +.PHONY: import-pages +import-pages: + @echo "Django: import pages from wordpress" + uv run manage.py import $(WORDPRESS_URL)/$(WORDPRESS_API)/pages WPPage + +.PHONY: import-posts +import-posts: + @echo "Django: import posts from wordpress" + uv run manage.py import $(WORDPRESS_URL)/$(WORDPRESS_API)/posts WPPost + +.PHONY: import-media +import-media: + @echo "Django: import media from wordpress" + uv run manage.py import $(WORDPRESS_URL)/$(WORDPRESS_API)/media WPMedia + +.PHONY: import-comments +import-comments: + @echo "Django: import comments from wordpress" + uv run manage.py import $(WORDPRESS_URL)/$(WORDPRESS_API)/comments WPComment + +.PHONY: import-all +import-all: import-authors import-categories import-tags import-pages import-posts import-media import-comments + @echo "Imported all WordPress data" + +# Convenience Commands +.PHONY: devstart +devstart: wp-build wp-up wp-load wt-migrate wt-superuser import-all wt-run + @echo "Development environment started" + +.PHONY: devstop +devstop: wp-down + @echo "Development environment stopped" + @echo "Note: There is no direct equivalent for 'dj stop' and 'wt stop' in the CLI, but WordPress container has been stopped." + +.PHONY: devdestroy +devdestroy: wp-destroy + @echo "Development environment destroyed" + +# Node.js Commands +.PHONY: node-setup +node-setup: + @echo "Installing Node.js dependencies" + @npm install + +.PHONY: node-build +node-build: + @echo "Building frontend assets" + @npm run build + +.PHONY: node-start +node-start: + @echo "Starting the frontend development server" + @npm start + +.PHONY: node-styles +node-styles: + @echo "Compiling CSS styles" + @npm run styles + +.PHONY: node-styles-watch +node-styles-watch: + @echo "Watching and compiling CSS styles" + @npm run styles:watch + +.PHONY: node-scripts +node-scripts: + @echo "Compiling JavaScript" + @npm run scripts + +.PHONY: node-scripts-watch +node-scripts-watch: + @echo "Watching and compiling JavaScript" + @npm run scripts:watch diff --git a/commands/cli.py b/commands/cli.py deleted file mode 100644 index 69ce60e..0000000 --- a/commands/cli.py +++ /dev/null @@ -1,315 +0,0 @@ -import subprocess -from pathlib import Path - -import rich_click as click - -# constants -ROOT = Path(__file__).parent.parent -WORDPRESS_ROOT = ROOT / "wordpress.docker" -WORDPRESS_URL = "http://localhost:8888" -WORDPRESS_API = "wp-json/wp/v2" -DC = "docker-compose" - - -@click.group() -def wp(): - """ - Set up a WORDPRESS container with a running wordpress site - - It is intend to be a local development tool and not suitable for a production environment. - """ - - -@click.group() -def wt(): - """ - Run commands against a WAGTIAL site, running in a virtual environment. - - It is intend to be a local development tool and probably would be run differently in a production environment. - """ - - -@click.group() -def dj(): - """ - Run commands against a DJANGO site, running in a virtual environment. - - It is intend to be a local development tool and probably would be run differently in a production environment. - """ - - -"""WORDPRESS COMMANDS""" - - -@wp.command() -def build(): - """Wordpress: initial setup""" - - # copy the .env.example file to .env if not exists - env_file = WORDPRESS_ROOT / ".env" - if not env_file.exists(): - with open(WORDPRESS_ROOT / ".env.example") as f: - env_content = f.read() - with open(WORDPRESS_ROOT / ".env", "w") as f2: - f2.write(env_content) - - # create directory for plugins - plugins_dir = WORDPRESS_ROOT / "wp-content/plugins" - if not plugins_dir.exists(): - plugins_dir.mkdir(parents=True) - - # clone the plugins into the plugins directory, match with the plugins in init.sh - plugins = [ - "https://github.com/valu-digital/wp-graphql-offset-pagination.git", - ] - - for plugin in plugins: - if not Path(plugins_dir / Path(plugin).stem).exists(): - subprocess.run(["git", "clone", plugin], cwd=plugins_dir) - else: - print(f"Plugin {plugin} already exists") - - -@wp.command() -def up(): - """Wordpress: start the container""" - subprocess.run([DC, "up", "-d"], cwd=WORDPRESS_ROOT) - - -@wp.command() -def down(): - """Wordpress: stop the container""" - subprocess.run([DC, "down"], cwd=WORDPRESS_ROOT) - - -@wp.command() -def destroy(): - """Wordpress: destroy the container""" - subprocess.run([DC, "down", "--volumes"], cwd=WORDPRESS_ROOT) - - cleanup = click.prompt("Do you want to clean up the files? (y/n)", type=str) - - if cleanup == "y": - env_file = WORDPRESS_ROOT / ".env" - if env_file.exists(): - env_file.unlink() - print("Removed .env file") - - wp_content = WORDPRESS_ROOT / "wp-content" - if wp_content.exists(): - subprocess.run(["rm", "-rf", WORDPRESS_ROOT / "wp-content"]) - print("Removed wp-content directory") - - wp_xml = WORDPRESS_ROOT / "xml" - if wp_xml.exists(): - subprocess.run(["rm", "-rf", WORDPRESS_ROOT / "xml"]) - print("Removed xml directory") - - wt_database = ROOT / "db.sqlite3" - if wt_database.exists(): - subprocess.run(["rm", "-rf", ROOT / "db.sqlite3"]) - print("Removed wagtail database") - - -@wp.command() -def load(): - """Wordpress: import the demo data""" - # if docker-compose is not running, start it - running = subprocess.run( - [DC, "ps"], cwd=WORDPRESS_ROOT, capture_output=True - ).stdout.decode("utf-8") - if "wordpress" not in running: - subprocess.call(["wp", "up"]) - - # import the demo data - subprocess.run([DC, "exec", "-T", "wordpress", "bin/init.sh"], cwd=WORDPRESS_ROOT) - - -"""WAGTAIL/DJANGO COMMANDS""" - - -@wt.command() -def migrate(): - """Wagtail: run migrations""" - subprocess.run(["python", "manage.py", "migrate"], cwd=ROOT) - - -@wt.command() -def superuser(): - """Wagtail: create superuser""" - subprocess.run(["python", "manage.py", "createsuperuser"], cwd=ROOT) - - -@wt.command() -def run(): - """Wagtail: run the server""" - subprocess.run(["python", "manage.py", "runserver"], cwd=ROOT) - - -@wt.command() -def fixtree(): - """Wagtail: fix the tree""" - subprocess.run(["python", "manage.py", "fixtree"], cwd=ROOT) - - -"""IMPORT COMMANDS""" - - -@dj.command() -def authors(): - """Django: import authors from wordpress""" - subprocess.run( - [ - "python", - "manage.py", - "import", - f"{WORDPRESS_URL}/{WORDPRESS_API}/users", - "WPAuthor", - ], - cwd=ROOT, - ) - - -@dj.command() -def categories(): - """Django: import categories from wordpress""" - subprocess.run( - [ - "python", - "manage.py", - "import", - f"{WORDPRESS_URL}/{WORDPRESS_API}/categories", - "WPCategory", - ], - cwd=ROOT, - ) - - -@dj.command() -def tags(): - """Django: import tags from wordpress""" - subprocess.run( - [ - "python", - "manage.py", - "import", - f"{WORDPRESS_URL}/{WORDPRESS_API}/tags", - "WPTag", - ], - cwd=ROOT, - ) - - -@dj.command() -def pages(): - """Django: import pages from wordpress""" - subprocess.run( - [ - "python", - "manage.py", - "import", - f"{WORDPRESS_URL}/{WORDPRESS_API}/pages", - "WPPage", - ], - cwd=ROOT, - ) - - -@dj.command() -def posts(): - """Django: import posts from wordpress""" - subprocess.run( - [ - "python", - "manage.py", - "import", - f"{WORDPRESS_URL}/{WORDPRESS_API}/posts", - "WPPost", - ], - cwd=ROOT, - ) - - -@dj.command() -def media(): - """Django: import media from wordpress""" - subprocess.run( - [ - "python", - "manage.py", - "import", - f"{WORDPRESS_URL}/{WORDPRESS_API}/media", - "WPMedia", - ], - cwd=ROOT, - ) - - -@dj.command() -def comments(): - """Django: import comments from wordpress""" - subprocess.run( - [ - "python", - "manage.py", - "import", - f"{WORDPRESS_URL}/{WORDPRESS_API}/comments", - "WPComment", - ], - cwd=ROOT, - ) - - -@dj.command() -def all(): - """Django: import all data from wordpress""" - subprocess.call(["dj", "authors"]) - subprocess.call(["dj", "categories"]) - subprocess.call(["dj", "tags"]) - subprocess.call(["dj", "pages"]) - subprocess.call(["dj", "posts"]) - subprocess.call(["dj", "media"]) - subprocess.call(["dj", "comments"]) - - -@click.group() -def go(): - """ - Master CLI for Wagtail-WordPress Connector - - The commands are provided for convienince, the result of running the wt or dj commands\n - is the same as running the management commands directly. - """ - pass - - -# Add command groups to the main CLI -go.add_command(wp) -go.add_command(wt) -go.add_command(dj) - - -@go.command() -def devstart(): - """Run all commands""" - subprocess.run(["wp", "build"]) - subprocess.run(["wp", "up"]) - subprocess.run(["wp", "load"]) - subprocess.run(["wt", "migrate"]) - subprocess.run(["wt", "superuser"]) - subprocess.run(["dj", "all"]) - subprocess.run(["wt", "run"]) - - -@go.command() -def devstop(): - """Stop all running services""" - subprocess.run(["wp", "down"]) - subprocess.run(["dj", "stop"]) - subprocess.run(["wt", "stop"]) - - -@go.command() -def devdestroy(): - """Destroy and cleanup wordpress and wagtail""" - subprocess.run(["wp", "destroy"]) From 8c89fafa3f9f8e24c4c54bd20644d6abe9f94b76 Mon Sep 17 00:00:00 2001 From: Nick Moreton Date: Wed, 21 May 2025 22:12:42 +0100 Subject: [PATCH 2/3] Rewrite commands without using click --- commands/anchor_links.py | 56 ------------------ commands/find_anchor_links.py | 95 ++++++++++++++++++++++++++++++ commands/helpers.py | 48 +++++++++++++++ commands/inspector.py | 99 ------------------------------- commands/wp_api_inspector.py | 107 ++++++++++++++++++++++++++++++++++ pyproject.toml | 1 + uv.lock | 2 + 7 files changed, 253 insertions(+), 155 deletions(-) delete mode 100644 commands/anchor_links.py create mode 100755 commands/find_anchor_links.py create mode 100644 commands/helpers.py delete mode 100644 commands/inspector.py create mode 100644 commands/wp_api_inspector.py diff --git a/commands/anchor_links.py b/commands/anchor_links.py deleted file mode 100644 index 2f425fd..0000000 --- a/commands/anchor_links.py +++ /dev/null @@ -1,56 +0,0 @@ -import requests -import rich_click as click -from bs4 import BeautifulSoup as bs - -from .inspector import BASE_ENDPOINT, ENDPOINTS - - -@click.command() -@click.argument("endpoint", required=False) -def a(endpoint): - """ - Use this command to inspect the wordpress API. - - Specifically look for anchor links in the response of the content field. - Ths anchor links we are interested in are the ones that are not followed by an image tag - and link to another page on the same site. e.g. - Hello world! - External links are not of interest. - """ - # If there's no endpoint, show all available endpoints - if not endpoint: - for key in ENDPOINTS: - k = click.style(key, fg="yellow") - v = click.style(ENDPOINTS[key], fg="green") - click.echo(f"{k} : {v}") - help_text = click.style("Use the --help option for more information", fg="red") - click.echo(help_text) - return - - # If the endpoint is not in the list, show an error message - if endpoint not in ENDPOINTS: - click.echo(f"Endpoint {endpoint} not found") - return - - url = f"{BASE_ENDPOINT}{ENDPOINTS[endpoint]}" - response = requests.get(url) - response.raise_for_status() - data = response.json() - for item in data: - if "content" in item: - content = item["content"]["rendered"] - # if "Hello world! + External links are not of interest. + """ + # If the endpoint is not in the list, show an error message + if endpoint not in ENDPOINTS: + print(f"Endpoint {display_colored_text(endpoint, 'red')} not found") + return + + url = f"{BASE_ENDPOINT}{ENDPOINTS[endpoint]}" + try: + response = requests.get(url) + response.raise_for_status() + data = response.json() + + found_links = False + + for item in data: + if "content" in item: + content = item["content"]["rendered"] + soup = bs(content, "html.parser") + + for a in soup.find_all("a"): + next_el = a.next_element + if next_el and not next_el.name == "img": + href = a.get("href") + if href and href.startswith("http://localhost:8888"): + found_links = True + title = "no title" + if item.get("title"): + title = item["title"] + if isinstance(title, dict) and "rendered" in title: + title = title["rendered"] + if item.get("name"): + title = item["name"] + + print( + display_colored_text( + f"Title: {title} ID: {item['id']}", "blue" + ) + ) + print(a) + print() + + if not found_links: + print(display_colored_text("No relevant anchor links found", "yellow")) + + except requests.exceptions.RequestException as e: + print(display_colored_text(f"Error accessing the API: {e}", "red")) + + +def main(): + """Main function to handle command line arguments and execute the script.""" + parser = argparse.ArgumentParser( + description="Find anchor links in WordPress API content." + ) + + parser.add_argument( + "endpoint", + nargs="?", + help="The WordPress API endpoint to inspect. If not provided, will list all available endpoints.", + ) + + args = parser.parse_args() + + if not args.endpoint: + show_endpoints() + return + + find_anchor_links(args.endpoint) + + +if __name__ == "__main__": + main() diff --git a/commands/helpers.py b/commands/helpers.py new file mode 100644 index 0000000..fea1040 --- /dev/null +++ b/commands/helpers.py @@ -0,0 +1,48 @@ +""" +Helper functions and constants for WordPress API inspection commands. +""" + +import os +from colorama import Fore, Style + +# Base endpoint for WordPress API +BASE_ENDPOINT = os.environ.get("WP_API_ENDPOINT", "http://localhost:8888/wp-json") + +# Default number of records per page +PERPAGE = 100 + +# Endpoints available in the WordPress API +ENDPOINTS = { + "home": "/", + "posts": "/wp/v2/posts", + "pages": "/wp/v2/pages", + "categories": "/wp/v2/categories", + "tags": "/wp/v2/tags", + "media": "/wp/v2/media", + "users": "/wp/v2/users", + "comments": "/wp/v2/comments", +} + + +def display_colored_text(text, color): + """Helper function to display colored text.""" + colors = { + "red": Fore.RED, + "green": Fore.GREEN, + "yellow": Fore.YELLOW, + "blue": Fore.BLUE, + } + return f"{colors.get(color, '')}{text}{Style.RESET_ALL}" + + +def show_endpoints(): + """Display all available endpoints.""" + print("Available endpoints:") + for key in ENDPOINTS: + k = display_colored_text(key, "yellow") + v = display_colored_text(ENDPOINTS[key], "green") + print(f"{k} : {v}") + help_text = display_colored_text( + "Use the --help option for more information", "red" + ) + print(help_text) diff --git a/commands/inspector.py b/commands/inspector.py deleted file mode 100644 index 756e34c..0000000 --- a/commands/inspector.py +++ /dev/null @@ -1,99 +0,0 @@ -import pprint - -import requests -import rich_click as click - -BASE_ENDPOINT = "http://localhost:8888/wp-json" -ENDPOINTS = { - "home": "/", - "posts": "/wp/v2/posts", - "pages": "/wp/v2/pages", - "categories": "/wp/v2/categories", - "tags": "/wp/v2/tags", - "media": "/wp/v2/media", - "users": "/wp/v2/users", - "comments": "/wp/v2/comments", -} -PERPAGE = 100 - - -@click.command() -@click.argument("endpoint", required=False) -@click.option( - "--all", - "-a", - is_flag=True, - help="Show all records, might need to use the -p option to increase the number of records per page", -) -@click.option( - "--perpage", "-p", default=PERPAGE, help="Request this number of records per page" -) -@click.option( - "--record", "-r", default=None, help="Limit the returned record to it's ID number" -) -def i(endpoint, all, perpage, record): - """ - Use this command to inspect the wordpress API. - - You can use the endpoint argument to specify the endpoint you want to inspect. - - If you don't specify an endpoint, an index of available endpoints will be shown. - - """ - # If there's no endpoint, show all available endpoints - if not endpoint: - for key in ENDPOINTS: - k = click.style(key, fg="yellow") - v = click.style(ENDPOINTS[key], fg="green") - click.echo(f"{k} : {v}") - help_text = click.style("Use the --help option for more information", fg="red") - click.echo(help_text) - return - - # If the endpoint is not in the list, show an error message - if endpoint not in ENDPOINTS: - click.echo(f"Endpoint {endpoint} not found") - return - - if record: - ENDPOINTS[endpoint] = f"{ENDPOINTS[endpoint]}/{record}" - - try: - if response := requests.get( - f"{BASE_ENDPOINT}{ENDPOINTS[endpoint]}?per_page={perpage}" - ): - if response.status_code != 200: - click.echo(f"Error: {response.status_code}") - return - - if all: - data = response.json() - for i, record in enumerate(data): - click.echo(click.style(f"Record {i}", fg="blue")) - for key, value in record.items(): - if isinstance(value, dict): - click.echo(click.style(f"{key}:", fg="yellow")) - click.echo(f"{pprint.pformat(value)}") - else: - k = click.style(key, fg="yellow") - v = click.style(pprint.pformat(value), fg="green") - click.echo(f"{k}: {v}") - return - - if isinstance(data := response.json(), list): - data = data[0] - else: - data = data - - for key, value in data.items(): - if isinstance(value, dict): - click.echo(click.style(f"{key}:", fg="yellow")) - click.echo(f"{pprint.pformat(value)}") - else: - k = click.style(key, fg="yellow") - v = click.style(pprint.pformat(value), fg="green") - click.echo(f"{k}: {v}") - - except requests.exceptions.ConnectionError: - click.echo("Error: Could not connect to the API") - return diff --git a/commands/wp_api_inspector.py b/commands/wp_api_inspector.py new file mode 100644 index 0000000..d3014b7 --- /dev/null +++ b/commands/wp_api_inspector.py @@ -0,0 +1,107 @@ +import argparse +import pprint + +import requests +from colorama import init +from commands.helpers import ( + BASE_ENDPOINT, + ENDPOINTS, + PERPAGE, + display_colored_text, + show_endpoints, +) + +# Initialize colorama +init() + + +def inspect_endpoint(endpoint, all_records=False, perpage=PERPAGE, record=None): + """Inspect a specific WordPress API endpoint.""" + # If the endpoint is not in the list, show an error message + if endpoint not in ENDPOINTS: + print(f"Endpoint {endpoint} not found") + return + + endpoint_url = ENDPOINTS[endpoint] + if record: + endpoint_url = f"{endpoint_url}/{record}" + + try: + response = requests.get(f"{BASE_ENDPOINT}{endpoint_url}?per_page={perpage}") + + if response.status_code != 200: + print(f"Error: {response.status_code}") + return + + data = response.json() + + if all_records and isinstance(data, list): + for i, record in enumerate(data): + print(display_colored_text(f"Record {i}", "blue")) + display_record(record) + return + + # If not showing all records, display the first one or the single object + if isinstance(data, list): + data = data[0] + + display_record(data) + + except requests.exceptions.ConnectionError: + print("Error: Could not connect to the API") + + +def display_record(record): + """Display a record with formatted output.""" + for key, value in record.items(): + if isinstance(value, dict): + print(display_colored_text(f"{key}:", "yellow")) + print(f"{pprint.pformat(value)}") + else: + k = display_colored_text(key, "yellow") + v = display_colored_text(pprint.pformat(value), "green") + print(f"{k}: {v}") + + +def main(): + """Main function to handle command line arguments and execute the inspector.""" + parser = argparse.ArgumentParser( + description="Use this command to inspect the WordPress API." + ) + + parser.add_argument( + "endpoint", + nargs="?", + help="Specify the endpoint you want to inspect. If not provided, an index of available endpoints will be shown.", + ) + + parser.add_argument( + "--all", + "-a", + action="store_true", + help="Show all records, might need to use the -p option to increase the number of records per page", + ) + + parser.add_argument( + "--perpage", + "-p", + type=int, + default=PERPAGE, + help=f"Request this number of records per page (default: {PERPAGE})", + ) + + parser.add_argument( + "--record", "-r", help="Limit the returned record to its ID number" + ) + + args = parser.parse_args() + + if not args.endpoint: + show_endpoints() + return + + inspect_endpoint(args.endpoint, args.all, args.perpage, args.record) + + +if __name__ == "__main__": + main() diff --git a/pyproject.toml b/pyproject.toml index 37c1f34..e503c30 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,6 +16,7 @@ dependencies = [ [dependency-groups] dev = [ + "colorama>=0.4.6", "coverage>=7.6.12", "pre-commit>=4.1.0", "responses>=0.25.6", diff --git a/uv.lock b/uv.lock index ed52d41..45a6014 100644 --- a/uv.lock +++ b/uv.lock @@ -722,6 +722,7 @@ dependencies = [ [package.dev-dependencies] dev = [ + { name = "colorama" }, { name = "coverage" }, { name = "pre-commit" }, { name = "responses" }, @@ -741,6 +742,7 @@ requires-dist = [ [package.metadata.requires-dev] dev = [ + { name = "colorama", specifier = ">=0.4.6" }, { name = "coverage", specifier = ">=7.6.12" }, { name = "pre-commit", specifier = ">=4.1.0" }, { name = "responses", specifier = ">=0.25.6" }, From 4fecb44d41ca0b107315537d59c9dd150a338802 Mon Sep 17 00:00:00 2001 From: Nick Moreton Date: Wed, 21 May 2025 22:17:00 +0100 Subject: [PATCH 3/3] Remove click and rich-click from dependencies --- Makefile | 18 ++++++------- pyproject.toml | 10 ------- uv.lock | 71 -------------------------------------------------- 3 files changed, 9 insertions(+), 90 deletions(-) diff --git a/Makefile b/Makefile index 9de6fa2..9bbb4c8 100644 --- a/Makefile +++ b/Makefile @@ -44,9 +44,9 @@ help: @echo " make node-scripts-watch - Watch and compile JavaScript" @echo "" @echo "Convenience Commands:" - @echo " make devstart - Run all commands to set up and start the development environment" - @echo " make devstop - Stop all running services" - @echo " make devdestroy - Destroy and cleanup wordpress and wagtail" + @echo " make start - Run all commands to set up and start the development environment" + @echo " make stop - Stop all running services" + @echo " make destroy - Destroy and cleanup wordpress and wagtail" # WordPress Commands .PHONY: wp-build @@ -168,17 +168,17 @@ import-all: import-authors import-categories import-tags import-pages import-pos @echo "Imported all WordPress data" # Convenience Commands -.PHONY: devstart -devstart: wp-build wp-up wp-load wt-migrate wt-superuser import-all wt-run +.PHONY: start +start: wp-build wp-up wp-load wt-migrate wt-superuser import-all wt-run @echo "Development environment started" -.PHONY: devstop -devstop: wp-down +.PHONY: stop +stop: wp-down @echo "Development environment stopped" @echo "Note: There is no direct equivalent for 'dj stop' and 'wt stop' in the CLI, but WordPress container has been stopped." -.PHONY: devdestroy -devdestroy: wp-destroy +.PHONY: destroy +destroy: wp-destroy @echo "Development environment destroyed" # Node.js Commands diff --git a/pyproject.toml b/pyproject.toml index e503c30..c77a951 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,7 +10,6 @@ dependencies = [ "django-extensions>=3.2.3", "jmespath>=1.0.1", "requests>=2.32.3", - "rich-click>=1.8.6", "wagtail>=7.0", ] @@ -29,12 +28,3 @@ build-backend = "hatchling.build" [tool.hatch.build.targets.wheel] packages = ["."] - -[project.scripts] -go = "commands.cli:go" -wp = "commands.cli:wp" -wt = "commands.cli:wt" -dj = "commands.cli:dj" - -i = "commands.inspector:i" -a = "commands.anchor_links:a" diff --git a/uv.lock b/uv.lock index 45a6014..2610193 100644 --- a/uv.lock +++ b/uv.lock @@ -86,18 +86,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/0e/f6/65ecc6878a89bb1c23a086ea335ad4bf21a588990c3f535a227b9eea9108/charset_normalizer-3.4.1-py3-none-any.whl", hash = "sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85", size = 49767 }, ] -[[package]] -name = "click" -version = "8.1.8" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/b9/2e/0090cbf739cee7d23781ad4b89a9894a41538e4fcf4c31dcdd705b78eb8b/click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a", size = 226593 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2", size = 98188 }, -] - [[package]] name = "colorama" version = "0.4.6" @@ -364,27 +352,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/60/fe/31f76f5cb2579bdda208aa257ce5482653f22ab1bad3e128fe2f803fa2f1/laces-0.1.2-py3-none-any.whl", hash = "sha256:980cdaf9a31e883a2b8198132e2388931a4eb8814f5bfa5d8bba13ff9f657b7c", size = 22462 }, ] -[[package]] -name = "markdown-it-py" -version = "3.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "mdurl" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528 }, -] - -[[package]] -name = "mdurl" -version = "0.1.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979 }, -] - [[package]] name = "nodeenv" version = "1.9.1" @@ -494,15 +461,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/43/b3/df14c580d82b9627d173ceea305ba898dca135feb360b6d84019d0803d3b/pre_commit-4.1.0-py2.py3-none-any.whl", hash = "sha256:d29e7cb346295bcc1cc75fc3e92e343495e3ea0196c9ec6ba53f49f10ab6ae7b", size = 220560 }, ] -[[package]] -name = "pygments" -version = "2.19.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7c/2d/c3338d48ea6cc0feb8446d8e6937e1408088a72a39937982cc6111d17f84/pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f", size = 4968581 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c", size = 1225293 }, -] - [[package]] name = "pyyaml" version = "6.0.2" @@ -558,33 +516,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/92/c4/8d23584b3a3471ea6f5a18cfb035e11eeb9fa9b3112d901477c6ad10cc4e/responses-0.25.6-py3-none-any.whl", hash = "sha256:9cac8f21e1193bb150ec557875377e41ed56248aed94e4567ed644db564bacf1", size = 34730 }, ] -[[package]] -name = "rich" -version = "13.9.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markdown-it-py" }, - { name = "pygments" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ab/3a/0316b28d0761c6734d6bc14e770d85506c986c85ffb239e688eeaab2c2bc/rich-13.9.4.tar.gz", hash = "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098", size = 223149 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/19/71/39c7c0d87f8d4e6c020a393182060eaefeeae6c01dab6a84ec346f2567df/rich-13.9.4-py3-none-any.whl", hash = "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90", size = 242424 }, -] - -[[package]] -name = "rich-click" -version = "1.8.6" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "click" }, - { name = "rich" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ea/e3/ff1c715b673ec9e01f4482d8d0edfd9adf891f3630d83e695b38337a3889/rich_click-1.8.6.tar.gz", hash = "sha256:8a2448fd80e3d4e16fcb3815bfbc19be9bae75c9bb6aedf637901e45f3555752", size = 38247 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7e/09/c20b04b6c9cf273995753f226ca51656e00f8a37f1e723f8c713b93b2ad4/rich_click-1.8.6-py3-none-any.whl", hash = "sha256:55fb571bad7d3d69ac43ca45f05b44616fd019616161b1815ff053567b9a8e22", size = 35076 }, -] - [[package]] name = "ruff" version = "0.11.10" @@ -716,7 +647,6 @@ dependencies = [ { name = "django-extensions" }, { name = "jmespath" }, { name = "requests" }, - { name = "rich-click" }, { name = "wagtail" }, ] @@ -736,7 +666,6 @@ requires-dist = [ { name = "django-extensions", specifier = ">=3.2.3" }, { name = "jmespath", specifier = ">=1.0.1" }, { name = "requests", specifier = ">=2.32.3" }, - { name = "rich-click", specifier = ">=1.8.6" }, { name = "wagtail", specifier = ">=7.0" }, ]