-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
167 additions
and
87 deletions.
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 |
---|---|---|
@@ -0,0 +1,31 @@ | ||
name: Publish Python package to PyPI | ||
|
||
on: | ||
push: | ||
branches: | ||
- master # Set this to your default branch | ||
|
||
jobs: | ||
build-and-publish: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v2 | ||
- name: Set up Python | ||
uses: actions/setup-python@v2 | ||
with: | ||
python-version: '3.9' # Use the Python version compatible with your project | ||
|
||
- name: Install dependencies | ||
run: | | ||
python -m pip install --upgrade pip | ||
python -m pip install build | ||
- name: Build package | ||
run: python -m build | ||
|
||
- name: Publish to PyPI | ||
if: github.event_name == 'push' && startsWith(github.ref, 'refs/heads/master') | ||
uses: pypa/[email protected] | ||
with: | ||
password: ${{ secrets.PYPI_TOKEN }} | ||
user: sysrev |
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,23 @@ | ||
name: Biobricks codecov | ||
|
||
on: [push, pull_request] | ||
|
||
env: | ||
BIOBRICKS_TEST_TOKEN: ${{ secrets.BIOBRICKS_TEST_TOKEN }} | ||
|
||
jobs: | ||
build: | ||
runs-on: ubuntu-latest | ||
name: Test biobricks | ||
steps: | ||
- uses: actions/checkout@v2 # Updated to use v2 | ||
- uses: actions/setup-python@v2 | ||
with: | ||
python-version: '3.10' | ||
- name: Install requirements | ||
run: pip install -r requirements.txt # Removed the working-directory override for this step | ||
- name: Run tests and collect coverage | ||
run: pytest --cov=./ --cov-report=xml | ||
working-directory: ./ # Set the working directory only for the test step | ||
- name: Upload coverage reports to Codecov with GitHub Action | ||
uses: codecov/codecov-action@v3 |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
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,9 +1,4 @@ | ||
A Python client for sysrev.com | ||
|
||
See Demo.ipynb for implementation of client on example project. | ||
|
||
To install PySysrev, simply run `pip install PySysrev` | ||
|
||
Then inside Python, run the following commands: | ||
>>> import PySysrev | ||
>>> df = PySysrev.getAnnotations(3144) | ||
# Sysrev Python Client | ||
The Sysrev package provides: | ||
1. `SysrevClient` object for using the sysrev.com API | ||
2. (soon) a method for synchronizing local sysrev projects with remote sysrev projects. |
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
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 @@ | ||
from .funcs import SysrevClient |
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,103 @@ | ||
import requests | ||
|
||
class LabelTransformer: | ||
|
||
def handle_boolean(self, label_value): | ||
if isinstance(label_value, bool): | ||
return label_value | ||
elif str(label_value).lower() in ['yes', 'no']: | ||
return str(label_value).lower() == 'yes' | ||
else: | ||
raise ValueError("Invalid boolean value") | ||
|
||
def handle_categorical_or_string(self, label_value): | ||
if isinstance(label_value, str): | ||
return [label_value] | ||
elif isinstance(label_value, list) and all(isinstance(item, str) for item in label_value): | ||
return label_value | ||
else: | ||
raise ValueError("Invalid value for categorical or string type") | ||
|
||
def transform_label(self, label_type, label_value): | ||
if label_type == 'boolean': | ||
return self.handle_boolean(label_value) | ||
elif label_type in ['categorical', 'string']: | ||
return self.handle_categorical_or_string(label_value) | ||
else: | ||
raise ValueError("Invalid label type") | ||
|
||
class SysrevClient(): | ||
|
||
def __init__(self, api_key, base_url="https://www.sysrev.com"): | ||
self.api_key = api_key | ||
self.base_url = base_url | ||
|
||
def get_project_info(self, project_id): | ||
endpoint = f"{self.base_url}/api-json/project-info" | ||
headers = {"Authorization": f"Bearer {self.api_key}"} | ||
response = requests.get(endpoint, headers=headers, params={"project-id": project_id}) | ||
return response.json() | ||
|
||
def set_labels(self, project_id, article_id, label_ids, label_values, label_types, confirm=False, change=False, resolve=False): | ||
endpoint = f"{self.base_url}/api-json/set-labels" | ||
headers = {"Authorization": f"Bearer {self.api_key}", "Content-Type": "application/json"} | ||
|
||
assert len(label_ids) == len(label_values) == len(label_types), "Length of label_ids, label_values, and label_types should be the same." | ||
|
||
# construct label_values_dict | ||
tf = LabelTransformer() | ||
label_values_dict = {label_ids[i]: tf.transform_label(label_types[i], label_values[i]) for i in range(len(label_ids))} | ||
|
||
# Constructing the data payload as per the server's expectation | ||
data = {"project-id": project_id, "article-id": article_id, "label-values": label_values_dict} | ||
data.update({ "confirm?": confirm, "change?": change, "resolve?": resolve }) | ||
|
||
# Sending a POST request to the server | ||
response = requests.post(endpoint, json=data, headers=headers) | ||
return response.json() | ||
|
||
def get_project_articles(self, project_id, offset=0, limit=10, sort_by=None, sort_dir=None): | ||
endpoint = f"{self.base_url}/api-json/project-articles" | ||
headers = {"Authorization": f"Bearer {self.api_key}", "Content-Type": "application/json"} | ||
body = {"project-id": project_id, "n-offset": offset, "n-count": limit} | ||
|
||
# Add optional sorting keys if provided | ||
if sort_by: body["sort-by"] = sort_by | ||
if sort_dir: body["sort-dir"] = sort_dir | ||
|
||
# Make the POST request with the simplified body | ||
response = requests.post(endpoint, headers=headers, json=body) | ||
return response.json() | ||
|
||
def fetch_all_articles(self, project_id, limit=10, sort_by=None, sort_dir=None): | ||
offset = 0 | ||
while True: | ||
result = self.get_project_articles(project_id, offset=offset, limit=limit, sort_by=sort_by, sort_dir=sort_dir) | ||
articles = result.get('result', []) | ||
if not articles: | ||
break # Stop iteration if no articles are left | ||
yield from articles # Yield each article in the current batch | ||
offset += len(articles) | ||
|
||
def get_article_info(self, project_id, article_id): | ||
endpoint = f"{self.base_url}/api-json/article-info/{article_id}" | ||
headers = {"Authorization": f"Bearer {self.api_key}", "Content-Type": "application/json"} | ||
body = {"project-id": project_id,} | ||
return requests.get(endpoint, headers=headers, json=body) | ||
|
||
def upload_jsonlines(self, file_path, project_id): | ||
url = f"{self.base_url}/api-json/import-files/{project_id}" | ||
headers = {"Authorization": f"Bearer {self.api_key}"} | ||
|
||
# Prepare the file for upload | ||
with open(file_path, 'rb') as f: | ||
files = {'file': (file_path.split('/')[-1], f, 'application/octet-stream')} | ||
# Let requests handle "Content-Type" | ||
response = requests.post(url, headers=headers, files=files) | ||
|
||
return response | ||
|
||
def get_article_file(self, project_id, article_id, hash): | ||
url = f"{self.base_url}/api-json/files/{project_id}/article/{article_id}/download/{hash}" | ||
headers = {"Authorization": f"Bearer {self.api_key}", "Content-Type": "application/json"} | ||
|