Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .DS_Store
Binary file not shown.
42 changes: 42 additions & 0 deletions examples/POST API test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#!/usr/bin/env python

import os
import sys
import logging
import coloredlogs
from requests.auth import HTTPBasicAuth

sys.path.append('/Users/demitri/Documents/Repositories/GitHub/wordpress_orm')

import wordpress_orm as wp
from wordpress_orm import wp_session, exc
from wordpress_orm.entities import Post

# coloredlogs is configured with environment variables... weird
# define them here instead of from the shell
os.environ["COLOREDLOGS_LOG_FORMAT"] = "%(asctime)s,%(msecs)d %(levelname)-8s [%(filename)s:%(lineno)d] %(message)s"

logger = logging.getLogger("wordpress_orm")
logger.setLevel(logging.DEBUG)

use_color_logs = True
if use_color_logs:
coloredlogs.install(level=logging.DEBUG, logger=logger)
else:
ch = logging.StreamHandler() # output to console
ch.setLevel(logging.DEBUG) # set log level for output
logger.addHandler(ch) # add to logger

wordpress_api = wp.API(url="http://brie6.cshl.edu/wordpress/index.php/wp-json/wp/v2/")
wordpress_api.authenticator = HTTPBasicAuth(os.environ['SB_WP_USERNAME'], os.environ['SB_WP_PASSWORD'])

with wordpress_api.Session():
new_post = Post(api=wordpress_api)
logger.debug(new_post)
new_post.s.title = "API POST Test: New Post Title"
new_post.s.slug = "api-post-test-new-post-title"
new_post.s.content = "This is content for a new post."
new_post.s.excerpt = "This is the new post's excerpt, which appears to be required."
new_post.s.sticky = True
new_post.post()

147 changes: 147 additions & 0 deletions misc/autocomplete_wp.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
# ----------------------------------------------
# Bash autocomplete script for the WordPress CLI
# ----------------------------------------------
#
# For Bash users, source this file in your shell (e.g. ~/.bashrc)
# to enable autocompletion of "wp" commands.
#
_wp_cli()
{
local cur prev

cur=${COMP_WORDS[COMP_CWORD]}
prev=${COMP_WORDS[COMP_CWORD-1]}

case ${COMP_CWORD} in
1)
# top level commands here
COMPREPLY=($(compgen -W "cache cap cli comment config core cron db embed eval eval-file export help i18n import language media menu network option package plugin post post-type rewrite role scaffold search-replace server shell sidebar site super-admin taxonomy term theme transient user widget --path=<path> --url=<url> --ssh=[<scheme>:][<user>@]<host|container>[:<port>][<path>] --http=<http> --user=<id|login|email> --skip-plugins[=<plugins>] --skip-themes[=<themes>] --skip-packages --require=<path> --no-color --color --debug[=<group>] --prompt[=<assoc>] --quiet" -- ${cur}))
;;
2)
# second level commands, per top level command
case ${prev} in
'cache')
COMPREPLY=($(compgen -W "add decr delete flush get incr replace set type" -- ${cur}))
;;
'cap')
COMPREPLY=($(compgen -W "add list remove" -- ${cur}))
;;
'cli')
COMPREPLY=($(compgen -W "alias check-update cmd-dump completions has-command info param-dump update version" -- ${cur}))
;;
'comment')
COMPREPLY=($(compgen -W "approve count create delete exists generate get list meta recount spam status trash unapprove unspam untrash update" -- ${cur}))
;;
'config')
COMPREPLY=($(compgen -W "create delete edit get has list path set shuffle-salts" -- ${cur}))
;;
'core')
COMPREPLY=($(compgen -W "check-update download install is-installed multisite-convert multisite-install update update-db verify-checksums version" -- ${cur}))
;;
'cron')
COMPREPLY=($(compgen -W "event schedule test" -- ${cur}))
;;
'db')
COMPREPLY=($(compgen -W "check clean cli columns create drop export import optimize prefix query repair reset search size tables" -- ${cur}))
;;
'embed')
COMPREPLY=($(compgen -W "cache fetch handler provider" -- ${cur}))
;;
#'eval')
# COMPREPLY=($(compgen -W "" -- ${cur}))
# ;;
#'eval-file')
# COMPREPLY=($(compgen -W "" -- ${cur}))
# ;;
#'export')
# COMPREPLY=($(compgen -W "" -- ${cur}))
# ;;
'help')
COMPREPLY=($(compgen -W "cache cap cli comment config core cron db embed eval eval-file export help i18n import language media menu network option package plugin post post-type rewrite role scaffold search-replace server shell sidebar site super-admin taxonomy term theme transient user widget" -- ${cur}))
;;
'i18n')
COMPREPLY=($(compgen -W "make-pot" -- ${cur}))
;;
#'import')
# COMPREPLY=($(compgen -W "" -- ${cur}))
# ;;
'language')
COMPREPLY=($(compgen -W "core plugin theme" -- ${cur}))
;;
'media')
COMPREPLY=($(compgen -W "image-size import regenerate" -- ${cur}))
;;
'menu')
COMPREPLY=($(compgen -W "create delete item list location" -- ${cur}))
;;
'network')
COMPREPLY=($(compgen -W "meta" -- ${cur}))
;;
'option')
COMPREPLY=($(compgen -W "add delete get list patch pluck update" -- ${cur}))
;;
'package')
COMPREPLY=($(compgen -W "browse install list path uninstall update" -- ${cur}))
;;
'plugin')
COMPREPLY=($(compgen -W "activate deactivate delete get install is-active is-installed list path search status toggle uninstall update verify-checksums" -- ${cur}))
;;
'post')
COMPREPLY=($(compgen -W "create delete edit generate get list meta term update" -- ${cur}))
;;
'post-type')
COMPREPLY=($(compgen -W "get list" -- ${cur}))
;;
'rewrite')
COMPREPLY=($(compgen -W "flush list structure" -- ${cur}))
;;
'role')
COMPREPLY=($(compgen -W "create delete exists list reset" -- ${cur}))
;;
'scaffold')
COMPREPLY=($(compgen -W "_s block child-theme plugin plugin-tests post-type taxonomy theme-tests" -- ${cur}))
;;
#'search-replace')
# COMPREPLY=($(compgen -W "" -- ${cur}))
# ;;
'server')
COMPREPLY=($(compgen -W "--host= --port= --docroot= --config=" -- ${cur}))
;;
'shell')
COMPREPLY=($(compgen -W "--basic" -- ${cur}))
;;
'sidebar')
COMPREPLY=($(compgen -W "list" -- ${cur}))
;;
'site')
COMPREPLY=($(compgen -W "activate archive create deactivate delete empty list mature meta option private public spam switch-language unarchive unmature unspam" -- ${cur}))
;;
'super-admin')
COMPREPLY=($(compgen -W "add list remove" -- ${cur}))
;;
'taxonomy')
COMPREPLY=($(compgen -W "get list" -- ${cur}))
;;
'term')
COMPREPLY=($(compgen -W "create delete generate get list meta recount update" -- ${cur}))
;;
'theme')
COMPREPLY=($(compgen -W "activate delete disable enable get install is-active is-installed list mod path search status update" -- ${cur}))
;;
'transient')
COMPREPLY=($(compgen -W "delete get set type" -- ${cur}))
;;
'user')
COMPREPLY=($(compgen -W "add-cap add-role check-password create delete generate get import-csv list list-caps meta remove-cap remove-role reset-password session set-role spam term unspam update" -- ${cur}))
;;
'widget')
COMPREPLY=($(compgen -W "add deactivate delete list move reset update" -- ${cur}))
;;
esac
;;
*)
COMPREPLY=()
;;
esac
}
complete -F _wp_cli wp
21 changes: 21 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import setuptools

with open("README.md", "r") as fh:
long_description = fh.read()

setuptools.setup(
name="wordpress_orm",
version="1.0.0",
author="Demitri Muna",
author_email="demitri@github.com",
description="A object-oriented Python wrapper for the WordPress API.",
long_description=long_description,
long_description_content_type="text/markdown",
url="https://github.com/demitri/wordpress_orm",
packages=setuptools.find_packages(),
classifiers=[
"Programming Language :: Python :: 3",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
],
)
5 changes: 5 additions & 0 deletions wordpress_orm/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@

name = "wordpress_orm"

from .api import API
import logging
from .api import wp_session

from .entities.wordpress_entity import WPEntity, WPRequest
from .cache import WPORMCacheObjectNotFoundError

logger = logging.getLogger(__name__.split(".")[0]) # package name
67 changes: 57 additions & 10 deletions wordpress_orm/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import requests

from .entities import post, user, media, category, comment, page, tag
from . import exc
from . import exc #, logger
from .cache import WPORMCache, WPORMCacheObjectNotFoundError

from .entities import Category
Expand All @@ -21,12 +21,14 @@
#from .entities import Taxonomy
from .entities import User

logger = logging.getLogger("{}".format(__loader__.name.split(".")[0])) # package name
#package_name = __name__.split(".")[0]
logger = logging.getLogger(__name__.split(".")[0]) # package name

@contextmanager
def wp_session(api=None):
api.session = requests.Session()
yield api
# ---- called after end of 'with' block ----
api.session.close()
api.session = None

Expand All @@ -35,9 +37,16 @@ class API:

'''
def __init__(self, url=None):
self.base_url = url
self._base_url = url
self.session = None

# A valid "requests" authentication handler,
# see: http://docs.python-requests.org/en/master/api/?highlight=get#authentication
#
# Options: HTTPBasicAuth(username, password), HTTPProxyAuth(username, password), HTTPDigestAuth(username, password)
#
self.authenticator = None

self.wordpress_object_cache = WPORMCache() # dict() # key = class name, value = object

#
Expand All @@ -64,19 +73,56 @@ def register_custom_class(self, theclass):
# if class_name not in self.wordpress_object_cache:
# self.wordpress_object_cache[class_name] = dict()

def auth(self):
'''
Returns a valid requests authentication handler.
'''
if self.authenticator is None or isinstance(self.authenticator, requests.auth.AuthBase):
return self.authenticator
else:
raise Exception("Unknown or unsupported authentication method.")

@contextmanager
def Session(self):
'''
Returns requests.Session object; use in the form 'with api.Session()' to use a single session in a block.

Calling this method creates a new Session() object, but if used in a 'with' block, any existing value in
'self.session' is restored after exiting the block.
'''
old_session = self.session # save existing session if there is one
new_session = requests.Session() # create new session
self.session = new_session
yield new_session

# ---------- below here is executed after 'with' block ----------

self.session = old_session # restore original session (if there was one)

@property
def base_url(self):
return self._base_url

@base_url.setter
def base_url(self, url):
if not url[-1] == "/":
url = url + "/"
self._base_url = url


def PostRequest(self, **kwargs):
''' Factory method that returns a new PostRequest attached to this API. '''
return post.PostRequest(api=kwargs.pop('api', self), **kwargs)

def post(self, id=None, slug=None):
def post(self, id=None, slug=None, embed=True):
'''
Returns a Post object from the WordPress API with the provided ID.

id : WordPress ID
embed : retrieve full content of related entities instead of the WordPress ID, see: https://developer.wordpress.org/rest-api/using-the-rest-api/linking-and-embedding/#embedding
'''
if len([x for x in [id, slug] if x is not None]) > 1:
raise Exception("Only one of [id, slug] can be specified at a time.")
raise Exception("Only one of [id, slug] can be specified at a time (both were specified).")
if not any([id, slug]):
# none in list are defined
raise Exception("At least one of 'id' or 'slug' must be specified.")
Expand All @@ -99,7 +145,7 @@ def post(self, id=None, slug=None):
if slug:
pr.slug = slug

posts = pr.get()
posts = pr.get(embed=embed)

if len(posts) == 1:
return posts[0]
Expand All @@ -120,10 +166,11 @@ def media(self, id=None, slug=None):
id : WordPress ID
'''
if len([x for x in [id, slug] if x is not None]) > 1:
raise Exception("Only one of [id, slug] can be specified at a time.")
raise Exception("Only one of [id, slug] can be specified at a time (both were specified).")
elif id is None and slug is None:
# be careful of id=0 case
raise Exception("At least one of 'id' or 'slug' must be specified.")
elif id == 0:
return None

# check cache first
try:
Expand Down Expand Up @@ -152,7 +199,7 @@ def media(self, id=None, slug=None):
else:
# more than one found
logger.debug(media_list)
assert False, "Should not get here!"
assert False, "More than one media item found. (parameters: id={0} slug={1}) Should not get here! Items found: {2}".format(id, slug, media_list)

def user(self, id=None, username=None, slug=None):
'''
Expand Down Expand Up @@ -299,7 +346,7 @@ def page(self, id=None, slug=None):
if not any([id, slug]):
# none in list are defined
raise Exception("At least one of 'id' or 'slug' must be specified.")

# check cache first
try:
if id:
Expand Down
Loading