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

Viridianforge/doc rewrite #34

Merged
merged 3 commits into from
Nov 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 0 additions & 2 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,3 @@ jobs:
- name: Test with pytest
run: |
pytest --cov-report=xml --cov=src/grpc_requests
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
28 changes: 28 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,34 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.1.12](pending) - Pending

## Added

- Method to print out a generic descriptor added to utils collection
- Helper methods to print out a method's request and responses in a human readable format

## Changed

- Documentation revamped
- Version checks to avoid using deprecated methods added to async client

## Deprecated

- Method to retrieve fields for the descriptor of a method's input type.

## Added

## [0.1.11](https://github.com/wesky93/grpc_requests/releases/tag/v0.1.11) - 2023-10-05

## Added

- Method to retrieve fields for the descriptor of a method's input type.

## Changes

- Updates to minimum versons of requirements to address vulnerabilities

## [0.1.10](https://github.com/wesky93/grpc_requests/releases/tag/v0.1.10) - 2023-03-07

## Fixed
Expand Down
144 changes: 35 additions & 109 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,151 +1,77 @@
# grpc requests
# grpc_requests

[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/grpc-requests?style=flat-square)](https://pypi.org/project/grpc-requests)
[![PyPI](https://img.shields.io/pypi/v/grpc-requests?style=flat-square)](https://pypi.org/project/grpc-requests)
[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/grpc-requests?style=flat-square)](https://pypi.org/project/grpc-requests)
[![PyPI download month](https://img.shields.io/pypi/dm/grpc-requests?style=flat-square)](https://pypi.org/project/grpc-requests)
[![codecov](https://codecov.io/gh/spaceone-dev/grpc_requests/branch/master/graph/badge.svg)](https://codecov.io/gh/spaceone-dev/grpc_requests)
![Views](https://views.whatilearened.today/views/github/spaceone-dev/grpc_requests.svg)
[![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
![Views](https://views.whatilearened.today/views/github/wesky93/grpc_requests.svg)

## GRPC for Humans

Leverage [reflection](https://github.com/grpc/grpc/blob/master/doc/server-reflection.md)
to interact with GRPC in a familiar manner for users of the [requests](https://requests.readthedocs.io/en/latest/) library.

```python
from grpc_requests import Client

client = Client.get_by_endpoint("localhost:50051")
assert client.service_names == ["helloworld.Greeter"]

request_data = {"name": 'sinsky'}
result = client.request("helloworld.Greeter", "SayHello", request_data)
print(result) # {"message":"Hello sinsky"}

request_data = {"name": "sinsky"}
say_hello_response = client.request("helloworld.Greeter", "SayHello", request_data)
assert say_hello_response == {"message":"Hello sinsky!"}
```

## Features

- supports creating clients easily when connecting to servers implementing grpc reflection
- supports implementing stub clients for connecting to servers that do not implement reflection
- support all unary and stream methods
- supports both TLS and compression connections
- supports AsyncIO API
- Create a client easily when connecting to servers implementing grpc reflection
- Still support creating a client from stubs when reflection isn't available
- All unary and stream methods supported
- TLS and compression connections supported
- AsyncIO API supported

## Install

```shell script
pip install grpc_requests
```

## Use it like RPC

If your server supports reflection, use the `Client` class:

```python
from grpc_requests import Client

client = Client.get_by_endpoint("localhost:50051")
# if you want a TLS connection
# client = Client.get_by_endpoint("localhost:443",ssl=True)
# or if you want a compression enabled connection
# client = Client.get_by_endpoint("localhost:443",compression=grpc.Compression.Gzip)
assert client.service_names == ["helloworld.Greeter",'grpc.health.v1.Health']

health = client.service('grpc.health.v1.Health')
assert health.method_names == ('Check', 'Watch')

result = health.Check()
assert result == {'status': 'SERVING'}
```

If not, use the `StubClient` class:

```python
from grpc_requests import StubClient
from .helloworld_pb2 import Descriptor

service_descriptor = DESCRIPTOR.services_by_name['Greeter'] # or you can just use _GREETER

## Usage

client = StubClient.get_by_endpoint("localhost:50051",service_descriptors=[service_descriptor,])
assert client.service_names == ["helloworld.Greeter"]
```
In short:

In both cases, the same methods are used to interact with the server.

```python
greeter = client.service("helloworld.Greeter")

request_data = {"name": 'sinsky'}
result = greeter.SayHello(request_data)
results = greeter.SayHelloGroup(request_data)

requests_data = [{"name": 'sinsky'}]
result = greeter.HelloEveryone(requests_data)
results = greeter.SayHelloOneByOne(requests_data)

```

## Examples

- [helloworld reflection client](src/examples/helloworld_reflection.py)

### Reflection Client but you can send message by stub
Instantiate a client using the URL of a GRPC server and any authentication
credentials you may need. If the server utilizes SSL (and it probably does)
make sure to toggle that flag.

```python
from grpc_requests import Client
from helloworld_pb2 import HelloRequest

port = '50051'
host = "localhost"
endpoint = f"{host}:{port}"

client = Client.get_by_endpoint(endpoint)
print(client.service_names) # ["helloworld.Greeter"]

service = "helloworld.Greeter"
method = 'SayHello'

result = client.unary_unary(service, method, HelloRequest(name='sinsky'))
print(type(result)) # result is dict Type!!! not Stub Object!
print(result) # {"message":"Hellow sinsky"}

# or get raw response data
result = client.unary_unary(service, method, HelloRequest(name='sinsky'),raw_output=True)
print(type(result)) # HelloReply stub class
metadata = [{"authorization":"bearer my.cool.jwt"}]
client = Client.get_by_endpoint("cool.servers.arecool:443", ssl=True, metadata=metadata)
```

### AsyncIO API

```python
from grpc_requests.aio import AsyncClient
The [examples page](./src/examples/README.md) provides more thorough examples of
usage scenarioes, and the [unit tests](./src/tests/) are also a useful reference point.

client = AsyncClient("localhost:50051")
## Contributing

health = await client.service('grpc.health.v1.Health')
assert health.method_names == ('Check', 'Watch')
Contributions from the community are welcomed and greatly appreciated.

result = await health.Check()
assert result == {'status': 'SERVING'}
Before opening a PR, [tests.sh](./tests.sh) can be used to ensure the contribution passes
linting and unit test checks.

greeter = await client.service("helloworld.Greeter")
PRs should be targeted to merge with the `develop` branch. When opening a PR,
please assign it to a maintainer for review. The maintainers will take it from
there.

request_data = {"name": 'sinsky'}
result = await greeter.SayHello(request_data)

results =[x async for x in await greeter.SayHelloGroup(request_data)]

requests_data = [{"name": 'sinsky'}]
result = await greeter.HelloEveryone(requests_data)
results = [x async for x in await greeter.SayHelloOneByOne(requests_data)]

```
## Questions, Comments, Issues?

## Road map
For questions, please start a conversation on the [discussions page](https://github.com/wesky93/grpc_requests/discussions)!

- [x] support no reflection server(Stub Client)
- [x] support async API!
- [ ] Document!
- [ ] pluggable interceptor
For feature requests or bugs, please open an [issue](https://github.com/wesky93/grpc_requests/issues) and assign it the appropriate tag.

## Maintainers

- sinsky - [wesky93](https://github.com/wesky93)
- Wayne Manselle - [ViridianForge](https://github.com/ViridianForge)
- Wayne Manselle - [ViridianForge](https://viridianforge.tech)
1 change: 1 addition & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ classifiers =
Programming Language :: Python :: 3.8
Programming Language :: Python :: 3.9
Programming Language :: Python :: 3.10
Programming Language :: Python :: 3.11
Topic :: Software Development :: Libraries :: Python Modules


Expand Down
Empty file.
20 changes: 0 additions & 20 deletions src/deprecated_test_cases/helloworld.proto

This file was deleted.

29 changes: 0 additions & 29 deletions src/deprecated_test_cases/helloworld_pb2.py

This file was deleted.

Loading