Scope Parser#

This component defines a Scope object and exposes use of a parser which can parse scope strings into trees of Scope objects. It should be regarded as very similar to the existing MutableScope object in globus_sdk.scopes. Key differences from MutableScope:

  • Scope.parse is available, for parsing scopes from strings

  • The Globus SDK does not support using Scope in all of the locations where MutableScope is supported – Scope objects must be stringified for use

  • Scope objects define a __contains__ method, allowing one to check if one scope properly contains another


The scope trees produced by parsing represent prospective consent structures as would be produced by a single authentication flow in Auth. No external APIs (e.g., the Get Consents API) are used to validate or mutate the data.


class globus_sdk.experimental.scope_parser.Scope(scope_string: str, *, optional: bool = False, dependencies: list[Scope] | None = None)[source]#

A scope object is a representation of a scope which allows modifications to be made. In particular, it supports handling scope dependencies via add_dependency.

str(Scope(…)) produces a valid scope string for use in various methods.

  • scope_string (str) – The string which will be used as the basis for this Scope

  • optional (bool) – The scope may be marked as optional. This means that the scope can be declined by the user without declining consent for other scopes

__init__(scope_string: str, *, optional: bool = False, dependencies: list[Scope] | None = None) None[source]#
static parse(scope_string: str) list[Scope][source]#

Parse an arbitrary scope string to a list of scopes.

Zero or more than one scope may be returned, as in the case of an empty string or space-delimited scopes.


Parsing passes through an intermediary representation which treats scopes as a graph. This ensures that the behavior of parses matches the treatment of scope strings in Globus Auth authorization flows. However, this also means that the parsing does not allow for strings which represent consent trees with structures in which the same scope appears in multiple parts of the tree.


scope_string (str) – The string to parse

classmethod deserialize(scope_string: str) Scope[source]#

Deserialize a scope string to a scope object.

This is the special case of parsing in which exactly one scope must be returned by the parse. If more than one scope is returned by the parse, a ValueError will be raised.


scope_string (str) – The string to parse

add_dependency(scope: str | Scope, *, optional: bool | None = None) Scope[source]#

Add a scope dependency. The dependent scope relationship will be stored in the Scope and will be evident in its string representation.

  • scope (str) – The scope upon which the current scope depends

  • optional (bool, optional) – Mark the dependency an optional one. By default it is not. An optional scope dependency can be declined by the user without declining consent for the primary scope

__repr__() str[source]#

Return repr(self).

__str__() str[source]#

Return str(self).

__contains__(other: Any) bool[source]#


The __contains__ method is a non-authoritative convenience for comparing parsed scopes. Although the essence and intent of the check is summarized below, there is no guarantee that it correctly reflects the permissions of a token or tokens. The structure of the data for a given consent in Globus Auth is not perfectly reflected in the parse tree.

in and not in are defined as permission coverage checks

scope1 in scope2 means that a token scoped for scope2 has all of the permissions of a token scoped for scope1.

A scope is covered by another scope if

  • the top level strings match

  • the optional-ness matches OR only the covered scope is optional

  • the dependencies of the covered scope are all covered by dependencies of the covering scope

Therefore, the following are true:

>>> s = lambda x: Scope.deserialize(x)  # define this for brevity below
# self inclusion works, including when optional
>>> s("foo") in s("foo")
>>> s("*foo") in s("*foo")
# an optional scope is covered by a non-optional one, but not the reverse
>>> s("*foo") in s("foo")
>>> s("foo") not in s("*foo")
# dependencies have the expected meanings
>>> s("foo") in s("foo[bar]")
>>> s("foo[bar]") not in s("foo")
>>> s("foo[bar]") in s("foo[bar[baz]]")
# dependencies are not transitive and obey "optionalness" matching
>>> s("foo[bar]") not in s("foo[fizz[bar]]")
>>> s("foo[bar]") not in s("foo[*bar]")

list of weak references to the object (if defined)

class globus_sdk.experimental.scope_parser.ScopeParseError[source]#

The error raised if scope parsing fails.

class globus_sdk.experimental.scope_parser.ScopeCycleError[source]#

The error raised if scope parsing discovers a cycle.