Skip to content

Commit

Permalink
account: Cleanup in code docs
Browse files Browse the repository at this point in the history
  • Loading branch information
akkornel committed Jul 5, 2021
1 parent 651b745 commit a1212a8
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 43 deletions.
32 changes: 16 additions & 16 deletions src/stanford/mais/account/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class AccountClient():
Once you have a client instantiated, you can use :meth:`get` to fetch an
account. For your convenience, instances of this class also implement
`__getitem__`, so instead of doing…
``__getitem__``, so instead of doing…
.. code-block:: default
Expand All @@ -70,7 +70,7 @@ class AccountClient():
.. code-block:: default
aclient = AccountClient(...)
lelandjr_exists = (True if 'lelandjr' in client else False)
lelandjr_exists = (True if 'lelandjr' in aclient else False)
Through the use of caching, if you then decide to fetch the account
after confirming its existance, the entry will be served from cache
Expand All @@ -84,7 +84,7 @@ class AccountClient():
client: stanford.mais.client.MAISClient
"""A :class:`~stanford.mais.client.MAISClient` instance.
This configures the API endpoint (accessed via `client.urls['account']`)
This configures the API endpoint (accessed via ``client.urls['account']``)
and client key/cert to use. It must be provided when calling the class
constructor.
Expand All @@ -100,8 +100,9 @@ class AccountClient():
Normally, this should not be set, and a new session will be requested from
the client. But if you would like to use a custom
:class:`requests.Session` instance (such as for mock testing), provide it
as the ``custom_session`` and it will be used for all requests.
:class:`~requests.Session` instance (such as for mock testing), provide it
to the constructor as the ``custom_session`` and it will be used for all
requests.
"""

_cache: MutableMapping[str, 'Account'] = dataclasses.field(repr=False, default_factory=dict)
Expand Down Expand Up @@ -141,12 +142,11 @@ def get(
) -> 'Account':
"""Fetch an Account.
This is a convenience wrapper around :meth:`Account.get`, which
provides this client as the `client`. All other parameters provided
are passed through to :meth:`Account.get`, and the resulting instance
is returned.
This is a convenience wrapper around :meth:`Account.get`. All other
parameters provided are passed through to :meth:`~Account.get`, and the
resulting instance is returned.
Refer to :meth:`~Account.get` for details on parameters, exceptions,
Refer to :meth:`Account.get` for details on parameters, exceptions,
etc..
"""
return Account.get(
Expand Down Expand Up @@ -186,7 +186,7 @@ def __contains__(
def only_active(
self,
) -> 'AccountView':
"""Create a modified ``AccountClient`` that can only see active
"""Create a modified :class:``AccountClient`` that can only see active
accounts.
The returned client instance has been modified so that
Expand Down Expand Up @@ -220,7 +220,7 @@ def only_active(
def only_inactive(
self,
) -> 'AccountView':
"""Create a modified ``AccountClient`` that can only see inactive
"""Create a modified :class:``AccountClient`` that can only see inactive
accounts.
The returned client instance has been modified so that
Expand All @@ -242,8 +242,8 @@ def only_inactive(
def only_people(
self,
) -> 'AccountView':
"""Create a modified ``AccountClient`` that can only see accounts of
people.
"""Create a modified :class:``AccountClient`` that can only see
accounts of people.
The returned client instance has been modified so that
:meth:`~AccountClient.get` only returns the accounts of people. If you
Expand Down Expand Up @@ -287,8 +287,8 @@ def only_people(
def only_functional(
self,
) -> 'AccountView':
"""Create a modified ``AccountClient`` that can only see functional
accounts.
"""Create a modified :class:``AccountClient`` that can only see
functional accounts.
The returned client instance has been modified so that
:meth:`~AccountClient.get` only returns functional accounts. If you
Expand Down
40 changes: 27 additions & 13 deletions src/stanford/mais/account/account.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,18 @@ class Account():
This contains the services currently associated with the account. Each
service has a service name, and the value is a dataclass which contains
status and service-specific information.
It is a :class:`~collections.abc.Mapping` of :class:`str` (the service
name) to subclasses of
:class:`~stanford.mais.account.service.AccountService`. To learn the key
name for each service, refer to the documentation for that subclass.
.. note::
From time to time, new services are defined. Those services will
**not** appear in this mapping until a software update is released,
defining a new subclass for that service. If you need to access the
service's data before that time, refer to the `services` key in the
parsed JSON.
"""

last_updated: datetime.datetime
Expand All @@ -155,10 +167,10 @@ class Account():
separator.
* If the account is for a person (that is, `type` is "self"), then this
string will be `person/` followed by the RegID of the person.
string will be ``person/`` followed by the RegID of the person.
* If the account is for a functional account (`type` is "functional"),
then this string will be `organization/` followed by the RegID of the
then this string will be ``organization/`` followed by the RegID of the
Org which owns the functional account.
* **statusDate**: The date when this account was last changed, in the
Expand Down Expand Up @@ -197,27 +209,29 @@ def get(
for the same input will return the same result instance, thanks to the
use of a cache.
*WARNING*: This will looks up accounts of all types, both accounts for
people and also functional accounts. Check the :meth:`type` before
assuming you are working with a SUNetID.
.. warning::
This will looks up accounts of all types, both accounts for
people and also functional accounts. Check :meth:`is_person` before
assuming you are working with a SUNetID.
*WARNING*: This memoization means that, should an account change status
after lookup, that status change will not be noticed until after the
module is reloaded. That means this code should *not* be used by
long-running client code.
.. warning::
This memoization means that, should an account change status
after lookup, that status change will not be noticed until after the
module is reloaded. That means this code should *not* be used by
long-running client code.
:param client: An :class:`AccountClient` representing our API endpoint.
:param sunetid: The to look up. This must be an actual id, not an alias.
:param sunetid: The ID to look up. This must be an actual id, not an alias.
:raises ChildProcessError: Something went wrong on the server side (a 400 or 500 error was returned).
:raises IndexError: The input is too long. Maybe the input is an alias?
:raises KeyError: The given SUNetID does not exist.
:raises KeyError: The given ID does not exist. Maybe it was an alias?
:raises PermissionError: You did not use a valid certificate, or do not have permissions to perform the operation.
:raises UnicodeEncodeError: The ID you provided included non-ASCII characters.
:raises ValueError: The input contains non-ASCII characters.
:raises requests.Timeout: The MaIS Workgroup API did not respond in time.
Expand Down
12 changes: 8 additions & 4 deletions src/stanford/mais/account/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ class AccountServiceSEAS(AccountService):
"""``seas`` service for an Account.
The "Stanford Electronic Alias Service". If this service is active, then
the account has an associated `@stanford.edu` email address, even if they
the account has an associated *@stanford.edu* email address, even if they
don't have a Stanford email box.
.. note::
Expand Down Expand Up @@ -427,7 +427,7 @@ def _from_json(
class AccountServiceLeland(AccountService):
"""``leland`` service for an Account.
This represents the Stanford `Shared Computing`_ environment, originally
This represents the Stanford `Shared Computing`_ environment, once
known as `Leland`_ and known today as `FarmShare`_. If active, users are
able to log in to FarmShare.
Expand Down Expand Up @@ -517,12 +517,16 @@ class AccountServiceAFS(AccountService):
The path to the account's home directory.
.. note::
This is used as the account's `homeDirectory` in LDAP. As such, you
This is used as the account's ``homeDirectory`` in LDAP. As such, you
will probably want to override it.
.. note::
This setting assumes that AFS is mounted at path ``/afs`` on a ssytem.
This is normally, but not always, the case.
This is normally, but not always, the case. This setting also assumes
that your system has an up-to-date copy of the
`CellServDB <https://docs.openafs.org/Reference/5/CellServDB.html>`_
file, which should be the case if you are using a packaged OpenAFS
client.
"""

@classmethod
Expand Down
35 changes: 25 additions & 10 deletions src/stanford/mais/account/validate.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ class AccountValidationResults(NamedTuple):
This class contains the results of an account validation, called via
:func:`validate`.
.. note::
Many of these properties are collections. That means, if you want to
use things like subscripting, you will want to convert to a
more-specific type (such as :class:`list` before using it).
"""

raw: Optional[str]
Expand All @@ -55,47 +60,54 @@ class AccountValidationResults(NamedTuple):
collection. Otherwise, this will be the original list/set/tuple that was
provided to :func:`validate`, but made into a set.
The set union of `full`, `base`, `inactive`, and `unknown` should equal
The set union of `full`, `base`, `inactive`, and `unknown` is equal to
this list.
"""

full: Collection[str]
"""
The list of active, full (or full-sponsored) SUNetIDs found in `raw_set`.
The set of active, full (or full-sponsored) SUNetIDs found in `raw_set`.
"""

base: Collection[str]
"""
The list of active, base (or base-sponsored) SUNetIDs found in `raw_set`.
The set of active, base (or base-sponsored) SUNetIDs found in `raw_set`.
"""

inactive: Collection[str]
"""
The list of inactive SUNetIDs found in `raw_set`.
The set of inactive SUNetIDs found in `raw_set`.
"""

unknown: Collection[str]
"""
The list of entries from `raw_set` that are not SUNetIDs.
The set of entries from `raw_set` that are not SUNetIDs.
"""

@functools.singledispatch
def validate(
raw: str,
client: stanford.mais.account.AccountClient,
) -> AccountValidationResults:
"""Given a list of SUNetIDs, in string or collection form, validate and
check status.
"""Given a list of SUNetIDs; as a string or a list, tuple, or set; validate
and check status.
This takes a list of SUNetIDs, and returns a list of SUNetIDs which have
been checked against the Accounts API for both activity and service level.
The returned result shows which SUNetIDs are active full (or
full-sponsored), active base (or base-sponsored), or inactive.
If the input is a string, then the input string may be separated by commas,
and/or any kind of whitespace. If the input is some other form of
collection (list, tuple, or set), the function assumes that all whitespace
etc. have been removed.
and/or whitespace, (where "whitespace" is a space, newline/linefeed, form
feed, carriage return, tab/horizontal tab, or vertical tab character). If
the input is a list, tuple, or set; the function assumes that all
whitespace etc. have been removed.
.. note::
"List, tuple, or set" is used instead of the generic "collection"
because a :class:`str` is also a collection (of other :class:`str`).
See `typing issue #256 <https://github.com/python/typing/issues/256>`_
for the discussion around this issue.
This is designed to catch most exceptions. Exceptions related to
validation (for example, attempting to validate an obviously-invalid
Expand Down Expand Up @@ -180,6 +192,9 @@ def _(
unknown.add(sunetid)
continue

# Overwrite the input SUNetID with the normalized one.
sunetid = account.sunetid

# Next, catch inactives
if account.is_active is False:
debug(f"Account {sunetid} NOT active.")
Expand Down

0 comments on commit a1212a8

Please sign in to comment.