Skip to main content

A library for dealing with JSON as python objects

Project description

jsonobject

Build Status Downloads Supported Versions Contributors

jsonobject is a python library for handling deeply nested JSON objects as well-schema'd python objects.

jsonobject is made by Dimagi, where we build, use, and contribute to OSS in our mission to reduce inequity in the world.

jsonobject is inspired by and largely API compatible with the Document/DocumentSchema portion of couchdbkit. Because jsonobject is not only simpler and standalone, but also faster, we also maintain a fork of couchdbkit, jsonobject-couchdbkit, that is backed by jsonobject and works seamlessly as a swap-in replacement for the main library.

It is used heavily in CommCare HQ (source), and the API is largely stable, but more advanced features may change in the future.

Getting Started

To install using pip, simply run

pip install jsonobject

Example

The code below defines a simple user model, and its natural mapping to JSON.

from jsonobject import *

class User(JsonObject):
    username = StringProperty()
    name = StringProperty()
    active = BooleanProperty(default=False)
    date_joined = DateTimeProperty()
    tags = ListProperty(unicode)

Once it is defined, it can be used to wrap or produce deserialized JSON.

>>> user1 = User(
    name='John Doe',
    username='jdoe',
    date_joined=datetime.datetime.utcnow(),
    tags=['generic', 'anonymous']
)
>>> user1.to_json()
{
    'name': u'John Doe',
    'username': u'jdoe',
    'active': False,
    'date_joined': '2013-08-05T02:46:58Z',
    'tags': [u'generic', u'anonymous']
}

Notice that the datetime is converted to an ISO format string in JSON, but is a real datetime on the object:

>>> user1.date_joined
datetime.datetime(2013, 8, 5, 2, 46, 58)

The jsonobject Constructor

A JsonObject subclass that has been defined as User above comes with a lot of built-in functionality. The basic operations are

  1. Make a new object from deserialized JSON (e.g. the output of json.loads)
  2. Construct a new object with given values
  3. Modify an object
  4. Dump to deserialized json (e.g. the input of json.dumps)

1 & 2 are accomplished with the constructor. There are two main ways to call the constructor:

User(
    name='John Doe',
    username='jdoe',
    date_joined=datetime.datetime.utcnow(),
    tags=['generic', 'anonymous']
)

as above (satisfies #2) and

User({
    'name': u'John Doe',
    'username': u'jdoe',
    'active': False,
    'date_joined': '2013-08-05T02:46:58Z',
    'tags': [u'generic', u'anonymous']
})

(satisfies #1). These two styles can also be mixed and matched:

User({
    'name': u'John Doe',
    'username': u'jdoe',
    'active': False,
    'tags': [u'generic', u'anonymous']
}, date_joined=datetime.datetime.utcnow())

Notice how datetimes are stored as strings in the deserialized JSON, but as datetime.datetimes in the nice python object—we will refer to these as the "json" representation and the "python" representation, or alternatively the "unwrapped" representation and the "wrapped" representation.

Gotcha. When calling the constructor, remember that the keyword argument style requires you to pass in the "python" representation (e.g. a datetime) while the json-wrapping style of passing in a dict requires you to give it in the "json" representation (e.g. a datetime-formatted string).

Property Types

There are two main kinds of property types: scalar types (like string, bool, int, datetime, etc.) and container types (list, dict, set). They are dealt with separately below.

Scalar Types

All scalar properties can take the value None in addition to the values particular to their type (strings, bools, etc). If set to the wrong type, properties raise a jsonobject.exceptions.BadValueError:

class Foo(jsonobject.JsonObject):
    b = jsonobject.BooleanProperty()
>>> Foo(b=0)
Traceback (most recent call last):
  [...]
jsonobject.exceptions.BadValueError: 0 not of type <type 'bool'>

jsonobject.StringProperty

Maps to a unicode. Usage:

class Foo(jsonobject.JsonObject):
    s = jsonobject.StringProperty()

If you set it to an ascii str it will implicitly convert to unicode:

>>> Foo(s='hi')  # converts to unicode
Foo(s=u'hi')

If you set it to a non-ascii str, it will fail with a UnicodeDecodeError:

>>> Foo(s='\xff')
Traceback (most recent call last):
  [...]
UnicodeDecodeError: 'ascii' codec can't decode byte 0xff in position 0: ordinal not in range(128)

jsonobject.BooleanProperty

Maps to a bool.

jsonobject.IntegerProperty

Maps to an int or long.

jsonobject.FloatProperty

Maps to a float.

jsonobject.DecimalProperty

Maps to a decimal.Decimal and stored as a JSON string. This type, unlike FloatProperty, stores the "human" representation of the digits. Usage:

class Foo(jsonobject.JsonObject):
    number = jsonobject.DecimalProperty()

If you set it to an int or float, it will implicitly convert to Decimal:

>>> Foo(number=1)
Foo(number=Decimal('1'))
>>> Foo(number=1.2)
Foo(number=Decimal('1.2'))

If you set it to a str or unicode, however, it raises an AssertionError:

>>> Foo(number='1.0')
Traceback (most recent call last):
  [...]
AssertionError

Todo: this should really raise a BadValueError.

If you pass in json in which the Decimal value is a str or unicode, but it is malformed, it throws the same errors as decimal.Decimal.

>>> Foo({'number': '1.0'})
Foo(number=Decimal('1.0'))
>>> Foo({'number': '1.0.0'})
Traceback (most recent call last):
  [...]
decimal.InvalidOperation: Invalid literal for Decimal: '1.0.0'

jsonobject.DateProperty

Maps to a datetime.date and stored as a JSON string of the format '%Y-%m-%d'. Usage:

class Foo(jsonobject.JsonObject):
    date = jsonobject.DateProperty()

Wrapping a badly formatted string raises a BadValueError:

>>> Foo({'date': 'foo'})
Traceback (most recent call last):
  [...]
jsonobject.exceptions.BadValueError: 'foo' is not a date-formatted string

jsonobject.DateTimeProperty

Maps to a timezone-unaware datetime.datetime and stored as a JSON string of the format '%Y-%m-%dT%H:%M:%SZ'.

While it works perfectly with good inputs, it is extremely sloppy when it comes to dealing with inputs that don't match the exact specified format. Rather than matching stricty, it simply truncates the string to the first 19 characters and tries to parse that as '%Y-%m-%dT%H:%M:%S'. This ignores both microseconds and, even worse, the timezone. This is a holdover from couchdbkit.

In newer versions of jsonboject, you may optionally specify a DateTimeProperty as exact:

class Foo(jsonobject.JsonObject):
    date = jsonobject.DateTimeProperty(exact=True)

This provides a much cleaner conversion model that has the following properties:

  1. It preserves microseconds
  2. The incoming JSON representation must match '%Y-%m-%dT%H:%M:%S.%fZ' exactly. (This is similar to the default output, except for the mandatory 6 decimal places, i.e. milliseconds.)
  3. Representations that don't match exactly will be rejected with a BadValueError.

Recommendation: If you are not locked into couchdbkit's earlier bad behavior, you should always use the exact=True flag on DateTimePropertys and TimePropertys (below).

jsonobject.TimeProperty

Maps to a datetime.time, stored as a JSON string of the format '%H:%M:%S'.

To get access to milliseconds and strict behavior, use the exact=True setting which strictly accepts the format '%H:%M:%S.%f'. This is always recommended. For more information please read the previous section on DateTimeProperty.

Container Types

Container types generally take a first argument, item_type, specifying the type of the contained objects.

jsonobject.ObjectProperty(item_type)

Maps to a dict that has a schema specified by item_type, which must be itself a subclass of JsonObject. Usage:

class Bar(jsonobject.JsonObject):
    name = jsonobject.StringProperty()


class Foo(jsonobject.JsonObject):
    bar = jsonobject.ObjectProperty(Bar)

If not specified, it will be set to a new object with default values:

>>> Foo()
Foo(bar=Bar(name=None))

If you want it set to None you must do so explicitly.

jsonobject.ListProperty(item_type)

Maps to a list with items of type item_type, which can be any of the following:

  • an instance of a property class. This is the most flexible option, and all validation (required, etc.) will be done as as specified by the property instance.
  • a property class, which will be instantiated with required=True
  • one of their corresponding python types (i.e. int for IntegerProperty, etc.)
  • a JsonObject subclass

Note that a property class (as well as the related python type syntax) will be instantiated with required=True, so ListProperty(IntegerProperty) and ListProperty(int) do not allow None, and ListProperty(IntegerProperty()) does allow None.

The serialization behavior of whatever item type is given is recursively applied to each member of the list.

If not specified, it will be set to an empty list.

jsonobject.SetProperty(item_type)

Maps to a set and stored as a list (with only unique elements). Otherwise its behavior is very much like ListProperty's.

jsonobject.DictProperty(item_type)

Maps to a dict with string keys and values specified by item_type. Otherwise its behavior is very much like ListProperty's.

If not specified, it will be set to an empty dict.

Other

jsonobject.DefaultProperty()

This flexibly wraps any valid JSON, including all scalar and container types, dynamically detecting the value's type and treating it with the corresponding property.

Property options

Certain parameters may be passed in to any property.

For example, required is one such parameter in the example below:

class User(JsonObject):
    username = StringProperty(required=True)

Here is a complete list of properties:

  • default

    Specifies a default value for the property

  • name

    The name of the property within the JSON representation*. This defaults to the name of the python property, but you can override it if you wish. This can be useful, for example, to get around conflicting with python keywords:

    >>> class Route(JsonObject):
    ...     from_ = StringProperty(name='from')
    ...     to = StringProperty()  # name='to' by default
    >>> Route(from_='me', to='you').to_json()
    {'from': u'me', 'to': u'you'}
    

    Notice how an underscore is present in the python property name ('from_'), but absent in the JSON property name ('from').

    \*If you're wondering how `StringProperty`'s `name` parameter could possibly default to `to` in the example above, when it doesn't have access to the `Route` class's properties at init time, you're completely right. The behavior described is implemented in `JsonObject`'s `__metaclass__`, which *does* have access to the `Route` class's properties.
  • choices

    A list of allowed values for the property. (Unless otherwise specified, None is also an allowed value.)

  • required

    Defaults to False. For scalar properties requires means that the value None may not be used. For container properties it means they may not be empty or take the value None.

  • exclude_if_none

    Defaults to False. When set to true, this property will be excluded from the JSON output when its value is falsey. (Note that currently this is at odds with the parameter's name, since the condition is that it is falsey, not that it is None).

  • validators

    A single validator function or list of validator functions. Each validator function should raise an exception on invalid input and do nothing otherwise.

  • verbose_name

    This property does nothing and was added to match couchdbkit's API.

Performance Comparison with Couchdbkit

In order to do a direct comparison with couchdbkit, the test suite includes a large sample schema originally written with couchdbkit. It is easy to swap in jsonobject for couchdbkit and run the tests with each. Here are the results:

$ python -m unittest test.test_couchdbkit
....
----------------------------------------------------------------------
Ran 4 tests in 1.403s

OK
$ python -m unittest test.test_couchdbkit
....
----------------------------------------------------------------------
Ran 4 tests in 0.153s

OK

Development Lifecycle

jsonobject versions follow semantic versioning. Version information can be found in CHANGES.md.

Information for developers and maintainers, such as how to run tests and release new versions, can be found in LIFECYCLE.md.

Project details


Release history Release notifications | RSS feed

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

jsonobject-2.3.1.dev20250522235411.tar.gz (596.2 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

jsonobject-2.3.1.dev20250522235411-cp313-cp313-musllinux_1_2_x86_64.whl (2.6 MB view details)

Uploaded CPython 3.13musllinux: musl 1.2+ x86-64

jsonobject-2.3.1.dev20250522235411-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.6 MB view details)

Uploaded CPython 3.13manylinux: glibc 2.17+ x86-64manylinux: glibc 2.5+ x86-64

jsonobject-2.3.1.dev20250522235411-cp312-cp312-musllinux_1_2_x86_64.whl (2.6 MB view details)

Uploaded CPython 3.12musllinux: musl 1.2+ x86-64

jsonobject-2.3.1.dev20250522235411-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.6 MB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ x86-64manylinux: glibc 2.5+ x86-64

jsonobject-2.3.1.dev20250522235411-cp311-cp311-musllinux_1_2_x86_64.whl (2.6 MB view details)

Uploaded CPython 3.11musllinux: musl 1.2+ x86-64

jsonobject-2.3.1.dev20250522235411-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.6 MB view details)

Uploaded CPython 3.11manylinux: glibc 2.17+ x86-64

jsonobject-2.3.1.dev20250522235411-cp310-cp310-musllinux_1_2_x86_64.whl (2.5 MB view details)

Uploaded CPython 3.10musllinux: musl 1.2+ x86-64

jsonobject-2.3.1.dev20250522235411-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.5 MB view details)

Uploaded CPython 3.10manylinux: glibc 2.17+ x86-64

jsonobject-2.3.1.dev20250522235411-cp39-cp39-musllinux_1_2_x86_64.whl (2.5 MB view details)

Uploaded CPython 3.9musllinux: musl 1.2+ x86-64

jsonobject-2.3.1.dev20250522235411-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.5 MB view details)

Uploaded CPython 3.9manylinux: glibc 2.17+ x86-64

File details

Details for the file jsonobject-2.3.1.dev20250522235411.tar.gz.

File metadata

File hashes

Hashes for jsonobject-2.3.1.dev20250522235411.tar.gz
Algorithm Hash digest
SHA256 71f688cd828158f1c82e579e4afb1e4b6410fefd42719bf6d51687f24f78a780
MD5 5e45fd6aab0b00c207edef7afcc709c0
BLAKE2b-256 86089e94135c2c7f7685bb25d3366f626d99f2980f5790b529ffcef59210a26c

See more details on using hashes here.

Provenance

The following attestation bundles were made for jsonobject-2.3.1.dev20250522235411.tar.gz:

Publisher: pypi.yml on dimagi/jsonobject

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file jsonobject-2.3.1.dev20250522235411-cp313-cp313-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for jsonobject-2.3.1.dev20250522235411-cp313-cp313-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 87157f3e4c4d2cd91ef0c28b8abb9444e1fe3798fae806568c7b47417ddeeea9
MD5 33aab1711c4864428c426388af6d19c8
BLAKE2b-256 049dcc0feb76d59a6c878ec9f31f7953580dbdf50fb8f2d71a4724c28f0c3eda

See more details on using hashes here.

Provenance

The following attestation bundles were made for jsonobject-2.3.1.dev20250522235411-cp313-cp313-musllinux_1_2_x86_64.whl:

Publisher: pypi.yml on dimagi/jsonobject

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file jsonobject-2.3.1.dev20250522235411-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for jsonobject-2.3.1.dev20250522235411-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 feaf0340ee7898e4be8afe7d2cd37448e976fd9f42734ebc18f6e8215388bcbc
MD5 19cd84975acd683b9829e1bacefc9ff7
BLAKE2b-256 598bbf00d2c9d4bdb6de9eac79bb7f53bf04a3e5e910aa1832173d7266f948ba

See more details on using hashes here.

Provenance

The following attestation bundles were made for jsonobject-2.3.1.dev20250522235411-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: pypi.yml on dimagi/jsonobject

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file jsonobject-2.3.1.dev20250522235411-cp312-cp312-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for jsonobject-2.3.1.dev20250522235411-cp312-cp312-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 d9ea9bca4b1f4305fcac15f1b9873a3a789e4a3c756e2ffad027aefabc11b698
MD5 bf4068620362d2e5257abf0d6d1d97bf
BLAKE2b-256 7d0cf13fe59604138610874c08088ffeb6352c5f05c45535f2a7b363e55624c9

See more details on using hashes here.

Provenance

The following attestation bundles were made for jsonobject-2.3.1.dev20250522235411-cp312-cp312-musllinux_1_2_x86_64.whl:

Publisher: pypi.yml on dimagi/jsonobject

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file jsonobject-2.3.1.dev20250522235411-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for jsonobject-2.3.1.dev20250522235411-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 0c447f8332900206543e42d2f4f437580af615f6d89ffed34b2908da82469e1d
MD5 a8ee357ca8b3ba9cb53f6f8d26e2fd3e
BLAKE2b-256 943ac695628f328fab53bac81b90708e6eb3671de1d3d5be40ae409f9277f4ec

See more details on using hashes here.

Provenance

The following attestation bundles were made for jsonobject-2.3.1.dev20250522235411-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: pypi.yml on dimagi/jsonobject

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file jsonobject-2.3.1.dev20250522235411-cp311-cp311-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for jsonobject-2.3.1.dev20250522235411-cp311-cp311-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 daed5f60e441a21bddcba46e16ab0a4f8a1d341af8bbaad06963a9ea9a35e4bd
MD5 8bc84c5555904e46fa70ec8693047574
BLAKE2b-256 4a4f428b5227d074c6878fb3c2573a9f680caccf20e157b788a55bb2e97e38cd

See more details on using hashes here.

Provenance

The following attestation bundles were made for jsonobject-2.3.1.dev20250522235411-cp311-cp311-musllinux_1_2_x86_64.whl:

Publisher: pypi.yml on dimagi/jsonobject

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file jsonobject-2.3.1.dev20250522235411-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for jsonobject-2.3.1.dev20250522235411-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 bd341ba658968464976e49a5121b89dee523b74aaba4cd4364c026ba8063a7cd
MD5 ba06519ffec0aa856ba17c68a51f2f8c
BLAKE2b-256 1fca8bbb2f12420b6f495911f7cae1e082d6467214cee4f5420399254b3228f3

See more details on using hashes here.

Provenance

The following attestation bundles were made for jsonobject-2.3.1.dev20250522235411-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: pypi.yml on dimagi/jsonobject

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file jsonobject-2.3.1.dev20250522235411-cp310-cp310-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for jsonobject-2.3.1.dev20250522235411-cp310-cp310-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 106957df2c6e670bb83d552b9be0cb367931134d2c9361e94a8b865a7858b016
MD5 3546c4e10cf7591ee5a3568896b2796c
BLAKE2b-256 99f102298f70b6eb466b016926db5bdfcf92a38ab25f66cba7b36099c72f5183

See more details on using hashes here.

Provenance

The following attestation bundles were made for jsonobject-2.3.1.dev20250522235411-cp310-cp310-musllinux_1_2_x86_64.whl:

Publisher: pypi.yml on dimagi/jsonobject

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file jsonobject-2.3.1.dev20250522235411-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for jsonobject-2.3.1.dev20250522235411-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 1c574aaee1f11b8791253405669d50612092107c1b836d8519a878ddecaf64bd
MD5 47f3ad334b5f2897770375a1b655827c
BLAKE2b-256 420d38650cccbebaf7ee14c1e13ddffd1b6bd1f0f4c85a0ecdbc64d0a380f6b9

See more details on using hashes here.

Provenance

The following attestation bundles were made for jsonobject-2.3.1.dev20250522235411-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: pypi.yml on dimagi/jsonobject

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file jsonobject-2.3.1.dev20250522235411-cp39-cp39-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for jsonobject-2.3.1.dev20250522235411-cp39-cp39-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 76104c08cd0932ce41ca27612b82e57793e6ce46120a37e2ca25fd4d8fd8e38d
MD5 a68c04103f67b46199d0787f05327549
BLAKE2b-256 ce2b0301455f16f9905a6e6934eba0a38418bb742ed55c34d99ae047eef56af0

See more details on using hashes here.

Provenance

The following attestation bundles were made for jsonobject-2.3.1.dev20250522235411-cp39-cp39-musllinux_1_2_x86_64.whl:

Publisher: pypi.yml on dimagi/jsonobject

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file jsonobject-2.3.1.dev20250522235411-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for jsonobject-2.3.1.dev20250522235411-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 5da8b9d6934d5c581231043b6066dd83f03b4dcf91cb09e63dc11d15c0450a69
MD5 5f3cbd427309db7a61e3b5af3118955d
BLAKE2b-256 df47fc33b922158a02c579693ade78e78b71c2267e3c9718d8dee4c7ff4e313e

See more details on using hashes here.

Provenance

The following attestation bundles were made for jsonobject-2.3.1.dev20250522235411-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: pypi.yml on dimagi/jsonobject

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page