Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-user-state-client
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
edx-user-state-client
Commits
18d31d57
Commit
18d31d57
authored
Jul 27, 2015
by
Calen Pennington
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Improve documentation and allow the possible future use of different scopes through the same client
parent
864ba98a
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
46 additions
and
37 deletions
+46
-37
doc/conf.py
+5
-1
edx_user_state_client/interface.py
+35
-30
edx_user_state_client/tests.py
+6
-6
No files found.
doc/conf.py
View file @
18d31d57
...
...
@@ -291,4 +291,8 @@ texinfo_documents = [
# Example configuration for intersphinx: refer to the Python standard library.
intersphinx_mapping
=
{
'https://docs.python.org/'
:
None
}
intersphinx_mapping
=
{
'https://docs.python.org/'
:
None
,
'http://xblock.readthedocs.org/en/latest/'
:
None
,
'http://opaque-keys.readthedocs.org/en/stable/'
:
None
,
}
edx_user_state_client/interface.py
View file @
18d31d57
...
...
@@ -7,23 +7,33 @@ from collections import namedtuple
from
contracts
import
contract
,
new_contract
,
ContractsMeta
from
datetime
import
datetime
from
opaque_keys.edx.keys
import
UsageKey
from
opaque_keys.edx.keys
import
UsageKey
,
DefinitionKey
from
xblock.fields
import
Scope
,
ScopeBase
new_contract
(
'UsageKey'
,
UsageKey
)
new_contract
(
'DefinitionKey'
,
DefinitionKey
)
new_contract
(
'basestring'
,
basestring
)
new_contract
(
'datetime'
,
datetime
)
new_contract
(
'block_key'
,
'UsageKey|DefinitionKey|str|NoneType'
)
class
XBlockUserState
(
namedtuple
(
'_XBlockUserState'
,
[
'username'
,
'block_key'
,
'state'
,
'updated'
])):
class
XBlockUserState
(
namedtuple
(
'_XBlockUserState'
,
[
'username'
,
'block_key'
,
'state'
,
'updated'
,
'scope'
])):
"""
The current state of a single XBlock.
Arguments:
username: The username of the user that stored this state.
block_key: The :class:`UsageKey` of the XBlock.
block_key: The key identifying the scoped state. Depending on the :class:`~xblock.fields.BlockScope` of
``scope``, this may take one of several types:
* ``USAGE``: :class:`~opaque_keys.edx.keys.UsageKey`
* ``DEFINITION``: :class:`~opaque_keys.edx.keys.DefinitionKey`
* ``TYPE``: :class:`str`
* ``ALL``: ``None``
state: A dict mapping field names to the values of those fields for this XBlock.
updated: A :class:`datetime.datetime` that identifies when this state was stored.
scope: A :class:`xblock.fields.Scope` identifying which XBlock scope this state is coming from.
"""
__slots__
=
()
...
...
@@ -54,14 +64,6 @@ class XBlockUserStateClient(object):
This also implies that the client is running as a user, and whatever is
backing it is smart enough to do authorization checks.
3. This does not yet cover export-related functionality.
Open Questions:
1. Is it sufficient to just send the block_key in and extract course +
version info from it?
2. Do we want to use the username as the identifier? Privacy implications?
Ease of debugging?
3. Would a get_many_by_type() be useful?
"""
__metaclass__
=
ContractsMeta
...
...
@@ -86,7 +88,7 @@ class XBlockUserStateClient(object):
@contract
(
username
=
"basestring"
,
block_key
=
UsageKey
,
block_key
=
"block_key"
,
scope
=
ScopeBase
,
fields
=
"seq(basestring)|set(basestring)|None"
,
returns
=
XBlockUserState
,
...
...
@@ -98,12 +100,15 @@ class XBlockUserStateClient(object):
Arguments:
username: The name of the user whose state should be retrieved
block_key
(UsageKey): The UsageK
ey identifying which xblock state to load.
block_key
: The k
ey identifying which xblock state to load.
scope (Scope): The scope to load data from
fields: A list of field values to retrieve. If None, retrieve all stored fields.
Returns
Returns
:
XBlockUserState: The current state of the block for the specified username and block_key.
Raises:
DoesNotExist if no entry is found.
"""
try
:
return
next
(
self
.
get_many
(
username
,
[
block_key
],
scope
,
fields
=
fields
))
...
...
@@ -112,7 +117,7 @@ class XBlockUserStateClient(object):
@contract
(
username
=
"basestring"
,
block_key
=
UsageKey
,
block_key
=
"block_key"
,
state
=
"dict(basestring: *)"
,
scope
=
ScopeBase
,
returns
=
None
,
...
...
@@ -124,7 +129,7 @@ class XBlockUserStateClient(object):
Arguments:
username: The name of the user whose state should be retrieved
block_key
(UsageKey): The UsageK
ey identifying which xblock state to load.
block_key
: The k
ey identifying which xblock state to load.
state (dict): A dictionary mapping field names to values
scope (Scope): The scope to store data to
"""
...
...
@@ -132,7 +137,7 @@ class XBlockUserStateClient(object):
@contract
(
username
=
"basestring"
,
block_key
=
UsageKey
,
block_key
=
"block_key"
,
scope
=
ScopeBase
,
fields
=
"seq(basestring)|set(basestring)|None"
,
returns
=
None
,
...
...
@@ -144,7 +149,7 @@ class XBlockUserStateClient(object):
Arguments:
username: The name of the user whose state should be deleted
block_key
(UsageKey): The UsageK
ey identifying which xblock state to delete.
block_key
: The k
ey identifying which xblock state to delete.
scope (Scope): The scope to delete data from
fields: A list of fields to delete. If None, delete all stored fields.
"""
...
...
@@ -152,7 +157,7 @@ class XBlockUserStateClient(object):
@contract
(
username
=
"basestring"
,
block_key
=
UsageKey
,
block_key
=
"block_key"
,
scope
=
ScopeBase
,
fields
=
"seq(basestring)|set(basestring)|None"
,
returns
=
"dict(basestring: datetime)"
,
...
...
@@ -164,7 +169,7 @@ class XBlockUserStateClient(object):
Arguments:
username: The name of the user whose state should queried
block_key
(UsageKey): The UsageK
ey identifying which xblock modification dates to retrieve.
block_key
: The k
ey identifying which xblock modification dates to retrieve.
scope (Scope): The scope to retrieve from.
fields: A list of fields to query. If None, query all fields.
Specific implementations are free to return the same modification date
...
...
@@ -180,7 +185,7 @@ class XBlockUserStateClient(object):
@contract
(
username
=
"basestring"
,
block_keys
=
"seq(
UsageKey)|set(UsageK
ey)"
,
block_keys
=
"seq(
block_key)|set(block_k
ey)"
,
scope
=
ScopeBase
,
fields
=
"seq(basestring)|set(basestring)|None"
,
modify_docstring
=
False
,
...
...
@@ -192,19 +197,19 @@ class XBlockUserStateClient(object):
Arguments:
username: The name of the user whose state should be retrieved
block_keys
([UsageKey]): A list of UsageK
eys identifying which xblock states to load.
block_keys
: A list of k
eys identifying which xblock states to load.
scope (Scope): The scope to load data from
fields: A list of field values to retrieve. If None, retrieve all stored fields.
Yields:
XBlockUserState tuples for each specified
UsageK
ey in block_keys.
XBlockUserState tuples for each specified
k
ey in block_keys.
field_state is a dict mapping field names to values.
"""
raise
NotImplementedError
()
@contract
(
username
=
"basestring"
,
block_keys_to_state
=
"dict(
UsageK
ey: dict(basestring: *))"
,
block_keys_to_state
=
"dict(
block_k
ey: dict(basestring: *))"
,
scope
=
ScopeBase
,
returns
=
None
,
modify_docstring
=
False
,
...
...
@@ -216,7 +221,7 @@ class XBlockUserStateClient(object):
Arguments:
username: The name of the user whose state should be retrieved
block_keys_to_state (dict): A dict mapping
UsageK
eys to state dicts.
block_keys_to_state (dict): A dict mapping
k
eys to state dicts.
Each state dict maps field names to values. These state dicts
are overlaid over the stored state. To delete fields, use
:meth:`delete` or :meth:`delete_many`.
...
...
@@ -226,7 +231,7 @@ class XBlockUserStateClient(object):
@contract
(
username
=
"basestring"
,
block_keys
=
"seq(
UsageKey)|set(UsageK
ey)"
,
block_keys
=
"seq(
block_key)|set(block_k
ey)"
,
scope
=
ScopeBase
,
fields
=
"seq(basestring)|set(basestring)|None"
,
returns
=
None
,
...
...
@@ -239,7 +244,7 @@ class XBlockUserStateClient(object):
Arguments:
username: The name of the user whose state should be deleted
block_key
(UsageKey): The UsageK
ey identifying which xblock state to delete.
block_key
: The k
ey identifying which xblock state to delete.
scope (Scope): The scope to delete data from
fields: A list of fields to delete. If None, delete all stored fields.
"""
...
...
@@ -247,7 +252,7 @@ class XBlockUserStateClient(object):
@contract
(
username
=
"basestring"
,
block_keys
=
"seq(
UsageKey)|set(UsageK
ey)"
,
block_keys
=
"seq(
block_key)|set(block_k
ey)"
,
scope
=
ScopeBase
,
fields
=
"seq(basestring)|set(basestring)|None"
,
modify_docstring
=
False
,
...
...
@@ -259,7 +264,7 @@ class XBlockUserStateClient(object):
Arguments:
username: The name of the user whose state should be queried
block_key
(UsageKey): The UsageK
ey identifying which xblock modification dates to retrieve.
block_key
: The k
ey identifying which xblock modification dates to retrieve.
scope (Scope): The scope to retrieve from.
fields: A list of fields to query. If None, delete all stored fields.
Specific implementations are free to return the same modification date
...
...
@@ -279,7 +284,7 @@ class XBlockUserStateClient(object):
Arguments:
username: The name of the user whose history should be retrieved.
block_key
(UsageKey): The UsageK
ey identifying which xblock history to retrieve.
block_key
: The k
ey identifying which xblock history to retrieve.
scope (Scope): The scope to load data from.
Yields:
...
...
edx_user_state_client/tests.py
View file @
18d31d57
...
...
@@ -40,12 +40,12 @@ class _UserStateClientTestUtils(TestCase):
@contract
(
user
=
int
)
def
_user
(
self
,
user
):
"""Return the username for user ``user``"""
"""Return the username for user ``user``
.
"""
return
"user{}"
.
format
(
user
)
@contract
(
block
=
int
)
def
_block
(
self
,
block
):
"""Return a UsageKey for the block ``block``"""
"""Return a UsageKey for the block ``block``
.
"""
course
=
block
//
1000
return
BlockUsageLocator
(
self
.
_course
(
course
),
...
...
@@ -272,10 +272,10 @@ class _UserStateClientTestCRUD(_UserStateClientTestUtils):
def
test_get_many
(
self
):
self
.
set_many
(
user
=
0
,
block_to_state
=
{
0
:
{
'a'
:
'b'
},
1
:
{
'b'
:
'c'
}})
self
.
assertItemsEqual
(
[
entry
.
_replace
(
updated
=
Non
e
)
for
entry
in
self
.
get_many
(
user
=
0
,
blocks
=
[
0
,
1
])],
[
(
entry
.
username
,
entry
.
block_key
,
entry
.
stat
e
)
for
entry
in
self
.
get_many
(
user
=
0
,
blocks
=
[
0
,
1
])],
[
XBlockUserState
(
self
.
_user
(
0
),
self
.
_block
(
0
),
{
'a'
:
'b'
},
None
),
XBlockUserState
(
self
.
_user
(
0
),
self
.
_block
(
1
),
{
'b'
:
'c'
},
None
)
(
self
.
_user
(
0
),
self
.
_block
(
0
),
{
'a'
:
'b'
}
),
(
self
.
_user
(
0
),
self
.
_block
(
1
),
{
'b'
:
'c'
}
)
]
)
...
...
@@ -575,7 +575,7 @@ class DictUserStateClient(XBlockUserStateClient):
Add the specified state to the state history of this block.
"""
history_list
=
self
.
_history
.
setdefault
((
username
,
block_key
,
scope
),
[])
history_list
.
insert
(
0
,
XBlockUserState
(
username
,
block_key
,
state
,
datetime
.
now
()))
history_list
.
insert
(
0
,
XBlockUserState
(
username
,
block_key
,
state
,
datetime
.
now
()
,
scope
))
def
get_many
(
self
,
username
,
block_keys
,
scope
=
Scope
.
user_state
,
fields
=
None
):
for
key
in
block_keys
:
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment