Skip to content

Commit b32c3cc

Browse files
author
Keith Ingersoll
committed
initial commit
0 parents  commit b32c3cc

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+15475
-0
lines changed

.gitattributes

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
civis/tests/cassettes/*.yaml -diff

.gitignore

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# Byte-compiled / optimized / DLL files
2+
__pycache__/
3+
*.py[cod]
4+
*$py.class
5+
6+
# C extensions
7+
*.so
8+
9+
# Distribution / packaging
10+
.Python
11+
env/
12+
build/
13+
develop-eggs/
14+
dist/
15+
eggs/
16+
.eggs/
17+
parts/
18+
sdist/
19+
*.egg-info/
20+
*.egg
21+
22+
# Unit test / coverage reports
23+
htmlcov/
24+
.tox/
25+
.coverage
26+
.coverage.*
27+
.cache
28+
nosetests.xml
29+
coverage.xml
30+
*,cover
31+
32+
# Django stuff:
33+
*.log
34+
35+
# Internal
36+
swagger.json
37+
38+
# vim
39+
*.swp
40+
41+
# Sphinx docs
42+
docs/source/generated/
43+
docs/source/api_resources.rst

.gitmodules

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[submodule "docs/sphinxext"]
2+
path = docs/sphinxext
3+
url = https://github.com/numpy/numpydoc
4+
[submodule "docs/sphinx_rtd_theme"]
5+
path = docs/sphinx_rtd_theme
6+
url = https://github.com/snide/sphinx_rtd_theme.git

.travis.yml

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
language: python
2+
python:
3+
- "3.4"
4+
install:
5+
- pip install -r requirements.txt
6+
- pip install -r dev-requirements.txt
7+
- pip install -e .
8+
env:
9+
global:
10+
- CIVIS_API_KEY=FOOBAR
11+
before_script: flake8 civis
12+
script:
13+
- py.test --cov civis
14+
- sphinx-build -b html -nW docs/source/ docs/build/

CHANGELOG.md

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Change Log
2+
All notable changes to this project will be documented in this file.
3+
This project adheres to [Semantic Versioning](http://semver.org/).
4+
5+
6+
## 1.0.0 - 2016-11-07
7+
### Added
8+
- Initial release

CODE_OF_CONDUCT.md

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# Contributor Code of Conduct
2+
3+
As contributors and maintainers of this project, and in the interest of
4+
fostering an open and welcoming community, we pledge to respect all people who
5+
contribute through reporting issues, posting feature requests, updating
6+
documentation, submitting pull requests or patches, and other activities.
7+
8+
We are committed to making participation in this project a harassment-free
9+
experience for everyone, regardless of level of experience, gender, gender
10+
identity and expression, sexual orientation, disability, personal appearance,
11+
body size, race, ethnicity, age, religion, or nationality.
12+
13+
Examples of unacceptable behavior by participants include:
14+
15+
* The use of sexualized language or imagery
16+
* Personal attacks
17+
* Trolling or insulting/derogatory comments
18+
* Public or private harassment
19+
* Publishing other's private information, such as physical or electronic
20+
addresses, without explicit permission
21+
* Other unethical or unprofessional conduct
22+
23+
Project maintainers have the right and responsibility to remove, edit, or
24+
reject comments, commits, code, wiki edits, issues, and other contributions
25+
that are not aligned to this Code of Conduct, or to ban temporarily or
26+
permanently any contributor for other behaviors that they deem inappropriate,
27+
threatening, offensive, or harmful.
28+
29+
By adopting this Code of Conduct, project maintainers commit themselves to
30+
fairly and consistently applying these principles to every aspect of managing
31+
this project. Project maintainers who do not follow or enforce the Code of
32+
Conduct may be permanently removed from the project team.
33+
34+
This Code of Conduct applies both within project spaces and in public spaces
35+
when an individual is representing the project or its community.
36+
37+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
38+
reported by contacting a project maintainer at [email protected].
39+
All complaints will be reviewed and investigated and will result in a response
40+
that is deemed necessary and appropriate to the circumstances. Maintainers are
41+
obligated to maintain confidentiality with regard to the reporter of an
42+
incident.
43+
44+
45+
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
46+
version 1.3.0, available at
47+
[http://contributor-covenant.org/version/1/3/0/][version]
48+
49+
[homepage]: http://contributor-covenant.org
50+
[version]: http://contributor-covenant.org/version/1/3/0/

CONTRIBUTING.md

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Contributing to civis-python
2+
3+
We welcome bug reports and pull requests from everyone!
4+
This project is intended to be a safe, welcoming space for collaboration, and
5+
contributors are expected to adhere to the
6+
[Contributor Covenant](http://contributor-covenant.org) code of conduct.
7+
8+
9+
## Getting Started
10+
11+
1. Fork it ( https://github.com/civisanalytics/civis-python/fork ).
12+
2. Install it, with the development dependencies. See `README.md`.
13+
3. Make sure you are able to run the test suite locally (`py.test civis`).
14+
4. Create a feature branch (`git checkout -b my-new-feature`).
15+
5. Make your change. Don't forget tests.
16+
6. Make sure the test suite, including your new tests, passes
17+
(`py.test civis && flake8 civis`).
18+
7. Commit your changes (`git commit -am 'Add some feature'`).
19+
8. Push to the branch (`git push origin my-new-feature`).
20+
9. Create a new pull request.
21+
10. If the build fails, address any issues.
22+
23+
## Tips
24+
25+
- All pull requests must include test coverage. If you’re not sure how to test
26+
your changes, feel free to ask for help.
27+
- Contributions must conform to the guidelines encoded by `flake8`, based on
28+
PEP-8.
29+
- Don’t forget to add your change to the [CHANGELOG](CHANGELOG.md). See
30+
[Keep a CHANGELOG](http://keepachangelog.com/) for guidelines.
31+
32+
Thank you for taking the time to contribute!

LICENSE.md

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
Copyright (c) 2016, Civis Analytics
2+
All rights reserved.
3+
4+
Redistribution and use in source and binary forms, with or without
5+
modification, are permitted provided that the following conditions are met:
6+
7+
1. Redistributions of source code must retain the above copyright notice, this
8+
list of conditions and the following disclaimer.
9+
10+
2. Redistributions in binary form must reproduce the above copyright notice,
11+
this list of conditions and the following disclaimer in the documentation
12+
and/or other materials provided with the distribution.
13+
14+
3. Neither the name of the copyright holder nor the names of its contributors
15+
may be used to endorse or promote products derived from this software
16+
without specific prior written permission.
17+
18+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

MANIFEST.in

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
include requirements.txt
2+
include README.md
3+
include LICENSE.md
4+
include civis/_version.py

README.md

+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
Civis API Python Client
2+
=======================
3+
4+
# Introduction
5+
6+
The Civis API Python client is a Python package that helps analysts and
7+
developers interact with the Civis Platform. The package includes a set of
8+
tools around common workflows as well as a convenient interface to make
9+
requests directly to the Civis API. See the
10+
[full documentation](https://civis-python.readthedocs.io) for more details.
11+
12+
13+
# Installation
14+
15+
1. Get a Civis API key [(instructions)](https://civis.zendesk.com/hc/en-us/articles/216341583-Generating-an-API-Key)
16+
2. Add a `CIVIS_API_KEY` environment variable.
17+
3. You can add the following to `.bash_profile` for bash
18+
```
19+
export CIVIS_API_KEY="alphaNumericApiK3y"
20+
```
21+
4. Source your `.bash_profile`
22+
5. Install the package
23+
24+
```
25+
pip install git+git://github.com/civisanalytics/civis-python.git
26+
```
27+
6. Optionally, install `pandas` to enable some functionality in `civis-python`
28+
29+
```
30+
pip install pandas
31+
```
32+
33+
# Usage
34+
35+
`civis-python` includes a number of wrappers around the Civis API for
36+
common workflows.
37+
38+
```python
39+
import civis
40+
df = civis.io.read_civis(table="my_schema.my_table",
41+
database="database",
42+
use_pandas=True)
43+
```
44+
45+
The Civis API may also be directly accessed via the `APIClient` class.
46+
47+
```python
48+
import civis
49+
client = civis.APIClient()
50+
database = client.databases.list()
51+
```
52+
53+
See the [full documentation](https://civis-python.readthedocs.io) for a more
54+
complete user guide.
55+
56+
57+
# Contributing
58+
59+
See `CONTIBUTING.md` for information about contributing to this project.
60+
61+
62+
# License
63+
64+
BSD-3
65+
66+
See `LICENSE.md` for details.

civis/__init__.py

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from ._version import __version__
2+
from .civis import APIClient, find, find_one
3+
from . import io
4+
5+
__all__ = ["__version__", "APIClient", "find", "find_one", "io"]

civis/_utils.py

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import re
2+
import uuid
3+
4+
5+
UNDERSCORER1 = re.compile(r'(.)([A-Z][a-z]+)')
6+
UNDERSCORER2 = re.compile('([a-z0-9])([A-Z])')
7+
8+
9+
def maybe_get_random_name(name):
10+
if not name:
11+
name = uuid.uuid4().hex
12+
return name
13+
14+
15+
def camel_to_snake(word):
16+
# https://gist.github.com/jaytaylor/3660565
17+
word = UNDERSCORER1.sub(r'\1_\2', word)
18+
return UNDERSCORER2.sub(r'\1_\2', word).lower()
19+
20+
21+
def to_camelcase(s):
22+
return re.sub(r'(^|_)([a-zA-Z])', lambda m: m.group(2).upper(), s)

civis/_version.py

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
__version__ = "1.0.0"

civis/base.py

+89
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
from posixpath import join
2+
import threading
3+
4+
from civis.response import PaginatedResponse, convert_response_data_type
5+
6+
7+
def tostr_urljoin(*x):
8+
return join(*map(str, x))
9+
10+
11+
class CivisJobFailure(Exception):
12+
def __init__(self, err_msg, response=None):
13+
self.error_message = err_msg
14+
self.response = response
15+
16+
def __str__(self):
17+
return self.error_message
18+
19+
20+
class CivisAPIError(Exception):
21+
def __init__(self, response):
22+
if response.content: # the API itself gave an error response
23+
json = response.json()
24+
self.error_message = json["errorDescription"]
25+
else: # this was something like a 502
26+
self.error_message = response.reason
27+
28+
self.status_code = response.status_code
29+
self._response = response
30+
31+
def __str__(self):
32+
if self.status_code:
33+
return "({}) {}".format(self.status_code, self.error_message)
34+
else:
35+
return self.error_message
36+
37+
38+
class EmptyResultError(Exception):
39+
pass
40+
41+
42+
class CivisAPIKeyError(Exception):
43+
pass
44+
45+
46+
class Endpoint:
47+
48+
_base_url = "https://api.civisanalytics.com/"
49+
_lock = threading.Lock()
50+
51+
def __init__(self, session, return_type='civis'):
52+
self._session = session
53+
self._return_type = return_type
54+
55+
def _build_path(self, path):
56+
if not path:
57+
return self._base_url
58+
return tostr_urljoin(self._base_url, path.strip("/"))
59+
60+
def _make_request(self, method, path=None, params=None, data=None,
61+
**kwargs):
62+
url = self._build_path(path)
63+
64+
with self._lock:
65+
response = self._session.request(method, url, json=data,
66+
params=params, **kwargs)
67+
68+
if response.status_code in [204, 205]:
69+
return
70+
71+
if response.status_code == 401:
72+
auth_error = response.headers["www-authenticate"]
73+
raise CivisAPIKeyError(auth_error) from CivisAPIError(response)
74+
75+
if not response.ok:
76+
raise CivisAPIError(response)
77+
78+
return response
79+
80+
def _call_api(self, method, path=None, params=None, data=None, **kwargs):
81+
iterator = kwargs.pop('iterator', False)
82+
83+
if iterator:
84+
return PaginatedResponse(path, params, self)
85+
else:
86+
resp = self._make_request(method, path, params, data, **kwargs)
87+
resp = convert_response_data_type(resp,
88+
return_type=self._return_type)
89+
return resp

0 commit comments

Comments
 (0)