Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implements initial sync for v2 APIs #3

Merged
merged 31 commits into from
Oct 28, 2024
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
9d30359
chore(gitignore): ignore temporary files and folders
YaswanthKumar-eng Sep 17, 2024
0f2990c
chore(setup): initialize project structure and basic configuration
YaswanthKumar-eng Sep 17, 2024
725a33b
feat: implement v2 clients for sync and async operations
YaswanthKumar-eng Sep 17, 2024
6fc2706
chore(workflow): add GitHub Actions workflows directory
YaswanthKumar-eng Sep 17, 2024
70a6a75
feat(clients): updates sync and async clients
YaswanthKumar-eng Sep 20, 2024
5fcda9f
feat(v2SDK): updates v2 sdk clients
YaswanthKumar-eng Sep 23, 2024
5b796e5
chore: refactor and add from file function
guptadev21 Oct 21, 2024
b21496e
chore: add `get_token` and related methods to `Client` class
guptadev21 Oct 22, 2024
aff845f
chore: refactor
guptadev21 Oct 22, 2024
a915674
chore: update
guptadev21 Oct 22, 2024
2ee01ed
chore: update
guptadev21 Oct 22, 2024
ff01494
chore: update
guptadev21 Oct 22, 2024
99e0507
chore: add lint check
guptadev21 Oct 22, 2024
387cb43
chore: check on PR
guptadev21 Oct 22, 2024
8320905
chore: Update lint-check workflow and add CONTRIBUTING.md
guptadev21 Oct 22, 2024
35eb4d4
docs: Update README.md with Rapyuta IO SDK v2 information and contrib…
guptadev21 Oct 22, 2024
aa4660b
chore: remove things
guptadev21 Oct 23, 2024
e9b7367
chore: Update lint-check workflow and add CONTRIBUTING.md
guptadev21 Oct 23, 2024
038d953
chore: update
guptadev21 Oct 23, 2024
5c8c714
chore: update
guptadev21 Oct 23, 2024
066f255
chore: update
guptadev21 Oct 23, 2024
b929c7e
chore: Update
guptadev21 Oct 23, 2024
997cb9e
chore: add test files and list projects
guptadev21 Oct 24, 2024
3896d9e
chore: Update Python compatibility workflow and client.py
guptadev21 Oct 24, 2024
0b9144f
feat: add some functions
guptadev21 Oct 24, 2024
f1517ba
refactor: make the sdk work and cleanup
pallabpain Oct 28, 2024
e6b6bef
refactor: sync client
pallabpain Oct 28, 2024
86a70e8
refactor: remove async client
pallabpain Oct 28, 2024
7034692
test: fix broken test
pallabpain Oct 28, 2024
f25f486
ci: fix compatibility workflow
pallabpain Oct 28, 2024
e1796d6
docs: update readme
pallabpain Oct 28, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* @rapyuta-robotics/io-cli-owner @rapyuta-robotics/io-first-reviewer
20 changes: 20 additions & 0 deletions .github/workflows/conventional-commits.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: 💬 Check Commit Hygiene

on:
pull_request:
branches:
- main
- devel

jobs:
verify:
name: Conventional Commits
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
name: Checkout code

- uses: rapyuta-robotics/[email protected]
name: Check if commit messages are compliant
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
13 changes: 13 additions & 0 deletions .github/workflows/lint-check.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
name: "🧹 Ruff"

on: [pull_request]
pallabpain marked this conversation as resolved.
Show resolved Hide resolved

jobs:
lint:
name: Lint Check
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- uses: chartboost/ruff-action@v1
with:
args: "check"
11 changes: 11 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# python generated files
__pycache__/
*.py[oc]
build/
dist/
wheels/
*.egg-info

# venv
.venv
guptadev21 marked this conversation as resolved.
Show resolved Hide resolved
.ruff_cache
1 change: 1 addition & 0 deletions .python-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.12.5
38 changes: 38 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Contribution Guidelines
## 🌟 Setup Your Development Environment

The project uses [uv](https://docs.astral.sh/uv/) for development. It needs to be installed to set up the development environment.

```bash
curl -LsSf https://astral.sh/uv/install.sh | sh
```

Once `uv` is installed, a Python virtual environment can be quickly bootstrapped by running the following commands in the root of the repository:

```bash
uv venv
source .venv/bin/activate
```

This will create a virtual environment in the `.venv` directory and activate it.

Next, install all dependencies using the following command:

```bash
uv sync
```

New dependencies can be installed directly using `uv`. This modifies the `pyproject.toml` and `uv.lock`.

```bash
uv add <package-name>
```

### 🛠️ Linting and Formatting

You can check and fix the code style by running the following commands:

```bash
uvx ruff check --fix
uvx ruff format
```
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Rapyuta IO SDK v2
Rapyuta IO SDK v2 provides a comprehensive set of tools and functionalities to interact with the Rapyuta Robotics platform.

## Key Features

- 🚀 **Improved API Integration**: Seamless integration with Rapyuta Robotics APIs.
- ⚡ **Enhanced Performance**: Optimized for better performance and reduced latency.
- 🛠️ **Extended Functionality**: New modules and functions to support advanced robotics applications.
- 📚 **Better Documentation**: Comprehensive and easy-to-follow documentation.

## Contributing

We welcome contributions! Please read our [contributing guidelines](CONTRIBUTING.md) to get started.
24 changes: 24 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
[project]
name = "rapyuta-io-sdk-v2"
version = "0.1.0"
pallabpain marked this conversation as resolved.
Show resolved Hide resolved
description = "Version:2 for Rapyuta.io SDK"
dependencies = [
"httpx>=0.27.2",
"tenacity>=9.0.0",
]
readme = "README.md"
guptadev21 marked this conversation as resolved.
Show resolved Hide resolved
requires-python = ">= 3.8"

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[tool.rye]
managed = true
dev-dependencies = []

[tool.hatch.metadata]
allow-direct-references = true

[tool.hatch.build.targets.wheel]
packages = ["rapyuta_io_sdk_v2"]
1 change: 1 addition & 0 deletions rapyuta_io_sdk_v2/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# from rapyuta_io_sdk_v2.config import Configuration
46 changes: 46 additions & 0 deletions rapyuta_io_sdk_v2/async_client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# -*- coding: utf-8 -*-
# Copyright 2024 Rapyuta Robotics
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from contextlib import asynccontextmanager
from typing import AsyncGenerator

import httpx

from rapyuta_io_sdk_v2.client import Client
from rapyuta_io_sdk_v2.utils import handle_server_errors


class AsyncClient(Client):
def __init__(self, config):
super().__init__(config)

@asynccontextmanager
async def _get_client(self) -> AsyncGenerator[httpx.AsyncClient, None]:
async with httpx.AsyncClient(
headers=self._get_headers(),
) as async_client:
yield async_client

@staticmethod
async def get_token(self, email: str, password: str) -> str:
url = "{}/user/login/".format(self.v2api_host)
headers = {"Content-Type": "application/json"}
data = {"email": email, "password": password}
response = httpx.post(url=url, headers=headers, json=data, timeout=10)
handle_server_errors(response)
return response.json().get("token")

@staticmethod
async def expire_token(token: str) -> None:
pass
77 changes: 77 additions & 0 deletions rapyuta_io_sdk_v2/client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# -*- coding: utf-8 -*-
# Copyright 2024 Rapyuta Robotics
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from typing import Dict, Optional

import httpx

from rapyuta_io_sdk_v2.config import Configuration
from rapyuta_io_sdk_v2.constants import GET_USER_PATH
from rapyuta_io_sdk_v2.utils import handle_server_errors


class Client(object):
PROD_V2API_URL = "https://api.rapyuta.io"

def __init__(self, config: Configuration = None):
self.config = config
self.v2api_host = config.hosts.get("v2api_host", self.PROD_V2API_URL)

def _get_headers(self, with_project: bool = True) -> dict:
headers = {
"Authorization": "Bearer " + self.config.auth_token,
"Content-Type": "application/json",
"project": self.config.project_guid,
"organizationguid": self.config.organization_guid,
}
return headers

def get_authenticated_user(self) -> Optional[Dict]:
try:
_core_api_host = self.config.hosts.get("core_api_host")
url = "{}{}".format(_core_api_host, GET_USER_PATH)
headers = self._get_headers()
response = httpx.get(url=url, headers=headers, timeout=10)
handle_server_errors(response)
return response.json()
except Exception:
raise

@staticmethod
def get_token(self, email: str, password: str) -> str:
"""Get the authentication token for the user.

Args:
email (str)
password (str)

Returns:
str: authentication token
"""
url = "{}/user/login/".format(self.v2api_host)
headers = {"Content-Type": "application/json"}
data = {"email": email, "password": password}
response = httpx.post(url=url, headers=headers, json=data, timeout=10)
handle_server_errors(response)
return response.json().get("token")

@staticmethod
def expire_token(token: str) -> None:
pass

def set_project(self, project_guid: str):
self.config.project_guid = project_guid

def set_organization(self, organization_guid: str):
self.config.organization_guid = organization_guid
92 changes: 92 additions & 0 deletions rapyuta_io_sdk_v2/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# -*- coding: utf-8 -*-
# Copyright 2024 Rapyuta Robotics
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import json
from dataclasses import dataclass

from rapyuta_io_sdk_v2.constants import (
NAMED_ENVIRONMENTS,
PROD_ENVIRONMENT_SUBDOMAIN,
STAGING_ENVIRONMENT_SUBDOMAIN,
)
from rapyuta_io_sdk_v2.exceptions import (
ValidationError,
)


@dataclass
guptadev21 marked this conversation as resolved.
Show resolved Hide resolved
class Configuration(object):
email: str
_password: str
auth_token: str
project_guid: str
organization_guid: str
environment: str = "ga" # Default environment is prod

def __init__(
self,
project_guid: str,
organization_guid: str,
password: str = None,
auth_token: str = None,
environment: str = None,
email: str = None,
):
self.email = email
self._password = password
self.auth_token = auth_token
self.project_guid = project_guid
self.organization_guid = organization_guid
self.environment = environment
self.hosts = {}
self.set_environment(environment)

@staticmethod
def from_file(self, file_path: str) -> "Configuration":
with open(file_path, "r") as file:
guptadev21 marked this conversation as resolved.
Show resolved Hide resolved
data = json.load(file)
return Configuration(
email=data.get("email"),
password=data.get("password"),
project_guid=data.get("project_guid"),
organization_guid=data.get("organization_guid"),
environment=data.get("environment"),
)

def set_project(self, project) -> None:
self.project_guid = project
guptadev21 marked this conversation as resolved.
Show resolved Hide resolved

def set_organization(self, organization_guid) -> None:
guptadev21 marked this conversation as resolved.
Show resolved Hide resolved
self.organization_guid = organization_guid

def set_environment(self, name: str) -> None:
subdomain = PROD_ENVIRONMENT_SUBDOMAIN
if name is not None:
is_valid_env = name in NAMED_ENVIRONMENTS or name.startswith("pr")
if not is_valid_env:
raise ValidationError("Invalid environment")
subdomain = STAGING_ENVIRONMENT_SUBDOMAIN
else:
name = "ga"

catalog = "https://{}catalog.{}".format(name, subdomain)
core = "https://{}apiserver.{}".format(name, subdomain)
guptadev21 marked this conversation as resolved.
Show resolved Hide resolved
rip = "https://{}rip.{}".format(name, subdomain)
v2api = "https://{}api.{}".format(name, subdomain)

self.hosts["environment"] = name
self.hosts["catalog_host"] = catalog
self.hosts["core_api_host"] = core
pallabpain marked this conversation as resolved.
Show resolved Hide resolved
self.hosts["rip_host"] = rip
self.hosts["v2api_host"] = v2api
22 changes: 22 additions & 0 deletions rapyuta_io_sdk_v2/constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
# Copyright 2024 Rapyuta Robotics
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

LOGIN_ROUTE_PATH = "/user/login"
guptadev21 marked this conversation as resolved.
Show resolved Hide resolved
GET_USER_PATH = "/api/user/me/get"
guptadev21 marked this conversation as resolved.
Show resolved Hide resolved


STAGING_ENVIRONMENT_SUBDOMAIN = "apps.okd4v2.okd4beta.rapyuta.io"
PROD_ENVIRONMENT_SUBDOMAIN = "apps.okd4v2.prod.rapyuta.io"
NAMED_ENVIRONMENTS = ["v11", "v12", "v13", "v14", "v15", "qa", "dev"]
guptadev21 marked this conversation as resolved.
Show resolved Hide resolved
Loading
Loading