├── .github
└── workflows
│ └── python-package.yml
├── .gitignore
├── .gitlab-ci.yml
├── .readthedocs.yaml
├── CONTRIBUTORS_NOTICE.md
├── LICENCE
├── MANIFEST.in
├── README.md
├── docs
├── Makefile
├── conf.py
├── images
│ ├── logo.jpg
│ └── logo.png
├── index.rst
├── installation.rst
├── make.bat
├── modules.rst
├── quickstart.rst
├── requirements.txt
├── setup.rst
├── sevenbridges.http.rst
├── sevenbridges.meta.rst
├── sevenbridges.models.compound.billing.rst
├── sevenbridges.models.compound.files.rst
├── sevenbridges.models.compound.jobs.rst
├── sevenbridges.models.compound.limits.rst
├── sevenbridges.models.compound.markers.rst
├── sevenbridges.models.compound.projects.rst
├── sevenbridges.models.compound.rst
├── sevenbridges.models.compound.tasks.rst
├── sevenbridges.models.compound.volumes.rst
├── sevenbridges.models.rst
├── sevenbridges.rst
├── sevenbridges.tests.rst
└── sevenbridges.transfer.rst
├── requirements-dev.txt
├── requirements.txt
├── setup.cfg
├── setup.py
├── sevenbridges
├── __init__.py
├── api.py
├── config.py
├── decorators.py
├── errors.py
├── http
│ ├── __init__.py
│ ├── client.py
│ └── error_handlers.py
├── meta
│ ├── __init__.py
│ ├── collection.py
│ ├── comp_mutable_dict.py
│ ├── data.py
│ ├── fields.py
│ ├── resource.py
│ └── transformer.py
├── models
│ ├── __init__.py
│ ├── actions.py
│ ├── app.py
│ ├── async_jobs.py
│ ├── automation.py
│ ├── billing_analysis_breakdown.py
│ ├── billing_egress_breakdown.py
│ ├── billing_group.py
│ ├── billing_storage_breakdown.py
│ ├── bulk.py
│ ├── compound
│ │ ├── __init__.py
│ │ ├── analysis_cost.py
│ │ ├── analysis_cost_breakdown.py
│ │ ├── billing
│ │ │ ├── __init__.py
│ │ │ ├── invoice_period.py
│ │ │ ├── project_breakdown.py
│ │ │ └── task_breakdown.py
│ │ ├── egress_cost.py
│ │ ├── error.py
│ │ ├── files
│ │ │ ├── __init__.py
│ │ │ ├── download_info.py
│ │ │ ├── file_origin.py
│ │ │ ├── file_storage.py
│ │ │ └── metadata.py
│ │ ├── import_result.py
│ │ ├── jobs
│ │ │ ├── __init__.py
│ │ │ ├── job.py
│ │ │ ├── job_docker.py
│ │ │ ├── job_instance.py
│ │ │ ├── job_instance_disk.py
│ │ │ └── job_log.py
│ │ ├── limits
│ │ │ ├── __init__.py
│ │ │ └── rate.py
│ │ ├── markers
│ │ │ ├── __init__.py
│ │ │ └── position.py
│ │ ├── measurement.py
│ │ ├── price.py
│ │ ├── price_breakdown.py
│ │ ├── projects
│ │ │ ├── __init__.py
│ │ │ ├── permissions.py
│ │ │ └── settings.py
│ │ ├── tasks
│ │ │ ├── __init__.py
│ │ │ ├── batch_by.py
│ │ │ ├── batch_group.py
│ │ │ ├── execution_status.py
│ │ │ ├── input.py
│ │ │ └── output.py
│ │ └── volumes
│ │ │ ├── __init__.py
│ │ │ ├── import_destination.py
│ │ │ ├── properties.py
│ │ │ ├── service.py
│ │ │ ├── volume_file.py
│ │ │ ├── volume_object.py
│ │ │ └── volume_prefix.py
│ ├── dataset.py
│ ├── division.py
│ ├── drs_import.py
│ ├── endpoints.py
│ ├── enums.py
│ ├── execution_details.py
│ ├── file.py
│ ├── invoice.py
│ ├── link.py
│ ├── marker.py
│ ├── member.py
│ ├── project.py
│ ├── rate_limit.py
│ ├── storage_export.py
│ ├── storage_import.py
│ ├── task.py
│ ├── team.py
│ ├── team_member.py
│ ├── user.py
│ └── volume.py
├── transfer
│ ├── __init__.py
│ ├── download.py
│ ├── upload.py
│ └── utils.py
└── version.py
├── sonar-project.properties
└── tests
├── __init__.py
├── conftest.py
├── providers.py
├── test_actions.py
├── test_apps.py
├── test_async_jobs.py
├── test_automations.py
├── test_billing_groups.py
├── test_config.py
├── test_datasets.py
├── test_decorators.py
├── test_divisions.py
├── test_drs_import.py
├── test_endpoints_rate.py
├── test_error_handlers.py
├── test_exports.py
├── test_files.py
├── test_imports.py
├── test_marker.py
├── test_pagination.py
├── test_projects.py
├── test_tasks.py
├── test_teams.py
├── test_transformer.py
├── test_upload.py
├── test_users.py
├── test_utils.py
├── test_volumes.py
└── verifiers.py
/.github/workflows/python-package.yml:
--------------------------------------------------------------------------------
1 | name: Build
2 |
3 | on:
4 | push:
5 | branches:
6 | - develop
7 | pull_request:
8 | branches:
9 | - develop
10 | release:
11 | types:
12 | - published
13 |
14 | jobs:
15 | tests:
16 | runs-on: ubuntu-latest
17 | strategy:
18 | matrix:
19 | python-version:
20 | - 3.8
21 | - 3.9
22 | steps:
23 | - uses: actions/checkout@v2
24 | - name: Set up Python ${{ matrix.python-version }}
25 | uses: actions/setup-python@v2
26 | with:
27 | python-version: ${{ matrix.python-version }}
28 | - name: Install dependencies
29 | run: |
30 | pip install -r requirements-dev.txt
31 | - name: Test with pytest
32 | run: |
33 | flake8
34 | pytest --verbose --cov-config setup.cfg
35 |
36 | release:
37 | needs: tests
38 | if: github.event_name == 'release' && github.event.action == 'published'
39 | runs-on: ubuntu-latest
40 | steps:
41 | - uses: actions/checkout@v2
42 | - name: Set up Python
43 | uses: actions/setup-python@v2
44 | with:
45 | python-version: 3.9
46 | - name: Build and publish
47 | env:
48 | TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }}
49 | TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
50 | run: |
51 | pip install wheel twine
52 | export PACKAGE_VERSION=${GITHUB_REF:10}
53 | echo "__version__ = '$PACKAGE_VERSION'" > sevenbridges/version.py
54 | python setup.py sdist bdist_wheel
55 | twine upload dist/*
56 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Compiled source #
2 | ###################
3 | __pycache__/
4 | *.py[cod]
5 | *$py.class
6 |
7 | # Distribution / packaging #
8 | ############################
9 | build/
10 | dist/
11 | *.egg-info/
12 | *.egg
13 |
14 | # Installer logs #
15 | ##################
16 | pip-log.txt
17 | pip-delete-this-directory.txt
18 |
19 | # Unit test / coverage reports #
20 | ################################
21 | .tox/
22 | .coverage
23 | .coverage.*
24 | coverage_report/
25 | .cache
26 | .pytest_cache
27 | nosetests.xml
28 | coverage.xml
29 | htmlcov
30 |
31 | # Sphinx documentation #
32 | ########################
33 | docs/_build/
34 |
35 | # IPython Notebook #
36 | ####################
37 | .ipynb_checkpoints
38 |
39 | # Distutils #
40 | #############
41 | MANIFEST
42 |
43 | # OS generated files #
44 | ######################
45 | .DS_Store*
46 | ehthumbs.db
47 | Icon?
48 | Thumbs.db
49 |
50 | # Editor Files #
51 | ################
52 | *~
53 | *.swp
54 |
55 | # IntelliJ specific files/directories #
56 | #######################################
57 | .idea
58 | *.ipr
59 | *.iws
60 | *.iml
61 |
62 | # Eclipse specific files/directories #
63 | ######################################
64 | .project
65 | .pydevproject
66 | .python-version
67 | .settings
68 |
--------------------------------------------------------------------------------
/.gitlab-ci.yml:
--------------------------------------------------------------------------------
1 | image: python:3.9-slim-buster
2 |
3 | stages:
4 | - test
5 | - sonar
6 |
7 | .test: &test
8 | stage: test
9 | before_script:
10 | - python --version
11 | - pip install -r requirements-dev.txt
12 | - export PYTHONPATH=$(pwd):$PYTHONPATH
13 | script:
14 | - flake8
15 | - pytest --verbose --cov-config setup.cfg
16 | artifacts:
17 | paths:
18 | - test-report/*
19 | coverage: '/TOTAL.*\s+(\d+\%)/'
20 |
21 | # Test with python 3.6
22 | test:3.6:
23 | <<: *test
24 | image: python:3.6-slim-buster
25 |
26 | # Test with python 3.7
27 | test:3.7:
28 | <<: *test
29 | image: python:3.7-slim-buster
30 |
31 | # Test with python 3.8
32 | test:3.8:
33 | <<: *test
34 | image: python:3.8-slim-buster
35 |
36 | # Test with python 3.9
37 | test:3.9:
38 | <<: *test
39 | image: python:3.9-slim-buster
40 |
41 | sonar:
42 | stage: sonar
43 | image: emeraldsquad/sonar-scanner:2.2.0
44 | script: infinity sonar scanner
45 | allow_failure: true
46 | dependencies:
47 | - test:3.9
48 | rules:
49 | - when: always
50 |
--------------------------------------------------------------------------------
/.readthedocs.yaml:
--------------------------------------------------------------------------------
1 | # Read the Docs configuration file for Sphinx projects
2 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
3 |
4 | version: 2
5 |
6 | build:
7 | os: ubuntu-22.04
8 | tools:
9 | python: "3.9"
10 |
11 | # Build documentation in the "docs/" directory with Sphinx
12 | sphinx:
13 | configuration: docs/conf.py
14 |
15 | formats:
16 | - pdf
17 |
18 | python:
19 | install:
20 | - requirements: docs/requirements.txt
21 |
--------------------------------------------------------------------------------
/CONTRIBUTORS_NOTICE.md:
--------------------------------------------------------------------------------
1 | Notice to Contributors to Seven Bridges Open Source Projects
2 | ------------------------------------------------------------
3 |
4 | We require contributors to our open-source projects to sign a Seven
5 | Bridges Contributor Agreement (SBCA). The SBCA doesn’t require you to
6 | lose rights to your work, but only to share the copyright with Seven
7 | Bridges jointly, and when applicable to grant Seven Bridges and other
8 | collaborators and users of the project a patent license.
9 |
10 | This is a common arrangement in larger open source projects, and
11 | provides several benefits to both the project and its contributors. The
12 | SBCA allows Seven Bridges to defend the project from hostile
13 | intellectual property litigation--for example, if a contributor or their
14 | employer attempted to assert control of the project, or rescind their
15 | contribution. Seven Bridges could not do this without the consolidated
16 | ownership of the copyright that the SBCA provides. Since the Agreement
17 | establishes joint ownership of copyright, you and any other contributor
18 | will have the right to whatever you want to with your contribution,
19 | including contribute it to other open source projects or distribute it
20 | under proprietary licenses. If we distribute your contribution in any
21 | way, the SBCA obliges us to also make it available under an open source
22 | license approved by the Free Software Foundation (FSF) or Open Source
23 | Initiative (OSI).
24 |
25 | If you’re contributing on behalf of your employer, make sure that anyone
26 | signing the agreement is authorized to do so by your employer.
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | include LICENCE
2 | include README.md
3 |
--------------------------------------------------------------------------------
/docs/images/logo.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sbg/sevenbridges-python/ed3de94bab744a33f614111c1845af68b5433c54/docs/images/logo.jpg
--------------------------------------------------------------------------------
/docs/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sbg/sevenbridges-python/ed3de94bab744a33f614111c1845af68b5433c54/docs/images/logo.png
--------------------------------------------------------------------------------
/docs/index.rst:
--------------------------------------------------------------------------------
1 | .. sbg documentation master file, created by
2 | sphinx-quickstart on Mon Jan 18 19:03:18 2016.
3 | You can adapt this file completely to your liking, but it should at least
4 | contain the root `toctree` directive.
5 |
6 |
7 |
8 | sevenbridges-python documentation!
9 | ==================================
10 |
11 | sevenbridges-python is a `Python `_ library that provides an interface for the `Seven Bridges Platform `_ and `Cancer Genomics Cloud `_ public APIs.
12 |
13 | The Seven Bridges Platform is a cloud-based environment for conducting bioinformatic analyses. It is a central hub for teams to store, analyze, and jointly interpret their bioinformatic data. The Platform co-locates analysis pipelines alongside the largest genomic datasets to optimize processing, allocating storage and compute resources on demand.
14 |
15 | The The Cancer Genomics Cloud (CGC), powered by Seven Bridges, is also a cloud-based computation environment. It was built as one of three pilot systems funded by the National Cancer Institute to explore the paradigm of colocalizing massive genomics datasets, like The Cancer Genomics Atlas (TCGA), alongside secure and scalable computational resources to analyze them. The CGC makes more than a petabyte of multi-dimensional data available immediately to authorized researchers. You can add your own data to analyze alongside TCGA using predefined analytical workflows or your own tools.
16 |
17 | Content
18 | -------
19 |
20 | .. toctree::
21 | :maxdepth: 2
22 |
23 | installation
24 | quickstart
25 | sevenbridges
26 |
--------------------------------------------------------------------------------
/docs/installation.rst:
--------------------------------------------------------------------------------
1 | Installation
2 | ============
3 |
4 | The easiest way to install sevenbridges-python is using pip.
5 | ::
6 |
7 | $ pip install sevenbridges-python
8 |
9 |
10 | Get the Code
11 | ============
12 |
13 | sevenbridges-python is actively developed on GitHub, where the `code `_ is always available.
14 |
15 | The easiest way to obtain the source is to clone the public repository:
16 | ::
17 |
18 | $ git clone git://github.com/sbg/sevenbridges-python.git
19 |
20 | Once you have a copy of the source, you can embed it in your Python package,
21 | or install it into your site-packages by invoking:
22 | ::
23 |
24 | $ python setup.py install
25 |
26 | If you are interested in reviewing this documentation locally, clone the repository and
27 | invoke:
28 |
29 | ::
30 | $ make html
31 |
32 | from the docs folder.
33 |
--------------------------------------------------------------------------------
/docs/modules.rst:
--------------------------------------------------------------------------------
1 | sevenbridges
2 | ============
3 |
4 | .. toctree::
5 | :maxdepth: 4
6 |
7 | sevenbridges
8 |
--------------------------------------------------------------------------------
/docs/requirements.txt:
--------------------------------------------------------------------------------
1 | sphinx==5.3.0
2 | sphinx_rtd_theme==0.5.1
3 |
--------------------------------------------------------------------------------
/docs/setup.rst:
--------------------------------------------------------------------------------
1 | setup module
2 | ============
3 |
4 | .. automodule:: setup
5 | :members:
6 | :undoc-members:
7 | :show-inheritance:
8 |
--------------------------------------------------------------------------------
/docs/sevenbridges.http.rst:
--------------------------------------------------------------------------------
1 | sevenbridges\.http package
2 | ==========================
3 |
4 | .. automodule:: sevenbridges.http
5 | :members:
6 | :undoc-members:
7 | :show-inheritance:
8 |
9 | Submodules
10 | ----------
11 |
12 | sevenbridges\.http\.client module
13 | ---------------------------------
14 |
15 | .. automodule:: sevenbridges.http.client
16 | :members:
17 | :undoc-members:
18 | :show-inheritance:
19 |
20 | sevenbridges\.http\.error\_handlers module
21 | ------------------------------------------
22 |
23 | .. automodule:: sevenbridges.http.error_handlers
24 | :members:
25 | :undoc-members:
26 | :show-inheritance:
27 |
28 |
29 |
--------------------------------------------------------------------------------
/docs/sevenbridges.meta.rst:
--------------------------------------------------------------------------------
1 | sevenbridges\.meta package
2 | ==========================
3 |
4 | .. automodule:: sevenbridges.meta
5 | :members:
6 | :undoc-members:
7 | :show-inheritance:
8 |
9 | Submodules
10 | ----------
11 |
12 | sevenbridges\.meta\.collection module
13 | -------------------------------------
14 |
15 | .. automodule:: sevenbridges.meta.collection
16 | :members:
17 | :undoc-members:
18 | :show-inheritance:
19 |
20 | sevenbridges\.meta\.comp\_mutable\_dict module
21 | ----------------------------------------------
22 |
23 | .. automodule:: sevenbridges.meta.comp_mutable_dict
24 | :members:
25 | :undoc-members:
26 | :show-inheritance:
27 |
28 | sevenbridges\.meta\.data module
29 | -------------------------------
30 |
31 | .. automodule:: sevenbridges.meta.data
32 | :members:
33 | :undoc-members:
34 | :show-inheritance:
35 |
36 | sevenbridges\.meta\.fields module
37 | ---------------------------------
38 |
39 | .. automodule:: sevenbridges.meta.fields
40 | :members:
41 | :undoc-members:
42 | :show-inheritance:
43 |
44 | sevenbridges\.meta\.resource module
45 | -----------------------------------
46 |
47 | .. automodule:: sevenbridges.meta.resource
48 | :members:
49 | :undoc-members:
50 | :show-inheritance:
51 |
52 | sevenbridges\.meta\.transformer module
53 | --------------------------------------
54 |
55 | .. automodule:: sevenbridges.meta.transformer
56 | :members:
57 | :undoc-members:
58 | :show-inheritance:
59 |
60 |
61 |
--------------------------------------------------------------------------------
/docs/sevenbridges.models.compound.billing.rst:
--------------------------------------------------------------------------------
1 | sevenbridges\.models\.compound\.billing package
2 | ===============================================
3 |
4 | .. automodule:: sevenbridges.models.compound.billing
5 | :members:
6 | :undoc-members:
7 | :show-inheritance:
8 |
9 | Submodules
10 | ----------
11 |
12 | sevenbridges\.models\.compound\.billing\.invoice\_period module
13 | ---------------------------------------------------------------
14 |
15 | .. automodule:: sevenbridges.models.compound.billing.invoice_period
16 | :members:
17 | :undoc-members:
18 | :show-inheritance:
19 |
20 | sevenbridges\.models\.compound\.billing\.project\_breakdown module
21 | ------------------------------------------------------------------
22 |
23 | .. automodule:: sevenbridges.models.compound.billing.project_breakdown
24 | :members:
25 | :undoc-members:
26 | :show-inheritance:
27 |
28 | sevenbridges\.models\.compound\.billing\.task\_breakdown module
29 | ---------------------------------------------------------------
30 |
31 | .. automodule:: sevenbridges.models.compound.billing.task_breakdown
32 | :members:
33 | :undoc-members:
34 | :show-inheritance:
35 |
36 |
37 |
--------------------------------------------------------------------------------
/docs/sevenbridges.models.compound.files.rst:
--------------------------------------------------------------------------------
1 | sevenbridges\.models\.compound\.files package
2 | =============================================
3 |
4 | .. automodule:: sevenbridges.models.compound.files
5 | :members:
6 | :undoc-members:
7 | :show-inheritance:
8 |
9 | Submodules
10 | ----------
11 |
12 | sevenbridges\.models\.compound\.files\.download\_info module
13 | ------------------------------------------------------------
14 |
15 | .. automodule:: sevenbridges.models.compound.files.download_info
16 | :members:
17 | :undoc-members:
18 | :show-inheritance:
19 |
20 | sevenbridges\.models\.compound\.files\.file\_origin module
21 | ----------------------------------------------------------
22 |
23 | .. automodule:: sevenbridges.models.compound.files.file_origin
24 | :members:
25 | :undoc-members:
26 | :show-inheritance:
27 |
28 | sevenbridges\.models\.compound\.files\.file\_storage module
29 | -----------------------------------------------------------
30 |
31 | .. automodule:: sevenbridges.models.compound.files.file_storage
32 | :members:
33 | :undoc-members:
34 | :show-inheritance:
35 |
36 | sevenbridges\.models\.compound\.files\.metadata module
37 | ------------------------------------------------------
38 |
39 | .. automodule:: sevenbridges.models.compound.files.metadata
40 | :members:
41 | :undoc-members:
42 | :show-inheritance:
43 |
44 |
45 |
--------------------------------------------------------------------------------
/docs/sevenbridges.models.compound.jobs.rst:
--------------------------------------------------------------------------------
1 | sevenbridges\.models\.compound\.jobs package
2 | ============================================
3 |
4 | .. automodule:: sevenbridges.models.compound.jobs
5 | :members:
6 | :undoc-members:
7 | :show-inheritance:
8 |
9 | Submodules
10 | ----------
11 |
12 | sevenbridges\.models\.compound\.jobs\.job module
13 | ------------------------------------------------
14 |
15 | .. automodule:: sevenbridges.models.compound.jobs.job
16 | :members:
17 | :undoc-members:
18 | :show-inheritance:
19 |
20 | sevenbridges\.models\.compound\.jobs\.job\_docker module
21 | --------------------------------------------------------
22 |
23 | .. automodule:: sevenbridges.models.compound.jobs.job_docker
24 | :members:
25 | :undoc-members:
26 | :show-inheritance:
27 |
28 | sevenbridges\.models\.compound\.jobs\.job\_instance module
29 | ----------------------------------------------------------
30 |
31 | .. automodule:: sevenbridges.models.compound.jobs.job_instance
32 | :members:
33 | :undoc-members:
34 | :show-inheritance:
35 |
36 | sevenbridges\.models\.compound\.jobs\.job\_instance\_disk module
37 | ----------------------------------------------------------------
38 |
39 | .. automodule:: sevenbridges.models.compound.jobs.job_instance_disk
40 | :members:
41 | :undoc-members:
42 | :show-inheritance:
43 |
44 | sevenbridges\.models\.compound\.jobs\.job\_log module
45 | -----------------------------------------------------
46 |
47 | .. automodule:: sevenbridges.models.compound.jobs.job_log
48 | :members:
49 | :undoc-members:
50 | :show-inheritance:
51 |
52 |
53 |
--------------------------------------------------------------------------------
/docs/sevenbridges.models.compound.limits.rst:
--------------------------------------------------------------------------------
1 | sevenbridges\.models\.compound\.limits package
2 | ==============================================
3 |
4 | .. automodule:: sevenbridges.models.compound.limits
5 | :members:
6 | :undoc-members:
7 | :show-inheritance:
8 |
9 | Submodules
10 | ----------
11 |
12 | sevenbridges\.models\.compound\.limits\.rate module
13 | ---------------------------------------------------
14 |
15 | .. automodule:: sevenbridges.models.compound.limits.rate
16 | :members:
17 | :undoc-members:
18 | :show-inheritance:
19 |
20 |
21 |
--------------------------------------------------------------------------------
/docs/sevenbridges.models.compound.markers.rst:
--------------------------------------------------------------------------------
1 | sevenbridges\.models\.compound\.markers package
2 | ===============================================
3 |
4 | .. automodule:: sevenbridges.models.compound.markers
5 | :members:
6 | :undoc-members:
7 | :show-inheritance:
8 |
9 | Submodules
10 | ----------
11 |
12 | sevenbridges\.models\.compound\.markers\.position module
13 | --------------------------------------------------------
14 |
15 | .. automodule:: sevenbridges.models.compound.markers.position
16 | :members:
17 | :undoc-members:
18 | :show-inheritance:
19 |
20 |
21 |
--------------------------------------------------------------------------------
/docs/sevenbridges.models.compound.projects.rst:
--------------------------------------------------------------------------------
1 | sevenbridges\.models\.compound\.projects package
2 | ================================================
3 |
4 | .. automodule:: sevenbridges.models.compound.projects
5 | :members:
6 | :undoc-members:
7 | :show-inheritance:
8 |
9 | Submodules
10 | ----------
11 |
12 | sevenbridges\.models\.compound\.projects\.permissions module
13 | ------------------------------------------------------------
14 |
15 | .. automodule:: sevenbridges.models.compound.projects.permissions
16 | :members:
17 | :undoc-members:
18 | :show-inheritance:
19 |
20 | sevenbridges\.models\.compound\.projects\.settings module
21 | ---------------------------------------------------------
22 |
23 | .. automodule:: sevenbridges.models.compound.projects.settings
24 | :members:
25 | :undoc-members:
26 | :show-inheritance:
27 |
28 |
29 |
--------------------------------------------------------------------------------
/docs/sevenbridges.models.compound.rst:
--------------------------------------------------------------------------------
1 | sevenbridges\.models\.compound package
2 | ======================================
3 |
4 | .. automodule:: sevenbridges.models.compound
5 | :members:
6 | :undoc-members:
7 | :show-inheritance:
8 |
9 | Subpackages
10 | -----------
11 |
12 | .. toctree::
13 |
14 | sevenbridges.models.compound.billing
15 | sevenbridges.models.compound.files
16 | sevenbridges.models.compound.jobs
17 | sevenbridges.models.compound.limits
18 | sevenbridges.models.compound.markers
19 | sevenbridges.models.compound.projects
20 | sevenbridges.models.compound.tasks
21 | sevenbridges.models.compound.volumes
22 |
23 | Submodules
24 | ----------
25 |
26 | sevenbridges\.models\.compound\.error module
27 | --------------------------------------------
28 |
29 | .. automodule:: sevenbridges.models.compound.error
30 | :members:
31 | :undoc-members:
32 | :show-inheritance:
33 |
34 | sevenbridges\.models\.compound\.price module
35 | --------------------------------------------
36 |
37 | .. automodule:: sevenbridges.models.compound.price
38 | :members:
39 | :undoc-members:
40 | :show-inheritance:
41 |
42 | sevenbridges\.models\.compound\.price\_breakdown module
43 | -------------------------------------------------------
44 |
45 | .. automodule:: sevenbridges.models.compound.price_breakdown
46 | :members:
47 | :undoc-members:
48 | :show-inheritance:
49 |
50 |
51 |
--------------------------------------------------------------------------------
/docs/sevenbridges.models.compound.tasks.rst:
--------------------------------------------------------------------------------
1 | sevenbridges\.models\.compound\.tasks package
2 | =============================================
3 |
4 | .. automodule:: sevenbridges.models.compound.tasks
5 | :members:
6 | :undoc-members:
7 | :show-inheritance:
8 |
9 | Submodules
10 | ----------
11 |
12 | sevenbridges\.models\.compound\.tasks\.batch\_by module
13 | -------------------------------------------------------
14 |
15 | .. automodule:: sevenbridges.models.compound.tasks.batch_by
16 | :members:
17 | :undoc-members:
18 | :show-inheritance:
19 |
20 | sevenbridges\.models\.compound\.tasks\.batch\_group module
21 | ----------------------------------------------------------
22 |
23 | .. automodule:: sevenbridges.models.compound.tasks.batch_group
24 | :members:
25 | :undoc-members:
26 | :show-inheritance:
27 |
28 | sevenbridges\.models\.compound\.tasks\.execution\_status module
29 | ---------------------------------------------------------------
30 |
31 | .. automodule:: sevenbridges.models.compound.tasks.execution_status
32 | :members:
33 | :undoc-members:
34 | :show-inheritance:
35 |
36 | sevenbridges\.models\.compound\.tasks\.input module
37 | ---------------------------------------------------
38 |
39 | .. automodule:: sevenbridges.models.compound.tasks.input
40 | :members:
41 | :undoc-members:
42 | :show-inheritance:
43 |
44 | sevenbridges\.models\.compound\.tasks\.output module
45 | ----------------------------------------------------
46 |
47 | .. automodule:: sevenbridges.models.compound.tasks.output
48 | :members:
49 | :undoc-members:
50 | :show-inheritance:
51 |
52 |
53 |
--------------------------------------------------------------------------------
/docs/sevenbridges.models.compound.volumes.rst:
--------------------------------------------------------------------------------
1 | sevenbridges\.models\.compound\.volumes package
2 | ===============================================
3 |
4 | .. automodule:: sevenbridges.models.compound.volumes
5 | :members:
6 | :undoc-members:
7 | :show-inheritance:
8 |
9 | Submodules
10 | ----------
11 |
12 | sevenbridges\.models\.compound\.volumes\.import\_destination module
13 | -------------------------------------------------------------------
14 |
15 | .. automodule:: sevenbridges.models.compound.volumes.import_destination
16 | :members:
17 | :undoc-members:
18 | :show-inheritance:
19 |
20 | sevenbridges\.models\.compound\.volumes\.properties module
21 | ----------------------------------------------------------
22 |
23 | .. automodule:: sevenbridges.models.compound.volumes.properties
24 | :members:
25 | :undoc-members:
26 | :show-inheritance:
27 |
28 | sevenbridges\.models\.compound\.volumes\.service module
29 | -------------------------------------------------------
30 |
31 | .. automodule:: sevenbridges.models.compound.volumes.service
32 | :members:
33 | :undoc-members:
34 | :show-inheritance:
35 |
36 | sevenbridges\.models\.compound\.volumes\.volume\_file module
37 | ------------------------------------------------------------
38 |
39 | .. automodule:: sevenbridges.models.compound.volumes.volume_file
40 | :members:
41 | :undoc-members:
42 | :show-inheritance:
43 |
44 | sevenbridges\.models\.compound\.volumes\.volume\_object module
45 | --------------------------------------------------------------
46 |
47 | .. automodule:: sevenbridges.models.compound.volumes.volume_object
48 | :members:
49 | :undoc-members:
50 | :show-inheritance:
51 |
52 | sevenbridges\.models\.compound\.volumes\.volume\_prefix module
53 | --------------------------------------------------------------
54 |
55 | .. automodule:: sevenbridges.models.compound.volumes.volume_prefix
56 | :members:
57 | :undoc-members:
58 | :show-inheritance:
59 |
60 |
61 |
--------------------------------------------------------------------------------
/docs/sevenbridges.models.rst:
--------------------------------------------------------------------------------
1 | sevenbridges\.models package
2 | ============================
3 |
4 | .. automodule:: sevenbridges.models
5 | :members:
6 | :undoc-members:
7 | :show-inheritance:
8 |
9 | Subpackages
10 | -----------
11 |
12 | .. toctree::
13 |
14 | sevenbridges.models.compound
15 |
16 | Submodules
17 | ----------
18 |
19 | sevenbridges\.models\.actions module
20 | ------------------------------------
21 |
22 | .. automodule:: sevenbridges.models.actions
23 | :members:
24 | :undoc-members:
25 | :show-inheritance:
26 |
27 | sevenbridges\.models\.app module
28 | --------------------------------
29 |
30 | .. automodule:: sevenbridges.models.app
31 | :members:
32 | :undoc-members:
33 | :show-inheritance:
34 |
35 | sevenbridges\.models\.billing\_egress\_breakdown module
36 | -------------------------------------------------------
37 |
38 | .. automodule:: sevenbridges.models.billing_egress_breakdown
39 | :members:
40 | :undoc-members:
41 | :show-inheritance:
42 |
43 | sevenbridges\.models\.billing\_storage\_breakdown module
44 | --------------------------------------------------------
45 |
46 | .. automodule:: sevenbridges.models.billing_storage_breakdown
47 | :members:
48 | :undoc-members:
49 | :show-inheritance:
50 |
51 | sevenbridges\.models\.billing\_group module
52 | -------------------------------------------
53 |
54 | .. automodule:: sevenbridges.models.billing_group
55 | :members:
56 | :undoc-members:
57 | :show-inheritance:
58 |
59 | sevenbridges\.models\.division module
60 | -------------------------------------
61 |
62 | .. automodule:: sevenbridges.models.division
63 | :members:
64 | :undoc-members:
65 | :show-inheritance:
66 |
67 | sevenbridges\.models\.endpoints module
68 | --------------------------------------
69 |
70 | .. automodule:: sevenbridges.models.endpoints
71 | :members:
72 | :undoc-members:
73 | :show-inheritance:
74 |
75 | sevenbridges\.models\.enums module
76 | ----------------------------------
77 |
78 | .. automodule:: sevenbridges.models.enums
79 | :members:
80 | :undoc-members:
81 | :show-inheritance:
82 |
83 | sevenbridges\.models\.execution\_details module
84 | -----------------------------------------------
85 |
86 | .. automodule:: sevenbridges.models.execution_details
87 | :members:
88 | :undoc-members:
89 | :show-inheritance:
90 |
91 | sevenbridges\.models\.file module
92 | ---------------------------------
93 |
94 | .. automodule:: sevenbridges.models.file
95 | :members:
96 | :undoc-members:
97 | :show-inheritance:
98 |
99 | sevenbridges\.models\.invoice module
100 | ------------------------------------
101 |
102 | .. automodule:: sevenbridges.models.invoice
103 | :members:
104 | :undoc-members:
105 | :show-inheritance:
106 |
107 | sevenbridges\.models\.link module
108 | ---------------------------------
109 |
110 | .. automodule:: sevenbridges.models.link
111 | :members:
112 | :undoc-members:
113 | :show-inheritance:
114 |
115 | sevenbridges\.models\.marker module
116 | -----------------------------------
117 |
118 | .. automodule:: sevenbridges.models.marker
119 | :members:
120 | :undoc-members:
121 | :show-inheritance:
122 |
123 | sevenbridges\.models\.member module
124 | -----------------------------------
125 |
126 | .. automodule:: sevenbridges.models.member
127 | :members:
128 | :undoc-members:
129 | :show-inheritance:
130 |
131 | sevenbridges\.models\.project module
132 | ------------------------------------
133 |
134 | .. automodule:: sevenbridges.models.project
135 | :members:
136 | :undoc-members:
137 | :show-inheritance:
138 |
139 | sevenbridges\.models\.rate\_limit module
140 | ----------------------------------------
141 |
142 | .. automodule:: sevenbridges.models.rate_limit
143 | :members:
144 | :undoc-members:
145 | :show-inheritance:
146 |
147 | sevenbridges\.models\.storage\_export module
148 | --------------------------------------------
149 |
150 | .. automodule:: sevenbridges.models.storage_export
151 | :members:
152 | :undoc-members:
153 | :show-inheritance:
154 |
155 | sevenbridges\.models\.storage\_import module
156 | --------------------------------------------
157 |
158 | .. automodule:: sevenbridges.models.storage_import
159 | :members:
160 | :undoc-members:
161 | :show-inheritance:
162 |
163 | sevenbridges\.models\.task module
164 | ---------------------------------
165 |
166 | .. automodule:: sevenbridges.models.task
167 | :members:
168 | :undoc-members:
169 | :show-inheritance:
170 |
171 | sevenbridges\.models\.team module
172 | ---------------------------------
173 |
174 | .. automodule:: sevenbridges.models.team
175 | :members:
176 | :undoc-members:
177 | :show-inheritance:
178 |
179 | sevenbridges\.models\.team\_member module
180 | -----------------------------------------
181 |
182 | .. automodule:: sevenbridges.models.team_member
183 | :members:
184 | :undoc-members:
185 | :show-inheritance:
186 |
187 | sevenbridges\.models\.user module
188 | ---------------------------------
189 |
190 | .. automodule:: sevenbridges.models.user
191 | :members:
192 | :undoc-members:
193 | :show-inheritance:
194 |
195 | sevenbridges\.models\.volume module
196 | -----------------------------------
197 |
198 | .. automodule:: sevenbridges.models.volume
199 | :members:
200 | :undoc-members:
201 | :show-inheritance:
202 |
203 |
204 |
--------------------------------------------------------------------------------
/docs/sevenbridges.rst:
--------------------------------------------------------------------------------
1 | sevenbridges package
2 | ====================
3 |
4 | .. automodule:: sevenbridges
5 | :members:
6 | :undoc-members:
7 | :show-inheritance:
8 |
9 | Subpackages
10 | -----------
11 |
12 | .. toctree::
13 |
14 | sevenbridges.http
15 | sevenbridges.meta
16 | sevenbridges.models
17 | sevenbridges.tests
18 | sevenbridges.transfer
19 |
20 | Submodules
21 | ----------
22 |
23 | sevenbridges\.api module
24 | ------------------------
25 |
26 | .. automodule:: sevenbridges.api
27 | :members:
28 | :undoc-members:
29 | :show-inheritance:
30 |
31 | sevenbridges\.config module
32 | ---------------------------
33 |
34 | .. automodule:: sevenbridges.config
35 | :members:
36 | :undoc-members:
37 | :show-inheritance:
38 |
39 | sevenbridges\.decorators module
40 | -------------------------------
41 |
42 | .. automodule:: sevenbridges.decorators
43 | :members:
44 | :undoc-members:
45 | :show-inheritance:
46 |
47 | sevenbridges\.errors module
48 | ---------------------------
49 |
50 | .. automodule:: sevenbridges.errors
51 | :members:
52 | :undoc-members:
53 | :show-inheritance:
54 |
55 |
56 |
--------------------------------------------------------------------------------
/docs/sevenbridges.tests.rst:
--------------------------------------------------------------------------------
1 | sevenbridges\.tests package
2 | ===========================
3 |
4 | .. automodule:: sevenbridges.tests
5 | :members:
6 | :undoc-members:
7 | :show-inheritance:
8 |
9 | Submodules
10 | ----------
11 |
12 | sevenbridges\.tests\.conftest module
13 | ------------------------------------
14 |
15 | .. automodule:: sevenbridges.tests.conftest
16 | :members:
17 | :undoc-members:
18 | :show-inheritance:
19 |
20 | sevenbridges\.tests\.providers module
21 | -------------------------------------
22 |
23 | .. automodule:: sevenbridges.tests.providers
24 | :members:
25 | :undoc-members:
26 | :show-inheritance:
27 |
28 | sevenbridges\.tests\.test\_actions module
29 | -----------------------------------------
30 |
31 | .. automodule:: sevenbridges.tests.test_actions
32 | :members:
33 | :undoc-members:
34 | :show-inheritance:
35 |
36 | sevenbridges\.tests\.test\_apps module
37 | --------------------------------------
38 |
39 | .. automodule:: sevenbridges.tests.test_apps
40 | :members:
41 | :undoc-members:
42 | :show-inheritance:
43 |
44 | sevenbridges\.tests\.test\_config module
45 | ----------------------------------------
46 |
47 | .. automodule:: sevenbridges.tests.test_config
48 | :members:
49 | :undoc-members:
50 | :show-inheritance:
51 |
52 | sevenbridges\.tests\.test\_divisions module
53 | -------------------------------------------
54 |
55 | .. automodule:: sevenbridges.tests.test_divisions
56 | :members:
57 | :undoc-members:
58 | :show-inheritance:
59 |
60 | sevenbridges\.tests\.test\_endpoints\_rate module
61 | -------------------------------------------------
62 |
63 | .. automodule:: sevenbridges.tests.test_endpoints_rate
64 | :members:
65 | :undoc-members:
66 | :show-inheritance:
67 |
68 | sevenbridges\.tests\.test\_exports module
69 | -----------------------------------------
70 |
71 | .. automodule:: sevenbridges.tests.test_exports
72 | :members:
73 | :undoc-members:
74 | :show-inheritance:
75 |
76 | sevenbridges\.tests\.test\_files module
77 | ---------------------------------------
78 |
79 | .. automodule:: sevenbridges.tests.test_files
80 | :members:
81 | :undoc-members:
82 | :show-inheritance:
83 |
84 | sevenbridges\.tests\.test\_imports module
85 | -----------------------------------------
86 |
87 | .. automodule:: sevenbridges.tests.test_imports
88 | :members:
89 | :undoc-members:
90 | :show-inheritance:
91 |
92 | sevenbridges\.tests\.test\_marker module
93 | ----------------------------------------
94 |
95 | .. automodule:: sevenbridges.tests.test_marker
96 | :members:
97 | :undoc-members:
98 | :show-inheritance:
99 |
100 | sevenbridges\.tests\.test\_pagination module
101 | --------------------------------------------
102 |
103 | .. automodule:: sevenbridges.tests.test_pagination
104 | :members:
105 | :undoc-members:
106 | :show-inheritance:
107 |
108 | sevenbridges\.tests\.test\_projects module
109 | ------------------------------------------
110 |
111 | .. automodule:: sevenbridges.tests.test_projects
112 | :members:
113 | :undoc-members:
114 | :show-inheritance:
115 |
116 | sevenbridges\.tests\.test\_tasks module
117 | ---------------------------------------
118 |
119 | .. automodule:: sevenbridges.tests.test_tasks
120 | :members:
121 | :undoc-members:
122 | :show-inheritance:
123 |
124 | sevenbridges\.tests\.test\_teams module
125 | ---------------------------------------
126 |
127 | .. automodule:: sevenbridges.tests.test_teams
128 | :members:
129 | :undoc-members:
130 | :show-inheritance:
131 |
132 | sevenbridges\.tests\.test\_transformer module
133 | ---------------------------------------------
134 |
135 | .. automodule:: sevenbridges.tests.test_transformer
136 | :members:
137 | :undoc-members:
138 | :show-inheritance:
139 |
140 | sevenbridges\.tests\.test\_users module
141 | ---------------------------------------
142 |
143 | .. automodule:: sevenbridges.tests.test_users
144 | :members:
145 | :undoc-members:
146 | :show-inheritance:
147 |
148 | sevenbridges\.tests\.test\_utils module
149 | ---------------------------------------
150 |
151 | .. automodule:: sevenbridges.tests.test_utils
152 | :members:
153 | :undoc-members:
154 | :show-inheritance:
155 |
156 | sevenbridges\.tests\.test\_volumes module
157 | -----------------------------------------
158 |
159 | .. automodule:: sevenbridges.tests.test_volumes
160 | :members:
161 | :undoc-members:
162 | :show-inheritance:
163 |
164 | sevenbridges\.tests\.verifiers module
165 | -------------------------------------
166 |
167 | .. automodule:: sevenbridges.tests.verifiers
168 | :members:
169 | :undoc-members:
170 | :show-inheritance:
171 |
172 |
173 |
--------------------------------------------------------------------------------
/docs/sevenbridges.transfer.rst:
--------------------------------------------------------------------------------
1 | sevenbridges\.transfer package
2 | ==============================
3 |
4 | .. automodule:: sevenbridges.transfer
5 | :members:
6 | :undoc-members:
7 | :show-inheritance:
8 |
9 | Submodules
10 | ----------
11 |
12 | sevenbridges\.transfer\.download module
13 | ---------------------------------------
14 |
15 | .. automodule:: sevenbridges.transfer.download
16 | :members:
17 | :undoc-members:
18 | :show-inheritance:
19 |
20 | sevenbridges\.transfer\.upload module
21 | -------------------------------------
22 |
23 | .. automodule:: sevenbridges.transfer.upload
24 | :members:
25 | :undoc-members:
26 | :show-inheritance:
27 |
28 | sevenbridges\.transfer\.utils module
29 | ------------------------------------
30 |
31 | .. automodule:: sevenbridges.transfer.utils
32 | :members:
33 | :undoc-members:
34 | :show-inheritance:
35 |
36 |
37 |
--------------------------------------------------------------------------------
/requirements-dev.txt:
--------------------------------------------------------------------------------
1 | -r requirements.txt
2 |
3 | flake8==4.0.0
4 | pytest==6.2.4
5 | pytest-cov==2.11.1
6 | requests-mock==1.8.0
7 | faker==8.1.3
8 | sphinx==3.5.1
9 | sphinx_rtd_theme==0.5.1
10 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | requests>=2.25.1
2 | urllib3>=1.26.2
3 |
--------------------------------------------------------------------------------
/setup.cfg:
--------------------------------------------------------------------------------
1 | [tool:pytest]
2 | addopts =
3 | --cov=sevenbridges
4 | --cov-report=html:test-report/htmlcov
5 | --cov-report=xml:test-report/coverage.xml
6 | --cov-report=term
7 |
8 | [run]
9 | omit =
10 | tests/*
11 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | from pathlib import Path
2 |
3 | from setuptools import setup, find_packages
4 | from sevenbridges.version import __version__
5 |
6 | setup(
7 | name='sevenbridges-python',
8 | version=__version__,
9 | description='SBG API python client bindings',
10 | install_requires=Path('requirements.txt').read_text().split(),
11 | long_description=Path('README.md').read_text(encoding='utf-8'),
12 | long_description_content_type='text/markdown',
13 | platforms=['Windows', 'POSIX', 'MacOS'],
14 | maintainer='Seven Bridges Genomics Inc.',
15 | maintainer_email='dejan.knezevic@sbgenomics.com',
16 | url='https://github.com/sbg/sevenbridges-python',
17 | license='Apache Software License 2.0',
18 | include_package_data=True,
19 | packages=find_packages(exclude=["tests"]),
20 | keywords=[
21 | 'sevenbridges', 'sbg', 'api', 'cgc',
22 | 'cancer', 'genomics', 'cloud',
23 | ],
24 | classifiers=[
25 | 'License :: OSI Approved :: Apache Software License',
26 | 'Operating System :: OS Independent',
27 | 'Programming Language :: Python',
28 | 'Programming Language :: Python :: 3',
29 | 'Topic :: Software Development',
30 | 'Topic :: Scientific/Engineering :: Bio-Informatics',
31 | 'Topic :: Software Development :: Libraries :: Python Modules',
32 | ]
33 | )
34 |
--------------------------------------------------------------------------------
/sevenbridges/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 | sevenbridges-python
3 | ~~~~~~~~~~~~~~~~~~~
4 | :copyright: 2020 Seven Bridges Genomics Inc.
5 | :license: Apache 2.0
6 | """
7 | import ssl
8 | import logging
9 |
10 | # Read and set version globally
11 | # needs to be imported before other modules
12 | from sevenbridges.version import __version__
13 |
14 | from sevenbridges.api import Api
15 | from sevenbridges.config import Config
16 |
17 | from sevenbridges.models.invoice import Invoice
18 | from sevenbridges.models.billing_group import BillingGroup
19 | from sevenbridges.models.user import User
20 | from sevenbridges.models.endpoints import Endpoints
21 | from sevenbridges.models.project import Project
22 | from sevenbridges.models.task import Task
23 | from sevenbridges.models.app import App
24 | from sevenbridges.models.dataset import Dataset
25 | from sevenbridges.models.drs_import import DRSImportBulk
26 | from sevenbridges.models.bulk import BulkRecord
27 | from sevenbridges.models.team import Team, TeamMember
28 | from sevenbridges.models.member import Member, Permissions
29 | from sevenbridges.models.file import File
30 | from sevenbridges.models.storage_export import Export
31 | from sevenbridges.models.storage_import import Import
32 | from sevenbridges.models.volume import Volume
33 | from sevenbridges.models.marker import Marker
34 | from sevenbridges.models.division import Division
35 | from sevenbridges.models.automation import (
36 | Automation, AutomationRun, AutomationPackage, AutomationMember
37 | )
38 | from sevenbridges.models.async_jobs import AsyncJob
39 | from sevenbridges.models.compound.volumes.volume_object import VolumeObject
40 |
41 | from sevenbridges.models.enums import (
42 | AppCopyStrategy, AppRawFormat, AsyncFileOperations, AsyncJobStates,
43 | AutomationRunActions, DivisionRole, FileStorageType, ImportExportState,
44 | TaskStatus, TransferState, VolumeAccessMode, VolumeType, PartSize,
45 | AutomationStatus
46 | )
47 | from sevenbridges.errors import (
48 | SbgError, ResourceNotModified, ReadOnlyPropertyError, ValidationError,
49 | TaskValidationError, PaginationError, BadRequest, Unauthorized, Forbidden,
50 | NotFound, Conflict, TooManyRequests, ServerError, ServiceUnavailable,
51 | MethodNotAllowed, RequestTimeout, LocalFileAlreadyExists,
52 | ExecutionDetailsInvalidTaskType
53 | )
54 |
55 | logging.getLogger(__name__).addHandler(logging.NullHandler())
56 |
57 | __all__ = [
58 | # Models
59 | 'Api', 'AsyncJob', 'Automation', 'AutomationRun', 'AutomationMember',
60 | 'AutomationPackage', 'Config', 'Invoice', 'BillingGroup', 'User',
61 | 'Endpoints', 'Project', 'Task', 'App', 'Member', 'Permissions', 'File',
62 | 'Export', 'Import', 'Volume', 'VolumeObject', 'Marker', 'Division', 'Team',
63 | 'TeamMember', 'Dataset', 'DRSImportBulk', 'BulkRecord',
64 | # Enums
65 | 'AppCopyStrategy', 'AppRawFormat', 'AppCopyStrategy',
66 | 'AsyncFileOperations', 'AsyncJobStates', 'AutomationRunActions',
67 | 'DivisionRole', 'FileStorageType', 'ImportExportState',
68 | 'TaskStatus', 'TransferState', 'VolumeAccessMode', 'VolumeType',
69 | 'PartSize', 'AutomationStatus',
70 | # Errors
71 | 'SbgError', 'ResourceNotModified', 'ReadOnlyPropertyError',
72 | 'ValidationError', 'TaskValidationError', 'PaginationError', 'BadRequest',
73 | 'Unauthorized', 'Forbidden', 'NotFound', 'Conflict', 'TooManyRequests',
74 | 'ServerError', 'ServiceUnavailable', 'MethodNotAllowed', 'RequestTimeout',
75 | 'LocalFileAlreadyExists', 'ExecutionDetailsInvalidTaskType',
76 | # Version
77 | '__version__',
78 | ]
79 |
80 | required_ssl_version = (1, 0, 1)
81 | if ssl.OPENSSL_VERSION_INFO < required_ssl_version:
82 | raise SbgError(
83 | 'OpenSSL version included in this python version must be '
84 | 'at least 1.0.1 or greater. Please update your environment build.'
85 | )
86 |
--------------------------------------------------------------------------------
/sevenbridges/api.py:
--------------------------------------------------------------------------------
1 | from concurrent.futures import ThreadPoolExecutor
2 |
3 | from requests.adapters import DEFAULT_POOLSIZE
4 |
5 | from sevenbridges.errors import SbgError
6 | from sevenbridges.http.client import HttpClient
7 |
8 | from sevenbridges.models.app import App
9 | from sevenbridges.models.file import File
10 | from sevenbridges.models.task import Task
11 | from sevenbridges.models.team import Team
12 | from sevenbridges.models.user import User
13 | from sevenbridges.models.marker import Marker
14 | from sevenbridges.models.volume import Volume
15 | from sevenbridges.models.actions import Actions
16 | from sevenbridges.models.dataset import Dataset
17 | from sevenbridges.models.invoice import Invoice
18 | from sevenbridges.models.project import Project
19 | from sevenbridges.models.division import Division
20 | from sevenbridges.models.async_jobs import AsyncJob
21 | from sevenbridges.models.endpoints import Endpoints
22 | from sevenbridges.models.rate_limit import RateLimit
23 | from sevenbridges.models.storage_export import Export
24 | from sevenbridges.models.storage_import import Import
25 | from sevenbridges.models.drs_import import DRSImportBulk
26 | from sevenbridges.models.enums import RequestParameters
27 | from sevenbridges.models.billing_group import BillingGroup
28 | from sevenbridges.models.automation import (
29 | Automation, AutomationRun, AutomationPackage
30 | )
31 |
32 |
33 | class Api(HttpClient):
34 | """
35 | Api aggregates all resource classes into single place
36 | """
37 |
38 | actions = Actions
39 | apps = App
40 | async_jobs = AsyncJob
41 | automations = Automation
42 | automation_runs = AutomationRun
43 | automation_packages = AutomationPackage
44 | billing_groups = BillingGroup
45 | datasets = Dataset
46 | divisions = Division
47 | drs_imports = DRSImportBulk
48 | endpoints = Endpoints
49 | exports = Export
50 | files = File
51 | imports = Import
52 | invoices = Invoice
53 | markers = Marker
54 | projects = Project
55 | rate_limit = RateLimit
56 | tasks = Task
57 | teams = Team
58 | users = User
59 | volumes = Volume
60 |
61 | def __init__(
62 | self, url=None, token=None, oauth_token=None, config=None,
63 | timeout=None, download_max_workers=16, upload_max_workers=16,
64 | proxies=None, error_handlers=None, advance_access=False,
65 | pool_connections=DEFAULT_POOLSIZE, pool_maxsize=100,
66 | pool_block=True, max_parallel_requests=100,
67 | retry_count=RequestParameters.DEFAULT_RETRY_COUNT,
68 | backoff_factor=RequestParameters.DEFAULT_BACKOFF_FACTOR,
69 | debug=False,
70 | ):
71 | """
72 | Initializes api object.
73 |
74 | :param url: Api url.
75 | :param token: Secure token.
76 | :param oauth_token: Oauth token.
77 | :param config: Configuration profile.
78 | :param timeout: Client timeout.
79 | :param download_max_workers: Max number of threads for download.
80 | :param upload_max_workers: Max number of threads for upload.
81 | :param proxies: Proxy settings if any.
82 | :param error_handlers: List of error handlers - callables.
83 | :param advance_access: If True advance access features will be enabled.
84 | :param pool_connections: The number of urllib3 connection pools to
85 | cache.
86 | :param pool_maxsize: The maximum number of connections to save in the
87 | pool.
88 | :param pool_block: Whether the connection pool should block for
89 | connections.
90 | :param max_parallel_requests: Number which indicates number of parallel
91 | requests, only useful for multi thread applications.
92 | :return: Api object instance.
93 | """
94 | if not debug and url and url.startswith('http:'):
95 | raise SbgError(
96 | 'Seven Bridges api client requires https, '
97 | f'cannot initialize with url {url}'
98 | )
99 |
100 | super().__init__(
101 | url=url, token=token, oauth_token=oauth_token, config=config,
102 | timeout=timeout, proxies=proxies, error_handlers=error_handlers,
103 | advance_access=advance_access, pool_connections=pool_connections,
104 | pool_maxsize=pool_maxsize, pool_block=pool_block,
105 | max_parallel_requests=max_parallel_requests,
106 | retry_count=retry_count, backoff_factor=backoff_factor,
107 | )
108 |
109 | self.download_pool = ThreadPoolExecutor(
110 | max_workers=download_max_workers
111 | )
112 | self.upload_pool = ThreadPoolExecutor(max_workers=upload_max_workers)
113 |
--------------------------------------------------------------------------------
/sevenbridges/config.py:
--------------------------------------------------------------------------------
1 | import os
2 | import logging
3 | import configparser
4 |
5 | from sevenbridges.errors import SbgError
6 |
7 | logger = logging.getLogger(__name__)
8 |
9 |
10 | def format_proxies(proxies):
11 | """
12 | Helper method for request proxy key compatibility.
13 | :param proxies: Proxies dictionary
14 | :return: Dict compatible with request proxy format.
15 | """
16 | if proxies:
17 | return {
18 | 'http': proxies.get('http_proxy', None),
19 | 'https': proxies.get('https_proxy', None)
20 | }
21 | return {}
22 |
23 |
24 | class UserProfile:
25 | CREDENTIALS = os.path.join(
26 | os.path.expanduser('~'),
27 | '.sevenbridges',
28 | 'credentials'
29 | )
30 | CONFIG = os.path.join(
31 | os.path.expanduser('~'),
32 | '.sevenbridges',
33 | 'sevenbridges-python',
34 | 'config'
35 | )
36 |
37 | def __init__(self, profile):
38 | if not os.path.isfile(self.CREDENTIALS):
39 | raise SbgError('Missing credentials file.')
40 |
41 | self.profile = profile
42 |
43 | # noinspection PyTypeChecker
44 | self.credentials_parser = configparser.ConfigParser({
45 | 'auth_token': None,
46 | 'api_endpoint': None,
47 | }, allow_no_value=True)
48 | # noinspection PyTypeChecker
49 | self.config_parser = configparser.ConfigParser({
50 | 'http_proxy': None,
51 | 'https_proxy': None,
52 | 'advance_access': False,
53 | }, allow_no_value=True)
54 | self.credentials_parser.read(self.CREDENTIALS)
55 |
56 | if not os.path.isfile(self.CONFIG):
57 | self.config_parser = None
58 | logging.info('No custom configuration present. Skipping...')
59 | else:
60 | # noinspection PyTypeChecker
61 | self.config_parser = configparser.ConfigParser({
62 | 'http_proxy': None,
63 | 'https_proxy': None,
64 | 'advance_access': False,
65 | }, allow_no_value=True)
66 | self.config_parser.read(self.CONFIG)
67 |
68 | @property
69 | def api_endpoint(self):
70 | return self.credentials_parser.get(self.profile, 'api_endpoint')
71 |
72 | @property
73 | def auth_token(self):
74 | return self.credentials_parser.get(self.profile, 'auth_token')
75 |
76 | @property
77 | def proxies(self):
78 | try:
79 | return {
80 | 'http_proxy': self.config_parser.get(
81 | 'proxies', 'http_proxy'
82 | ) if self.config_parser else None,
83 | 'https_proxy': self.config_parser.get(
84 | 'proxies', 'https_proxy'
85 | ) if self.config_parser else None
86 | }
87 | except KeyError:
88 | return format_proxies({})
89 | except configparser.NoSectionError:
90 | return format_proxies({})
91 |
92 | @property
93 | def advance_access(self):
94 | try:
95 | return (
96 | self.config_parser.get('mode', 'advance_access')
97 | if self.config_parser
98 | else False
99 | )
100 | except KeyError:
101 | return False
102 | except configparser.NoSectionError:
103 | return False
104 |
105 |
106 | class Config:
107 | """
108 | Utility configuration class.
109 | """
110 |
111 | def __init__(self, profile=None, proxies=None, advance_access=None):
112 | """
113 | Configures the bindings to use api url and token specified
114 | in the .ini like configuration file.
115 | :param profile: ini section, if not supplied [default] profile is used.
116 | """
117 |
118 | self.profile = profile
119 |
120 | cfg_profile = None
121 |
122 | if not self.profile:
123 | # Try os.environ
124 | self.auth_token = os.environ.get('SB_AUTH_TOKEN')
125 | self.api_endpoint = os.environ.get('SB_API_ENDPOINT')
126 | self.proxies = {
127 | 'http': os.environ.get('HTTP_PROXY'),
128 | 'https': os.environ.get('HTTPS_PROXY')
129 | }
130 | if not self.auth_token:
131 | logger.warning('Missing SB_AUTH_TOKEN os variable.')
132 | raise SbgError('Missing SB_AUTH_TOKEN')
133 | if not self.api_endpoint:
134 | logger.warning('Missing SB_API_ENDPOINT os variable.')
135 | raise SbgError('Missing SB_API_ENDPOINT')
136 | self.advance_access = advance_access if advance_access else False
137 | else:
138 | cfg_profile = UserProfile(profile)
139 | self.auth_token = cfg_profile.auth_token
140 | self.api_endpoint = cfg_profile.api_endpoint
141 | self.advance_access = cfg_profile.advance_access
142 |
143 | if proxies:
144 | self.proxies = format_proxies(proxies)
145 | elif cfg_profile:
146 | self.proxies = format_proxies(cfg_profile.proxies)
147 |
148 | if advance_access:
149 | self.advance_access = advance_access
150 | elif cfg_profile:
151 | self.advance_access = cfg_profile.advance_access
152 |
153 | logger.info(
154 | 'Client settings: [url=%s] [token=%s] [proxy=%s]',
155 | self.api_endpoint,
156 | '*****',
157 | self.proxies
158 | )
159 |
--------------------------------------------------------------------------------
/sevenbridges/decorators.py:
--------------------------------------------------------------------------------
1 | import copy
2 | import logging
3 | import functools
4 | from json import JSONDecodeError
5 |
6 | import requests
7 |
8 | from sevenbridges.errors import (
9 | BadRequest, Unauthorized, Forbidden, NotFound, MethodNotAllowed,
10 | RequestTimeout, Conflict, TooManyRequests, SbgError, ServerError,
11 | ServiceUnavailable, NonJSONResponseError
12 | )
13 |
14 | logger = logging.getLogger(__name__)
15 |
16 |
17 | def inplace_reload(method):
18 | """
19 | Executes the wrapped function and reloads the object
20 | with data returned from the server.
21 | """
22 |
23 | # noinspection PyProtectedMember
24 | def wrapped(obj, *args, **kwargs):
25 | in_place = True if kwargs.get('inplace') in (True, None) else False
26 | api_object = method(obj, *args, **kwargs)
27 | if in_place and api_object:
28 | obj._data = api_object._data
29 | obj._dirty = api_object._dirty
30 | obj._old = copy.deepcopy(api_object._data.data)
31 | obj._data.fetched = False
32 | return obj
33 | elif api_object:
34 | return api_object
35 | else:
36 | return obj
37 |
38 | return wrapped
39 |
40 |
41 | def throttle(func):
42 | """Throttles number of parallel requests made by threads from single
43 | HttpClient session."""
44 |
45 | # noinspection PyProtectedMember
46 | @functools.wraps(func)
47 | def wrapper(http_client, *args, **kwargs):
48 | if http_client._throttle_limit:
49 | with http_client._throttle_limit:
50 | return func(http_client, *args, **kwargs)
51 | else:
52 | return func(http_client, *args, **kwargs)
53 | return wrapper
54 |
55 |
56 | def check_for_error(func):
57 | """
58 | Executes the wrapped function and inspects the response object
59 | for specific errors.
60 | """
61 |
62 | @functools.wraps(func)
63 | def wrapper(*args, **kwargs):
64 | try:
65 | response = func(*args, **kwargs)
66 | except requests.RequestException as e:
67 | raise SbgError(message=str(e))
68 | try:
69 | status_code = response.status_code
70 | if status_code in range(200, 204):
71 | return response
72 | if status_code == 204:
73 | return
74 | e = {
75 | 400: BadRequest,
76 | 401: Unauthorized,
77 | 403: Forbidden,
78 | 404: NotFound,
79 | 405: MethodNotAllowed,
80 | 408: RequestTimeout,
81 | 409: Conflict,
82 | 429: TooManyRequests,
83 | 500: ServerError,
84 | 503: ServiceUnavailable,
85 | }.get(status_code, SbgError)()
86 | data = response.json()
87 | if 'message' in data:
88 | e.message = data['message']
89 | if 'code' in data:
90 | e.code = data['code']
91 | if 'status' in data:
92 | e.status = data['status']
93 | if 'more_info' in data:
94 | e.more_info = data['more_info']
95 | raise e
96 | except JSONDecodeError:
97 | raise NonJSONResponseError(
98 | status=response.status_code,
99 | message=str(response.text)
100 | ) from None
101 | except ValueError as e:
102 | raise SbgError(message=str(e))
103 |
104 | return wrapper
105 |
--------------------------------------------------------------------------------
/sevenbridges/errors.py:
--------------------------------------------------------------------------------
1 | class SbgError(Exception):
2 | """Base class for SBG errors.
3 |
4 | Provides a base exception for all errors
5 | that are thrown by sevenbridges-python library.
6 | """
7 |
8 | def __init__(self, message=None, code=None, status=None, more_info=None):
9 | """
10 | :param code: Custom error code
11 | :param status: Http status code.
12 | :param message: Message describing the error.
13 | """
14 | self.code = code
15 | self.status = status
16 | self.message = message
17 | self.more_info = more_info
18 |
19 | def __str__(self):
20 | return str(self.message)
21 |
22 |
23 | class ResourceNotModified(SbgError):
24 | def __init__(self):
25 | super().__init__(
26 | code=-1,
27 | status=-1,
28 | message=(
29 | 'No relevant changes were detected in order to update the '
30 | 'resource on the server.'
31 | )
32 | )
33 |
34 |
35 | class NonJSONResponseError(SbgError):
36 | def __init__(self, status, code=None, message=None, more_info=None):
37 | super().__init__(
38 | code=code, status=status, message=message, more_info=more_info
39 | )
40 |
41 |
42 | class ReadOnlyPropertyError(SbgError):
43 | def __init__(self, message):
44 | super().__init__(
45 | code=-1, status=-1, message=message
46 | )
47 |
48 |
49 | class ValidationError(SbgError):
50 | def __init__(self, message):
51 | super().__init__(
52 | code=-1, status=-1, message=message
53 | )
54 |
55 |
56 | class TaskValidationError(SbgError):
57 | def __init__(self, message, task=None):
58 | self.task = task
59 | super().__init__(
60 | code=-1, status=-1, message=message
61 | )
62 |
63 |
64 | class PaginationError(SbgError):
65 | def __init__(self, message):
66 | super().__init__(
67 | code=-1, status=-1, message=message
68 | )
69 |
70 |
71 | class AdvanceAccessError(SbgError):
72 | def __init__(self, message=None):
73 | super().__init__(
74 | code=-1, status=-1, message=message
75 | )
76 |
77 |
78 | class BadRequest(SbgError):
79 | def __init__(self, code=None, message=None, more_info=None):
80 | super().__init__(
81 | code=code, status=400, message=message, more_info=more_info)
82 |
83 |
84 | class Unauthorized(SbgError):
85 | def __init__(self, code=None, message=None, more_info=None):
86 | super().__init__(
87 | code=code, status=401, message=message, more_info=more_info
88 | )
89 |
90 |
91 | class Forbidden(SbgError):
92 | def __init__(self, code=None, message=None, more_info=None):
93 | super().__init__(
94 | code=code, status=403, message=message, more_info=more_info
95 | )
96 |
97 |
98 | class NotFound(SbgError):
99 | def __init__(self, code=None, message=None, more_info=None):
100 | super().__init__(
101 | code=code, status=404, message=message, more_info=more_info
102 | )
103 |
104 |
105 | class Conflict(SbgError):
106 | def __init__(self, code=None, message=None, more_info=None):
107 | super().__init__(
108 | code=code, status=409, message=message, more_info=more_info
109 | )
110 |
111 |
112 | class TooManyRequests(SbgError):
113 | def __init__(self, code=None, message=None, more_info=None):
114 | super().__init__(
115 | code=code, status=429, message=message, more_info=more_info
116 | )
117 |
118 |
119 | class ServerError(SbgError):
120 | def __init__(self, code=None, message=None, more_info=None):
121 | super().__init__(
122 | code=code, status=500, message=message, more_info=more_info
123 | )
124 |
125 |
126 | class ServiceUnavailable(SbgError):
127 | def __init__(self, code=None, message=None, more_info=None):
128 | super().__init__(
129 | code=code, status=503, message=message, more_info=more_info
130 | )
131 |
132 |
133 | class MethodNotAllowed(SbgError):
134 | def __init__(self, code=None, message=None, more_info=None):
135 | super().__init__(
136 | code=code, status=405, message=message, more_info=more_info
137 | )
138 |
139 |
140 | class RequestTimeout(SbgError):
141 | def __init__(self, code=None, message=None, more_info=None):
142 | super().__init__(
143 | code=code, status=408, message=message, more_info=more_info
144 | )
145 |
146 |
147 | class LocalFileAlreadyExists(SbgError):
148 | def __init__(self, code=None, message=None, more_info=None):
149 | super().__init__(
150 | code=code, status=-1, message=message, more_info=more_info
151 | )
152 |
153 |
154 | class ExecutionDetailsInvalidTaskType(SbgError):
155 | def __init__(self, code=None, message=None, more_info=None):
156 | super().__init__(
157 | code=code, status=-1, message=message, more_info=more_info
158 | )
159 |
160 |
161 | class URITooLong(SbgError):
162 | def __init__(self, code=None, message=None, more_info=None):
163 | super().__init__(
164 | code=code, status=414, message=message, more_info=more_info
165 | )
166 |
--------------------------------------------------------------------------------
/sevenbridges/http/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sbg/sevenbridges-python/ed3de94bab744a33f614111c1845af68b5433c54/sevenbridges/http/__init__.py
--------------------------------------------------------------------------------
/sevenbridges/http/error_handlers.py:
--------------------------------------------------------------------------------
1 | import time
2 | import logging
3 |
4 |
5 | logger = logging.getLogger(__name__)
6 |
7 |
8 | def repeatable_handler(f):
9 | """
10 | Marks 'repeatable' error handlers. Error handler is repeatable if propagate
11 | input response in case of no error handling occurred.
12 | """
13 | f.is_repeatable = True
14 | return f
15 |
16 |
17 | @repeatable_handler
18 | def rate_limit_sleeper(api, response):
19 | """
20 | Pauses the execution if rate limit is breached.
21 | :param api: Api instance.
22 | :param response: requests.Response object
23 |
24 | """
25 | while response.status_code == 429:
26 | headers = response.headers
27 | remaining_time = headers.get('X-RateLimit-Reset')
28 | sleep = max(int(remaining_time) - int(time.time()), 0)
29 |
30 | logger.warning('Rate limit reached! Waiting for [%s]s', sleep)
31 | time.sleep(sleep)
32 |
33 | response = api.session.send(response.request)
34 | return response
35 |
36 |
37 | @repeatable_handler
38 | def maintenance_sleeper(api, response, sleep=300):
39 | """
40 | Pauses the execution if sevenbridges api is under maintenance.
41 | :param api: Api instance.
42 | :param response: requests.Response object.
43 | :param sleep: Time to sleep in between the requests.
44 | """
45 | while response.status_code == 503:
46 | content_type = response.headers.get('Content-Type')
47 | if content_type is None or 'application/json' not in content_type:
48 | return response
49 | logger.info(
50 | 'Service unavailable: Response=[%s]',
51 | response.__dict__
52 | )
53 | response_body = response.json()
54 | if 'code' in response_body:
55 | if response_body['code'] == 0:
56 | logger.warning(
57 | 'API Maintenance in progress! Waiting for [%s]s',
58 | sleep
59 | )
60 | time.sleep(sleep)
61 | response = api.session.send(response.request)
62 | else:
63 | return response
64 | else:
65 | return response
66 | return response
67 |
68 |
69 | @repeatable_handler
70 | def general_error_sleeper(api, response, sleep=300):
71 | """
72 | Pauses the execution if response status code is > 500.
73 | :param api: Api instance.
74 | :param response: requests.Response object
75 | :param sleep: Time to sleep in between the requests.
76 |
77 | """
78 | while response.status_code >= 500:
79 | logger.warning(
80 | 'Caught [%s] status code! Waiting for [%s]s',
81 | response.status_code,
82 | sleep
83 | )
84 | time.sleep(sleep)
85 | response = api.session.send(response.request)
86 | return response
87 |
--------------------------------------------------------------------------------
/sevenbridges/meta/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sbg/sevenbridges-python/ed3de94bab744a33f614111c1845af68b5433c54/sevenbridges/meta/__init__.py
--------------------------------------------------------------------------------
/sevenbridges/meta/collection.py:
--------------------------------------------------------------------------------
1 | from sevenbridges.errors import PaginationError, SbgError
2 | from sevenbridges.models.compound.volumes.volume_object import VolumeObject
3 | from sevenbridges.models.compound.volumes.volume_prefix import VolumePrefix
4 | from sevenbridges.models.link import Link, VolumeLink
5 |
6 |
7 | class Collection(list):
8 | """
9 | Wrapper for SevenBridges pageable resources.
10 | Among the actual collection items it contains information regarding
11 | the total number of entries available in on the server and resource href.
12 | """
13 |
14 | resource = None
15 |
16 | def __init__(self, resource, href, total, items, links, api):
17 | super().__init__(items)
18 | self.resource = resource
19 | self.href = href
20 | self.links = links
21 | self._items = items
22 | self._total = total
23 | self._api = api
24 |
25 | @property
26 | def total(self):
27 | return int(self._total)
28 |
29 | def all(self):
30 | """
31 | Fetches all available items.
32 | :return: Collection object.
33 | """
34 | page = self._load(self.href)
35 | while True:
36 | try:
37 | for item in page._items:
38 | yield item
39 | page = page.next_page()
40 | except PaginationError:
41 | break
42 |
43 | def _load(self, url):
44 | if self.resource is None:
45 | raise SbgError('Undefined collection resource.')
46 | else:
47 | response = self._api.get(url, append_base=False)
48 | data = response.json()
49 | total = response.headers['x-total-matching-query']
50 | items = [
51 | self.resource(api=self._api, **group)
52 | for group in data['items']
53 | ]
54 | links = [Link(**link) for link in data['links']]
55 | href = data['href']
56 | return Collection(
57 | resource=self.resource, href=href, total=total,
58 | items=items, links=links, api=self._api
59 | )
60 |
61 | def next_page(self):
62 | """
63 | Fetches next result set.
64 | :return: Collection object.
65 | """
66 | for link in self.links:
67 | if link.rel.lower() == 'next':
68 | return self._load(link.href)
69 | raise PaginationError('No more entries.')
70 |
71 | def previous_page(self):
72 | """
73 | Fetches previous result set.
74 | :return: Collection object.
75 | """
76 | for link in self.links:
77 | if link.rel.lower() == 'prev':
78 | return self._load(link.href)
79 | raise PaginationError('No more entries.')
80 |
81 | def __repr__(self):
82 | return (
83 | f''
84 | )
85 |
86 |
87 | class VolumeCollection(Collection):
88 | def __init__(self, href, items, links, prefixes, api):
89 | super().__init__(
90 | VolumeObject, href, 0, items, links, api)
91 | self.prefixes = prefixes
92 |
93 | @property
94 | def total(self):
95 | return -1
96 |
97 | def next_page(self):
98 | """
99 | Fetches next result set.
100 | :return: VolumeCollection object.
101 | """
102 | for link in self.links:
103 | if link.next:
104 | return self._load(link.next)
105 | raise PaginationError('No more entries.')
106 |
107 | def previous_page(self):
108 | raise PaginationError('Cannot paginate backwards')
109 |
110 | def _load(self, url):
111 | if self.resource is None:
112 | raise SbgError('Undefined collection resource.')
113 | else:
114 | response = self._api.get(url, append_base=False)
115 | data = response.json()
116 | items = [
117 | self.resource(api=self._api, **group) for group in
118 | data['items']
119 | ]
120 | prefixes = [
121 | VolumePrefix(api=self._api, **prefix) for prefix in
122 | data['prefixes']
123 | ]
124 | links = [VolumeLink(**link) for link in data['links']]
125 | href = data['href']
126 | return VolumeCollection(
127 | href=href, items=items, links=links,
128 | prefixes=prefixes, api=self._api
129 | )
130 |
131 | def __repr__(self):
132 | return f''
133 |
--------------------------------------------------------------------------------
/sevenbridges/meta/comp_mutable_dict.py:
--------------------------------------------------------------------------------
1 | # noinspection PyProtectedMember,PyUnresolvedReferences
2 | class CompoundMutableDict(dict):
3 | """
4 | Resource used for mutable compound dictionaries.
5 | """
6 |
7 | # noinspection PyMissingConstructor
8 | def __init__(self, **kwargs):
9 | self._parent = kwargs.pop('_parent')
10 | self._api = kwargs.pop('api')
11 | for k, v in kwargs.items():
12 | super().__setitem__(k, v)
13 |
14 | def __setitem__(self, key, value):
15 | super().__setitem__(key, value)
16 | if self._name not in self._parent._dirty:
17 | self._parent._dirty.update({self._name: {}})
18 | if key in self._parent._data[self._name]:
19 | if self._parent._data[self._name][key] != value:
20 | self._parent._dirty[self._name][key] = value
21 | self._parent._data[self._name][key] = value
22 | else:
23 | self._parent._data[self._name][key] = value
24 | self._parent._dirty[self._name][key] = value
25 |
26 | def __repr__(self):
27 | values = {}
28 | for k, _ in self.items():
29 | values[k] = self[k]
30 | return str(values)
31 |
32 | __str__ = __repr__
33 |
34 | def update(self, e=None, **f):
35 | other = {}
36 | if e:
37 | other.update(e, **f)
38 | else:
39 | other.update(**f)
40 | for k, v in other.items():
41 | if other[k] != self[k]:
42 | self[k] = other[k]
43 |
44 | def items(self):
45 | values = []
46 | for k in self.keys():
47 | values.append((k, self[k]))
48 | return values
49 |
50 | def equals(self, other):
51 | if not type(other) == type(self):
52 | return False
53 | return (
54 | self is other or
55 | self._parent._data[self._name] == other._parent._data[self._name]
56 | )
57 |
--------------------------------------------------------------------------------
/sevenbridges/meta/data.py:
--------------------------------------------------------------------------------
1 | import logging
2 |
3 |
4 | logger = logging.getLogger(__name__)
5 |
6 |
7 | class DataContainer:
8 | """
9 | Utility for fetching data from the API server using,
10 | resource identifier or href.
11 | """
12 |
13 | def __init__(self, urls, api, parent):
14 | self.data = {}
15 | self._URL = urls
16 | self.api = api
17 | self.parent = parent
18 | self.fetched = False
19 |
20 | def fetch(self, item=None):
21 |
22 | logger.debug(
23 | 'Property "%s" is not set, fetching resource from server', item
24 | ) if item else logger.debug(
25 | 'Requested property is not set, fetching resource from server',
26 | )
27 |
28 | href = self.data.get('href', None)
29 | headers = dict(self.api.headers)
30 |
31 | if href:
32 | self.data = self.api.get(
33 | href,
34 | headers=headers,
35 | append_base=False
36 | ).json()
37 | logger.debug('Resource fetched using the "href" property.')
38 | elif self._URL is not None and 'get' in self._URL:
39 | resource_id = self.data.get('id', None)
40 | if resource_id is None:
41 | logger.debug(
42 | 'Failed to fetch resource, "id" or "href" property '
43 | 'not set'
44 | )
45 | return
46 | self.data = self.api.get(
47 | self._URL['get'].format(id=resource_id),
48 | headers=headers,
49 | append_base=True
50 | ).json()
51 |
52 | logger.debug('Resource fetched using the id property.')
53 | else:
54 | logger.debug(
55 | 'Skipping resource fetch, retrieval for this resource is '
56 | 'not available.'
57 | )
58 | return
59 | self.parent.update_old()
60 | self.fetched = True
61 |
62 | def __getitem__(self, item):
63 | if item not in self.data and not self.fetched:
64 | self.fetch(item=item)
65 | try:
66 | return self.data[item]
67 | except KeyError:
68 | return None
69 |
70 | def __setitem__(self, key, value):
71 | self.data[key] = value
72 |
--------------------------------------------------------------------------------
/sevenbridges/models/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sbg/sevenbridges-python/ed3de94bab744a33f614111c1845af68b5433c54/sevenbridges/models/__init__.py
--------------------------------------------------------------------------------
/sevenbridges/models/actions.py:
--------------------------------------------------------------------------------
1 | import logging
2 |
3 | from sevenbridges.http.client import client_info
4 | from sevenbridges.meta.resource import Resource
5 | from sevenbridges.meta.transformer import Transform
6 | from sevenbridges.models.enums import FeedbackType
7 |
8 | logger = logging.getLogger(__name__)
9 |
10 |
11 | class Actions(Resource):
12 | _URL = {
13 | 'send_feedback': '/action/notifications/feedback',
14 | 'bulk_copy': '/action/files/copy'
15 | }
16 |
17 | def __str__(self):
18 | return ''
19 |
20 | # noinspection PyShadowingBuiltins
21 | @classmethod
22 | def send_feedback(cls, type=FeedbackType.IDEA, referrer=None, text=None,
23 | api=None):
24 | """
25 | Sends feedback to sevenbridges.
26 | :param type: FeedbackType wither IDEA, PROBLEM or THOUGHT.
27 | :param text: Feedback text.
28 | :param referrer: Feedback referrer.
29 | :param api: Api instance.
30 | """
31 | api = api if api else cls._API
32 | data = {
33 | 'type': type,
34 | 'text': text,
35 | 'referrer': referrer if referrer else str(client_info)
36 | }
37 |
38 | extra = {
39 | 'resource': cls.__name__,
40 | 'query': data
41 | }
42 | logger.info('Sending feedback', extra=extra)
43 | api.post(url=cls._URL['send_feedback'], data=data)
44 |
45 | @classmethod
46 | def bulk_copy_files(cls, files, destination_project, api=None):
47 | """
48 | Bulk copy of files.
49 | :param files: List containing files to be copied.
50 | :param destination_project: Destination project.
51 | :param api: Api instance.
52 | :return: MultiStatus copy result.
53 | """
54 | api = api if api else cls._API
55 | files = [Transform.to_file(file) for file in files]
56 | data = {
57 | 'project': destination_project,
58 | 'file_ids': files
59 | }
60 | extra = {
61 | 'resource': cls.__name__,
62 | 'query': data
63 | }
64 | logger.info('Performing bulk copy', extra=extra)
65 | return api.post(url=cls._URL['bulk_copy'], data=data).json()
66 |
--------------------------------------------------------------------------------
/sevenbridges/models/async_jobs.py:
--------------------------------------------------------------------------------
1 | import logging
2 |
3 | from sevenbridges.meta.resource import Resource
4 | from sevenbridges.models.file import FileBulkRecord
5 | from sevenbridges.meta.transformer import Transform
6 | from sevenbridges.meta.fields import (
7 | BasicListField, DateTimeField, IntegerField, StringField, HrefField
8 | )
9 |
10 | logger = logging.getLogger(__name__)
11 |
12 |
13 | class AsyncFileBulkRecord(FileBulkRecord):
14 |
15 | @classmethod
16 | def parse_records(cls, result, api=None):
17 | api = api or cls._API
18 |
19 | records = []
20 | for item in result:
21 | record = cls(api=api)
22 | if 'error' in item:
23 | record.error = item['error']
24 | if 'resource' in item:
25 | record.resource = item['resource']
26 | records.append(record)
27 | return records
28 |
29 |
30 | class AsyncJob(Resource):
31 | """
32 | Central resource for managing async jobs
33 | """
34 |
35 | _URL = {
36 | 'list_file_jobs': '/async/files',
37 | 'get_file_copy_job': '/async/files/copy/{id}',
38 | 'get_file_delete_job': '/async/files/delete/{id}',
39 | 'bulk_copy_files': '/async/files/copy',
40 | 'bulk_delete_files': '/async/files/delete',
41 | 'get_file_move_job': '/async/files/move/{id}',
42 | 'bulk_move_files': '/async/files/move',
43 | }
44 |
45 | href = HrefField(read_only=True)
46 | id = StringField(read_only=True)
47 | type = StringField(read_only=True)
48 | state = StringField(read_only=True)
49 | result = BasicListField(read_only=True)
50 | total_files = IntegerField(read_only=True)
51 | failed_files = IntegerField(read_only=True)
52 | completed_files = IntegerField(read_only=True)
53 | started_on = DateTimeField(read_only=True)
54 | finished_on = DateTimeField(read_only=True)
55 |
56 | def __str__(self):
57 | return f''
58 |
59 | def __eq__(self, other):
60 | if type(other) is not type(self):
61 | return False
62 | return self is other or self.id == other.id
63 |
64 | @classmethod
65 | def get_file_copy_job(cls, id, api=None):
66 | """
67 | Retrieve file copy async job
68 | :param id: Async job identifier
69 | :param api: Api instance
70 | :return:
71 | """
72 | id = Transform.to_async_job(id)
73 |
74 | api = api if api else cls._API
75 | async_job = api.get(
76 | url=cls._URL['get_file_copy_job'].format(id=id)
77 | ).json()
78 | return AsyncJob(api=api, **async_job)
79 |
80 | @classmethod
81 | def get_file_move_job(cls, id, api=None):
82 | """
83 | Retrieve file move async job
84 | :param id: Async job identifier
85 | :param api: Api instance
86 | :return:
87 | """
88 | id = Transform.to_async_job(id)
89 |
90 | api = api if api else cls._API
91 | async_job = api.get(
92 | url=cls._URL['get_file_move_job'].format(id=id)
93 | ).json()
94 | return AsyncJob(api=api, **async_job)
95 |
96 | @classmethod
97 | def get_file_delete_job(cls, id, api=None):
98 | """
99 | :param id: Async job identifier
100 | :param api: Api instance
101 | :return:
102 | """
103 | id = Transform.to_async_job(id)
104 |
105 | api = api if api else cls._API
106 | async_job = api.get(
107 | url=cls._URL['get_file_delete_job'].format(id=id)
108 | ).json()
109 | return AsyncJob(api=api, **async_job)
110 |
111 | def get_result(self, api=None):
112 | """
113 | Get async job result in bulk format
114 | :return: List of AsyncFileBulkRecord objects
115 | """
116 | api = api or self._API
117 | if not self.result:
118 | return []
119 | return AsyncFileBulkRecord.parse_records(
120 | result=self.result,
121 | api=api
122 | )
123 |
124 | @classmethod
125 | def list_file_jobs(cls, offset=None, limit=None, api=None):
126 | """Query ( List ) async jobs
127 | :param offset: Pagination offset
128 | :param limit: Pagination limit
129 | :param api: Api instance
130 | :return: Collection object
131 | """
132 | api = api or cls._API
133 | return super()._query(
134 | api=api,
135 | url=cls._URL['list_file_jobs'],
136 | offset=offset,
137 | limit=limit,
138 | )
139 |
140 | @classmethod
141 | def file_bulk_copy(cls, files, api=None):
142 | api = api or cls._API
143 | data = {'items': files}
144 | logger.info('Submitting async job for copying files in bulk')
145 | response = api.post(
146 | url=cls._URL['bulk_copy_files'], data=data
147 | ).json()
148 | return AsyncJob(api=api, **response)
149 |
150 | @classmethod
151 | def file_bulk_move(cls, files, api=None):
152 | api = api or cls._API
153 | data = {'items': files}
154 | logger.info('Submitting async job for moving files in bulk')
155 | response = api.post(
156 | url=cls._URL['bulk_move_files'], data=data
157 | ).json()
158 | return AsyncJob(api=api, **response)
159 |
160 | @classmethod
161 | def file_bulk_delete(cls, files, api=None):
162 | api = api or cls._API
163 | data = {'items': files}
164 | logger.info('Submitting async job for deleting files in bulk')
165 | response = api.post(
166 | url=cls._URL['bulk_delete_files'], data=data
167 | ).json()
168 | return AsyncJob(api=api, **response)
169 |
--------------------------------------------------------------------------------
/sevenbridges/models/billing_analysis_breakdown.py:
--------------------------------------------------------------------------------
1 | from sevenbridges.meta.resource import Resource
2 | from sevenbridges.meta.fields import (
3 | UuidField, CompoundField, StringField,
4 | DateTimeField, FloatField, BooleanField
5 | )
6 | from sevenbridges.models.compound.analysis_cost import AnalysisCost
7 |
8 |
9 | class BillingGroupAnalysisBreakdown(Resource):
10 | _URL = {
11 | 'query': '/billing/groups/{id}/breakdown/analysis'
12 | }
13 |
14 | project_name = StringField(read_only=True)
15 | analysis_app_name = StringField(read_only=True)
16 | analysis_name = StringField(read_only=True)
17 | analysis_type = StringField(read_only=True)
18 | analysis_id = UuidField(read_only=True)
19 | ran_by = StringField(read_only=True)
20 | analysis_status = StringField(read_only=True)
21 | analysis_cost = CompoundField(AnalysisCost, read_only=True)
22 | refunded_amount = FloatField(read_only=True)
23 | time_started = DateTimeField(read_only=True)
24 | time_finished = DateTimeField(read_only=True)
25 | project_locked = BooleanField(read_only=True)
26 |
27 | @classmethod
28 | def query(cls, bg_id, api=None, date_from=None, date_to=None,
29 | invoice_id=None, fields=None, offset=None, limit=None):
30 | """
31 | Query (List) billing group analysis breakdown. Date parameters must be
32 | string in format MM-DD-YYYY
33 |
34 | :param fields:
35 | :param invoice_id:
36 | :param date_to: include all analysis transactions charged before and
37 | including date_to
38 | :param date_from: include all analysis transactions charged after and
39 | including date_from
40 | :param bg_id: Billing Group ID
41 | :param offset: Pagination offset.
42 | :param limit: Pagination limit.
43 | :param api: Api instance.
44 | :return: Collection object.
45 | """
46 | api = api or cls._API
47 |
48 | return super(BillingGroupAnalysisBreakdown, cls)._query(
49 | url=cls._URL['query'].format(id=bg_id), offset=offset, limit=limit,
50 | date_from=date_from, date_to=date_to, invoice_id=invoice_id,
51 | fields=fields, api=api
52 | )
53 |
54 | def __str__(self):
55 | return ''
56 |
--------------------------------------------------------------------------------
/sevenbridges/models/billing_egress_breakdown.py:
--------------------------------------------------------------------------------
1 | from sevenbridges.meta.resource import Resource
2 | from sevenbridges.meta.fields import (
3 | StringField, CompoundField, BooleanField
4 | )
5 | from sevenbridges.models.compound.measurement import Measurement
6 | from sevenbridges.models.compound.egress_cost import EgressCost
7 |
8 |
9 | class BillingGroupEgressBreakdown(Resource):
10 | _URL = {
11 | 'query': '/billing/groups/{id}/breakdown/egress'
12 | }
13 |
14 | project_name = StringField(read_only=True)
15 | downloaded_by = StringField(read_only=True)
16 | downloaded = CompoundField(Measurement, read_only=True)
17 | egress_cost = CompoundField(EgressCost, read_only=True)
18 | project_locked = BooleanField(read_only=True)
19 |
20 | @classmethod
21 | def query(cls, bg_id, api=None, date_from=None, date_to=None,
22 | invoice_id=None, fields=None, offset=None, limit=None):
23 | """
24 | Query (List) billing group egress breakdown. Date parameters must be
25 | string in format MM-DD-YYYY
26 |
27 | :param fields:
28 | :param invoice_id:
29 | :param date_to: include all egress transactions charged before and
30 | including date_to
31 | :param date_from: include all egress transactions charged after and
32 | including date_from
33 | :param bg_id: Billing Group ID
34 | :param offset: Pagination offset.
35 | :param limit: Pagination limit.
36 | :param api: Api instance.
37 | :return: Collection object.
38 | """
39 | api = api or cls._API
40 |
41 | return super(BillingGroupEgressBreakdown, cls)._query(
42 | url=cls._URL['query'].format(id=bg_id), offset=offset, limit=limit,
43 | date_from=date_from, date_to=date_to, invoice_id=invoice_id,
44 | fields=fields, api=api
45 | )
46 |
47 | def __str__(self):
48 | return ''
49 |
--------------------------------------------------------------------------------
/sevenbridges/models/billing_group.py:
--------------------------------------------------------------------------------
1 | from sevenbridges.meta.fields import (
2 | HrefField, UuidField, StringField, BooleanField, CompoundField
3 | )
4 | from sevenbridges.meta.resource import Resource
5 | from sevenbridges.models.billing_analysis_breakdown import (
6 | BillingGroupAnalysisBreakdown
7 | )
8 | from sevenbridges.models.billing_storage_breakdown import (
9 | BillingGroupStorageBreakdown
10 | )
11 | from sevenbridges.models.billing_egress_breakdown import (
12 | BillingGroupEgressBreakdown
13 | )
14 | from sevenbridges.models.compound.price import Price
15 |
16 |
17 | class BillingGroup(Resource):
18 | """
19 | Central resource for managing billing groups.
20 | """
21 | _URL = {
22 | 'query': '/billing/groups',
23 | 'get': '/billing/groups/{id}'
24 | }
25 | href = HrefField(read_only=True)
26 | id = UuidField(read_only=True)
27 | owner = StringField(read_only=True)
28 | name = StringField(read_only=True)
29 | type = StringField(read_only=True)
30 | pending = BooleanField(read_only=True)
31 | disabled = BooleanField(read_only=False)
32 | balance = CompoundField(Price, read_only=True)
33 |
34 | def __str__(self):
35 | return f''
36 |
37 | def __eq__(self, other):
38 | if type(other) is not type(self):
39 | return False
40 | return self is other or self.id == other.id
41 |
42 | @classmethod
43 | def query(cls, offset=None, limit=None, api=None):
44 | """
45 | Query (List) billing group.
46 | :param offset: Pagination offset.
47 | :param limit: Pagination limit.
48 | :return: Collection object.
49 | :param api: Api instance.
50 | """
51 | api = api or cls._API
52 | return super()._query(
53 | url=cls._URL['query'], offset=offset, limit=limit, fields='_all',
54 | api=api
55 | )
56 |
57 | def analysis_breakdown(self, date_from=None, date_to=None, invoice_id=None,
58 | fields=None, offset=None, limit=None):
59 | """
60 | Get Billing group analysis breakdown for the current billing group.
61 | """
62 | return BillingGroupAnalysisBreakdown.query(
63 | bg_id=self.id, api=self._api, date_from=date_from, date_to=date_to,
64 | invoice_id=invoice_id, fields=fields, offset=offset, limit=limit
65 | )
66 |
67 | def storage_breakdown(self, date_from=None, date_to=None, invoice_id=None,
68 | fields=None, offset=None, limit=None):
69 | """
70 | Get Billing group storage breakdown for the current billing group.
71 | """
72 | return BillingGroupStorageBreakdown.query(
73 | bg_id=self.id, api=self._api, date_from=date_from, date_to=date_to,
74 | invoice_id=invoice_id, fields=fields, offset=offset, limit=limit
75 | )
76 |
77 | def egress_breakdown(self, date_from=None, date_to=None, invoice_id=None,
78 | fields=None, offset=None, limit=None):
79 | """
80 | Get Billing group egress breakdown for the current billing group.
81 | """
82 | return BillingGroupEgressBreakdown.query(
83 | bg_id=self.id, api=self._api, date_from=date_from, date_to=date_to,
84 | invoice_id=invoice_id, fields=fields, offset=offset, limit=limit
85 | )
86 |
--------------------------------------------------------------------------------
/sevenbridges/models/billing_storage_breakdown.py:
--------------------------------------------------------------------------------
1 | from sevenbridges.meta.resource import Resource
2 | from sevenbridges.meta.fields import (
3 | CompoundField, StringField, BooleanField
4 | )
5 | from sevenbridges.models.compound.measurement import Measurement
6 |
7 |
8 | class BillingGroupStorageBreakdown(Resource):
9 | _URL = {
10 | 'query': '/billing/groups/{id}/breakdown/storage'
11 | }
12 |
13 | project_name = StringField(read_only=True)
14 | project_created_by = StringField(read_only=True)
15 | location = StringField(read_only=True)
16 | active = CompoundField(Measurement, read_only=True)
17 | archived = CompoundField(Measurement, read_only=True)
18 | project_locked = BooleanField(read_only=True)
19 |
20 | @classmethod
21 | def query(cls, bg_id, api=None, date_from=None, date_to=None,
22 | invoice_id=None, fields=None, offset=None, limit=None):
23 | """
24 | Query (List) billing group storage breakdown. Date parameters must be
25 | string in format MM-DD-YYYY
26 |
27 | :param fields:
28 | :param invoice_id:
29 | :param date_to: include all storage transactions charged before and
30 | including date_to
31 | :param date_from: include all storage transactions charged after and
32 | including date_from
33 | :param bg_id: Billing Group ID
34 | :param offset: Pagination offset.
35 | :param limit: Pagination limit.
36 | :param api: Api instance.
37 | :return: Collection object.
38 | """
39 | api = api or cls._API
40 |
41 | return super(BillingGroupStorageBreakdown, cls)._query(
42 | url=cls._URL['query'].format(id=bg_id), offset=offset, limit=limit,
43 | date_from=date_from, date_to=date_to, invoice_id=invoice_id,
44 | fields=fields, api=api
45 | )
46 |
47 | def __str__(self):
48 | return ''
49 |
--------------------------------------------------------------------------------
/sevenbridges/models/bulk.py:
--------------------------------------------------------------------------------
1 | from sevenbridges.meta.resource import Resource
2 | from sevenbridges.meta.fields import CompoundField
3 | from sevenbridges.models.compound.error import Error
4 |
5 |
6 | class BulkRecord(Resource):
7 | error = CompoundField(cls=Error, read_only=False)
8 | resource = CompoundField(cls=Resource, read_only=False)
9 |
10 | def __str__(self):
11 | return f''
12 |
13 | @property
14 | def valid(self):
15 | return self.error is None
16 |
17 | @classmethod
18 | def parse_records(cls, response, api=None):
19 | api = api or cls._API
20 | records = []
21 | data = response.json()
22 | for item in data.get('items', []):
23 | record = cls(api=api)
24 | record._set('error', item.get('error'))
25 | record._set('resource', item.get('resource'))
26 | records.append(record)
27 | return records
28 |
--------------------------------------------------------------------------------
/sevenbridges/models/compound/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sbg/sevenbridges-python/ed3de94bab744a33f614111c1845af68b5433c54/sevenbridges/models/compound/__init__.py
--------------------------------------------------------------------------------
/sevenbridges/models/compound/analysis_cost.py:
--------------------------------------------------------------------------------
1 | from sevenbridges.meta.resource import Resource
2 | from sevenbridges.meta.fields import StringField, CompoundField
3 | from sevenbridges.models.compound.analysis_cost_breakdown import (
4 | AnalysisCostBreakdown
5 | )
6 |
7 |
8 | class AnalysisCost(Resource):
9 | """
10 | AnalysisCost resource contains an information regarding the currency, the
11 | monet value and breakdown of a analysis cost.
12 | """
13 | currency = StringField(read_only=True)
14 | amount = StringField(read_only=True)
15 | breakdown = CompoundField(AnalysisCostBreakdown, read_only=True)
16 |
17 | def __str__(self):
18 | return (
19 | f''
21 | )
22 |
--------------------------------------------------------------------------------
/sevenbridges/models/compound/analysis_cost_breakdown.py:
--------------------------------------------------------------------------------
1 | from sevenbridges.meta.resource import Resource
2 | from sevenbridges.meta.fields import FloatField
3 |
4 |
5 | class AnalysisCostBreakdown(Resource):
6 | """
7 | AnalysisCostBreakdown resource contains price breakdown by storage and
8 | computation.
9 | """
10 | storage = FloatField(read_only=True)
11 | computation = FloatField(read_only=True)
12 | data_transfer_in = FloatField(read_only=True)
13 |
14 | def __str__(self):
15 | return (
16 | f''
16 |
--------------------------------------------------------------------------------
/sevenbridges/models/compound/billing/project_breakdown.py:
--------------------------------------------------------------------------------
1 | from sevenbridges.meta.resource import Resource
2 | from sevenbridges.models.compound.price import Price
3 | from sevenbridges.models.compound.billing.task_breakdown import TaskBreakdown
4 | from sevenbridges.meta.fields import (
5 | HrefField, CompoundField, CompoundListField
6 | )
7 |
8 |
9 | class ProjectBreakdown(Resource):
10 | """
11 | Project breakdown resource contains information regarding
12 | billing group project breakdown costs.
13 | """
14 | href = HrefField(read_only=True)
15 | analysis_spending = CompoundField(Price, read_only=True)
16 | task_breakdown = CompoundListField(TaskBreakdown, read_only=True)
17 |
18 | def __str__(self):
19 | return f''
20 |
--------------------------------------------------------------------------------
/sevenbridges/models/compound/billing/task_breakdown.py:
--------------------------------------------------------------------------------
1 | from sevenbridges.meta.resource import Resource
2 | from sevenbridges.models.compound.price import Price
3 | from sevenbridges.meta.fields import (
4 | StringField, HrefField, CompoundField, DateTimeField
5 | )
6 |
7 |
8 | class TaskBreakdown(Resource):
9 | """
10 | Task breakdown resource contains information regarding
11 | billing group analysis breakdown costs.
12 | """
13 | href = HrefField(read_only=True)
14 | runner_username = StringField(read_only=True)
15 | time_started = DateTimeField(read_only=True)
16 | time_finished = DateTimeField(read_only=True)
17 | task_cost = CompoundField(Price, read_only=True)
18 |
19 | def __str__(self):
20 | return f''
21 |
--------------------------------------------------------------------------------
/sevenbridges/models/compound/egress_cost.py:
--------------------------------------------------------------------------------
1 | from sevenbridges.meta.resource import Resource
2 | from sevenbridges.meta.fields import StringField
3 |
4 |
5 | class EgressCost(Resource):
6 | """
7 | EgressCost resource contains an information regarding the currency and the
8 | monet value of a egress cost.
9 | """
10 | currency = StringField(read_only=True)
11 | amount = StringField(read_only=True)
12 |
13 | def __str__(self):
14 | return f''
15 |
--------------------------------------------------------------------------------
/sevenbridges/models/compound/error.py:
--------------------------------------------------------------------------------
1 | from sevenbridges.meta.resource import Resource
2 | from sevenbridges.meta.fields import IntegerField, StringField
3 |
4 |
5 | class Error(Resource):
6 | """
7 | Error resource describes the error that happened and provides
8 | http status, custom codes and messages as well as the link to
9 | online resources.
10 | """
11 | status = IntegerField(read_only=True)
12 | code = IntegerField(read_only=True)
13 | message = StringField(read_only=True)
14 | more_info = StringField(read_only=True)
15 |
16 | def __str__(self):
17 | return f''
18 |
--------------------------------------------------------------------------------
/sevenbridges/models/compound/files/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sbg/sevenbridges-python/ed3de94bab744a33f614111c1845af68b5433c54/sevenbridges/models/compound/files/__init__.py
--------------------------------------------------------------------------------
/sevenbridges/models/compound/files/download_info.py:
--------------------------------------------------------------------------------
1 | from sevenbridges.meta.resource import Resource
2 | from sevenbridges.meta.fields import HrefField
3 |
4 |
5 | class DownloadInfo(Resource):
6 | """
7 | Download info resource contains download url for the file.
8 | """
9 | url = HrefField(read_only=True)
10 |
11 | def __str__(self):
12 | return f''
13 |
--------------------------------------------------------------------------------
/sevenbridges/models/compound/files/file_origin.py:
--------------------------------------------------------------------------------
1 | from sevenbridges.meta.resource import Resource
2 | from sevenbridges.meta.fields import StringField
3 |
4 |
5 | class FileOrigin(Resource):
6 | """
7 | File origin resource contains information about origin of a file.
8 | Among others it contains information about the task if the file
9 | was produced during executions of a analysis.
10 | """
11 | task = StringField(read_only=True)
12 |
13 | def __str__(self):
14 | return f''
15 |
--------------------------------------------------------------------------------
/sevenbridges/models/compound/files/file_storage.py:
--------------------------------------------------------------------------------
1 | from sevenbridges.meta.resource import Resource
2 | from sevenbridges.meta.fields import StringField
3 |
4 |
5 | class FileStorage(Resource):
6 | """
7 | File storage resource contains information about the storage location
8 | of the file if the file is imported on or exported to an external volume.
9 | """
10 | type = StringField(read_only=True)
11 | volume = StringField(read_only=True)
12 | location = StringField(read_only=True)
13 |
14 | def __str__(self):
15 | return f''
16 |
--------------------------------------------------------------------------------
/sevenbridges/models/compound/files/metadata.py:
--------------------------------------------------------------------------------
1 | from sevenbridges.meta.comp_mutable_dict import CompoundMutableDict
2 | from sevenbridges.meta.resource import Resource
3 |
4 |
5 | # noinspection PyProtectedMember
6 | class Metadata(CompoundMutableDict, Resource):
7 | """
8 | File metadata resource.
9 | """
10 | _name = 'metadata'
11 |
12 | def __init__(self, **kwargs):
13 | super().__init__(**kwargs)
14 |
15 | def __getitem__(self, item):
16 | try:
17 | return self._parent._data[self._name][item]
18 | except KeyError:
19 | return None
20 |
21 | def __eq__(self, other):
22 | if type(other) is not type(self):
23 | return False
24 | return self is other or dict(self) == dict(other)
25 |
--------------------------------------------------------------------------------
/sevenbridges/models/compound/import_result.py:
--------------------------------------------------------------------------------
1 | from sevenbridges.meta.fields import CompoundField
2 | from sevenbridges.meta.resource import Resource
3 | from sevenbridges.models.file import File
4 | from sevenbridges.models.compound.error import Error
5 |
6 |
7 | class FileImportResult(Resource):
8 | """
9 | File result resource used for actions that may return resource or error out
10 | """
11 | error = CompoundField(Error, read_only=True)
12 | resource = CompoundField(File, read_only=True)
13 |
14 | def __str__(self):
15 | return f'{str(self.error) if self.error else str(self.resource)}'
16 |
--------------------------------------------------------------------------------
/sevenbridges/models/compound/jobs/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sbg/sevenbridges-python/ed3de94bab744a33f614111c1845af68b5433c54/sevenbridges/models/compound/jobs/__init__.py
--------------------------------------------------------------------------------
/sevenbridges/models/compound/jobs/job.py:
--------------------------------------------------------------------------------
1 | from sevenbridges.meta.fields import (
2 | StringField, DateTimeField, CompoundField, BooleanField
3 | )
4 | from sevenbridges.meta.resource import Resource
5 | from sevenbridges.models.compound.jobs.job_docker import JobDocker
6 | from sevenbridges.models.compound.jobs.job_instance import Instance
7 | from sevenbridges.models.compound.jobs.job_log import Logs
8 |
9 |
10 | class Job(Resource):
11 | """
12 | Job resource contains information for a single executed node
13 | in the analysis.
14 | """
15 | name = StringField(read_only=True)
16 | start_time = DateTimeField(read_only=True)
17 | end_time = DateTimeField(read_only=True)
18 | status = StringField(read_only=True)
19 | command_line = StringField(read_only=True)
20 | retried = BooleanField(read_only=True)
21 | instance = CompoundField(Instance, read_only=True)
22 | docker = CompoundField(JobDocker, read_only=True)
23 | logs = CompoundField(Logs, read_only=True)
24 |
25 | def __str__(self):
26 | return f''
27 |
--------------------------------------------------------------------------------
/sevenbridges/models/compound/jobs/job_docker.py:
--------------------------------------------------------------------------------
1 | from sevenbridges.meta.resource import Resource
2 | from sevenbridges.meta.fields import StringField
3 |
4 |
5 | class JobDocker(Resource):
6 | """
7 | JobDocker resource contains information for a docker image that was
8 | used for execution of a single job.
9 | """
10 | checksum = StringField(read_only=True)
11 |
12 | def __str__(self):
13 | return f''
20 | )
21 |
--------------------------------------------------------------------------------
/sevenbridges/models/compound/jobs/job_instance_disk.py:
--------------------------------------------------------------------------------
1 | from sevenbridges.meta.fields import StringField, IntegerField
2 | from sevenbridges.meta.resource import Resource
3 |
4 |
5 | class Disk(Resource):
6 | """
7 | Disk resource contains information about EBS disk size.
8 | """
9 | size = IntegerField(read_only=True)
10 | unit = StringField(read_only=True)
11 | type = StringField(read_only=True)
12 |
13 | def __str__(self):
14 | return f''
15 |
--------------------------------------------------------------------------------
/sevenbridges/models/compound/jobs/job_log.py:
--------------------------------------------------------------------------------
1 | import re
2 | import logging
3 |
4 |
5 | from sevenbridges.errors import SbgError, ReadOnlyPropertyError
6 | from sevenbridges.meta.comp_mutable_dict import CompoundMutableDict
7 | from sevenbridges.meta.resource import Resource
8 | from sevenbridges.models.file import File
9 |
10 |
11 | logger = logging.getLogger(__name__)
12 |
13 |
14 | # noinspection PyProtectedMember
15 | class Logs(CompoundMutableDict, Resource):
16 | """
17 | Task output resource.
18 | """
19 | _name = 'logs'
20 |
21 | def __init__(self, **kwargs):
22 | super().__init__(**kwargs)
23 |
24 | def __getitem__(self, item):
25 | try:
26 | log = self._parent._data[self._name][item]
27 | match = re.match(r'.*files/(.*)/.*', log)
28 | if match:
29 | file_id = match.groups()[0]
30 | return File(id=file_id, api=self._api)
31 | else:
32 | raise SbgError(f'Unable to fetch {item} log file!')
33 | except Exception as e:
34 | logger.debug(
35 | 'Failed to retrieve log file due to an error: %s', str(e)
36 | )
37 |
38 | def __setitem__(self, key, value):
39 | raise ReadOnlyPropertyError('Can not modify read only properties.')
40 |
--------------------------------------------------------------------------------
/sevenbridges/models/compound/limits/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sbg/sevenbridges-python/ed3de94bab744a33f614111c1845af68b5433c54/sevenbridges/models/compound/limits/__init__.py
--------------------------------------------------------------------------------
/sevenbridges/models/compound/limits/rate.py:
--------------------------------------------------------------------------------
1 | from sevenbridges.meta.fields import IntegerField, DateTimeField
2 | from sevenbridges.meta.resource import Resource
3 |
4 |
5 | class Rate(Resource):
6 | """
7 | Rate resource.
8 | """
9 | limit = IntegerField(read_only=True)
10 | remaining = IntegerField(read_only=True)
11 | reset = DateTimeField(read_only=True)
12 |
13 | def __str__(self):
14 | return f''
15 |
--------------------------------------------------------------------------------
/sevenbridges/models/compound/markers/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sbg/sevenbridges-python/ed3de94bab744a33f614111c1845af68b5433c54/sevenbridges/models/compound/markers/__init__.py
--------------------------------------------------------------------------------
/sevenbridges/models/compound/markers/position.py:
--------------------------------------------------------------------------------
1 | from sevenbridges.meta.comp_mutable_dict import CompoundMutableDict
2 | from sevenbridges.meta.resource import Resource
3 |
4 |
5 | class MarkerPosition(CompoundMutableDict, Resource):
6 | """
7 | Marker position resource
8 | """
9 | _name = 'position'
10 |
11 | def __init__(self, **kwargs):
12 | super().__init__(**kwargs)
13 |
14 | def __getitem__(self, item):
15 | try:
16 | # noinspection PyProtectedMember
17 | return self._parent._data[self._name][item]
18 | except KeyError:
19 | return None
20 |
--------------------------------------------------------------------------------
/sevenbridges/models/compound/measurement.py:
--------------------------------------------------------------------------------
1 | from sevenbridges.meta.resource import Resource
2 | from sevenbridges.meta.fields import StringField, FloatField, CompoundField
3 |
4 |
5 | class StorageCost(Resource):
6 | """
7 | Storage cost resource contains breakdown information regarding the amount
8 | of cost and the currency used.
9 | """
10 | amount = FloatField(read_only=True)
11 | currency = StringField(read_only=True)
12 |
13 | def __str__(self):
14 | return (
15 | f''
17 | )
18 |
19 |
20 | class Measurement(Resource):
21 | """
22 | Measurement resource contains an information regarding the size and the
23 | unit of a certain resource.
24 | """
25 | size = FloatField(read_only=True)
26 | unit = StringField(read_only=True)
27 | cost = CompoundField(StorageCost, read_only=True)
28 |
29 | def __str__(self):
30 | return f''
31 |
--------------------------------------------------------------------------------
/sevenbridges/models/compound/price.py:
--------------------------------------------------------------------------------
1 | from sevenbridges.meta.resource import Resource
2 | from sevenbridges.meta.fields import StringField, FloatField, CompoundField
3 | from sevenbridges.models.compound.price_breakdown import Breakdown
4 |
5 |
6 | class Price(Resource):
7 | """
8 | Price resource contains an information regarding the currency and the
9 | monet value of a certain resource.
10 | """
11 | currency = StringField(read_only=True)
12 | amount = FloatField(read_only=True)
13 | breakdown = CompoundField(Breakdown, read_only=True)
14 |
15 | def __str__(self):
16 | return f''
17 |
--------------------------------------------------------------------------------
/sevenbridges/models/compound/price_breakdown.py:
--------------------------------------------------------------------------------
1 | from sevenbridges.meta.resource import Resource
2 | from sevenbridges.meta.fields import StringField
3 |
4 |
5 | class Breakdown(Resource):
6 | """
7 | Breakdown resource contains price breakdown by storage and computation.
8 | """
9 | storage = StringField(read_only=True)
10 | computation = StringField(read_only=True)
11 | data_transfer = StringField(read_only=True)
12 |
13 | def __str__(self):
14 | if self.data_transfer:
15 | return (
16 | f''
19 | )
20 | return (
21 | f''
23 | )
24 |
--------------------------------------------------------------------------------
/sevenbridges/models/compound/projects/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sbg/sevenbridges-python/ed3de94bab744a33f614111c1845af68b5433c54/sevenbridges/models/compound/projects/__init__.py
--------------------------------------------------------------------------------
/sevenbridges/models/compound/projects/permissions.py:
--------------------------------------------------------------------------------
1 | from sevenbridges.meta.comp_mutable_dict import CompoundMutableDict
2 | from sevenbridges.meta.resource import Resource
3 |
4 |
5 | # noinspection PyProtectedMember
6 | class Permissions(CompoundMutableDict, Resource):
7 | """
8 | Members permissions resource.
9 | """
10 | _name = 'permissions'
11 |
12 | def __init__(self, **kwargs):
13 | super().__init__(**kwargs)
14 |
15 | def __getitem__(self, item):
16 | try:
17 | return self._parent._data[self._name][item]
18 | except KeyError:
19 | return None
20 |
--------------------------------------------------------------------------------
/sevenbridges/models/compound/projects/settings.py:
--------------------------------------------------------------------------------
1 | # noinspection PyProtectedMember
2 | from sevenbridges.meta.comp_mutable_dict import CompoundMutableDict
3 | from sevenbridges.meta.resource import Resource
4 |
5 |
6 | class Settings(CompoundMutableDict, Resource):
7 | """
8 | Project settings resource.
9 | """
10 | _name = 'settings'
11 |
12 | def __init__(self, **kwargs):
13 | super().__init__(**kwargs)
14 |
15 | def __getitem__(self, item):
16 | try:
17 | # noinspection PyProtectedMember
18 | return self._parent._data[self._name][item]
19 | except KeyError:
20 | return None
21 |
--------------------------------------------------------------------------------
/sevenbridges/models/compound/tasks/__init__.py:
--------------------------------------------------------------------------------
1 | from sevenbridges.models.enums import FileApiFormats
2 | from sevenbridges.models.file import File
3 |
4 |
5 | def map_input_output(item, api):
6 | """
7 | Maps item to appropriate sevebridges object.
8 | :param item: Input/Output value.
9 | :param api: Api instance.
10 | :return: Mapped object.
11 | """
12 | if isinstance(item, list):
13 | return [map_input_output(it, api) for it in item]
14 |
15 | elif isinstance(item, dict) and 'class' in item:
16 | file_class_list = [
17 | FileApiFormats.FILE.lower(),
18 | FileApiFormats.FOLDER.lower()
19 | ]
20 | if item['class'].lower() in file_class_list:
21 | _secondary_files = []
22 | for _file in item.get('secondaryFiles', []):
23 | _secondary_files.append({'id': _file['path']})
24 | data = {
25 | 'id': item['path']
26 | }
27 | # map class to type
28 | if item['class'].lower() == FileApiFormats.FOLDER.lower():
29 | data['type'] = 'folder'
30 | else:
31 | data['type'] = 'file'
32 |
33 | # map cwl 1 file name
34 | if 'basename' in item:
35 | data['name'] = item['basename']
36 |
37 | data.update(
38 | {k: item[k] for k in item if k not in ['path', 'basename']}
39 | )
40 | data.update({
41 | '_secondary_files': _secondary_files or None,
42 | 'fetched': True
43 | })
44 | return File(api=api, **data)
45 | else:
46 | return item
47 |
--------------------------------------------------------------------------------
/sevenbridges/models/compound/tasks/batch_by.py:
--------------------------------------------------------------------------------
1 | from sevenbridges.meta.resource import Resource
2 |
3 |
4 | # noinspection PyUnresolvedReferences,PyProtectedMember
5 | class BatchBy(Resource, dict):
6 | """
7 | Task batch by resource.
8 | """
9 | _name = 'batch_by'
10 |
11 | # noinspection PyMissingConstructor
12 | def __init__(self, **kwargs):
13 | self.parent = kwargs.pop('_parent')
14 | self.api = kwargs.pop('api')
15 | for k, v in kwargs.items():
16 | super().__setitem__(k, v)
17 |
18 | def __setitem__(self, key, value):
19 | super().__setitem__(key, value)
20 | self.parent._data[self._name][key] = value
21 | if self._name not in self.parent._dirty:
22 | self.parent._dirty.update({self._name: {}})
23 | self.parent._dirty[self._name][key] = value
24 |
25 | def __getitem__(self, item):
26 | try:
27 | return self.parent._data[self._name][item]
28 | except KeyError:
29 | return None
30 |
31 | def __repr__(self):
32 | values = {}
33 | for k, _ in self.items():
34 | values[k] = self[k]
35 | return str(values)
36 |
37 | __str__ = __repr__
38 |
39 | def update(self, e=None, **f):
40 | other = {}
41 | if e:
42 | other.update(e, **f)
43 | else:
44 | other.update(**f)
45 | for k, v in other.items():
46 | if other[k] != self[k]:
47 | self[k] = other[k]
48 |
49 | def equals(self, other):
50 | if not type(other) == type(self):
51 | return False
52 | return (
53 | self is other or
54 | self._parent._data[self._name] == other._parent._data[self._name]
55 | )
56 |
--------------------------------------------------------------------------------
/sevenbridges/models/compound/tasks/batch_group.py:
--------------------------------------------------------------------------------
1 | from sevenbridges.meta.resource import Resource
2 | from sevenbridges.meta.fields import StringField, DictField
3 |
4 |
5 | class BatchGroup(Resource):
6 | """
7 | Batch group for a batch task.
8 | Represents the group that is assigned to the child task
9 | from the batching criteria that was used when the task was started.
10 | """
11 | value = StringField(read_only=True)
12 | fields = DictField(read_only=True)
13 |
14 | def __str__(self):
15 | return ''
16 |
--------------------------------------------------------------------------------
/sevenbridges/models/compound/tasks/execution_status.py:
--------------------------------------------------------------------------------
1 | from sevenbridges.meta.fields import IntegerField, StringField, BooleanField
2 | from sevenbridges.meta.resource import Resource
3 |
4 |
5 | class ExecutionStatus(Resource):
6 | """
7 | Task execution status resource.
8 |
9 | Contains information about the number of completed task steps,
10 | total number of task steps, current execution message and information
11 | regarding computation limits.
12 |
13 | In case of a batch task it also contains the number of queued, running,
14 | completed, failed and aborted tasks.
15 | """
16 | steps_completed = IntegerField(read_only=True)
17 | steps_total = IntegerField(read_only=True)
18 | message = StringField(read_only=True)
19 | message_code = StringField(read_only=True)
20 | queued = IntegerField(read_only=True)
21 | running = IntegerField(read_only=True)
22 | completed = IntegerField(read_only=True)
23 | failed = IntegerField(read_only=True)
24 | aborted = IntegerField(read_only=True)
25 | system_limit = BooleanField(read_only=True)
26 | account_limit = BooleanField(read_only=True)
27 | instance_init = BooleanField(read_only=True)
28 | queued_duration = IntegerField(read_only=True)
29 | running_duration = IntegerField(read_only=True)
30 | execution_duration = IntegerField(read_only=True)
31 | duration = IntegerField(read_only=True)
32 |
33 | def __str__(self):
34 | return ''
35 |
--------------------------------------------------------------------------------
/sevenbridges/models/compound/tasks/input.py:
--------------------------------------------------------------------------------
1 | from sevenbridges.meta.comp_mutable_dict import CompoundMutableDict
2 | from sevenbridges.meta.resource import Resource
3 |
4 | # noinspection PyProtectedMember
5 | from sevenbridges.models.compound.tasks import map_input_output
6 |
7 |
8 | # noinspection PyProtectedMember
9 | class Input(CompoundMutableDict, Resource):
10 | """
11 | Task input resource.
12 | """
13 | _name = 'inputs'
14 |
15 | def __init__(self, **kwargs):
16 | super().__init__(**kwargs)
17 |
18 | def __getitem__(self, item):
19 | # noinspection PyBroadException
20 | try:
21 | inputs = self._parent._data[self._name][item]
22 | return map_input_output(inputs, self._api)
23 | except Exception:
24 | return None
25 |
--------------------------------------------------------------------------------
/sevenbridges/models/compound/tasks/output.py:
--------------------------------------------------------------------------------
1 | from sevenbridges.errors import ReadOnlyPropertyError
2 | from sevenbridges.meta.comp_mutable_dict import CompoundMutableDict
3 | from sevenbridges.meta.resource import Resource
4 | from sevenbridges.models.compound.tasks import map_input_output
5 |
6 |
7 | # noinspection PyProtectedMember
8 | class Output(CompoundMutableDict, Resource):
9 | """
10 | Task output resource.
11 | """
12 | _name = 'outputs'
13 |
14 | def __init__(self, **kwargs):
15 | super().__init__(**kwargs)
16 |
17 | def __getitem__(self, item):
18 | # noinspection PyBroadException
19 | try:
20 | output = self._parent._data[self._name][item]
21 | return map_input_output(output, self._api)
22 | except Exception:
23 | return None
24 |
25 | def __setitem__(self, key, value):
26 | raise ReadOnlyPropertyError('Can not modify read only properties.')
27 |
--------------------------------------------------------------------------------
/sevenbridges/models/compound/volumes/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sbg/sevenbridges-python/ed3de94bab744a33f614111c1845af68b5433c54/sevenbridges/models/compound/volumes/__init__.py
--------------------------------------------------------------------------------
/sevenbridges/models/compound/volumes/import_destination.py:
--------------------------------------------------------------------------------
1 | from sevenbridges.meta.resource import Resource
2 | from sevenbridges.meta.fields import StringField
3 |
4 |
5 | class ImportDestination(Resource):
6 | """
7 | ImportDestination resource describes the location of the file
8 | imported on to SevenBridges platform or related product.
9 | """
10 | project = StringField(read_only=True)
11 | parent = StringField(read_only=True)
12 | name = StringField(read_only=True)
13 |
14 | def __str__(self):
15 | return f''
16 |
--------------------------------------------------------------------------------
/sevenbridges/models/compound/volumes/properties.py:
--------------------------------------------------------------------------------
1 | from sevenbridges.meta.comp_mutable_dict import CompoundMutableDict
2 | from sevenbridges.meta.resource import Resource
3 |
4 |
5 | # noinspection PyProtectedMember
6 | class VolumeProperties(CompoundMutableDict, Resource):
7 | """
8 | Volume permissions resource.
9 | """
10 | _name = 'properties'
11 |
12 | def __init__(self, **kwargs):
13 | super().__init__(**kwargs)
14 |
15 | def __getitem__(self, item):
16 | try:
17 | return self._parent._data[self._name][item]
18 | except KeyError:
19 | return None
20 |
--------------------------------------------------------------------------------
/sevenbridges/models/compound/volumes/service.py:
--------------------------------------------------------------------------------
1 | from sevenbridges.meta.comp_mutable_dict import CompoundMutableDict
2 |
3 | from sevenbridges.meta.resource import Resource
4 |
5 |
6 | class VolumeService(CompoundMutableDict, Resource):
7 | """
8 | Volume Service resource. Contains information about external
9 | storage provider.
10 | """
11 | _name = 'service'
12 |
13 | def __init__(self, **kwargs):
14 | super().__init__(**kwargs)
15 |
16 | def __getitem__(self, item):
17 | try:
18 | # noinspection PyProtectedMember
19 | return self._parent._data[self._name][item]
20 | except KeyError:
21 | return None
22 |
--------------------------------------------------------------------------------
/sevenbridges/models/compound/volumes/volume_file.py:
--------------------------------------------------------------------------------
1 | from sevenbridges.meta.fields import StringField
2 | from sevenbridges.meta.resource import Resource
3 |
4 |
5 | class VolumeFile(Resource):
6 | """
7 | VolumeFile resource describes the location of the file
8 | on the external volume.
9 | """
10 | volume = StringField(read_only=True)
11 | location = StringField(read_only=True)
12 |
13 | def __str__(self):
14 | return f''
15 |
16 | def __eq__(self, other):
17 | if type(other) is not type(self):
18 | return False
19 | return self is other or self.location == other.location
20 |
--------------------------------------------------------------------------------
/sevenbridges/models/compound/volumes/volume_object.py:
--------------------------------------------------------------------------------
1 | from sevenbridges.meta.fields import StringField, DictField
2 | from sevenbridges.meta.resource import Resource
3 |
4 |
5 | class VolumeObject(Resource):
6 | """
7 | Volume object resource contains information about single
8 | file (object) entry in a specific volume.
9 | """
10 | href = StringField(read_only=True)
11 | location = StringField(read_only=True)
12 | volume = StringField(read_only=True)
13 | type = StringField(read_only=True)
14 | metadata = DictField(read_only=True)
15 |
16 | def __str__(self):
17 | return f''
18 |
--------------------------------------------------------------------------------
/sevenbridges/models/compound/volumes/volume_prefix.py:
--------------------------------------------------------------------------------
1 | from sevenbridges.meta.fields import StringField
2 | from sevenbridges.meta.resource import Resource
3 |
4 |
5 | class VolumePrefix(Resource):
6 | """
7 | Volume prefix resource contains information about volume prefixes
8 | """
9 | href = StringField(read_only=True)
10 | prefix = StringField(read_only=True)
11 | volume = StringField(read_only=True)
12 |
13 | def __str__(self):
14 | return f''
15 |
--------------------------------------------------------------------------------
/sevenbridges/models/dataset.py:
--------------------------------------------------------------------------------
1 | import logging
2 |
3 | from sevenbridges.models.link import Link
4 | from sevenbridges.models.member import Member
5 | from sevenbridges.decorators import inplace_reload
6 | from sevenbridges.meta.resource import Resource
7 | from sevenbridges.meta.collection import Collection
8 | from sevenbridges.meta.transformer import Transform
9 | from sevenbridges.meta.fields import HrefField, StringField
10 |
11 |
12 | logger = logging.getLogger(__name__)
13 |
14 |
15 | class Dataset(Resource):
16 | """Central resource for managing datasets."""
17 |
18 | _URL = {
19 | 'query': '/datasets',
20 | 'owned_by': '/datasets/{username}',
21 | 'get': '/datasets/{id}',
22 | 'delete': '/datasets/{id}',
23 | 'members': '/datasets/{id}/members',
24 | 'member': '/datasets/{id}/members/{username}',
25 | 'permissions': '/datasets/{id}/members/{username}/permissions',
26 | }
27 |
28 | href = HrefField(read_only=True)
29 | id = StringField(read_only=True)
30 | name = StringField(read_only=False)
31 | description = StringField(read_only=False)
32 |
33 | def __str__(self):
34 | return f''
35 |
36 | def __eq__(self, other):
37 | if type(other) is not type(self):
38 | return False
39 | return self is other or self.id == other.id
40 |
41 | @classmethod
42 | def query(cls, visibility=None, api=None):
43 | """Query ( List ) datasets
44 | :param visibility: If provided as 'public', retrieves public datasets
45 | :param api: Api instance
46 | :return: Collection object
47 | """
48 | api = api if api else cls._API
49 |
50 | return super()._query(
51 | url=cls._URL['query'],
52 | visibility=visibility,
53 | fields='_all', api=api
54 | )
55 |
56 | @classmethod
57 | def get_owned_by(cls, username, api=None):
58 | """Query ( List ) datasets by owner
59 | :param api: Api instance
60 | :param username: Owner username
61 | :return: Collection object
62 | """
63 | api = api if api else cls._API
64 |
65 | return super()._query(
66 | url=cls._URL['owned_by'].format(username=username),
67 | fields='_all',
68 | api=api
69 | )
70 |
71 | @inplace_reload
72 | def save(self, inplace=True):
73 | """Save all modification to the dataset on the server.
74 | :param inplace: Apply edits on the current instance or get a new one.
75 | :return: Dataset instance.
76 | """
77 | modified_data = self._modified_data()
78 | if modified_data:
79 | dataset_request_data = {}
80 |
81 | name = modified_data.pop('name', None)
82 | description = modified_data.pop('description', None)
83 | dataset_request_data.update(modified_data)
84 |
85 | if name:
86 | dataset_request_data['name'] = name
87 |
88 | if description:
89 | dataset_request_data['description'] = description
90 |
91 | response = self._api.patch(
92 | url=self._URL['get'].format(id=self.id),
93 | data=dataset_request_data
94 | )
95 | data = response.json()
96 |
97 | dataset = Dataset(api=self._api, **data)
98 | return dataset
99 |
100 | def get_members(self, api=None):
101 | """Retrieve dataset members
102 | :param api: Api instance
103 | :return: Collection object
104 | """
105 | api = api or self._API
106 |
107 | response = api.get(url=self._URL['members'].format(id=self.id))
108 |
109 | data = response.json()
110 | total = response.headers['x-total-matching-query']
111 | members = [Member(api=api, **member) for member in data['items']]
112 | links = [Link(**link) for link in data['links']]
113 | href = data['href']
114 |
115 | return Collection(
116 | resource=Member,
117 | href=href,
118 | total=total,
119 | items=members,
120 | links=links,
121 | api=api
122 | )
123 |
124 | def get_member(self, username, api=None):
125 | """Retrieve dataset member
126 | :param username: Member name
127 | :param api: Api instance
128 | :return: Member object
129 | """
130 | api = api if api else self._API
131 |
132 | response = api.get(
133 | url=self._URL['member'].format(id=self.id, username=username),
134 | )
135 | data = response.json()
136 | return Member(api=api, **data)
137 |
138 | def add_member(self, username, permissions, api=None):
139 | """Add member to a dataset
140 | :param username: Member username
141 | :param permissions: Permissions dict
142 | :param api: Api instance
143 | :return: New member instance
144 | """
145 | api = api or self._API
146 | data = {
147 | 'username': username,
148 | 'permissions': permissions
149 | }
150 |
151 | response = api.post(
152 | url=self._URL['members'].format(id=self.id),
153 | data=data
154 | )
155 | data = response.json()
156 | return Member(api=api, **data)
157 |
158 | def remove_member(self, member, api=None):
159 | """Remove member from a dataset
160 | :param member: Member username
161 | :param api: Api instance
162 | :return: None
163 | """
164 | api = api or self._API
165 | username = Transform.to_member(member)
166 |
167 | api.delete(
168 | url=self._URL['member'].format(
169 | id=self.id,
170 | username=username
171 | )
172 | )
173 |
--------------------------------------------------------------------------------
/sevenbridges/models/division.py:
--------------------------------------------------------------------------------
1 | from sevenbridges.meta.fields import HrefField, StringField
2 | from sevenbridges.meta.resource import Resource
3 |
4 |
5 | class Division(Resource):
6 | """
7 | Central resource for managing divisions.
8 | """
9 | _URL = {
10 | 'query': '/divisions',
11 | 'get': '/divisions/{id}',
12 | }
13 |
14 | href = HrefField(read_only=True)
15 | id = StringField(read_only=True)
16 | name = StringField(read_only=True)
17 |
18 | def __str__(self):
19 | return f''
20 |
21 | def __eq__(self, other):
22 | if type(other) is not type(self):
23 | return False
24 | return self is other or self.id == other.id
25 |
26 | @classmethod
27 | def query(cls, offset=None, limit=None, api=None):
28 | """
29 | Query (List) divisions.
30 |
31 | :param offset: Pagination offset.
32 | :param limit: Pagination limit.
33 | :param api: Api instance.
34 | :return: Collection object.
35 | """
36 | api = api if api else cls._API
37 | return super()._query(
38 | url=cls._URL['query'], offset=offset, limit=limit,
39 | fields='_all', api=api
40 | )
41 |
42 | def get_teams(self, offset=None, limit=None):
43 | return self._api.teams.query(
44 | division=self.id, offset=offset, limit=limit
45 | )
46 |
47 | def get_members(self, role=None, offset=None, limit=None):
48 | return self._api.users.query(self, role=role, offset=offset,
49 | limit=limit)
50 |
--------------------------------------------------------------------------------
/sevenbridges/models/drs_import.py:
--------------------------------------------------------------------------------
1 | import logging
2 |
3 | from sevenbridges.errors import SbgError
4 | from sevenbridges.meta.fields import (
5 | HrefField, StringField, DateTimeField, CompoundListField
6 | )
7 | from sevenbridges.meta.resource import Resource
8 | from sevenbridges.meta.transformer import Transform
9 | from sevenbridges.models.compound.import_result import FileImportResult
10 | from sevenbridges.models.file import File
11 |
12 | logger = logging.getLogger(__name__)
13 |
14 |
15 | class DRSImportBulk(Resource):
16 | """
17 | Central resource for managing DRS imports.
18 | """
19 | _URL = {
20 | 'get': '/bulk/drs/imports/{id}',
21 | 'create': '/bulk/drs/imports/create',
22 | }
23 |
24 | id = StringField(read_only=True)
25 | href = HrefField(read_only=True)
26 | result = CompoundListField(FileImportResult, read_only=True)
27 | _result_files = [] # cache for result_files property
28 | state = StringField(read_only=True)
29 | started_on = DateTimeField(read_only=True)
30 | finished_on = DateTimeField(read_only=True)
31 |
32 | def __str__(self):
33 | return f''
34 |
35 | def __eq__(self, other):
36 | if type(other) is not type(self):
37 | return False
38 | return self is other or self.id == other.id
39 |
40 | @property
41 | def result_files(self):
42 | """
43 | Retrieve files that were successfully imported.
44 | :return: List of File objects
45 | """
46 | try:
47 | cached_file_ids = set([
48 | file.resource.id for file in self._result_files
49 | ])
50 |
51 | imported_file_ids = set([
52 | file.resource.id
53 | for file in self.result if file.resource
54 | ])
55 | file_ids_to_retrieve = imported_file_ids - cached_file_ids
56 | if file_ids_to_retrieve:
57 | files = File.bulk_get(
58 | files=file_ids_to_retrieve, api=self._api
59 | )
60 | self._result_files.extend(files)
61 | return self._result_files if self._result_files else None
62 | except TypeError:
63 | return None
64 |
65 | @classmethod
66 | def bulk_get(cls, import_job_id, api=None):
67 | """
68 | Retrieve DRS bulk import details
69 | :param import_job_id: Import id to be retrieved.
70 | :param api: Api instance.
71 | :return: DRSImportBulk object.
72 | """
73 | api = api or cls._API
74 |
75 | if not import_job_id:
76 | raise SbgError('DRS import is required!')
77 | elif not isinstance(import_job_id, str):
78 | raise SbgError('Invalid DRS import parameter!')
79 |
80 | response = api.get(
81 | url=cls._URL['get'].format(id=import_job_id)
82 | ).json()
83 | return DRSImportBulk(api=api, **response)
84 |
85 | @classmethod
86 | def bulk_submit(
87 | cls, imports, tags=None, conflict_resolution='SKIP', api=None
88 | ):
89 | """
90 | Submit DRS bulk import
91 | :param imports: List of dicts describing a wanted import.
92 | :param tags: list of tags to be applied.
93 | :param conflict_resolution: Type of file naming conflict resolution.
94 | :param api: Api instance.
95 | :return: DRSImportBulk object.
96 | """
97 | if not imports:
98 | raise SbgError('Imports are required')
99 |
100 | api = api or cls._API
101 |
102 | items = []
103 | for import_ in imports:
104 | project = import_.get('project')
105 | parent = import_.get('parent')
106 |
107 | if project and parent:
108 | raise SbgError(
109 | 'Project and parent identifiers are mutually exclusive'
110 | )
111 | elif project:
112 | import_['project'] = Transform.to_project(project)
113 | elif parent:
114 | import_['parent'] = Transform.to_file(parent)
115 | else:
116 | raise SbgError('Project or parent identifier is required.')
117 |
118 | items.append(import_)
119 |
120 | data = {
121 | 'conflict_resolution': conflict_resolution,
122 | 'tags': tags,
123 | 'items': items
124 | }
125 | response = api.post(url=cls._URL['create'], data=data).json()
126 | return DRSImportBulk(api=api, **response)
127 |
--------------------------------------------------------------------------------
/sevenbridges/models/endpoints.py:
--------------------------------------------------------------------------------
1 | import logging
2 |
3 | from sevenbridges.meta.resource import Resource
4 | from sevenbridges.meta.fields import HrefField
5 |
6 | logger = logging.getLogger(__name__)
7 |
8 |
9 | class Endpoints(Resource):
10 | """
11 | Central resource for managing Endpoints.
12 | """
13 | _URL = {
14 | 'get': '/'
15 | }
16 |
17 | rate_limit_url = HrefField(read_only=True)
18 | user_url = HrefField(read_only=True)
19 | users_url = HrefField(read_only=True)
20 | billing_url = HrefField(read_only=True)
21 | projects_url = HrefField(read_only=True)
22 | files_url = HrefField(read_only=True)
23 | tasks_url = HrefField(read_only=True)
24 | apps_url = HrefField(read_only=True)
25 | action_url = HrefField(read_only=True)
26 | upload_url = HrefField(read_only=True)
27 |
28 | @classmethod
29 | def get(cls, api=None, **kwargs):
30 | """
31 | Get api links.
32 | :param api: Api instance.
33 | :return: Endpoints object.
34 | """
35 | api = api if api else cls._API
36 | extra = {
37 | 'resource': cls.__name__,
38 | 'query': {}
39 | }
40 | logger.info('Getting resources', extra=extra)
41 | endpoints = api.get(url=cls._URL['get']).json()
42 | return Endpoints(api=api, **endpoints)
43 |
44 | def __str__(self):
45 | return ''
46 |
--------------------------------------------------------------------------------
/sevenbridges/models/enums.py:
--------------------------------------------------------------------------------
1 | class RequestParameters:
2 | MAX_URL_LENGTH = 6000
3 | DEFAULT_TIMEOUT = 300
4 | DEFAULT_RETRY_COUNT = 6
5 | DEFAULT_BACKOFF_FACTOR = 1
6 | DEFAULT_BULK_LIMIT = 100
7 |
8 |
9 | class PartSize:
10 | KB = 1024
11 | MB = 1024 * KB
12 | GB = 1024 * MB
13 | TB = 1024 * GB
14 | MAXIMUM_UPLOAD_SIZE = 5 * GB
15 | MAXIMUM_OBJECT_SIZE = 5 * TB
16 | MAXIMUM_TOTAL_PARTS = 10000
17 |
18 | DOWNLOAD_MINIMUM_PART_SIZE = 5 * MB
19 | UPLOAD_MINIMUM_PART_SIZE = 5 * MB
20 | UPLOAD_RECOMMENDED_SIZE = 32 * MB
21 |
22 |
23 | class TransferState:
24 | ABORTED = 'ABORTED'
25 | RUNNING = 'RUNNING'
26 | PAUSED = 'PAUSED'
27 | COMPLETED = 'COMPLETED'
28 | PREPARING = 'PREPARING'
29 | STOPPED = 'STOPPED'
30 | FAILED = 'FAILED'
31 |
32 |
33 | class VolumeType:
34 | S3 = 'S3'
35 | GOOGLE = 'GCS'
36 | OSS = 'OSS'
37 |
38 |
39 | class VolumeAccessMode:
40 | READ_ONLY = 'RO'
41 | READ_WRITE = 'RW'
42 |
43 |
44 | class FileStorageType:
45 | VOLUME = 'VOLUME'
46 | PLATFORM = 'PLATFORM'
47 |
48 |
49 | class FileApiFormats:
50 | FILE = 'File'
51 | FOLDER = 'Directory'
52 |
53 |
54 | class ImportExportState:
55 | PENDING = 'PENDING'
56 | RUNNING = 'RUNNING'
57 | COMPLETED = 'COMPLETED'
58 | FAILED = 'FAILED'
59 |
60 |
61 | class TaskStatus:
62 | DRAFT = 'DRAFT'
63 | CREATING = 'CREATING'
64 | QUEUED = 'QUEUED'
65 | RUNNING = 'RUNNING'
66 | COMPLETED = 'COMPLETED'
67 | ABORTED = 'ABORTED'
68 | ABORTING = 'ABORTING'
69 | FAILED = 'FAILED'
70 |
71 | terminal_states = [COMPLETED, FAILED, ABORTED]
72 |
73 |
74 | class FeedbackType:
75 | IDEA = 'IDEA'
76 | THOUGHT = 'THOUGHT'
77 | PROBLEM = 'PROBLEM'
78 |
79 |
80 | class AppRawFormat:
81 | JSON = 'json'
82 | YAML = 'yaml'
83 |
84 |
85 | class AppCopyStrategy:
86 | CLONE = 'clone'
87 | DIRECT = 'direct'
88 | TRANSIENT = 'transient'
89 | CLONE_DIRECT = 'clone_direct'
90 |
91 |
92 | class AutomationRunActions:
93 | STOP = 'stop'
94 | RERUN = 'rerun'
95 |
96 |
97 | class AsyncJobStates:
98 | RUNNING = 'RUNNING'
99 | FINISHED = 'FINISHED'
100 | SUBMITTED = 'SUBMITTED'
101 | RESOLVING = 'RESOLVING'
102 |
103 |
104 | class AsyncFileOperations:
105 | COPY = 'copy'
106 | DELETE = 'delete'
107 | MOVE = 'move'
108 |
109 |
110 | class DivisionRole:
111 | MEMBER = 'member'
112 | ADMIN = 'admin'
113 | EXTERNAL_COLLABORATOR = 'external_collaborator'
114 |
115 |
116 | class AutomationStatus:
117 | CREATED = 'CREATED'
118 | FINISHED = 'FINISHED'
119 | ABORTED = 'ABORTED'
120 | FAILED = 'FAILED'
121 | RUNNING = 'RUNNING'
122 | SENT_TO_EXECUTION = 'SENT_TO_EXECUTION'
123 | QUEUED_FOR_EXECUTION = 'QUEUED_FOR_EXECUTION'
124 | QUEUED_FOR_TERMINATION = 'QUEUED_FOR_TERMINATION'
125 |
126 | terminal_states = [FINISHED, FAILED, ABORTED]
127 |
--------------------------------------------------------------------------------
/sevenbridges/models/execution_details.py:
--------------------------------------------------------------------------------
1 | from sevenbridges.meta.resource import Resource
2 | from sevenbridges.models.compound.jobs.job import Job
3 | from sevenbridges.meta.fields import (
4 | HrefField, DateTimeField, StringField, CompoundListField
5 | )
6 |
7 |
8 | class ExecutionDetails(Resource):
9 | """
10 | Task execution details.
11 | """
12 | href = HrefField(read_only=True)
13 | start_time = DateTimeField(read_only=True)
14 | end_time = DateTimeField(read_only=True)
15 | status = StringField(read_only=True)
16 | message = StringField(read_only=True)
17 | jobs = CompoundListField(Job, read_only=True)
18 |
19 | def __str__(self):
20 | return ''
21 |
--------------------------------------------------------------------------------
/sevenbridges/models/invoice.py:
--------------------------------------------------------------------------------
1 | from sevenbridges.meta.fields import (
2 | HrefField, StringField, BooleanField, CompoundField
3 | )
4 | from sevenbridges.meta.resource import Resource
5 | from sevenbridges.models.compound.billing.invoice_period import InvoicePeriod
6 | from sevenbridges.models.compound.price import Price
7 |
8 |
9 | class Invoice(Resource):
10 | """
11 | Central resource for managing invoices.
12 | """
13 | _URL = {
14 | 'query': '/billing/invoices',
15 | 'get': '/billing/invoices/{id}'
16 | }
17 | href = HrefField(read_only=True)
18 | id = StringField(read_only=True)
19 | pending = BooleanField(read_only=True)
20 | analysis_costs = CompoundField(Price, read_only=True)
21 | storage_costs = CompoundField(Price, read_only=True)
22 | total = CompoundField(Price, read_only=True)
23 | invoice_period = CompoundField(InvoicePeriod, read_only=True)
24 |
25 | def __str__(self):
26 | return f''
27 |
28 | def __eq__(self, other):
29 | if type(other) is not type(self):
30 | return False
31 | return self is other or self.id == other.id
32 |
33 | @classmethod
34 | def query(cls, offset=None, limit=None, api=None):
35 | """
36 | Query (List) invoices.
37 | :param offset: Pagination offset.
38 | :param limit: Pagination limit.
39 | :param api: Api instance.
40 | :return: Collection object.
41 | """
42 | api = api if api else cls._API
43 | return super()._query(
44 | url=cls._URL['query'], offset=offset, limit=limit, fields='_all',
45 | api=api
46 | )
47 |
--------------------------------------------------------------------------------
/sevenbridges/models/link.py:
--------------------------------------------------------------------------------
1 | from sevenbridges.meta.fields import HrefField, StringField
2 | from sevenbridges.meta.resource import Resource
3 |
4 |
5 | class Link(Resource):
6 | """
7 | Pagination links.
8 | """
9 | href = HrefField(read_only=True)
10 | rel = StringField(read_only=True)
11 | method = StringField(read_only=True)
12 |
13 | def __str__(self):
14 | return (
15 | f''
16 | )
17 |
18 |
19 | class VolumeLink(Resource):
20 | """
21 | Pagination links for volumes.
22 | """
23 | next = HrefField(read_only=True)
24 |
25 | def __str__(self):
26 | return f''
27 |
--------------------------------------------------------------------------------
/sevenbridges/models/marker.py:
--------------------------------------------------------------------------------
1 | import logging
2 |
3 | from sevenbridges.decorators import inplace_reload
4 | from sevenbridges.errors import ResourceNotModified
5 | from sevenbridges.meta.fields import (
6 | HrefField, StringField, CompoundField, DateTimeField
7 | )
8 | from sevenbridges.meta.resource import Resource
9 | from sevenbridges.meta.transformer import Transform
10 | from sevenbridges.models.compound.markers.position import MarkerPosition
11 |
12 | logger = logging.getLogger(__name__)
13 |
14 |
15 | class Marker(Resource):
16 | _URL = {
17 | 'query': '/genome/markers',
18 | 'get': '/genome/markers/{id}',
19 | 'delete': '/genome/markers/{id}'
20 | }
21 |
22 | href = HrefField(read_only=True)
23 | id = StringField(read_only=True)
24 | file = StringField(read_only=True)
25 | name = StringField(read_only=False)
26 | chromosome = StringField(read_only=False)
27 | position = CompoundField(MarkerPosition, read_only=False)
28 | created_time = DateTimeField(read_only=True)
29 | created_by = StringField(read_only=True)
30 |
31 | def __str__(self):
32 | return f''
33 |
34 | def __eq__(self, other):
35 | if type(other) is not type(self):
36 | return False
37 | return self is other or self.id == other.id
38 |
39 | @classmethod
40 | def query(cls, file, offset=None, limit=None, api=None):
41 | """
42 | Queries genome markers on a file.
43 | :param file: Genome file - Usually bam file.
44 | :param offset: Pagination offset.
45 | :param limit: Pagination limit.
46 | :param api: Api instance.
47 | :return: Collection object.
48 | """
49 | api = api if api else cls._API
50 |
51 | file = Transform.to_file(file)
52 | return super()._query(
53 | url=cls._URL['query'], offset=offset, limit=limit,
54 | file=file, fields='_all', api=api
55 | )
56 |
57 | @classmethod
58 | def create(cls, file, name, position, chromosome, private=True, api=None):
59 | """
60 | Create a marker on a file.
61 | :param file: File object or identifier.
62 | :param name: Marker name.
63 | :param position: Marker position object.
64 | :param chromosome: Chromosome number.
65 | :param private: Whether the marker is private or public.
66 | :param api: Api instance.
67 | :return: Marker object.
68 | """
69 | api = api if api else cls._API
70 |
71 | file = Transform.to_file(file)
72 | data = {
73 | 'file': file,
74 | 'name': name,
75 | 'position': position,
76 | 'chromosome': chromosome,
77 | 'private': private
78 | }
79 |
80 | extra = {
81 | 'resource': cls.__name__,
82 | 'query': data
83 | }
84 | logger.info('Creating marker', extra=extra)
85 | marker_data = api.post(url=cls._URL['query'], data=data).json()
86 | return Marker(api=api, **marker_data)
87 |
88 | @inplace_reload
89 | def save(self, inplace=True):
90 | """
91 | Saves all modification to the marker on the server.
92 | :param inplace Apply edits on the current instance or get a new one.
93 | :return: Marker instance.
94 | """
95 | modified_data = self._modified_data()
96 | if modified_data:
97 | extra = {
98 | 'resource': type(self).__name__,
99 | 'query': {
100 | 'id': self.id,
101 | 'modified_data': modified_data
102 | }
103 | }
104 | logger.info('Saving marker', extra=extra)
105 | data = self._api.patch(url=self._URL['get'].format(id=self.id),
106 | data=modified_data).json()
107 | marker = Marker(api=self._api, **data)
108 | return marker
109 | else:
110 | raise ResourceNotModified()
111 |
--------------------------------------------------------------------------------
/sevenbridges/models/member.py:
--------------------------------------------------------------------------------
1 | import logging
2 |
3 | from sevenbridges.decorators import inplace_reload
4 | from sevenbridges.errors import ResourceNotModified
5 | from sevenbridges.meta.fields import HrefField, StringField, CompoundField
6 | from sevenbridges.meta.resource import Resource
7 | from sevenbridges.models.compound.projects.permissions import Permissions
8 |
9 | logger = logging.getLogger(__name__)
10 |
11 |
12 | class Member(Resource):
13 | """
14 | Central resource for managing members.
15 | This resource is reused on both projects and volumes.
16 | """
17 | _URL = {
18 | 'permissions': '/permissions'
19 | }
20 | href = HrefField(read_only=True)
21 | id = StringField(read_only=True)
22 | username = StringField(read_only=False)
23 | email = StringField(read_only=False)
24 | type = StringField(read_only=False)
25 | permissions = CompoundField(Permissions, read_only=False)
26 |
27 | def __str__(self):
28 | return f''
29 |
30 | def __eq__(self, other):
31 | if type(other) is not type(self):
32 | return False
33 | return (
34 | self is other or
35 | self.id == other.id or
36 | self.username == other.username
37 | )
38 |
39 | @inplace_reload
40 | def save(self, inplace=True):
41 | """
42 | Saves modification to the api server.
43 | """
44 | data = self._modified_data()
45 | data = data['permissions']
46 | if data:
47 | url = self.href + self._URL['permissions']
48 | extra = {'resource': type(self).__name__, 'query': data}
49 | logger.info('Modifying permissions', extra=extra)
50 | self._api.patch(url=url, data=data, append_base=False)
51 | else:
52 | raise ResourceNotModified()
53 |
--------------------------------------------------------------------------------
/sevenbridges/models/rate_limit.py:
--------------------------------------------------------------------------------
1 | from sevenbridges.meta.fields import CompoundField
2 | from sevenbridges.meta.resource import Resource
3 | from sevenbridges.models.compound.limits.rate import Rate
4 |
5 |
6 | class RateLimit(Resource):
7 | """
8 | Rate limit resource contains info regarding request and computation
9 | rate limits.
10 | """
11 |
12 | _URL = {
13 | 'get': '/rate_limit'
14 | }
15 | rate = CompoundField(Rate, read_only=True)
16 | instance_limit = CompoundField(Rate, read_only=True)
17 |
18 | @classmethod
19 | def get(cls, id=None, api=None):
20 | api = api if api else cls._API
21 | resource = api.get(url=cls._URL['get']).json()
22 | return cls(api=api, **resource)
23 |
--------------------------------------------------------------------------------
/sevenbridges/models/team.py:
--------------------------------------------------------------------------------
1 | import logging
2 |
3 | from sevenbridges.decorators import inplace_reload
4 | from sevenbridges.errors import ResourceNotModified
5 | from sevenbridges.meta.collection import Collection
6 | from sevenbridges.meta.fields import HrefField, StringField
7 | from sevenbridges.meta.resource import Resource
8 | from sevenbridges.meta.transformer import Transform
9 | from sevenbridges.models.link import Link
10 | from sevenbridges.models.team_member import TeamMember
11 |
12 | logger = logging.getLogger(__name__)
13 |
14 |
15 | class Team(Resource):
16 | """
17 | Central resource for managing teams.
18 | """
19 | _URL = {
20 | 'query': '/teams',
21 | 'get': '/teams/{id}',
22 | 'members_query': '/teams/{id}/members',
23 | 'members_get': '/teams/{id}/members/{member}',
24 | }
25 |
26 | href = HrefField(read_only=True)
27 | id = StringField(read_only=True)
28 | name = StringField(read_only=False)
29 |
30 | def __str__(self):
31 | return f''
32 |
33 | def __eq__(self, other):
34 | if type(other) is not type(self):
35 | return False
36 | return self is other or self.id == other.id
37 |
38 | @classmethod
39 | def query(cls, division, list_all=False, offset=None, limit=None,
40 | api=None):
41 | """
42 | :param division: Division slug.
43 | :param list_all: List all teams in division.
44 | :param offset: Pagination offset.
45 | :param limit: Pagination limit.
46 | :param api: Api instance.
47 | :return: Collection object.
48 | """
49 | division = Transform.to_division(division)
50 | api = api if api else cls._API
51 | return super()._query(
52 | url=cls._URL['query'], division=division, _all=list_all,
53 | offset=offset, limit=limit, fields='_all', api=api
54 | )
55 |
56 | @classmethod
57 | def create(cls, name, division, api=None):
58 | """
59 | Create team within a division
60 | :param name: Team name.
61 | :param division: Parent division.
62 | :param api: Api instance.
63 | :return: Team object.
64 | """
65 |
66 | division = Transform.to_division(division)
67 | api = api if api else cls._API
68 | data = {
69 | 'name': name,
70 | 'division': division
71 | }
72 |
73 | extra = {
74 | 'resource': cls.__name__,
75 | 'query': data
76 | }
77 | logger.info('Creating team', extra=extra)
78 | created_team = api.post(cls._URL['query'], data=data).json()
79 | return Team(api=api, **created_team)
80 |
81 | @inplace_reload
82 | def save(self, inplace=True):
83 | """
84 | Saves all modification to the team on the server.
85 | :param inplace Apply edits on the current instance or get a new one.
86 | :return: Team instance.
87 | """
88 | modified_data = self._modified_data()
89 | if modified_data:
90 | extra = {
91 | 'resource': type(self).__name__,
92 | 'query': {
93 | 'id': self.id,
94 | 'modified_data': modified_data
95 | }
96 | }
97 | logger.info('Saving team', extra=extra)
98 | data = self._api.patch(url=self._URL['get'].format(id=self.id),
99 | data=modified_data).json()
100 | team = Team(api=self._api, **data)
101 | return team
102 | else:
103 | raise ResourceNotModified()
104 |
105 | def get_members(self, offset=None, limit=None):
106 | """
107 | Fetch team members for current team.
108 | :param offset: Pagination offset.
109 | :param limit: Pagination limit.
110 | :return: Collection object.
111 | """
112 | extra = {
113 | 'resource': type(self).__name__,
114 | 'query': {'id': self.id}
115 | }
116 | logger.info('Get team members', extra=extra)
117 | response = self._api.get(
118 | url=self._URL['members_query'].format(id=self.id),
119 | params={'offset': offset, 'limit': limit}
120 | )
121 | data = response.json()
122 | total = response.headers['x-total-matching-query']
123 | members = [TeamMember(api=self._api, **member) for member in
124 | data['items']]
125 | links = [Link(**link) for link in data['links']]
126 | href = data['href']
127 | return Collection(resource=TeamMember, href=href, total=total,
128 | items=members, links=links, api=self._api)
129 |
130 | def add_member(self, user):
131 | """
132 | Add member to team
133 | :param user: User object or user's username
134 | :return: Added user.
135 | """
136 | user = Transform.to_user(user)
137 | data = {
138 | 'id': user
139 | }
140 | extra = {
141 | 'resource': type(self).__name__,
142 | 'query': {
143 | 'id': self.id,
144 | 'data': data,
145 | }
146 | }
147 | logger.info('Adding team member using id', extra=extra)
148 | response = self._api.post(
149 | url=self._URL['members_query'].format(id=self.id), data=data)
150 | member_data = response.json()
151 | return TeamMember(api=self._api, **member_data)
152 |
153 | def remove_member(self, user):
154 | """
155 | Remove member from the team.
156 | :param user: User to be removed.
157 | """
158 | member = Transform.to_user(user)
159 | extra = {
160 | 'resource': type(self).__name__,
161 | 'query': {
162 | 'id': self.id,
163 | 'user': user,
164 | }
165 | }
166 | logger.info('Removing team member', extra=extra)
167 | self._api.delete(
168 | url=self._URL['members_get'].format(id=self.id, member=member)
169 | )
170 |
--------------------------------------------------------------------------------
/sevenbridges/models/team_member.py:
--------------------------------------------------------------------------------
1 | import logging
2 |
3 | from sevenbridges.meta.fields import HrefField, StringField
4 | from sevenbridges.meta.resource import Resource
5 |
6 | logger = logging.getLogger(__name__)
7 |
8 |
9 | class TeamMember(Resource):
10 | """
11 | Central resource for managing team members.
12 | """
13 | href = HrefField(read_only=True)
14 | id = StringField(read_only=True)
15 | username = StringField(read_only=False)
16 | role = StringField(read_only=True)
17 |
18 | def __eq__(self, other):
19 | if type(other) is not type(self):
20 | return False
21 | return self is other or self.id == other.id
22 |
23 | def __str__(self):
24 | return f''
25 |
--------------------------------------------------------------------------------
/sevenbridges/models/user.py:
--------------------------------------------------------------------------------
1 | import logging
2 |
3 | from sevenbridges.meta.resource import Resource
4 | from sevenbridges.meta.fields import HrefField, StringField
5 | from sevenbridges.meta.transformer import Transform
6 |
7 | logger = logging.getLogger(__name__)
8 |
9 |
10 | class User(Resource):
11 | """
12 | Central resource for managing users.
13 | """
14 | _URL = {
15 | 'me': '/user',
16 | 'get': '/users/{id}',
17 | 'query': '/users',
18 | 'delete': '/users/{username}'
19 | }
20 |
21 | href = HrefField(read_only=True)
22 | username = StringField(read_only=True)
23 | email = StringField(read_only=True)
24 | first_name = StringField(read_only=True)
25 | last_name = StringField(read_only=True)
26 | affiliation = StringField(read_only=True)
27 | phone = StringField(read_only=True)
28 | address = StringField(read_only=True)
29 | state = StringField(read_only=True)
30 | country = StringField(read_only=True)
31 | zip_code = StringField(read_only=True)
32 | city = StringField(read_only=True)
33 | role = StringField(read_only=True)
34 |
35 | def __eq__(self, other):
36 | if type(other) is not type(self):
37 | return False
38 | return self is other or self.username == other.username
39 |
40 | def __str__(self):
41 | return f''
42 |
43 | @classmethod
44 | def me(cls, api=None):
45 | """
46 | Retrieves current user information.
47 | :param api: Api instance.
48 | :return: User object.
49 | """
50 | api = api if api else cls._API
51 | extra = {
52 | 'resource': cls.__name__,
53 | 'query': {}
54 | }
55 | logger.info('Fetching user information', extra=extra)
56 | user_data = api.get(cls._URL['me']).json()
57 | return User(api=api, **user_data)
58 |
59 | @classmethod
60 | def get(cls, user, api=None):
61 | api = api if api else cls._API
62 | user = Transform.to_user(user)
63 | return super().get(id=user, api=api)
64 |
65 | @classmethod
66 | def query(cls, division, role=None, offset=None, limit=None, api=None):
67 | """Query division users
68 | :param division: Division slug.
69 | :param role: User role in division.
70 | :param offset: Pagination offset.
71 | :param limit: Pagination limit.
72 | :param api: Api instance.
73 | :return: Collection object.
74 | """
75 | api = api or cls._API
76 | params = {
77 | 'division': Transform.to_division(division),
78 | }
79 | if role:
80 | params['role'] = role
81 |
82 | return super()._query(
83 | url=cls._URL['query'],
84 | api=api,
85 | offset=offset,
86 | limit=limit,
87 | **params
88 | )
89 |
90 | def disable(self, api=None):
91 | """
92 | Disable user
93 | :param api: Api instance.
94 | :return:
95 | """
96 | api = api or self._API
97 | api.delete(
98 | url=self._URL['delete'].format(username=self.username)
99 | )
100 |
--------------------------------------------------------------------------------
/sevenbridges/transfer/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sbg/sevenbridges-python/ed3de94bab744a33f614111c1845af68b5433c54/sevenbridges/transfer/__init__.py
--------------------------------------------------------------------------------
/sevenbridges/transfer/utils.py:
--------------------------------------------------------------------------------
1 | import sys
2 |
3 | import math
4 |
5 |
6 | class Part:
7 | def __init__(self, start=None, size=None):
8 | self._start = start
9 | self._size = size
10 |
11 | @property
12 | def start(self):
13 | return self._start
14 |
15 | @property
16 | def size(self):
17 | return self._size
18 |
19 |
20 | class Progress:
21 | def __init__(self, num_of_parts, parts_done, bytes_done,
22 | file_size, duration):
23 | self._num_of_parts = num_of_parts
24 | self._parts_done = parts_done
25 | self._bytes_done = bytes_done
26 | self._file_size = file_size
27 | self._duration = duration
28 |
29 | @property
30 | def num_of_parts(self):
31 | return self._num_of_parts
32 |
33 | @property
34 | def parts_done(self):
35 | return self._parts_done
36 |
37 | @property
38 | def bytes_done(self):
39 | return self._bytes_done
40 |
41 | @property
42 | def file_size(self):
43 | return self._file_size
44 |
45 | @property
46 | def duration(self):
47 | return self._duration
48 |
49 | @property
50 | def progress(self):
51 | progress = (self._bytes_done / float(self._file_size)) * 100
52 | progress = progress if progress <= 100 else 100
53 | return progress
54 |
55 | @property
56 | def bandwidth(self):
57 | return (self._bytes_done / 1000000) / self.duration
58 |
59 |
60 | def total_parts(file_size, part_size):
61 | return int(math.ceil(file_size / float(part_size)))
62 |
63 |
64 | def simple_progress_bar(progress):
65 | sys.stdout.write(
66 | '\rTransfer: Progress[%.2f%%], Bandwidth[%.2fMB/s], Parts[total=%s, '
67 | 'Done=%s], Duration[%.2fs]\b' % (
68 | progress.progress, progress.bandwidth, progress.num_of_parts,
69 | progress.parts_done, progress.duration
70 | )
71 | )
72 | sys.stdout.flush()
73 |
--------------------------------------------------------------------------------
/sevenbridges/version.py:
--------------------------------------------------------------------------------
1 | __version__ = '0.0.1.dev0+local'
2 |
--------------------------------------------------------------------------------
/sonar-project.properties:
--------------------------------------------------------------------------------
1 | sonar.projectKey=sevenbridges
2 | sonar.projectName=sevenbridges-python
3 |
4 | sonar.sources=sevenbridges
5 | sonar.exclusions=tests/**/*.py,test-report/*.xml
6 |
7 | sonar.test=tests/**/*.py
8 |
9 | sonar.python.coverage.reportPaths=test-report/coverage.xml
10 | sonar.coverage.exclusions=tests/*
11 |
12 | sonar.issue.ignore.multicriteria=r1
13 |
14 | # Ignore warning about too many parameters
15 | sonar.issue.ignore.multicriteria.r1.ruleKey=python:S107
16 | sonar.issue.ignore.multicriteria.r1.resourceKey=sevenbridges/**/*.py
17 |
--------------------------------------------------------------------------------
/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sbg/sevenbridges-python/ed3de94bab744a33f614111c1845af68b5433c54/tests/__init__.py
--------------------------------------------------------------------------------
/tests/conftest.py:
--------------------------------------------------------------------------------
1 | import faker
2 | import pytest
3 | import requests_mock
4 |
5 | from sevenbridges import Api
6 | from tests import providers, verifiers
7 |
8 | generator = faker.Factory.create()
9 |
10 | requests_mock.mock.case_sensitive = True
11 |
12 |
13 | @pytest.fixture
14 | def request_mocker(request):
15 | """
16 | :param request: pytest request object for cleaning up.
17 | :return: Returns instance of requests mocker used to mock HTTP calls.
18 | """
19 | m = requests_mock.Mocker()
20 | m.start()
21 | request.addfinalizer(m.stop)
22 | return m
23 |
24 |
25 | class Precondition:
26 | """
27 | Aggregated data provided for all server side data mocking.
28 | """
29 |
30 | def __init__(self, request_mocker, base_url):
31 | self.user = providers.UserProvider(request_mocker, base_url)
32 | self.endpoints = providers.EndpointProvider(request_mocker, base_url)
33 | self.rate = providers.RateLimitProvider(request_mocker, base_url)
34 | self.project = providers.ProjectProvider(request_mocker, base_url)
35 | self.member = providers.MemberProvider(request_mocker, base_url)
36 | self.file = providers.FileProvider(request_mocker, base_url)
37 | self.app = providers.AppProvider(request_mocker, base_url)
38 | self.task = providers.TaskProvider(request_mocker, base_url)
39 | self.volume = providers.VolumeProvider(request_mocker, base_url)
40 | self.action = providers.ActionProvider(request_mocker, base_url)
41 | self.division = providers.DivisionProvider(request_mocker, base_url)
42 | self.team = providers.TeamProvider(request_mocker, base_url)
43 | self.marker = providers.MarkerProvider(request_mocker, base_url)
44 | self.imports = providers.ImportsProvider(request_mocker, base_url)
45 | self.exports = providers.ExportsProvider(request_mocker, base_url)
46 | self.team_member = providers.TeamMemberProvider(
47 | request_mocker, base_url)
48 | self.datasets = providers.DatasetProvider(request_mocker, base_url)
49 | self.automations = providers.AutomationProvider(
50 | request_mocker, base_url)
51 | self.automation_runs = providers.AutomationRunProvider(
52 | request_mocker, base_url)
53 | self.automation_members = providers.AutomationMemberProvider(
54 | request_mocker, base_url
55 | )
56 | self.automation_packages = providers.AutomationPackageProvider(
57 | request_mocker, base_url
58 | )
59 | self.async_jobs = providers.AsyncJobProvider(request_mocker, base_url)
60 | self.cp_uploads = providers.CodePackageUploadProvider(
61 | request_mocker, base_url
62 | )
63 | self.uploads = providers.FileUploadProvider(request_mocker, base_url)
64 | self.drs_imports = providers.DRSImportProvider(
65 | request_mocker, base_url
66 | )
67 | self.billing_group = providers.BillingGroupProvider(
68 | request_mocker, base_url
69 | )
70 | self.billing_group_storage_breakdown = (
71 | providers.BillingGroupStorageBreakdownProvider(
72 | request_mocker, base_url
73 | )
74 | )
75 |
76 |
77 | class Verifier:
78 | """
79 | Aggregated action verificator.
80 | """
81 |
82 | def __init__(self, request_mocker):
83 | self.user = verifiers.UserVerifier(request_mocker)
84 | self.endpoints = verifiers.EndpointVerifier(request_mocker)
85 | self.project = verifiers.ProjectVerifier(request_mocker)
86 | self.member = verifiers.MemberVerifier(request_mocker)
87 | self.file = verifiers.FileVerifier(request_mocker)
88 | self.app = verifiers.AppVerifier(request_mocker)
89 | self.task = verifiers.TaskVerifier(request_mocker)
90 | self.volume = verifiers.VolumeVerifier(request_mocker)
91 | self.action = verifiers.ActionVerifier(request_mocker)
92 | self.division = verifiers.DivisionVerifier(request_mocker)
93 | self.team = verifiers.TeamVerifier(request_mocker)
94 | self.marker = verifiers.MarkerVerifier(request_mocker)
95 | self.imports = verifiers.ImportsVerifier(request_mocker)
96 | self.exports = verifiers.ExportsVerifier(request_mocker)
97 | self.datasets = verifiers.DatasetVerifier(request_mocker)
98 | self.automations = verifiers.AutomationVerifier(request_mocker)
99 | self.automation_runs = verifiers.AutomationRunVerifier(request_mocker)
100 | self.automation_members = verifiers.AutomationMemberVerifier(
101 | request_mocker
102 | )
103 | self.async_jobs = verifiers.AsyncJobVerifier(request_mocker)
104 | self.automation_packages = verifiers.AutomationPackageVerifier(
105 | request_mocker
106 | )
107 | self.drs_imports = verifiers.DRSImportsVerifier(request_mocker)
108 | self.billing_group = verifiers.BillingGroupVerifier(request_mocker)
109 | self.billing_group_storage_breakdown = (
110 | verifiers.BillingGroupStorageBreakdownVerifier(request_mocker)
111 | )
112 |
113 |
114 | @pytest.fixture
115 | def given(request_mocker, base_url):
116 | """
117 | Fixture returning Precondition.
118 | """
119 | return Precondition(request_mocker, base_url)
120 |
121 |
122 | @pytest.fixture
123 | def verifier(request_mocker):
124 | """
125 | Fixture returning Verificator.
126 | """
127 | return Verifier(request_mocker)
128 |
129 |
130 | @pytest.fixture
131 | def api(base_url):
132 | """
133 | Fixture returning instance of Api with randomly generated endpoint URL
134 | and authentication token.
135 | """
136 | return Api(url=base_url, token=generator.uuid4())
137 |
138 |
139 | @pytest.fixture
140 | def base_url():
141 | return generator.url(schemes=['https'])[:-1]
142 |
143 |
144 | @pytest.fixture
145 | def config_parser():
146 | class ConfigParser:
147 | def __init__(self, data):
148 | self.data = data
149 |
150 | def get(self, profile, item):
151 | return self.data[profile][item]
152 |
153 | def read(self, stream):
154 | pass
155 |
156 | class Mock:
157 | def __init__(self, data):
158 | self.data = data
159 |
160 | def __call__(self, *args, **kwargs):
161 | data = dict(kwargs)
162 | data.update(self.data)
163 | return ConfigParser(data)
164 |
165 | return Mock
166 |
--------------------------------------------------------------------------------
/tests/test_actions.py:
--------------------------------------------------------------------------------
1 | import faker
2 |
3 | generator = faker.Factory.create()
4 |
5 |
6 | def test_action_feedback(api, given, verifier):
7 | # given
8 | given.action.feedback_set()
9 |
10 | # send feedback
11 | api.actions.send_feedback(text=generator.name())
12 |
13 | # verify
14 | verifier.action.feedback_received()
15 |
16 |
17 | def test_action_bulk_copy(api, given, verifier):
18 |
19 | file_id = generator.uuid4()
20 | # given
21 | given.action.can_bulk_copy(id=file_id)
22 |
23 | # copy files
24 | result = api.actions.bulk_copy_files([file_id], "test")
25 |
26 | # verify
27 | assert file_id in result.values()
28 | verifier.action.bulk_copy_done()
29 |
--------------------------------------------------------------------------------
/tests/test_apps.py:
--------------------------------------------------------------------------------
1 | import faker
2 | import pytest
3 |
4 | from sevenbridges.errors import SbgError
5 |
6 |
7 | generator = faker.Factory.create()
8 |
9 |
10 | @pytest.mark.parametrize("visibility", ["private", "public", None])
11 | def test_apps_query(api, given, verifier, visibility):
12 | # preconditions
13 | total = 10
14 | given.app.apps_exist(visibility, total)
15 |
16 | # action
17 | apps = api.apps.query(visibility=visibility)
18 |
19 | # verification
20 | assert apps.total == total
21 | assert len(apps) == total
22 |
23 | verifier.app.apps_fetched(visibility)
24 |
25 |
26 | def test_apps_get_revision(api, given, verifier):
27 | # preconditions
28 | app_id = 'me/my-project/my-app'
29 | app_revision = 1
30 | given.app.app_with_revision_exists(id=app_id, revision=app_revision)
31 |
32 | # action
33 | app = api.apps.get_revision(app_id, 1)
34 |
35 | # verification
36 | assert app.id == app_id
37 | assert app_id in repr(app)
38 | assert app.revision == app_revision
39 |
40 | verifier.app.app_fetched(app_id, app_revision)
41 |
42 |
43 | @pytest.mark.parametrize("app_id", ["me/my-project/app"])
44 | def test_app_copy(api, given, verifier, app_id):
45 | # preconditions
46 | copied_name = 'new-app'
47 | app_revision = 1
48 | given.app.app_with_revision_exists(id=app_id, revision=app_revision)
49 | given.app.app_can_be_copied(id=app_id, new_name=copied_name)
50 |
51 | # action
52 | app = api.apps.get_revision(app_id, 1)
53 | app_copy = app.copy('me/my-project/', copied_name)
54 |
55 | # verification
56 | assert app_copy.name == copied_name
57 |
58 | verifier.app.app_copied(app_id)
59 |
60 |
61 | def test_install_app(api, given, verifier):
62 | # preconditions
63 | app_id = "me/my-project/my-app"
64 | given.app.app_exists(id=app_id)
65 | given.app.app_can_be_installed(id=app_id)
66 |
67 | raw = {'sbg:id': app_id}
68 |
69 | # action
70 | app = api.apps.install_app(app_id, raw)
71 |
72 | # verification
73 | assert app.id == app_id
74 | verifier.app.app_installed(app_id)
75 |
76 |
77 | def test_install_app_formats(api, given, verifier):
78 | # preconditions
79 | app_json_id = "me/my-project/my-app-json"
80 | app_yaml_id = "me/my-project/my-app-yaml"
81 | app_invalid_id = "me/my-project/my-app-invalid"
82 |
83 | given.app.app_exists(id=app_json_id)
84 | given.app.app_exists(id=app_yaml_id)
85 | given.app.app_exists(id=app_invalid_id)
86 | given.app.app_can_be_installed(id=app_json_id)
87 | given.app.app_can_be_installed(id=app_yaml_id)
88 | given.app.app_can_be_installed(id=app_invalid_id)
89 |
90 | raw_json = {'sbg:id': app_json_id}
91 | raw_yaml = {'sbg:id': app_yaml_id}
92 | raw_invalid = {'sbg:id': app_invalid_id}
93 |
94 | # action
95 | app_json = api.apps.install_app(app_json_id, raw_json, raw_format='json')
96 | app_yaml = api.apps.install_app(app_yaml_id, raw_yaml, raw_format='yaml')
97 |
98 | with pytest.raises(SbgError):
99 | api.apps.install_app(app_invalid_id, raw_invalid, raw_format='invalid')
100 |
101 | # verification
102 | assert app_json.id == app_json_id
103 | assert app_yaml.id == app_yaml_id
104 | verifier.app.app_installed(app_json_id)
105 | verifier.app.app_installed(app_yaml_id)
106 |
107 |
108 | def test_create_app_revision(api, given, verifier):
109 | # preconditions
110 | app_id = "me/my-project/my-app"
111 | revision = 1
112 | given.app.app_exists(id=app_id, revision=1)
113 | given.app.revision_can_be_created(id=app_id, revision=revision)
114 |
115 | raw = {'sbg:id': app_id, 'revision': revision}
116 |
117 | # action
118 | app = api.apps.create_revision(app_id, revision, raw)
119 |
120 | # verification
121 | assert app.id == app_id
122 | assert app.revision == revision
123 |
124 | verifier.app.revision_created(app_id, revision)
125 |
--------------------------------------------------------------------------------
/tests/test_async_jobs.py:
--------------------------------------------------------------------------------
1 | import faker
2 | import pytest
3 |
4 | from sevenbridges.models.async_jobs import AsyncFileBulkRecord
5 | from sevenbridges.models.enums import AsyncFileOperations, AsyncJobStates
6 |
7 | generator = faker.Factory.create()
8 |
9 |
10 | def test_list_file_jobs(api, given, verifier):
11 | # preconditions
12 | total = 10
13 | given.async_jobs.list_file_jobs(total)
14 |
15 | # action
16 | jobs = api.async_jobs.list_file_jobs()
17 |
18 | # verification
19 | assert len(jobs) == total
20 | verifier.async_jobs.listed()
21 |
22 |
23 | def test_get_copy_files_job(api, given, verifier):
24 | # preconditions
25 | id = generator.uuid4()
26 | given.async_jobs.exists(id=id, type=AsyncFileOperations.COPY)
27 |
28 | # action
29 | job = api.async_jobs.get_file_copy_job(id=id)
30 |
31 | # verification
32 | assert job.id == id
33 | verifier.async_jobs.file_copy_job_fetched(id=id)
34 |
35 |
36 | def test_get_move_files_job(api, given, verifier):
37 | # preconditions
38 | id = generator.uuid4()
39 | given.async_jobs.exists(id=id, type=AsyncFileOperations.MOVE)
40 |
41 | # action
42 | job = api.async_jobs.get_file_move_job(id=id)
43 |
44 | # verification
45 | assert job.id == id
46 | verifier.async_jobs.file_move_job_fetched(id=id)
47 |
48 |
49 | def test_get_delete_files_job(api, given, verifier):
50 | # preconditions
51 | id = generator.uuid4()
52 | given.async_jobs.exists(id=id, type=AsyncFileOperations.DELETE)
53 |
54 | # action
55 | job = api.async_jobs.get_file_delete_job(id=id)
56 |
57 | # verification
58 | assert job.id == id
59 | verifier.async_jobs.file_delete_job_fetched(id=id)
60 |
61 |
62 | def test_get_results(api, given, verifier):
63 | # preconditions
64 | id = generator.uuid4()
65 |
66 | expected_result = [
67 | {'resource': {'id': generator.uuid4()}},
68 | {'error': {'status': 404}},
69 | ]
70 | given.async_jobs.exists(
71 | id=id,
72 | result=expected_result,
73 | type=AsyncFileOperations.COPY,
74 | )
75 |
76 | # action
77 | job = api.async_jobs.get_file_copy_job(id=id)
78 | result = job.get_result()
79 |
80 | # verification
81 | verifier.async_jobs.file_copy_job_fetched(id=id)
82 | assert all(isinstance(r, AsyncFileBulkRecord) for r in result)
83 | assert len(result) == 2
84 | assert result[0].valid
85 | assert not result[1].valid
86 |
87 |
88 | @pytest.mark.parametrize("location", ['parent', 'project'])
89 | def test_async_copy_files(api, given, verifier, location):
90 | # preconditions
91 | total = 10
92 | files = [
93 | {
94 | 'file': generator.uuid4(),
95 | 'location': generator.uuid4(),
96 | 'name': generator.slug()
97 | } for _ in range(total)
98 | ]
99 | given.async_jobs.can_copy_files(files=files)
100 |
101 | # action
102 | job = api.async_jobs.file_bulk_copy(files=files)
103 |
104 | # verification
105 | assert job.state == AsyncJobStates.SUBMITTED
106 | assert len(job.result) == total
107 | verifier.async_jobs.async_files_copied()
108 |
109 |
110 | @pytest.mark.parametrize("location", ['parent', 'project'])
111 | def test_async_move_files(api, given, verifier, location):
112 | # preconditions
113 | total = 10
114 | files = [
115 | {
116 | 'file': generator.uuid4(),
117 | 'location': generator.uuid4(),
118 | 'name': generator.slug()
119 | } for _ in range(total)
120 | ]
121 | given.async_jobs.can_move_files(files=files)
122 |
123 | # action
124 | job = api.async_jobs.file_bulk_move(files=files)
125 |
126 | # verification
127 | assert job.state == AsyncJobStates.SUBMITTED
128 | assert len(job.result) == total
129 | verifier.async_jobs.async_files_moved()
130 |
131 |
132 | def test_async_delete_files(api, given, verifier):
133 | # preconditions
134 | total = 10
135 | files = [
136 | {
137 | 'file': generator.uuid4(),
138 | } for _id in range(total)
139 | ]
140 | given.async_jobs.can_delete_files(files=files)
141 |
142 | # action
143 | job = api.async_jobs.file_bulk_delete(files=files)
144 |
145 | # verification
146 | assert job.state == AsyncJobStates.SUBMITTED
147 | assert len(job.result) == total
148 | verifier.async_jobs.async_files_deleted()
149 |
--------------------------------------------------------------------------------
/tests/test_billing_groups.py:
--------------------------------------------------------------------------------
1 | import pytest
2 | import faker
3 |
4 | generator = faker.Factory.create()
5 |
6 |
7 | def test_billing_group_query(api, given, verifier):
8 | # preconditions
9 | total = 10
10 | given.billing_group.exist(total)
11 |
12 | # action
13 | billing_groups = api.billing_groups.query()
14 |
15 | # verification
16 | assert billing_groups.total == total
17 | assert len(billing_groups) == total
18 |
19 | verifier.billing_group.groups_fetched()
20 |
21 |
22 | @pytest.mark.parametrize('with_cost', [True, False])
23 | def test_billing_storage_breakdown(api, given, verifier, with_cost):
24 | # precondition
25 | given.billing_group.exist(1)
26 |
27 | # action
28 | billing_groups = api.billing_groups.query()
29 | billing_group = billing_groups[0]
30 |
31 | # precondition
32 | total = 5
33 | given.billing_group_storage_breakdown.exist(
34 | bg_id=billing_group.id,
35 | num_of_objects=total,
36 | with_cost=with_cost
37 | )
38 |
39 | # action
40 | storage_breakdown = billing_group.storage_breakdown()
41 |
42 | # verification
43 | verifier.billing_group.groups_fetched()
44 | verifier.billing_group_storage_breakdown.fetched(
45 | billing_group=billing_group
46 | )
47 |
48 | verifier.billing_group_storage_breakdown.fetched(
49 | billing_group=billing_group
50 | )
51 | assert len(storage_breakdown) == total
52 | for breakdown in storage_breakdown:
53 | if with_cost:
54 | assert breakdown.active is not None
55 | assert breakdown.archived is not None
56 | else:
57 | assert breakdown.active is None
58 | assert breakdown.archived is None
59 |
--------------------------------------------------------------------------------
/tests/test_config.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | import faker
4 | import configparser
5 |
6 | from sevenbridges import Config, Api
7 | from sevenbridges.config import UserProfile
8 |
9 | generator = faker.Factory.create()
10 |
11 |
12 | def test_os_environ_config(base_url, monkeypatch):
13 | mock_env = {
14 | 'SB_AUTH_TOKEN': 'token',
15 | 'SB_API_ENDPOINT': base_url
16 | }
17 | monkeypatch.setattr(os, 'environ', mock_env)
18 | config = Config()
19 | assert config.api_endpoint == base_url
20 | assert config.auth_token == 'token'
21 |
22 |
23 | def test_os_environ_config_with_api(base_url, monkeypatch):
24 | mock_env = {
25 | 'SB_AUTH_TOKEN': 'token',
26 | 'SB_API_ENDPOINT': base_url,
27 | 'HTTP_PROXY': base_url,
28 | 'HTTPS_PROXY': base_url,
29 | }
30 | monkeypatch.setattr(os, 'environ', mock_env)
31 |
32 | api = Api()
33 | assert api.url == base_url
34 | assert api.token == 'token'
35 | api.session.proxies['http'] = mock_env['HTTP_PROXY']
36 | api.session.proxies['https'] = mock_env['HTTPS_PROXY']
37 |
38 |
39 | def test_default_config(base_url, monkeypatch, config_parser):
40 | data = {
41 | 'default': {
42 | 'auth_token': 'token',
43 | 'api_endpoint': base_url
44 | },
45 | 'proxies': {
46 | 'http_proxy': 'http',
47 | 'https_proxy': 'https'
48 | }
49 | }
50 | parser = config_parser(data)
51 | monkeypatch.setattr(configparser, 'ConfigParser', parser)
52 | monkeypatch.setattr(os.path, 'isfile', lambda x: True)
53 |
54 | api = Api()
55 | assert api.session.proxies.get('http') == data['proxies']['http_proxy']
56 | assert api.session.proxies.get('https') == data['proxies']['https_proxy']
57 |
58 |
59 | def test_config_profile(base_url, monkeypatch, config_parser):
60 | data = {
61 | 'profile': {
62 | 'auth_token': 'token',
63 | 'api_endpoint': base_url
64 | },
65 | 'proxies': {
66 | 'http_proxy': 'http',
67 | 'https_proxy': 'https'
68 | }
69 | }
70 | parser = config_parser(data)
71 | monkeypatch.setattr(configparser, 'ConfigParser', parser)
72 | monkeypatch.setattr(os.path, 'isfile', lambda x: True)
73 |
74 | api = Api(config=Config('profile'))
75 | assert api.url == data['profile']['api_endpoint']
76 | assert api.token == data['profile']['auth_token']
77 |
78 |
79 | def test_config_profile_no_proxy(base_url, monkeypatch, config_parser):
80 | def is_file(f):
81 | if f == UserProfile.CREDENTIALS:
82 | return True
83 | else:
84 | return False
85 |
86 | data = {
87 | 'profile': {
88 | 'auth_token': 'token',
89 | 'api_endpoint': base_url
90 | }
91 | }
92 | parser = config_parser(data)
93 | monkeypatch.setattr(configparser, 'ConfigParser', parser)
94 | monkeypatch.setattr(os.path, 'isfile', is_file)
95 |
96 | api = Api(config=Config('profile'))
97 | assert api.url == data['profile']['api_endpoint']
98 | assert api.token == data['profile']['auth_token']
99 |
100 |
101 | def test_config_profile_explicit_proxy(base_url, monkeypatch, config_parser):
102 | def is_file(f):
103 | if f == UserProfile.CREDENTIALS:
104 | return True
105 | else:
106 | return False
107 |
108 | data = {
109 | 'profile': {
110 | 'auth_token': 'token',
111 | 'api_endpoint': base_url
112 | }
113 | }
114 |
115 | proxies = {
116 | 'http_proxy': 'http',
117 | 'https_proxy': 'https'
118 | }
119 | parser = config_parser(data)
120 | monkeypatch.setattr(configparser, 'ConfigParser', parser)
121 | monkeypatch.setattr(os.path, 'isfile', is_file)
122 |
123 | api = Api(config=Config('profile', proxies=proxies))
124 | assert api.url == data['profile']['api_endpoint']
125 | assert api.token == data['profile']['auth_token']
126 | assert api.session.proxies.get('http') == proxies['http_proxy']
127 | assert api.session.proxies.get('https') == proxies['https_proxy']
128 |
129 |
130 | def test_config_advance_access(base_url, monkeypatch, config_parser):
131 | def is_file(f):
132 | if f in [UserProfile.CREDENTIALS, UserProfile.CONFIG]:
133 | return True
134 | else:
135 | return False
136 |
137 | data = {
138 | 'profile': {
139 | 'auth_token': 'token',
140 | 'api_endpoint': base_url
141 | },
142 | 'mode': {
143 | 'advance_access': True
144 | }
145 | }
146 | parser = config_parser(data)
147 | monkeypatch.setattr(configparser, 'ConfigParser', parser)
148 | monkeypatch.setattr(os.path, 'isfile', is_file)
149 |
150 | api = Api(config=Config('profile'))
151 | assert api.aa is True
152 |
153 |
154 | def test_config_explicit_advance_access(base_url, monkeypatch, config_parser):
155 | def is_file(f):
156 | if f in [UserProfile.CREDENTIALS, UserProfile.CONFIG]:
157 | return True
158 | else:
159 | return False
160 |
161 | data = {
162 | 'profile': {
163 | 'auth_token': 'token',
164 | 'api_endpoint': base_url
165 | }
166 | }
167 | parser = config_parser(data)
168 | monkeypatch.setattr(configparser, 'ConfigParser', parser)
169 | monkeypatch.setattr(os.path, 'isfile', is_file)
170 |
171 | api = Api(config=Config('profile'), advance_access=True)
172 | assert api.aa is True
173 |
--------------------------------------------------------------------------------
/tests/test_datasets.py:
--------------------------------------------------------------------------------
1 | import faker
2 |
3 | generator = faker.Factory.create()
4 |
5 |
6 | def test_get(api, given, verifier):
7 | # precondition
8 | api.aa = True
9 | username = generator.user_name()
10 | dataset_name = generator.slug()
11 | id = f'{username}/{dataset_name}'
12 | given.datasets.exists(id=id)
13 |
14 | # action
15 | dataset = api.datasets.get(id=id)
16 |
17 | # verification
18 | assert dataset.id == id
19 | verifier.datasets.fetched(id=id)
20 |
21 |
22 | def test_query(api, given, verifier):
23 | # preconditions
24 | api.aa = True
25 | total = 10
26 | given.datasets.query(total)
27 |
28 | # action
29 | datasets = api.datasets.query()
30 |
31 | # verification
32 | assert len(datasets) == total
33 |
34 | verifier.datasets.queried()
35 |
36 |
37 | def test_query_by_owner(api, given, verifier):
38 | # preconditions
39 | api.aa = True
40 | total = 10
41 | username = generator.user_name()
42 | dataset_name = generator.slug()
43 | id = f'{username}/{dataset_name}'
44 | given.datasets.exists(id=id)
45 | given.datasets.owned_by(total, username)
46 |
47 | # action
48 | datasets = api.datasets.get_owned_by(username)
49 |
50 | # verification
51 | assert len(datasets) == total
52 |
53 | verifier.datasets.owned_by(username)
54 |
55 |
56 | def test_save(api, given, verifier):
57 | # precondition
58 | api.aa = True
59 | username = generator.user_name()
60 | dataset_name = generator.slug()
61 | id = f'{username}/{dataset_name}'
62 | given.datasets.exists(id=id)
63 | given.datasets.can_be_saved(id=id)
64 |
65 | # action
66 | dataset = api.datasets.get(id=id)
67 | dataset.name = generator.slug()
68 | dataset.description = generator.slug()
69 | dataset.save()
70 |
71 | # verification
72 | verifier.datasets.saved(id)
73 |
74 |
75 | def test_get_members(api, given, verifier):
76 | # precondition
77 | api.aa = True
78 | total = 10
79 | username = generator.user_name()
80 | dataset_name = generator.slug()
81 | id = f'{username}/{dataset_name}'
82 | given.datasets.exists(id=id)
83 | given.datasets.has_members(id, dataset_name, total)
84 |
85 | # action
86 | dataset = api.datasets.get(id)
87 | members = dataset.get_members()
88 |
89 | # verification
90 | assert len(members) == total
91 | verifier.datasets.members_retrieved(id)
92 |
93 |
94 | def test_get_member(api, given, verifier):
95 | # precondition
96 | api.aa = True
97 | username = generator.user_name()
98 | member_username = generator.user_name()
99 | dataset_name = generator.slug()
100 | id = f'{username}/{dataset_name}'
101 | given.datasets.exists(id=id)
102 | given.datasets.has_member(id, dataset_name, member_username)
103 |
104 | # action
105 | dataset = api.datasets.get(id)
106 | member = dataset.get_member(member_username)
107 |
108 | # verification
109 | assert member.username == member_username
110 | verifier.datasets.member_retrieved(id, member_username)
111 |
112 |
113 | def test_add_member(api, given, verifier):
114 | # precondition
115 | api.aa = True
116 | username = generator.user_name()
117 | member_username = generator.user_name()
118 | member_permissions = {
119 | "write": True,
120 | "read": True,
121 | "copy": True,
122 | "execute": True,
123 | "admin": True
124 | }
125 | dataset_name = generator.slug()
126 | id = f'{username}/{dataset_name}'
127 | given.datasets.exists(id=id)
128 | given.datasets.can_add_member(id, member_username)
129 |
130 | # action
131 | dataset = api.datasets.get(id)
132 | dataset.add_member(member_username, member_permissions)
133 |
134 | # verification
135 | verifier.datasets.member_added(id)
136 |
137 |
138 | def test_remove_member(api, given, verifier):
139 | # precondition
140 | api.aa = True
141 | username = generator.user_name()
142 | member_username = generator.user_name()
143 | dataset_name = generator.slug()
144 | id = f'{username}/{dataset_name}'
145 | given.datasets.exists(id=id)
146 | given.datasets.has_member(id, dataset_name, member_username)
147 | given.datasets.can_remove_member(id, member_username)
148 |
149 | # action
150 | dataset = api.datasets.get(id)
151 | dataset.remove_member(member_username)
152 |
153 | # verification
154 | verifier.datasets.member_removed(id, member_username)
155 |
--------------------------------------------------------------------------------
/tests/test_decorators.py:
--------------------------------------------------------------------------------
1 | import faker
2 | import pytest
3 |
4 | from sevenbridges.errors import NonJSONResponseError
5 |
6 | generator = faker.Factory.create()
7 |
8 |
9 | @pytest.mark.parametrize("status_code", [200, 500])
10 | def test_non_json_response(api, given, status_code):
11 | # preconditions
12 | given.app.app_exist_non_json(status_code=status_code)
13 |
14 | # action
15 | with pytest.raises(NonJSONResponseError):
16 | api.apps.query(visibility="private")
17 |
--------------------------------------------------------------------------------
/tests/test_divisions.py:
--------------------------------------------------------------------------------
1 | import faker
2 |
3 | generator = faker.Factory.create()
4 |
5 |
6 | def test_get_division(api, given, verifier):
7 | # precondition
8 | api.aa = True
9 | id = generator.uuid4()
10 | given.division.exists(id=id)
11 |
12 | # action
13 | division = api.divisions.get(id=id)
14 |
15 | # verification
16 | assert division.id == id
17 | verifier.division.division_fetched(id=id)
18 |
19 |
20 | def test_division_query(api, given, verifier):
21 | # preconditions
22 | api.aa = True
23 | total = 10
24 | given.division.query(total)
25 |
26 | # action
27 | divisions = api.divisions.query()
28 |
29 | # verification
30 | assert len(divisions) == total
31 |
32 | verifier.division.divisions_fetched()
33 |
34 |
35 | def test_get_teams(api, given, verifier):
36 | # preconditions
37 | api.aa = True
38 | total = 10
39 | id = generator.uuid4()
40 |
41 | given.division.exists(id=id)
42 | given.division.teams_exist(id, total)
43 |
44 | division = api.divisions.get(id=id)
45 | teams = division.get_teams()
46 |
47 | assert len(teams) == total
48 |
49 |
50 | def test_get_members(api, given, verifier):
51 | # preconditions
52 | api.aa = True
53 | total = 10
54 | id = generator.uuid4()
55 |
56 | given.division.exists(id=id)
57 | given.division.members_exist(id, total)
58 |
59 | division = api.divisions.get(id=id)
60 | members = division.get_members()
61 |
62 | assert len(members) == total
63 |
--------------------------------------------------------------------------------
/tests/test_drs_import.py:
--------------------------------------------------------------------------------
1 | import faker
2 |
3 | generator = faker.Factory.create()
4 |
5 |
6 | def test_imports_bulk_get(api, given, verifier):
7 | # preconditions
8 | total = 10
9 | file_ids = [generator.uuid4() for _ in range(total)]
10 | _import = {
11 | 'id': generator.uuid4(),
12 | 'result': [
13 | {'resource': {'id': _id, 'href': generator.url()}}
14 | for _id in file_ids
15 | ]
16 | }
17 |
18 | given.drs_imports.can_be_retrieved_in_bulk(_import)
19 |
20 | # action
21 | response = api.drs_imports.bulk_get(_import['id'])
22 |
23 | # verification
24 | assert len(response.result) == total
25 | verifier.drs_imports.bulk_retrieved(response.id)
26 |
27 |
28 | def test_imports_bulk_submit(api, given, verifier):
29 | # preconditions
30 | total = 10
31 |
32 | imports = [
33 | {
34 | "drs_uri": generator.name(),
35 | "project": generator.name(),
36 | "metadata": {
37 | generator.name(): generator.name(),
38 | generator.name(): generator.name()
39 | },
40 | "name": generator.name()
41 | }
42 | for _ in range(total)
43 | ]
44 | tags = [generator.name()]
45 |
46 | given.drs_imports.can_be_submitted_in_bulk(imports)
47 |
48 | # action
49 | response = api.drs_imports.bulk_submit(imports, tags)
50 |
51 | # verification
52 | assert len(response.result) == total
53 | verifier.drs_imports.bulk_submitted()
54 |
--------------------------------------------------------------------------------
/tests/test_endpoints_rate.py:
--------------------------------------------------------------------------------
1 | import faker
2 |
3 | generator = faker.Factory.create()
4 |
5 |
6 | # Endpoints
7 | def test_endpoints(api, given, verifier):
8 | # preconditions
9 | given.endpoints.defined()
10 |
11 | # action
12 | endpoints = api.endpoints.get()
13 |
14 | # verification
15 | assert 'upload' in endpoints.upload_url
16 | assert 'projects' in endpoints.projects_url
17 | assert 'action' in endpoints.action_url
18 | assert 'user' in endpoints.user_url
19 | assert 'users' in endpoints.users_url
20 | assert 'tasks' in endpoints.tasks_url
21 | assert 'apps' in endpoints.apps_url
22 | verifier.endpoints.fetched()
23 |
24 |
25 | # Rate
26 | def test_rate_limit(api, given):
27 | # preconditions
28 | mock = {'rate': {'limit': 100, 'remaining': 20},
29 | 'instance_limit': {'limit': 100, 'remaining': 20}}
30 | given.rate.limit_available(**mock)
31 |
32 | # action
33 | result = api.rate_limit.get()
34 |
35 | assert result.rate.limit == mock['rate']['limit']
36 | assert result.rate.remaining == mock['rate']['remaining']
37 | assert result.instance_limit.limit == mock['instance_limit']['limit']
38 | assert result.instance_limit.remaining == mock['instance_limit'][
39 | 'remaining']
40 |
--------------------------------------------------------------------------------
/tests/test_error_handlers.py:
--------------------------------------------------------------------------------
1 | import time
2 | from json import JSONDecodeError
3 |
4 | import faker
5 | import pytest
6 | import requests
7 |
8 | from sevenbridges.http.error_handlers import (
9 | rate_limit_sleeper, maintenance_sleeper, general_error_sleeper)
10 |
11 | generator = faker.Factory.create()
12 |
13 |
14 | class MockSession:
15 | def __init__(self, mock):
16 | self.mock = mock
17 |
18 | def send(self, response):
19 | return self.mock.pop()
20 |
21 |
22 | def test_rate_limit_sleeper(api):
23 | resp429 = requests.Response()
24 | resp429.headers = {
25 | 'X-RateLimit-Reset': time.time() + 1
26 | }
27 | resp429.status_code = 429
28 | resp200 = requests.Response()
29 | resp200.status_code = 200
30 |
31 | api._session = MockSession([resp429, resp200])
32 | resp = rate_limit_sleeper(api, resp429)
33 |
34 | assert resp.status_code == resp200.status_code
35 |
36 |
37 | def test_maintenance_sleeper_invalid_json(api):
38 | resp503 = requests.Response()
39 | resp503.status_code = 503
40 | resp503.headers = {'Content-Type': 'application/json'}
41 |
42 | api._session = MockSession([resp503])
43 | with pytest.raises(JSONDecodeError):
44 | maintenance_sleeper(api, resp503, 1)
45 |
46 |
47 | def test_maintenance_sleeper(api):
48 | resp503 = requests.Response()
49 | resp503.status_code = 503
50 | resp503.headers = {'Content-Type': 'application/json'}
51 | resp503._content = b'{"code": 0}'
52 | resp200 = requests.Response()
53 | resp200.status_code = 200
54 |
55 | api._session = MockSession([resp503, resp200])
56 | resp = maintenance_sleeper(api, resp503, 1)
57 |
58 | assert resp.status_code == resp200.status_code
59 |
60 |
61 | def test_general_error_sleeper(api):
62 | resp500 = requests.Response()
63 | resp500.status_code = 500
64 | resp200 = requests.Response()
65 | resp200.status_code = 200
66 |
67 | api._session = MockSession([resp500, resp200])
68 | resp = general_error_sleeper(api, resp500, 1)
69 |
70 | assert resp.status_code == resp200.status_code
71 |
--------------------------------------------------------------------------------
/tests/test_exports.py:
--------------------------------------------------------------------------------
1 | import faker
2 | import pytest
3 |
4 | generator = faker.Factory.create()
5 |
6 |
7 | def test_exports_query(api, given, verifier):
8 | # preconditions
9 | total = 10
10 | given.exports.query(total=10)
11 |
12 | # action
13 | exports = api.exports.query(limit=10)
14 |
15 | # verification
16 | assert exports.total == total
17 | assert len(exports) == total
18 |
19 | verifier.exports.queried()
20 |
21 |
22 | def test_exports_submit(api, given, verifier):
23 | # preconditions
24 | id = generator.uuid4()
25 | file = generator.name()
26 | volume = generator.name()
27 | location = f'{generator.name()}/{generator.name()}'
28 | given.exports.can_be_submitted(id=id)
29 |
30 | # action
31 | exports = api.exports.submit_export(file, volume, location)
32 |
33 | assert exports.id == id
34 | verifier.exports.submitted()
35 |
36 |
37 | def test_exports_bulk_get(api, given, verifier):
38 | # preconditions
39 | total = 10
40 |
41 | export_ids = [generator.uuid4() for _ in range(total)]
42 | exports = [{'id': id_} for id_ in export_ids]
43 | given.exports.can_be_retrieved_in_bulk(exports)
44 |
45 | # action
46 | response = api.exports.bulk_get(export_ids)
47 |
48 | # verification
49 | assert len(response) == total
50 | verifier.exports.bulk_retrieved()
51 |
52 |
53 | @pytest.mark.parametrize('copy_only', [True, False])
54 | def test_exports_bulk_submit(api, given, verifier, copy_only):
55 | # preconditions
56 | total = 10
57 |
58 | exports = [
59 | {
60 | 'file': generator.name(),
61 | 'volume': generator.name(),
62 | 'location': generator.name(),
63 | 'properties': {},
64 | 'overwrite': True
65 | }
66 | for _ in range(total)
67 | ]
68 | given.exports.can_be_submitted_in_bulk(exports)
69 |
70 | # action
71 | response = api.exports.bulk_submit(exports, copy_only=copy_only)
72 |
73 | # verification
74 | assert len(response) == total
75 | verifier.exports.bulk_submitted(copy_only)
76 |
--------------------------------------------------------------------------------
/tests/test_imports.py:
--------------------------------------------------------------------------------
1 | import faker
2 |
3 | generator = faker.Factory.create()
4 |
5 |
6 | def test_imports_query(api, given, verifier):
7 | # preconditions
8 | total = 10
9 | given.imports.query(total=10)
10 |
11 | # action
12 | imports = api.imports.query(limit=10)
13 |
14 | # verification
15 | assert imports.total == total
16 | assert len(imports) == total
17 |
18 | verifier.imports.queried()
19 |
20 |
21 | def test_import_submit(api, given, verifier):
22 | # preconditions
23 | id = generator.uuid4()
24 | volume = generator.name()
25 | location = generator.name()
26 | project = f'{generator.name()}/{generator.name()}'
27 | given.imports.can_be_submitted(id=id)
28 |
29 | # action
30 | imports = api.imports.submit_import(
31 | volume=volume,
32 | location=location,
33 | project=project
34 | )
35 |
36 | assert imports.id == id
37 | verifier.imports.submitted()
38 |
39 |
40 | def test_import_to_folder_submit(api, given, verifier):
41 | # preconditions
42 | id = generator.uuid4()
43 | volume = generator.name()
44 | location = generator.name()
45 | parent = f'{generator.name()}/'
46 | given.imports.can_be_submitted(id=id)
47 | preserve_folder_structure = False
48 |
49 | # action
50 | imports = api.imports.submit_import(
51 | volume=volume,
52 | location=location,
53 | parent=parent,
54 | preserve_folder_structure=preserve_folder_structure
55 | )
56 |
57 | assert imports.id == id
58 | verifier.imports.submitted()
59 |
60 |
61 | def test_imports_bulk_get(api, given, verifier):
62 | # preconditions
63 | total = 10
64 |
65 | import_ids = [generator.uuid4() for _ in range(total)]
66 | imports = [{'id': id_} for id_ in import_ids]
67 | given.imports.can_be_retrieved_in_bulk(imports)
68 |
69 | # action
70 | response = api.imports.bulk_get(import_ids)
71 |
72 | # verification
73 | assert len(response) == total
74 | verifier.imports.bulk_retrieved()
75 |
76 |
77 | def test_imports_bulk_submit(api, given, verifier):
78 | # preconditions
79 | total = 10
80 |
81 | imports = [
82 | {
83 | 'volume': generator.name(),
84 | 'location': generator.name(),
85 | 'project': generator.name(),
86 | 'name': generator.name(),
87 | 'overwrite': True
88 | }
89 | for _ in range(total)
90 | ]
91 | given.imports.can_be_submitted_in_bulk(imports)
92 |
93 | # action
94 | response = api.imports.bulk_submit(imports)
95 |
96 | # verification
97 | assert len(response) == total
98 | verifier.imports.bulk_submitted()
99 |
--------------------------------------------------------------------------------
/tests/test_marker.py:
--------------------------------------------------------------------------------
1 | import faker
2 |
3 | generator = faker.Factory.create()
4 |
5 |
6 | def test_markers_query(api, given, verifier):
7 | # preconditions
8 | total = 10
9 | file = generator.name()
10 | given.marker.query(total=10, file=file)
11 |
12 | # action
13 | markers = api.markers.query(file=file)
14 |
15 | # verification
16 | assert markers.total == total
17 | assert len(markers) == total
18 |
19 | verifier.marker.queried()
20 |
21 |
22 | def test_marker_create(api, given, verifier):
23 | # preconditions
24 | file = generator.uuid4()
25 | name = generator.name()
26 | chromosome = "chr1"
27 | position = {
28 | "start": 0,
29 | "end": 10
30 | }
31 | given.marker.created(name=name, file=file)
32 |
33 | marker = api.markers.create(file, name, position, chromosome)
34 |
35 | # verifier
36 | assert marker.name == name
37 | verifier.marker.created()
38 |
39 |
40 | def test_modify_marker(api, given, verifier):
41 | # preconditions
42 | _id = 'my/marker'
43 | name = generator.name()
44 | given.marker.exists(id=_id)
45 | given.marker.modified(id=_id, name=name)
46 |
47 | # action
48 | marker = api.markers.get(_id)
49 | marker.name = name
50 | marker.save()
51 |
52 | # verifier
53 | assert marker.name == name
54 | verifier.marker.modified(marker.id)
55 |
--------------------------------------------------------------------------------
/tests/test_pagination.py:
--------------------------------------------------------------------------------
1 | import faker
2 |
3 | generator = faker.Factory.create()
4 |
5 |
6 | def test_single_page_pagination(api, given, verifier):
7 | # preconditions
8 | limit = 2
9 | total = 10
10 | given.project.paginated_projects(limit, total)
11 | # action
12 | projects = api.projects.query(offset=0, limit=limit)
13 |
14 | # verification
15 | assert projects.total == total
16 | assert len(projects) == limit
17 | verifier.project.queried(0, limit)
18 |
19 |
20 | def test_all_pages_pagination(api, given, verifier):
21 | # preconditions
22 | limit = 2
23 | total = 10
24 | given.project.paginated_projects(limit, total)
25 |
26 | # action
27 | projects = api.projects.query(offset=0, limit=limit)
28 |
29 | # verification
30 | assert len(list(projects.all())) == total
31 | for i in range(0, limit, total):
32 | verifier.project.queried(i, limit)
33 |
34 |
35 | def test_single_page_back(api, given, verifier):
36 | # preconditions
37 | limit = 2
38 | total = 10
39 | given.project.paginated_projects(limit, total)
40 |
41 | # action
42 | projects = api.projects.query(offset=4, limit=limit)
43 |
44 | # verification
45 | projects.previous_page()
46 | verifier.project.queried(2, limit)
47 |
--------------------------------------------------------------------------------
/tests/test_teams.py:
--------------------------------------------------------------------------------
1 | import faker
2 |
3 | generator = faker.Factory.create()
4 |
5 |
6 | def test_get_team(api, given, verifier):
7 | # precondition
8 | api.aa = True
9 | id = generator.uuid4()
10 | given.team.exists(id=id)
11 |
12 | # action
13 | team = api.teams.get(id=id)
14 |
15 | # verification
16 | assert team.id == id
17 | verifier.team.team_fetched(id=id)
18 |
19 |
20 | def test_team_query(api, given, verifier):
21 | # preconditions
22 | api.aa = True
23 | total = 10
24 | given.team.query(total)
25 |
26 | # action
27 | teams = api.teams.query(division=generator.name())
28 |
29 | # verification
30 | assert len(teams) == total
31 | verifier.team.teams_fetched()
32 |
33 |
34 | def test_team_modify(api, given, verifier):
35 | api.aa = True
36 |
37 | id = generator.uuid4()
38 | new_name = generator.name()
39 |
40 | given.team.exists(id=id)
41 | given.team.modified(id=id, name=new_name)
42 |
43 | team = api.teams.get(id)
44 | team.name = new_name
45 | team.save()
46 |
47 | assert team.name == new_name
48 | verifier.team.modified(id=id)
49 |
50 |
51 | def test_team_created(api, given, verifier):
52 | # preconditions
53 | api.aa = True
54 | name = generator.name()
55 | given.team.created(name)
56 |
57 | # action
58 | team = api.teams.create(name, division=generator.name())
59 |
60 | # verification
61 | assert team.name == name
62 | verifier.team.created()
63 |
64 |
65 | def test_team_get_members(api, given, verifier):
66 | # preconditions
67 | api.aa = True
68 | total = 10
69 | id = generator.uuid4()
70 |
71 | given.team.exists(id=id)
72 | given.team_member.queried(id, total)
73 |
74 | # action
75 | team = api.teams.get(id)
76 | members = team.get_members()
77 |
78 | assert len(members) == total
79 | verifier.team.members_fetched(id)
80 |
--------------------------------------------------------------------------------
/tests/test_transformer.py:
--------------------------------------------------------------------------------
1 | import uuid
2 | from datetime import datetime
3 |
4 | import faker
5 | import pytest
6 |
7 | from sevenbridges import (
8 | Project, Task, App, File,
9 | User, BillingGroup, Marker, Division
10 | )
11 | from sevenbridges.errors import SbgError
12 | from sevenbridges.meta.transformer import Transform
13 | from sevenbridges.models.team import Team
14 | from sevenbridges.models.volume import Volume
15 |
16 | generator = faker.Factory.create()
17 |
18 |
19 | def random_uuid():
20 | return str(uuid.uuid4())
21 |
22 |
23 | @pytest.mark.parametrize("project", ['u/p', Project(id='u/p')])
24 | def test_transform_project(project):
25 | Transform.to_project(project)
26 |
27 |
28 | @pytest.mark.parametrize("project", [[], {}, b'', None, type])
29 | def test_transform_project_invalid_values(project):
30 | with pytest.raises(SbgError):
31 | Transform.to_project(project)
32 |
33 |
34 | @pytest.mark.parametrize("task", [random_uuid(), Task(id=random_uuid())])
35 | def test_transform_task(task):
36 | Transform.to_task(task)
37 |
38 |
39 | @pytest.mark.parametrize("task", [[], {}, b'', None, type])
40 | def test_transform_task_invalid_values(task):
41 | with pytest.raises(SbgError):
42 | Transform.to_task(task)
43 |
44 |
45 | @pytest.mark.parametrize("app", ['u/p/a/0', App(id='u/p/a/1')])
46 | def test_transform_app(app):
47 | Transform.to_app(app)
48 |
49 |
50 | @pytest.mark.parametrize("app", [[], {}, b'', None, type])
51 | def test_transform_app_invalid_values(app):
52 | with pytest.raises(SbgError):
53 | Transform.to_task(app)
54 |
55 |
56 | @pytest.mark.parametrize("file", [random_uuid(), File(id=random_uuid())])
57 | def test_transform_file(file):
58 | Transform.to_file(file)
59 |
60 |
61 | @pytest.mark.parametrize("file", [[], {}, b'', None, type])
62 | def test_transform_file_invalid_values(file):
63 | with pytest.raises(SbgError):
64 | Transform.to_file(file)
65 |
66 |
67 | @pytest.mark.parametrize("user", ['u', User(username='u')])
68 | def test_transform_user(user):
69 | Transform.to_user(user)
70 |
71 |
72 | @pytest.mark.parametrize("user", [[], {}, b'', None, type])
73 | def test_transform_user_invalid_values(user):
74 | with pytest.raises(SbgError):
75 | Transform.to_user(user)
76 |
77 |
78 | @pytest.mark.parametrize(
79 | "group", [random_uuid(), BillingGroup(id=random_uuid())]
80 | )
81 | def test_transform_billing_group(group):
82 | Transform.to_billing_group(group)
83 |
84 |
85 | @pytest.mark.parametrize("group", [[], {}, b'', None, type])
86 | def test_transform_billing_group_invalid_values(group):
87 | with pytest.raises(SbgError):
88 | Transform.to_billing_group(group)
89 |
90 |
91 | @pytest.mark.parametrize("volume", ['u/p', Volume(id='u/p')])
92 | def test_transform_volume(volume):
93 | Transform.to_volume(volume)
94 |
95 |
96 | @pytest.mark.parametrize("volume", [[], {}, b'', None, type])
97 | def test_transform_volume_invalid_values(volume):
98 | with pytest.raises(SbgError):
99 | Transform.to_volume(volume)
100 |
101 |
102 | @pytest.mark.parametrize("datestring,expected", [
103 | ('2017-01-10T14:04:23', '2017-01-10T14:04:23'),
104 | (datetime(2017, 1, 10, 14, 4, 23, 838459), '2017-01-10T14:04:23'),
105 | ])
106 | def test_transform_datestring(datestring, expected):
107 | assert Transform.to_datestring(datestring) == expected
108 |
109 |
110 | @pytest.mark.parametrize("datestring", ['', None, [], {}])
111 | def test_transform_datestring_invalid(datestring):
112 | with pytest.raises(SbgError):
113 | Transform.to_datestring(datestring)
114 |
115 |
116 | @pytest.mark.parametrize("marker", [str(generator.uuid4()),
117 | Marker(id=generator.uuid4())])
118 | def test_transform_marker(marker):
119 | Transform.to_marker(marker)
120 |
121 |
122 | @pytest.mark.parametrize("division", [generator.name(),
123 | Division(id=generator.name())])
124 | def test_transform_divisions(division):
125 | Transform.to_division(division)
126 |
127 |
128 | @pytest.mark.parametrize("team", [str(generator.uuid4()),
129 | Team(id=generator.uuid4())])
130 | def test_transform_teams(team):
131 | Transform.to_team(team)
132 |
--------------------------------------------------------------------------------
/tests/test_users.py:
--------------------------------------------------------------------------------
1 | # Users
2 | def test_get_my_info(api, given, verifier):
3 | # preconditions
4 | given.user.authenticated()
5 |
6 | # action
7 | api.users.me()
8 |
9 | # verification
10 | verifier.user.authenticated_user_fetched()
11 |
12 |
13 | def test_get_users_info(api, given, verifier):
14 | # preconditions
15 | username = 'test'
16 | given.user.exists(username=username)
17 |
18 | # action
19 | user = api.users.get(username)
20 |
21 | # verification
22 | assert user.username == username
23 | assert username in repr(user)
24 | verifier.user.fetched(username)
25 |
26 |
27 | def test_user_equality(api, given, verifier):
28 | # preconditions
29 | username = 'test'
30 | given.user.authenticated()
31 | given.user.exists(username=username)
32 |
33 | # action
34 | me = api.users.me()
35 | other = api.users.get(username)
36 |
37 | # verification
38 | assert me != other
39 | verifier.user.authenticated_user_fetched()
40 | verifier.user.fetched(username)
41 |
--------------------------------------------------------------------------------
/tests/test_utils.py:
--------------------------------------------------------------------------------
1 | from sevenbridges.transfer.utils import Part, Progress
2 |
3 |
4 | def test_transfer_utils():
5 | start = 10
6 | size = 20
7 | part = Part(start=start, size=size)
8 | assert part.start == start and part.size == size
9 |
10 | num_of_parts = 10
11 | parts_done = 2
12 | bytes_done = 2000000
13 | file_size = 10
14 | duration = 2
15 | p = Progress(num_of_parts, parts_done, bytes_done, file_size, duration)
16 |
17 | assert p.num_of_parts == num_of_parts
18 | assert p.file_size == file_size
19 | assert p.duration == duration
20 | assert p.bytes_done == bytes_done
21 | assert p.bandwidth == 1
22 | assert p.progress > 0
23 |
--------------------------------------------------------------------------------
/tests/test_volumes.py:
--------------------------------------------------------------------------------
1 | import faker
2 |
3 |
4 | generator = faker.Factory.create()
5 |
6 |
7 | def test_volumes_query(api, given, verifier):
8 | # preconditions
9 | total = 10
10 | given.volume.can_be_queried(total)
11 |
12 | # action
13 | volumes = api.volumes.query()
14 |
15 | # verification
16 | assert volumes.total == total
17 | assert len(volumes) == total
18 |
19 | verifier.volume.queried()
20 |
21 |
22 | def test_create_s3_volume(api, given, verifier):
23 | # preconditions
24 | name = generator.name()
25 | bucket = generator.name()
26 | access_key_id = generator.name()
27 | access_key_secret = generator.name()
28 | access_mode = 'RO'
29 | given.volume.volume_created(name='test')
30 |
31 | # action
32 | volume = api.volumes.create_s3_volume(name, bucket, access_key_id,
33 | access_key_secret, access_mode)
34 |
35 | # verifier
36 | assert volume.name == 'test'
37 | verifier.volume.created()
38 |
39 |
40 | def test_create_s3_volume_role_auth(api, given, verifier):
41 | # preconditions
42 | name = generator.name()
43 | bucket = generator.name()
44 | role_arn = generator.name()
45 | external_id = generator.name()
46 | access_mode = 'RO'
47 | given.volume.volume_created(name='test')
48 |
49 | # action
50 | volume = api.volumes.create_s3_volume_role_auth(
51 | name, bucket, role_arn, external_id, access_mode)
52 |
53 | # verifier
54 | assert volume.name == 'test'
55 | verifier.volume.created()
56 |
57 |
58 | def test_create_google_volume(api, given, verifier):
59 | # preconditions
60 | name = generator.name()
61 | bucket = generator.name()
62 | access_key_id = generator.name()
63 | access_key_secret = generator.name()
64 | access_mode = 'RO'
65 | given.volume.volume_created(name='test')
66 |
67 | # action
68 | volume = api.volumes.create_google_volume(name, bucket, access_key_id,
69 | access_key_secret, access_mode)
70 |
71 | # verifier
72 | assert volume.name == 'test'
73 | verifier.volume.created()
74 |
75 |
76 | def test_create_oss_volume(api, given, verifier):
77 | # preconditions
78 | name = generator.name()
79 | bucket = generator.name()
80 | endpoint = generator.name()
81 | access_key_id = generator.name()
82 | secret_access_key = generator.name()
83 | access_mode = 'RO'
84 | description = generator.text()
85 | given.volume.volume_created(name='test')
86 |
87 | # action
88 | volume = api.volumes.create_oss_volume(
89 | name, bucket, endpoint, access_key_id,
90 | secret_access_key, access_mode, description,
91 | )
92 |
93 | # verifier
94 | assert volume.name == 'test'
95 | verifier.volume.created()
96 |
97 |
98 | def test_modify_volume(api, given, verifier):
99 | # preconditions
100 | _id = 'my/volume'
101 | name = generator.name()
102 | description = generator.name()
103 | given.volume.exist(id=_id, name=name, description=generator.name())
104 | given.volume.can_be_modified(id=_id, description=description)
105 |
106 | # action
107 | volume = api.volumes.get(_id)
108 | volume.description = description
109 | volume.save()
110 |
111 | # verifier
112 | assert volume.description == description
113 | verifier.volume.modified(volume.id)
114 |
115 |
116 | def test_volume_pagination(api, given):
117 | # preconditions
118 | limit = 2
119 | total = 10
120 | volume_id = 'test_volume'
121 | volume_data = {'id': volume_id}
122 |
123 | given.volume.paginated_file_list(
124 | limit=limit,
125 | volume_id=volume_id,
126 | num_of_files=total,
127 | volume_data=volume_data
128 | )
129 | volume = api.volumes.get(id=volume_id)
130 |
131 | # action
132 | item_list = volume.list(limit=limit)
133 | items = [item for item in item_list.all()]
134 |
135 | # verifier
136 | assert len(item_list) == limit
137 | assert len(items) == total
138 |
139 |
140 | def test_volume_get_member(api, given, verifier):
141 | # precondition
142 | member_username = generator.user_name()
143 | id = generator.slug()
144 | given.volume.exist(id=id)
145 | given.volume.has_member(id, member_username)
146 |
147 | # action
148 | volume = api.volumes.get(id)
149 | member = volume.get_member(member_username)
150 |
151 | # verification
152 | assert member.username == member_username
153 | verifier.volume.member_retrieved(id, member_username)
154 |
--------------------------------------------------------------------------------