-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[VAN-126440] README added. #87
Merged
Merged
Changes from 5 commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
3854580
[VAN-126440] Created README.md.
2ebbc18
[VAN-126440] Updated README.md. Added query_examples.
96c6879
[VAN-126440] Updated README.md.
63afbff
Apply suggestions from code review
Shmalikov ef46bab
[VAN-126440] README.md updated.
9a41304
Update README.md
emily-watt-visier 09767f8
Update README.md
emily-watt-visier b0ec098
Merge pull request #88 from visier/doc-review-python-sdk
Shmalikov File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,247 @@ | ||
# python-sdk | ||
Visier Software Development Kit for Python | ||
# Visier API Python SDK (Beta) | ||
Welcome to the Visier API Python SDK! This SDK provides a convenient way to interact with the Visier API. | ||
|
||
**Note: This SDK is currently in beta.** | ||
|
||
## Description | ||
For detailed documentation of the Visier API, please visit the [Visier API Documentation](https://docs.visier.com/developer/apis/apis.htm). | ||
The Visier API is divided into five main categories: | ||
|
||
- [Authentication](https://docs.visier.com/developer/apis/authentication/swagger/current/index.html): Manage user | ||
authentication and tokens. | ||
- [Administration](https://docs.visier.com/developer/apis/administration/swagger/current/index.html): Manage your tenant | ||
or tenants in Visier. | ||
- [Analytic Model](https://docs.visier.com/developer/apis/analytic-model/swagger/current/index.html): Configure and | ||
manage the Analytic Model. | ||
- [Data In](https://docs.visier.com/developer/apis/data-in/swagger/current/index.html): Upload data to the Visier | ||
Platform. | ||
- [Data Out](https://docs.visier.com/developer/apis/data-out/swagger/current/index.html): Download data from the Visier | ||
Platform. | ||
|
||
The Visier API Python SDK consists of five main packages, each corresponding to a specific API category: | ||
|
||
- `visier-api-core` - It contains logic for authenticating, configuring, and contains classes to make requests. | ||
This package is required to be installed to use any other package of the SDK. | ||
- `visier-api-administration` - for managing your tenant or tenants in Visier. | ||
- `visier-api-analytic-model` - to configure and manage the Analytic Model. | ||
- `visier-api-data-in` - APIs to load data in to the Visier Platform. | ||
- `visier-api-data-out` - APIs get data out from the Visier Platform. | ||
|
||
Each package, except `visier-api-core`, contains API classes which are used to interact with different APIs in the Visier API. | ||
|
||
## Installation | ||
|
||
Install the packages individually based on the required functionality. | ||
The `visier-api-core` package is a dependency for all other packages and will be installed automatically. | ||
|
||
```bash | ||
pip install visier-api-administration | ||
pip install visier-api-analytic-model | ||
pip install visier-api-data-in | ||
pip install visier-api-data-out | ||
``` | ||
**Note**: This SDK supports Python 3.8 and above. | ||
|
||
## Usage | ||
To use the API, you need to provide the `ApiClient` with a `Configuration` object. | ||
The configuration can be created in three ways: | ||
- From environment variables. | ||
- From dictionary which could be loaded from env file. | ||
- By explicitly setting the configuration parameters. | ||
|
||
Configure the environment variables as described below, depending on the type of authentication you want to use: | ||
```env | ||
# Necessary for all types of auth | ||
VISIER_HOST=https://customer-specific.api.visier.io | ||
VISIER_APIKEY='visier-provided-api-key' | ||
VISIER_VANITY='visier-tenant-vanity-name' | ||
|
||
# For OAuth 2.0 authentication | ||
VISIER_CLIENT_ID='client-id-from-registration' # OAuth client ID (obtain from Visier app registration) | ||
VISIER_CLIENT_SECRET='client-secret-from-registration' # OAuth client secret (obtain from Visier app registration) | ||
|
||
# For 3-legged OAuth 2.0, include the redirect URI along with VISIER_CLIENT_ID and VISIER_CLIENT_SECRET. | ||
# The client will start a local server to handle the callback. | ||
# Register this redirect URI on the Visier platform. The default is http://localhost:5000/oauth2/callback. | ||
VISIER_REDIRECT_URI='http://localhost:5000/oauth2/callback' | ||
|
||
# For Basic authentication, provide ONLY the following and leave VISIER_CLIENT_ID and VISIER_CLIENT_SECRET blank: | ||
# For 2-legged OAuth 2.0, provide the following IN ADDITION TO VISIER_CLIENT_ID and VISIER_CLIENT_SECRET | ||
VISIER_USERNAME='visier-username' | ||
VISIER_PASSWORD='visier-password' | ||
``` | ||
|
||
After setting the environment variables, you can create a `Configuration` object using the `from_env` method: | ||
```python | ||
from visier_api_core import Configuration | ||
|
||
config = Configuration.from_env() | ||
``` | ||
|
||
Another way is to store environment variables in a .env file and load them using dotenv library. | ||
```python | ||
from dotenv import dotenv_values | ||
from visier_api_core import Configuration | ||
|
||
config_dict = dotenv_values(".env") | ||
config = Configuration.from_dict(config_dict) | ||
``` | ||
|
||
Also, you can explicitly set the configuration parameters. E.g. for 3-legged OAuth 2.0 authentication: | ||
|
||
```python | ||
from visier_api_core import Configuration | ||
|
||
def get_secret(secret_name): | ||
"""Your secret retrieval logic""" | ||
pass | ||
|
||
config = Configuration( | ||
host="https://api.visier.com", | ||
api_key=get_secret("api_key"), | ||
client_id=get_secret("client_id"), | ||
client_secret=get_secret("client_id"), | ||
vanity="your_vanity" | ||
) | ||
``` | ||
> **Warning:** Don't store sensitive information in code or in a repository. | ||
> Use environment variables or a secure storage solution. | ||
|
||
After you have the configuration object you can create the API client and start using the API. | ||
|
||
```python | ||
from visier_api_core import ApiClient, Configuration | ||
from visier_api_data_out import DataQueryApi | ||
|
||
config = Configuration.from_env() | ||
client = ApiClient(config) | ||
data_query_api = DataQueryApi(client) | ||
``` | ||
|
||
You can create the API client using default configuration object. | ||
```python | ||
from visier_api_data_out import DataQueryApi | ||
data_query_api = DataQueryApi() | ||
``` | ||
Internally, the configuration object is created using values from environment variables. | ||
You can change the default configuration object using the `Configuration.set_default` method. | ||
By default, this configuration object is used to create the default `ApiClient` object. | ||
The `ApiClient` object also has a `set_default` method. This default `ApiClient` object is used to create API objects implicitly. | ||
|
||
```python | ||
from dotenv import dotenv_values | ||
from visier_api_core import Configuration, ApiClient | ||
from visier_api_data_in import DataUploadApi, DataIntakeApi | ||
|
||
config_dict = dotenv_values(".env") | ||
config = Configuration.from_dict(config_dict) | ||
Configuration.set_default(config) | ||
|
||
# ApiClient will be created using default configuration object | ||
api_client = ApiClient() | ||
data_upload_api = DataUploadApi(api_client) | ||
|
||
# ApiClient also has a method to set default ApiClient | ||
ApiClient.set_default(ApiClient(config)) | ||
|
||
# You can create APIs objects implicitly using default ApiClient object | ||
data_intake_api = DataIntakeApi() | ||
``` | ||
|
||
Every API method has 3 different ways to be called: | ||
|
||
```python | ||
from visier_api_analytic_model import DataModelApi, PropertiesDTO | ||
|
||
analytic_object_id = 'Employee' | ||
data_model_api = DataModelApi() | ||
|
||
# DTO format | ||
properties = data_model_api.properties(analytic_object_id) | ||
|
||
# ApiResponse | ||
api_response = data_model_api.properties_with_http_info(analytic_object_id) | ||
if api_response.status_code == 200: | ||
properties = api_response.data | ||
|
||
# RESTResponseType | ||
# If you need to work with raw data, you can use this method. | ||
rest_response = data_model_api.properties_without_preload_content(analytic_object_id) | ||
if rest_response.status == 200: | ||
properties = PropertiesDTO.from_json(rest_response.data.decode()) | ||
``` | ||
|
||
All API DTOs are described in documentation for each API, e.g. [Data Out API DTOs](https://docs.visier.com/developer/apis/data-in/swagger/current/index.html#:~:text=files/%7Bfilename%7D-,Schemas,-Data%20types%20and). | ||
Each DTOs has a method `from_json` to create DTO object from json string. | ||
In some cases, you may need to switch from DTO format to CSV format. | ||
To do this, set the `Accept` header to `text/csv` when creating the `ApiClient` or when making a request. | ||
|
||
```python | ||
from visier_api_core import ApiClient | ||
from visier_api_data_out import DataQueryApi, AggregationQueryExecutionDTO | ||
|
||
with open('query_examples/aggregate/applicants-source.json') as f: | ||
headcount_json = f.read() | ||
aggr_query_dto = AggregationQueryExecutionDTO.from_json(headcount_json) | ||
|
||
# Configure the 'Accept' header to 'text/csv' either in the constructor | ||
# ApiClient(header_name='Accept', header_value='text/csv') or by using the set_default_header method. | ||
# The set_default_header method allows you to add additional headers if needed. | ||
api_client = ApiClient() | ||
api_client.set_default_header('Accept', 'text/csv') | ||
|
||
query_api = DataQueryApi(api_client) | ||
response = query_api.aggregate_without_preload_content(aggr_query_dto) | ||
|
||
# Passing 'Accept' header to request | ||
query_api = DataQueryApi() | ||
response = query_api.aggregate_without_preload_content(aggr_query_dto, _headers={'Accept': 'text/csv'}) | ||
|
||
with open('data.csv', mode='w') as f: | ||
f.write(response.data.decode()) | ||
``` | ||
You can find additional query body examples in the [query_examples](query_examples) directory. | ||
|
||
## Error Handling | ||
|
||
This Python SDK handles exceptions using custom exception classes derived from `OpenApiException`. Below are the main exception classes and their usage: | ||
|
||
- `OpenApiException`: The base exception class for all API exceptions. | ||
- `ApiValueError`: Raised when a function receives an argument with an inappropriate value, such as when an authentication token is not set, or when both `body` and `post_params` are provided. | ||
- `ApiException`: Raised for general HTTP API exceptions. This class is subclassed into: | ||
- `BadRequestException`: Raised for HTTP 400 errors. | ||
- `UnauthorizedException`: Raised for HTTP 401 errors. | ||
- `ForbiddenException`: Raised for HTTP 403 errors. | ||
- `NotFoundException`: Raised for HTTP 404 errors. | ||
- `ServiceException`: Raised for HTTP 500-599 errors. | ||
|
||
### Fields in `ApiException` | ||
|
||
- `status`: The HTTP status code of the response. | ||
- `reason`: The reason phrase returned by the server. | ||
- `body`: The body of the HTTP response. | ||
- `data`: The data parsed from the HTTP response. | ||
- `headers`: The headers of the HTTP response. | ||
|
||
Below is an example of how to handle these exceptions: | ||
|
||
```python | ||
from visier_api_core.exceptions import ApiException, BadRequestException, UnauthorizedException | ||
from visier_api_analytic_model import DataModelApi | ||
|
||
analytic_object_id = 'Employee' | ||
data_model_api = DataModelApi() | ||
|
||
try: | ||
# Requesting properties of an analytic object | ||
properties = data_model_api.properties(analytic_object_id) | ||
except BadRequestException as e: | ||
print(f"Bad request: {e}") | ||
except UnauthorizedException as e: | ||
print(f"Unauthorized: {e}") | ||
except ApiException as e: | ||
print(f"An error occurred: {e}") | ||
``` | ||
|
||
### More Examples | ||
You can find more examples at [github.com/visier/api-samples](https://github.com/visier/api-samples). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
{ | ||
"query": { | ||
"source": { | ||
"metric": "applicantCount" | ||
}, | ||
"axes": [ | ||
{ | ||
"dimensionLevelSelection": { | ||
"dimension" : { | ||
"name": "Application_Source", | ||
"qualifyingPath": "Applicant" | ||
}, | ||
"levelIds": [ | ||
"Application_Source" | ||
] | ||
} | ||
}, | ||
{ | ||
"dimensionLevelSelection": { | ||
"dimension" : { | ||
"name": "Applicant_Stage", | ||
"qualifyingPath": "Applicant" | ||
}, | ||
"levelIds": [ | ||
"Applicant_Stage" | ||
] | ||
} | ||
} | ||
], | ||
"filters": [ | ||
{ | ||
"selectionConcept": { | ||
"name": "isActiveApplicant", | ||
"qualifyingPath": "Applicant" | ||
} | ||
} | ||
], | ||
"timeIntervals": { | ||
"fromDateTime": "2020-10-01", | ||
"intervalPeriodType": "MONTH", | ||
"intervalPeriodCount": 3 | ||
} | ||
}, | ||
"options": { | ||
"zeroVisibility": "ELIMINATE", | ||
"nullVisibility": "ELIMINATE" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
{ | ||
"source": { | ||
"analyticObject": "Employee" | ||
}, | ||
"columns": [ | ||
{ | ||
"columnDefinition": { | ||
"property": { | ||
"name": "Employee.Full_Name", | ||
"qualifyingPath": "Employee" | ||
} | ||
} | ||
}, | ||
{ | ||
"columnDefinition": { | ||
"property": { | ||
"name": "Employee.Pay_Level", | ||
"qualifyingPath": "Employee" | ||
} | ||
} | ||
} | ||
], | ||
"filters": [ | ||
{ | ||
"selectionConcept": { | ||
"name": "isFemale", | ||
"qualifyingPath": "Employee" | ||
} | ||
} | ||
], | ||
"timeInterval": { | ||
"fromDateTime": "2020-10-01", | ||
"intervalPeriodType": "MONTH", | ||
"intervalPeriodCount": 1 | ||
} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
{ | ||
"source": { | ||
"metric": "employeeCount" | ||
}, | ||
"columns": [ | ||
{ | ||
"columnDefinition": { | ||
"property": { | ||
"name": "Employee.Age", | ||
"qualifyingPath": "Employee" | ||
} | ||
} | ||
}, | ||
{ | ||
"columnDefinition": { | ||
"property": { | ||
"name": "Employee.Start_Date", | ||
"qualifyingPath": "Employee" | ||
} | ||
} | ||
}, | ||
{ | ||
"columnDefinition": { | ||
"property": { | ||
"name": "Employee.Market_Compensation_Ratio", | ||
"qualifyingPath": "Employee" | ||
} | ||
} | ||
}, | ||
{ | ||
"columnDefinition": { | ||
"property": { | ||
"name": "Employee.Full_Name", | ||
"qualifyingPath": "Employee" | ||
} | ||
} | ||
}, | ||
{ | ||
"columnName": "Effective time", | ||
"columnDefinition": { | ||
"effectiveDateProperty": {} | ||
} | ||
} | ||
], | ||
"timeIntervals": { | ||
"fromDateTime": "2022-01-01", | ||
"intervalPeriodType": "MONTH", | ||
"intervalPeriodCount": 6, | ||
"intervalCount": 4 | ||
} | ||
} | ||
|
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is good. nice and clear