Skip to content
Merged
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
8 changes: 0 additions & 8 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,19 +1,11 @@
language: python
python:
- "2.6"
- "2.7"
- "3.2"
- "3.3"
- "3.4"
- "3.5"
- "3.6"
# command to install dependencies
install: |
if [ "$TRAVIS_PYTHON_VERSION" == 3.2 ]
then
pip install "setuptools<30"
fi

pip install -r requirements.txt

# command to run tests
Expand Down
9 changes: 9 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
Changelog
---------

0.5.0
``````
+ Added support for Access Keys.
+ Added support for order_by and limit, group_by options.
+ Deprecated python 2.6, 3.2 and 3.3.
+ Scoped Keys are now deprecated in favor of Access Keys.
+ Now permits more versions of the requests library. (issue #133)


0.4.0
``````

Expand Down
79 changes: 75 additions & 4 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Use pip to install!

pip install keen

This client is known to work on Python 2.6, 2.7, 3.2, 3.3, 3.4, 3.5 and 3.6.
This client is known to work on Python 2.7, 3.4, 3.5 and 3.6.

For versions of Python < 2.7.9, you’ll need to install pyasn1, ndg-httpsclient, pyOpenSSL.

Expand Down Expand Up @@ -470,10 +470,81 @@ returned by the server in the specified time. For example:

This will cause both add_event() and add_events() to timeout after 100 seconds. If this timeout limit is hit, a requests.Timeout will be raised. Due to a bug in the requests library, you might also see an SSLError (https://github.com/kennethreitz/requests/issues/1294)

Create Scoped Keys
Create Access Keys
''''''''''''''''''

The Python client enables you to create `Scoped Keys <https://keen.io/docs/security/#scoped-key>`_ easily. For example:
The Python client enables the creation and manipulation of `Access Keys <https://keen.io/docs/access/access-keys>`_. Examples:

.. code-block:: python

from keen.client import KeenClient
# You could also simply use: import keen
# If you do this, you will need your project ID and master key set in environment variables.

client = KeenClient(
project_id="xxxx",
master_key="zzzz"
)

# Create an access key. See: https://keen.io/docs/access/access-keys/#customizing-your-access-key
client.create_access_key(name="Dave_Barry_Key", is_enabled=True, permitted=["writes", "cached_queries"],
options={"cached_queries": {"allowed": ["dave_barry_in_cyberspace_sales"]}})

# Display all access keys associated with this client's project.
client.list_access_keys()

# Get details on a particular access key.
client.get_access_key(access_key_id="ABCDEFGHIJKLMNOPQRSTUVWXYZ")

# Revoke (disable) an access key.
client.revoke_access_key(access_key_id="ABCDEFGHIJKLMNOPQRSTUVWXYZ")

# Unrevoke (re-enable) an access key.
client.unrevoke_access_key(access_key_id="ABCDEFGHIJKLMNOPQRSTUVWXYZ")

# Change just the name of an access key.
client.update_access_key_name(access_key_id="ABCDEFGHIJKLMNOPQRSTUVWXYZ", name="Some_New_Name")

# Add new access key permissions to existing permissions on a given key.
# In this case the set of permissions currently contains "writes" and "cached_queries".
# This function call keeps the old permissions and adds "queries" to that set.
# ("writes", "cached_queries") + ("queries") = ("writes", "cached_queries", "queries")
client.add_access_key_permissions(access_key_id="ABCDEFGHIJKLMNOPQRSTUVWXYZ", permissions=["queries"])

# Remove one or more access key permissions from a given key.
# In this case the set of permissions currently contains "writes", "cached_queries", and "queries".
# This function call will keep the old permissions not explicitly removed here.
# So we will remove both "writes" and "queries" from the set, leaving only "cached_queries".
# ("writes", "cached_queries", "queries") - ("writes", "queries") = ("cached_queries")
client.remove_access_key_permissions(access_key_id="ABCDEFGHIJKLMNOPQRSTUVWXYZ", permissions=["writes", "queries"])

# We can also perform a full update on the permissions, replacing all existing permissions with a new list.
# In this case our existing permissions contains only "cached_queries".
# We will replace this set with the "writes" permission with this function call.
# ("cached_queries") REPLACE-WITH ("writes") = ("writes")
client.update_access_key_permissions(access_key_id="ABCDEFGHIJKLMNOPQRSTUVWXYZ", permissions=["writes"])

# Replace all existing key options with this new options object.
client.update_access_key_options(access_key_id="ABCDEFGHIJKLMNOPQRSTUVWXYZ", options={"writes": {
"autofill": {
"customer": {
"id": "93iskds39kd93id",
"name": "Ada Corp."
}
}
}})

# Replace everything but the key ID with what is supplied here.
# If a field is not supplied here, it will be set to a blank value.
# In this case, no options are supplied, so all options will be removed.
client.update_access_key_full(access_key_id="ABCDEFGHIJKLMNOPQRSTUVWXYZ", name="Strong_Bad", is_active=True, permitted=["queries"])


Create Scoped Keys (**Deprecated**)
''''''''''''''''''

The Python client enables you to create `Scoped Keys <https://keen.io/docs/security/#scoped-key>`_ easily, but Access Keys are better!
If you need to use them anyway, for legacy reasons, here's how:

.. code-block:: python

Expand Down Expand Up @@ -501,7 +572,7 @@ To run tests:
Changelog
---------

This project is in alpha stage at version 0.4.0 . See the full CHANGELOG `here <./CHANGELOG.rst>`_.
This project is in alpha stage at version 0.5.0 . See the full CHANGELOG `here <./CHANGELOG.rst>`_.


Questions & Support
Expand Down
122 changes: 122 additions & 0 deletions keen/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -496,3 +496,125 @@ def get_all_collections():
"""
_initialize_client_from_environment()
return _client.get_all_collections()

def create_access_key(name, is_active=True, permitted=[], options={}):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was there a deliberate decision made to put this right in __init__.py instead of doing something liked the Saved/Cached Query Interface? Just curious.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The answer to all of these was, for the most part, to avoid deviating from the existing patterns I saw. The other answer is that I wanted to create the simplest path for users to run Access Key operations, which meant hiding the client (shoving it in __init__ like the basic queries) but also allowing them to work with a specific client in case they have multiple projects they are running in a single Python process.

To be honest though, I made that decision pretty lightly and could be persuaded to move it into its own interface. I don't like how monolithic that file has become.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm ambivalent, so whatever feels right to you.

""" Creates a new access key. A master key must be set first.

:param name: the name of the access key to create
:param is_active: Boolean value dictating whether this key is currently active (default True)
:param permitted: list of strings describing which operation types this key will permit
Legal values include "writes", "queries", "saved_queries", "cached_queries",
"datasets", and "schema".
:param options: dictionary containing more details about the key's permitted and restricted
functionality
"""
_initialize_client_from_environment()
return _client.create_access_key(name=name, is_active=is_active,
permitted=permitted, options=options)

def list_access_keys():
"""
Returns a list of all access keys in this project. A master key must be set first.
"""
_initialize_client_from_environment()
return _client.list_access_keys()

def get_access_key(access_key_id):
"""
Returns details on a particular access key. A master key must be set first.

:param access_key_id: the 'key' value of the access key to retreive data from
"""
_initialize_client_from_environment()
return _client.get_access_key(access_key_id)

def update_access_key_name(access_key_id, name):
"""
Updates only the name portion of an access key.

:param access_key_id: the 'key' value of the access key to change the name of
:param name: the new name to give this access key
"""
_initialize_client_from_environment()
return _client.update_access_key_name(access_key_id, name)

def add_access_key_permissions(access_key_id, permissions):
"""
Adds to the existing list of permissions on this key with the contents of this list.
Will not remove any existing permissions or modify the remainder of the key.

:param access_key_id: the 'key' value of the access key to add permissions to
:param permissions: the new permissions to add to the existing list of permissions
"""
_initialize_client_from_environment()
return _client.add_access_key_permissions(access_key_id, permissions)

def remove_access_key_permissions(access_key_id, permissions):
"""
Removes a list of permissions from the existing list of permissions.
Will not remove all existing permissions unless all such permissions are included
in this list. Not to be confused with key revocation.

See also: revoke_access_key()

:param access_key_id: the 'key' value of the access key to remove some permissions from
:param permissions: the permissions you wish to remove from this access key
"""
_initialize_client_from_environment()
return _client.remove_access_key_permissions(access_key_id, permissions)

def update_access_key_permissions(access_key_id, permissions):
"""
Replaces all of the permissions on the access key but does not change
non-permission properties such as the key's name.

See also: add_access_key_permissions() and remove_access_key_permissions().

:param access_key_id: the 'key' value of the access key to change the permissions of
:param permissions: the new list of permissions for this key
"""
_initialize_client_from_environment()
return _client.update_access_key_permissions(access_key_id, permissions)

def update_access_key_options(self, access_key_id, options):
"""
Replaces all of the options on the access key but does not change
non-option properties such as permissions or the key's name.

:param access_key_id: the 'key' value of the access key to change the options of
:param options: the new dictionary of options for this key
"""
_initialize_client_from_environment()
return _client.update_access_key_options(access_key_id, options)

def update_access_key_full(access_key_id, name, is_active, permitted, options):
"""
Replaces the 'name', 'is_active', 'permitted', and 'options' values of a given key.
A master key must be set first.

:param access_key_id: the 'key' value of the access key for which the values will be replaced
:param name: the new name desired for this access key
:param is_active: whether the key should become enabled (True) or revoked (False)
:param permitted: the new list of permissions desired for this access key
:param options: the new dictionary of options for this access key
"""
_initialize_client_from_environment()
return _client.update_access_key_full(access_key_id, name, is_active, permitted, options)

def revoke_access_key(access_key_id):
"""
Revokes an access key. "Bad dog! No biscuit!"

:param access_key_id: the 'key' value of the access key to revoke
"""
_initialize_client_from_environment()
return _client.revoke_access_key(access_key_id)

def unrevoke_access_key(access_key_id):
"""
Re-enables an access key.

:param access_key_id: the 'key' value of the access key to re-enable (unrevoke)
"""
_initialize_client_from_environment()
return _client.unrevoke_access_key(access_key_id)
Loading