servicestack


Nameservicestack JSON
Version 0.1.3 PyPI version JSON
download
home_pagehttps://github.com/ServiceStack/servicestack-python
SummaryServiceStack Python Service Clients
upload_time2024-02-02 14:08:55
maintainer
docs_urlNone
authorServiceStack, Inc.
requires_python>=3.7
licenseBSD-3-Clause
keywords servicestack client dotnet
VCS
bugtrack_url
requirements typing_extensions requests dataclasses dataclasses-json marshmallow setuptools
Travis-CI No Travis.
coveralls test coverage No coveralls.
            ![ServiceStack and Python Banner](https://docs.servicestack.net/img/pages/servicestack-reference/python-reference.png)

ServiceStack's **Add ServiceStack Reference** feature allows clients to generate Native Types from directly within PyCharm using [ServiceStack IntelliJ Plugin](https://plugins.jetbrains.com/plugin/7749-servicestack/) - providing a simple way to give clients typed access to your ServiceStack Services.


[![](https://docs.servicestack.net/img/pages/servicestack-reference/python-add-servicestack-reference-youtube-splash.png)](https://youtu.be/WjbhfH45i5k)

> YouTube: [youtu.be/WjbhfH45i5k](https://youtu.be/WjbhfH45i5k)

### First class development experience

[Python](https://python.org) is one of the worlds most popular programming languages thanks to its ease of use and comprehensive libraries which sees it excels in many industries from education where it's often the first language taught in school to data science, machine learning and AI where it's often the dominant language used. To maximize the experience for calling ServiceStack APIs within these environments ServiceStack now supports Python as a 1st class Add ServiceStack Reference supported language which gives Python developers an end-to-end typed API for consuming ServiceStack APIs, complete with IDE integration in [PyCharm](https://www.jetbrains.com/pycharm/) as well as [built-in support in x dotnet tool](https://docs.servicestack.net/dotnet-tool#addupdate-servicestack-references) to generate Python DTOs for a remote ServiceStack instance from a single command-line.

### Ideal idiomatic Typed Message-based API

To maximize the utility of Python DTOs and enable richer tooling support, Python DTOs are generated as [dataclasses](https://docs.python.org/3/library/dataclasses.html) with support for [JSON serialization](https://pypi.org/project/dataclasses-json/) and annotated with Python 3 [type hints](https://docs.python.org/3/library/typing.html) - that's invaluable when scaling large Python code-bases and greatly improves discoverability of a remote API. DTOs are also enriched with interface markers through Python's multiple inheritance support which enables its optimal end-to-end typed API:

The Python DTOs and `JsonServiceClient` library follow Python's [PEP 8's naming conventions](https://www.python.org/dev/peps/pep-0008/) so they'll naturally fit into existing Python code bases. Here's a sample of [techstacks.io](https://techstacks.io) generated Python DTOs containing string and int Enums, an example AutoQuery and a standard Request & Response DTO showcasing the rich typing annotations and naming conventions used:

```python
class TechnologyTier(str, Enum):
    PROGRAMMING_LANGUAGE = 'ProgrammingLanguage'
    CLIENT = 'Client'
    HTTP = 'Http'
    SERVER = 'Server'
    DATA = 'Data'
    SOFTWARE_INFRASTRUCTURE = 'SoftwareInfrastructure'
    OPERATING_SYSTEM = 'OperatingSystem'
    HARDWARE_INFRASTRUCTURE = 'HardwareInfrastructure'
    THIRD_PARTY_SERVICES = 'ThirdPartyServices'

class Frequency(IntEnum):
    DAILY = 1
    WEEKLY = 7
    MONTHLY = 30
    QUARTERLY = 90

# @Route("/technology/search")
@dataclass_json(letter_case=LetterCase.CAMEL, undefined=Undefined.EXCLUDE)
@dataclass
class FindTechnologies(QueryDb2[Technology, TechnologyView], IReturn[QueryResponse[TechnologyView]], IGet):
    ids: Optional[List[int]] = None
    name: Optional[str] = None
    vendor_name: Optional[str] = None
    name_contains: Optional[str] = None
    vendor_name_contains: Optional[str] = None
    description_contains: Optional[str] = None

# @Route("/orgs/{Id}", "PUT")
@dataclass_json(letter_case=LetterCase.CAMEL, undefined=Undefined.EXCLUDE)
@dataclass
class UpdateOrganization(IReturn[UpdateOrganizationResponse], IPut):
    id: int = 0
    slug: Optional[str] = None
    name: Optional[str] = None
    description: Optional[str] = None
    color: Optional[str] = None
    text_color: Optional[str] = None
    link_color: Optional[str] = None
    background_color: Optional[str] = None
    background_url: Optional[str] = None
    logo_url: Optional[str] = None
    hero_url: Optional[str] = None
    lang: Optional[str] = None
    delete_posts_with_report_count: int = 0
    disable_invites: Optional[bool] = None
    default_post_type: Optional[str] = None
    default_subscription_post_types: Optional[List[str]] = None
    post_types: Optional[List[str]] = None
    moderator_post_types: Optional[List[str]] = None
    technology_ids: Optional[List[int]] = None

@dataclass_json(letter_case=LetterCase.CAMEL, undefined=Undefined.EXCLUDE)
@dataclass
class UpdateOrganizationResponse:
    response_status: Optional[ResponseStatus] = None
```

The smart Python `JsonServiceClient` available in the [servicestack](https://pypi.org/project/servicestack/) pip and conda packages enabling the same 
productive, typed API development experience available in our other 1st-class supported client platforms. 

Using [dataclasses](https://docs.python.org/3/library/dataclasses.html) enables DTOs to be populated using a single constructor expression utilizing named parameters which together with the generic `JsonServiceClient` enables end-to-end typed API Requests in a single LOC:

```python
from .dtos import *
from servicestack import JsonServiceClient

client = JsonServiceClient("https://test.servicestack.net")

response: HelloResponse = client.get(Hello(name="World"))
```

> The `HelloResponse` optional type hint doesn't change runtime behavior but enables static analysis tools and IDEs like PyCharm to provide rich intelli-sense and development time feedback.

## Installation

The only requirements for Python apps to perform typed API Requests are the generated Python DTOs and the generic `JsonServiceClient` which can be installed globally or in a virtual Python environment using [Python's pip](https://pypi.org/project/pip/):

    $ pip install servicestack

Or if preferred can be installed with [conda](https://conda.io):

    $ conda install conda-build.

 - Add conda-forge as channel using `conda config --add channels conda-forge`
 - On root directory run `conda build .`

### PyCharm ServiceStack Plugin

Python developers of [PyCharm](https://www.jetbrains.com/pycharm/) Professional and [FREE Community Edition](https://www.jetbrains.com/pycharm/features/#chooseYourEdition) can get a simplified development experience for consuming ServiceStack Services by installing the [ServiceStack Plugin](https://plugins.jetbrains.com/plugin/7749-servicestack) from the JetBrains Marketplace:

[![](https://docs.servicestack.net/img/pages/servicestack-reference/pycharm-servicestack-plugin.png)](https://plugins.jetbrains.com/plugin/7749-servicestack)

Where you'll be able to right-click on a directory and click on **ServiceStack Reference** on the context menu:

![](https://docs.servicestack.net/img/pages/servicestack-reference/pycharm-add-servicestack-reference.png)

To launch the **Add Python ServiceStack Reference** dialog where you can enter the remote URL of the ServiceStack endpoint you wish to call to generate the Typed Python DTOs for all APIs which by default will saved to `dtos.py`:

![](https://docs.servicestack.net/img/pages/servicestack-reference/pycharm-add-servicestack-reference-dialog.png)

Then just import the DTOs and `JsonServiceClient` to be able to consume any of the remote ServiceStack APIs:

```python
from .dtos import *
from servicestack import JsonServiceClient

client = JsonServiceClient("https://techstacks.io")

response = client.send(FindTechnologies(
    ids=[1, 2, 4, 6],
    vendor_name="Google",
    take=10))
```

If any of the the remote APIs change their DTOs can be updated by right-clicking on `dtos.py` and clicking **Update ServiceStack Reference**:

![](https://docs.servicestack.net/img/pages/servicestack-reference/pycharm-update-servicestack-reference.png)

### Simple command-line utility for Python

Developers using other Python IDEs and Text Editors like VS Code can utilize the cross-platform [`x` command line utility](https://docs.servicestack.net/dotnet-tool) for generating Python DTOs from the command-line.

To install first install the [latest .NET SDK](https://dotnet.microsoft.com/download) for your OS then install the [`x` dotnet tool](https://docs.servicestack.net/dotnet-tool) with:

    $ dotnet tool install --global x 

### Adding a ServiceStack Reference

To Add a Python ServiceStack Reference just call `x python` with the URL of a remote ServiceStack instance:

    $ x python https://techstacks.io

Result:

    Saved to: dtos.py

Calling `x python` with just a URL will save the DTOs using the Host name, you can override this by specifying a FileName as the 2nd argument:

    $ x python https://techstacks.io Tech

Result:

    Saved to: Tech.dtos.py

### Updating a ServiceStack Reference

To Update an existing ServiceStack Reference, call `x python` with the Filename:

    $ x python dtos.py

Result:

    Updated: dtos.py

Which will update the File with the latest Python Server DTOs from [techstacks.io](https://techstacks.io). You can also customize how DTOs are generated by uncommenting the [Python DTO Customization Options](https://docs.servicestack.net/#dto-customization-options) and updating them again.

### Updating all Python DTOs

Calling `x python` without any arguments will update all Python DTOs in the current directory:

    $ x python

Result:

    Updated: Tech.dtos.py
    Updated: dtos.py

### Smart Generic JsonServiceClient

The generic `JsonServiceClient` is a 1st class client with the same rich featureset of the smart ServiceClients in other [1st class supported languages](https://docs.servicestack.net/add-servicestack-reference#supported-languages) sporting a terse, typed flexible API with support for additional untyped params, custom URLs and HTTP Methods, dynamic response types including consuming API responses in raw text and binary data formats. Clients can be decorated to support generic functionality using instance and static Request, Response and Exception Filters.

It includes built-in support for a number of [ServiceStack Auth options](https://docs.servicestack.net/authentication-and-authorization) including [HTTP Basic Auth](https://en.wikipedia.org/wiki/Basic_access_authentication) and stateless Bearer Token Auth Providers like [API Key](https://docs.servicestack.net/api-key-authprovider) and [JWT Auth](https://docs.servicestack.net/jwt-authprovider) as well as [stateful Sessions](https://docs.servicestack.net/sessions) used by the popular **credentials** Auth Provider and an `on_authentication_required` callback for enabling custom authentication methods. The built-in auth options include auto-retry support for transparently authenticating and retrying authentication required requests as well as [Refresh Token Cookie](https://docs.servicestack.net/jwt-authprovider#refresh-token-cookies-supported-in-all-service-clients) support where it will transparently fetch new JWT Bearer Tokens automatically behind-the-scenes for friction-less stateless JWT support.

A snapshot of these above features is captured in the high-level public API below:

```python
class JsonServiceClient:
    base_url: str
    reply_base_url: str
    oneway_base_url: str
    headers: Optional[Dict[str, str]]
    bearer_token: Optional[str]
    refresh_token: Optional[str]
    refresh_token_uri: Optional[str]
    username: Optional[str]
    password: Optional[str]

    on_authentication_required: Callable[[], None]

    global_request_filter: Callable[[SendContext], None]  # static
    request_filter: Callable[[SendContext], None]

    global_response_filter: Callable[[Response], None]  # static
    response_filter: Callable[[Response], None]

    exception_filter: Callable[[Response, Exception], None]
    global_exception_filter: Callable[[Response, Exception], None]

    def __init__(self, base_url)

    def set_credentials(self, username, password)
    @property def token_cookie(self)
    @property def refresh_token_cookie(self)

    def get(self, request: IReturn[T], args: Dict[str, Any] = None) -> T
    def post(self, request: IReturn[T], body: Any = None, args: Dict[str, Any] = None) -> T
    def put(self, request: IReturn[T], body: Any = None, args: Dict[str, Any] = None) -> T
    def patch(self, request: IReturn[T], body: Any = None, args: Dict[str, Any] = None) -> T
    def delete(self, request: IReturn[T], args: Dict[str, Any] = None) -> T
    def options(self, request: IReturn[T], args: Dict[str, Any] = None) -> T
    def head(self, request: IReturn[T], args: Dict[str, Any] = None) -> T
    def send(self, request, method: Any = None, body: Any = None, args: Dict[str, Any] = None)

    def get_url(self, path: str, response_as: Type, args: Dict[str, Any] = None)
    def delete_url(self, path: str, response_as: Type, args: Dict[str, Any] = None)
    def options_url(self, path: str, response_as: Type, args: Dict[str, Any] = None)
    def head_url(self, path: str, response_as: Type, args: Dict[str, Any] = None)
    def post_url(self, path: str, body: Any = None, response_as: Type = None, args: Dict[str, Any] = None)
    def put_url(self, path: str, body: Any = None, response_as: Type = None, args: Dict[str, Any] = None)
    def patch_url(self, path: str, body: Any = None, response_as: Type = None, args: Dict[str, Any] = None)
    def send_url(self, path: str, method: str = None, response_as: Type = None, body: Any = None,
                 args: Dict[str, Any] = None)

    def send_all(self, request_dtos: List[IReturn[T]])  # Auto Batch Reply Requests
    def send_all_oneway(self, request_dtos: list)       # Auto Batch Oneway Requests
```

### Change Default Server Configuration

The above defaults are also overridable on the ServiceStack Server by modifying the default config on the `NativeTypesFeature` Plugin, e.g:

```csharp
var nativeTypes = this.GetPlugin<NativeTypesFeature>();
nativeTypes.MetadataTypesConfig.AddResponseStatus = true;
...
```

Python specific functionality can be added by `PythonGenerator`

```python
PythonGenerator.DefaultImports.Add("requests");
```

### Customize DTO Type generation

Additional Python specific customization can be statically configured like `PreTypeFilter`, `InnerTypeFilter` & `PostTypeFilter` (available in all languages) can be used to inject custom code in the generated DTOs output. 

Use the `PreTypeFilter` to generate source code before and after a Type definition, e.g. this will append the `Decorator` class decorator on non enum & interface types:

```csharp
PythonGenerator.PreTypeFilter = (sb, type) => {
    if (!type.IsEnum.GetValueOrDefault() && !type.IsInterface.GetValueOrDefault())
    {
        sb.AppendLine("@Decorator");
    }
};
```

The `InnerTypeFilter` gets invoked just after the Type Definition which can be used to generate common members for all Types and interfaces, e.g:

```csharp
PythonGenerator.InnerTypeFilter = (sb, type) => {
    sb.AppendLine("id:str = str(random.random())[2:]");
};
```

There's also `PrePropertyFilter` & `PostPropertyFilter` for generating source before and after properties, e.g:

```csharp
PythonGenerator.PrePropertyFilter = (sb , prop, type) => {
    if (prop.Name == "Id")
    {
        sb.AppendLine("@IsInt");
    }
};
```

### Emit custom code

To enable greater flexibility when generating complex Typed DTOs, you can use `[Emit{Language}]` attributes to generate code before each type or property.

These attributes can be used to generate different attributes or annotations to enable client validation for different validation libraries in different languages, e.g:

```csharp
[EmitCode(Lang.Python, "# App User")]
[EmitPython("@Validate")]
public class User : IReturn<User>
{
    [EmitPython("@IsNotEmpty", "@IsEmail")]
    [EmitCode(Lang.Swift | Lang.Dart, new[]{ "@isNotEmpty()", "@isEmail()" })]
    public string Email { get; set; }
}
```

Which will generate `[EmitPython]` code in Python DTOs:

```python
# App User
@Validate
@dataclass_json(letter_case=LetterCase.CAMEL, undefined=Undefined.EXCLUDE)
@dataclass
class User:
    @IsNotEmpty
    @IsEmail
    email: Optional[str] = None
```

Whilst the generic `[EmitCode]` attribute lets you emit the same code in multiple languages with the same syntax.

### Python Reference Example

Lets walk through a simple example to see how we can use ServiceStack's Python DTO annotations in our Python JsonServiceClient. Firstly we'll need to add a Python Reference to the remote ServiceStack Service by **right-clicking** on a project folder and clicking on `ServiceStack Reference...` (as seen in the above screenshot).

This will import the remote Services dtos into your local project which looks similar to:

```python
""" Options:
Date: 2021-08-14 15:33:39
Version: 5.111
Tip: To override a DTO option, remove "//" prefix before updating
BaseUrl: https://techstacks.io

#GlobalNamespace: 
#MakePropertiesOptional: False
#AddServiceStackTypes: True
#AddResponseStatus: False
#AddImplicitVersion: 
#AddDescriptionAsComments: True
#IncludeTypes: 
#ExcludeTypes: 
#DefaultImports: datetime,decimal,marshmallow.fields:*,servicestack:*,typing:*,dataclasses:dataclass/field,dataclasses_json:dataclass_json/LetterCase/Undefined/config,enum:Enum/IntEnum
#DataClass: 
#DataClassJson: 
"""

@dataclass_json(letter_case=LetterCase.CAMEL, undefined=Undefined.EXCLUDE)
@dataclass
class GetTechnologyResponse:
    created: datetime.datetime = datetime.datetime(1, 1, 1)
    technology: Optional[Technology] = None
    technology_stacks: Optional[List[TechnologyStack]] = None
    response_status: Optional[ResponseStatus] = None

# @Route("/technology/{Slug}")
@dataclass_json(letter_case=LetterCase.CAMEL, undefined=Undefined.EXCLUDE)
@dataclass
class GetTechnology(IReturn[GetTechnologyResponse], IRegisterStats, IGet):
    slug: Optional[str] = None
```

In keeping with idiomatic style of local `.py` sources, generated types are not wrapped within a module by default. This lets you reference the types you want directly using normal import destructuring syntax:

```python
from .dtos import GetTechnology, GetTechnologyResponse
```

Or import all Types into your preferred variable namespace with:

```python
from .dtos import *

request = GetTechnology()
```

### Making Typed API Requests

Making API Requests in Python is the same as all other [ServiceStack's Service Clients](https://docs.servicestack.net/clients-overview) by sending a populated Request DTO using a `JsonServiceClient` which returns typed Response DTO.

So the only things we need to make any API Request is the `JsonServiceClient` from the `servicestack` package and any DTO's we're using from generated Python ServiceStack Reference, e.g:

```python
from .dtos import GetTechnology, GetTechnologyResponse
from servicestack import JsonServiceClient

client = JsonServiceClient("https://techstacks.io")

request = GetTechnology()
request.slug = "ServiceStack"

r: GetTechnologyResponse = client.get(request)  # typed to GetTechnologyResponse
tech = r.technology                             # typed to Technology

print(f"{tech.name} by {tech.vendor_name} ({tech.product_url})")
print(f"`{tech.name} TechStacks: {r.technology_stacks}")
```

### Constructors Initializer

All Python Reference dataclass DTOs also implements **__init__** making them much nicer to populate using a constructor expression with named params syntax we're used to in C#, so instead of:

```python
request = Authenticate()
request.provider = "credentials"
request.user_name = user_name
request.password = password
request.remember_me = remember_me
response = client.post(request)
```

You can populate DTOs with a single constructor expression without any loss of Python's Typing benefits:

```python
response = client.post(Authenticate(
    provider='credentials',
    user_name=user_name,
    password=password,
    remember_me=remember_me))
```

### Sending additional arguments with Typed API Requests

Many AutoQuery Services utilize [implicit conventions](https://docs.servicestack.net/autoquery-rdbms#implicit-conventions) to query fields that aren't explicitly defined on AutoQuery Request DTOs, these can be queried by specifying additional arguments with the typed Request DTO, e.g:

```python
request = FindTechStacks()

r:QueryResponse[TechnologyStackView] = client.get(request, args={"vendorName": "ServiceStack"})
```

### Making API Requests with URLs

In addition to making Typed API Requests you can also call Services using relative or absolute urls, e.g:

```python
client.get("/technology/ServiceStack", response_as=GetTechnologyResponse)

client.get("https://techstacks.io/technology/ServiceStack", response_as=GetTechnologyResponse)

# https://techstacks.io/technology?Slug=ServiceStack
args = {"slug":"ServiceStack"}
client.get("/technology", args=args, response_as=GetTechnologyResponse) 
```

as well as POST Request DTOs to custom urls:

```python
client.post_url("/custom-path", request, args={"slug":"ServiceStack"})

client.post_url("http://example.org/custom-path", request)
```

### Raw Data Responses

The `JsonServiceClient` also supports Raw Data responses like `string` and `byte[]` which also get a Typed API once declared on Request DTOs using the `IReturn<T>` marker:

```csharp
public class ReturnString : IReturn<string> {}
public class ReturnBytes : IReturn<byte[]> {}
```

Which can then be accessed as normal, with their Response typed to a JavaScript `str` or `bytes` for raw `byte[]` responses:

```python
str:str = client.get(ReturnString())

data:bytes = client.get(ReturnBytes())
```

### Authenticating using Basic Auth

Basic Auth support is implemented in `JsonServiceClient` and follows the same API made available in the C# Service Clients where the `userName/password` properties can be set individually, e.g:

```python
client = JsonServiceClient(baseUrl)
client.username = user
client.password = pass

response = client.get(SecureRequest())
```

Or use `client.set_credentials()` to have them set both together.

### Authenticating using Credentials

Alternatively you can authenticate using userName/password credentials by 
[adding a Python Reference](#add-python-reference) 
to your remote ServiceStack Instance and sending a populated `Authenticate` Request DTO, e.g:

```python
request = Authenticate()
request.provider = "credentials"
request.user_name = user_name
request.password = password
request.remember_me = true

response:AuthenticateResponse = client.post(request)
```

This will populate the `JsonServiceClient` with [Session Cookies](https://docs.servicestack.net/sessions#cookie-session-ids) 
which will transparently be sent on subsequent requests to make authenticated requests.

### Authenticating using JWT

Use the `bearer_token` property to Authenticate with a [ServiceStack JWT Provider](https://docs.servicestack.net/jwt-authprovider) using a JWT Token:

```python
client.bearer_token = jwt
```

Alternatively you can use just a [Refresh Token](https://docs.servicestack.net/jwt-authprovider#refresh-tokens) instead:

```python
client.refresh_token = refresh_token
```

Where the client will automatically fetch a new JWT Bearer Token using the Refresh Token for authenticated requests.

### Authenticating using an API Key

Use the `bearer_token` property to Authenticate with an [API Key](https://docs.servicestack.net/api-key-authprovider):

```python
client.bearer_token = api_key
```

### Transparently handle 401 Unauthorized Responses

If the server returns a 401 Unauthorized Response either because the client was Unauthenticated or the 
configured Bearer Token or API Key used had expired or was invalidated, you can use `onAuthenticationRequired`
callback to re-configure the client before automatically retrying the original request, e.g:

```python
auth_client = JsonServiceClient(AUTH_URL)

client.on_authentication_required = lambda c=client, a=auth_client: [
    a.set_credentials(username, password),
    client.set_bearer_token(cast(AuthenticateResponse, a.get(Authenticate())).bearer_token)
]

# Automatically retries requests returning 401 Responses with new bearerToken
response = client.get(Secured())
```

### Automatically refresh Access Tokens

With the [Refresh Token support in JWT](https://docs.servicestack.net/jwt-authprovider#refresh-tokens) 
you can use the `refresh_token` property to instruct the Service Client to automatically fetch new JWT Tokens behind the scenes before automatically retrying failed requests due to invalid or expired JWTs, e.g:

```python
# Authenticate to get new Refresh Token
auth_client = JsonServiceClient(AUTH_URL)
auth_client.username = username
auth_client.password = password
auth_response = auth_client.get(Authenticate())

# Configure client with RefreshToken
client.refresh_token = auth_response.refresh_token

# Call authenticated Services and clients will automatically retrieve new JWT Tokens as needed
response = client.get(Secured())
```

Use the `refresh_token_uri` property when refresh tokens need to be sent to a different ServiceStack Server, e.g:

```python
client.refresh_token = refresh_token
client.refresh_token_uri = AUTH_URL + "/access-token"
```

## DTO Customization Options 

In most cases you'll just use the generated Python DTO's as-is, however you can further customize how the DTO's are generated by overriding the default options.

The header in the generated DTO's show the different options Python native types support with their defaults. Default values are shown with the comment prefix of `//`. To override a value, remove the `#` and specify the value to the right of the `:`. Any uncommented value will be sent to the server to override any server defaults.

The DTO comments allows for customizations for how DTOs are generated. The default options that were used to generate the DTO's are repeated in the header comments of the generated DTOs, options that are preceded by a Python comment `#` are defaults from the server, any uncommented value will be sent to the server 
to override any server defaults.

```python
""" Options:
Date: 2021-08-15 08:26:46
Version: 5.111
Tip: To override a DTO option, remove "#" prefix before updating
BaseUrl: https://techstacks.io

#GlobalNamespace: 
#MakePropertiesOptional: False
#AddServiceStackTypes: True
#AddResponseStatus: False
#AddImplicitVersion: 
#AddDescriptionAsComments: True
#IncludeTypes: 
#ExcludeTypes: 
#DefaultImports: datetime,decimal,marshmallow.fields:*,servicestack:*,typing:*,dataclasses:dataclass/field,dataclasses_json:dataclass_json/LetterCase/Undefined/config,enum:Enum/IntEnum
#DataClass: 
#DataClassJson: 
"""
```

We'll go through and cover each of the above options to see how they affect the generated DTO's:

### Change Default Server Configuration

The above defaults are also overridable on the ServiceStack Server by modifying the default config on the `NativeTypesFeature` Plugin, e.g:

```csharp
//Server example in C#
var nativeTypes = this.GetPlugin<NativeTypesFeature>();
nativeTypes.MetadataTypesConfig.AddResponseStatus = true;
...
```

We'll go through and cover each of the above options to see how they affect the generated DTO's:

### GlobalNamespace

As Python lacks the concept of namespaces this just emits a comment with the namespace name:

```python
# module dtos
```

### AddResponseStatus

Automatically add a `response_status` property on all Response DTO's, regardless if it wasn't already defined:

```python
class GetTechnologyResponse:
    ...
    response_status: Optional[ResponseStatus] = None
```

### AddImplicitVersion

Lets you specify the Version number to be automatically populated in all Request DTO's sent from the client: 

```python
class GetTechnology(IReturn[GetTechnologyResponse], IRegisterStats, IGet):
    version: int = 1
    ...
```

This lets you know what Version of the Service Contract that existing clients are using making it easy to implement ServiceStack's [recommended versioning strategy](http://stackoverflow.com/a/12413091/85785). 

### IncludeTypes

Is used as a Whitelist to specify only the types you would like to have code-generated:

```
""" Options:
IncludeTypes: GetTechnology,GetTechnologyResponse
```

Will only generate `GetTechnology` and `GetTechnologyResponse` DTO's:

```python
class GetTechnologyResponse:
    ...
class GetTechnology:
    ...
```

#### Include Generic Types

Use .NET's Type Name to include Generic Types, i.e. the Type name separated by the backtick followed by the number of generic arguments, e.g:

```
IncludeTypes: IReturn`1,MyPair`2
```

#### Include Request DTO and its dependent types

You can include a Request DTO and all its dependent types with a `.*` suffix on the Request DTO, e.g:

```
""" Options:
IncludeTypes: GetTechnology.*
```

Which will include the `GetTechnology` Request DTO, the `GetTechnologyResponse` Response DTO and all Types that they both reference.

#### Include All Types within a C# namespace

If your DTOs are grouped into different namespaces they can be all included using the `/*` suffix, e.g:

```
""" Options:
IncludeTypes: MyApp.ServiceModel.Admin/*
```

This will include all DTOs within the `MyApp.ServiceModel.Admin` C# namespace. 

#### Include All Services in a Tag Group

Services [grouped by Tag](https://docs.servicestack.net/api-design#group-services-by-tag) can be used in the `IncludeTypes` where tags can be specified using braces in the format `{tag}` or `{tag1,tag2,tag3}`, e.g:

```
""" Options:
IncludeTypes: {web,mobile}
```

Or individually:

```
""" Options:
IncludeTypes: {web},{mobile}
```

### ExcludeTypes
Is used as a Blacklist to specify which types you would like excluded from being generated:

```
""" Options:
ExcludeTypes: GetTechnology,GetTechnologyResponse
```

Will exclude `GetTechnology` and `GetTechnologyResponse` DTOs from being generated.

### DefaultImports

The `module:Symbols` short-hand syntax can be used for specifying additional imports in your generated Python DTO. There are 3 different syntaxes for specifying different Python imports:

```python
""" Options:
...
DefaultImports: datetime,typing:*,enum:Enum/IntEnum
"""
```

Which will generate the popular import form of:

```python
import datetime
from typing import *
from enum import Enum, IntEnum
```

### DataClass

Change what `dataclass` decorator is used, e.g:

```python
""" Options:
...
DataClass: init=False
"""
```

Will decorate every DTO with:

```python
@dataclass(init=False)
class GetTechnology(IReturn[GetTechnologyResponse], IRegisterStats, IGet):
    slug: Optional[str] = None
```


### DataClassJson

Change what `dataclass_json` decorator is used, e.g:

```python
""" Options:
...
DataClassJson: letter_case=LetterCase.PASCAL
"""
```

Will decorate every DTO with:

```python
@dataclass_json(letter_case=LetterCase.PASCAL)
class GetTechnology(IReturn[GetTechnologyResponse], IRegisterStats, IGet):
    slug: Optional[str] = None
```

Which will result in each type being serialized with PascalCase.

## Customize Serialization

The `servicestack` client lib allows for flexible serialization customization where you can change how different .NET Types are serialized and deserialized into native Python types.

To illustrate this we'll walk through how serialization of properties containing binary data to Base64 is implemented.

First we specify the Python DTO generator to emit `bytes` type hint for the popular .NET binary data types:

```csharp
PythonGenerator.TypeAliases[typeof(byte[]).Name] = "bytes";
PythonGenerator.TypeAliases[typeof(Stream).Name] = "bytes";
```

In the Python app we can then specify the serializers and deserializers to use for deserializing properties with the `bytes` data type which converts binary data to/from Base64:

```python
from servicestack import TypeConverters

def to_bytearray(value: Optional[bytes]):
    if value is None:
        return None
    return base64.b64encode(value).decode('ascii')

def from_bytearray(base64str: Optional[str]):
    return base64.b64decode(base64str)

TypeConverters.serializers[bytes] = to_bytearray
TypeConverters.deserializers[bytes] = from_bytearray
```

## Inspect Utils

To help clients with inspecting API Responses the `servicestack` library also includes a number of helpful utils to quickly visualizing API outputs.

For a basic indented object graph you can use `dump` to capture and `printdump` to print the output of any API Response, e.g:

```python
from dataclasses import dataclass
from dataclasses_json import dataclass_json, Undefined
from typing import Optional
from servicestack import printdump, printtable

@dataclass_json(undefined=Undefined.EXCLUDE)
@dataclass
class GithubRepo:
    name: str
    description: Optional[str] = None
    homepage: Optional[str] = None
    lang: Optional[str] = field(metadata=config(field_name="language"),default=None)
    watchers: Optional[int] = 0
    forks: Optional[int] = 0

response = requests.get(f'https://api.github.com/orgs/python/repos')
orgRepos = GithubRepo.schema().loads(response.text, many=True)
orgRepos.sort(key=operator.attrgetter('watchers'), reverse=True)

print(f'Top 3 {orgName} Repos:')
printdump(orgRepos[0:3])
```

Output:

```
Top 3 python Repos:
[
    {
        name: mypy,
        description: Optional static typing for Python 3 and 2 (PEP 484),
        homepage: http://www.mypy-lang.org/,
        lang: Python,
        watchers: 9638,
        forks: 1564
    },
    {
        name: peps,
        description: Python Enhancement Proposals,
        homepage: https://www.python.org/dev/peps/,
        lang: Python,
        watchers: 2459,
        forks: 921
    },
    {
        name: typeshed,
        description: Collection of library stubs for Python, with static types,
        homepage: ,
        lang: Python,
        watchers: 1942,
        forks: 972
    }
]
```

For tabular resultsets you can use `table` to capture and `printtable` to print API resultsets in a human-friendly markdown table with an optional `headers` parameter to specify the order and columns to display, e.g:

```python
print(f'\nTop 10 {orgName} Repos:')
printtable(orgRepos[0:10],headers=['name','lang','watchers','forks'])
```

Output:

```
Top 10 python Repos:
+--------------+-----------+------------+---------+
| name         | lang      |   watchers |   forks |
|--------------+-----------+------------+---------|
| mypy         | Python    |       9638 |    1564 |
| peps         | Python    |       2459 |     921 |
| typeshed     | Python    |       1942 |     972 |
| pythondotorg | Python    |       1038 |     432 |
| asyncio      |           |        945 |     178 |
| typing       | Python    |        840 |     130 |
| raspberryio  | Python    |        217 |      38 |
| typed_ast    | C         |        171 |      43 |
| planet       | Python    |        100 |     145 |
| psf-salt     | SaltStack |         87 |      50 |
+--------------+-----------+------------+---------+
```

Alternatively you can use `htmldump` to generate API responses in a HTML UI which is especially useful in [Python Jupyter Notebooks](https://docs.servicestack.net/jupyter-notebooks-python) to easily visualize API responses, e.g:

[![](https://docs.servicestack.net/img/pages/apps/jupyterlab-mybinder-techstacks.png)](https://github.com/ServiceStack/jupyter-notebooks/blob/main/techstacks.io-FindTechnologies.ipynb)

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/ServiceStack/servicestack-python",
    "name": "servicestack",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.7",
    "maintainer_email": "",
    "keywords": "servicestack,client,dotnet",
    "author": "ServiceStack, Inc.",
    "author_email": "team@servicestack.net",
    "download_url": "https://files.pythonhosted.org/packages/7e/84/86f137be988023166712b67c15f13d26f5aae3697421e5ff133bccbec2de/servicestack-0.1.3.tar.gz",
    "platform": null,
    "description": "![ServiceStack and Python Banner](https://docs.servicestack.net/img/pages/servicestack-reference/python-reference.png)\r\n\r\nServiceStack's **Add ServiceStack Reference** feature allows clients to generate Native Types from directly within PyCharm using [ServiceStack IntelliJ Plugin](https://plugins.jetbrains.com/plugin/7749-servicestack/) - providing a simple way to give clients typed access to your ServiceStack Services.\r\n\r\n\r\n[![](https://docs.servicestack.net/img/pages/servicestack-reference/python-add-servicestack-reference-youtube-splash.png)](https://youtu.be/WjbhfH45i5k)\r\n\r\n> YouTube: [youtu.be/WjbhfH45i5k](https://youtu.be/WjbhfH45i5k)\r\n\r\n### First class development experience\r\n\r\n[Python](https://python.org) is one of the worlds most popular programming languages thanks to its ease of use and comprehensive libraries which sees it excels in many industries from education where it's often the first language taught in school to data science, machine learning and AI where it's often the dominant language used. To maximize the experience for calling ServiceStack APIs within these environments ServiceStack now supports Python as a 1st class Add ServiceStack Reference supported language which gives Python developers an end-to-end typed API for consuming ServiceStack APIs, complete with IDE integration in [PyCharm](https://www.jetbrains.com/pycharm/) as well as [built-in support in x dotnet tool](https://docs.servicestack.net/dotnet-tool#addupdate-servicestack-references) to generate Python DTOs for a remote ServiceStack instance from a single command-line.\r\n\r\n### Ideal idiomatic Typed Message-based API\r\n\r\nTo maximize the utility of Python DTOs and enable richer tooling support, Python DTOs are generated as [dataclasses](https://docs.python.org/3/library/dataclasses.html) with support for [JSON serialization](https://pypi.org/project/dataclasses-json/) and annotated with Python 3 [type hints](https://docs.python.org/3/library/typing.html) - that's invaluable when scaling large Python code-bases and greatly improves discoverability of a remote API. DTOs are also enriched with interface markers through Python's multiple inheritance support which enables its optimal end-to-end typed API:\r\n\r\nThe Python DTOs and `JsonServiceClient` library follow Python's [PEP 8's naming conventions](https://www.python.org/dev/peps/pep-0008/) so they'll naturally fit into existing Python code bases. Here's a sample of [techstacks.io](https://techstacks.io) generated Python DTOs containing string and int Enums, an example AutoQuery and a standard Request & Response DTO showcasing the rich typing annotations and naming conventions used:\r\n\r\n```python\r\nclass TechnologyTier(str, Enum):\r\n    PROGRAMMING_LANGUAGE = 'ProgrammingLanguage'\r\n    CLIENT = 'Client'\r\n    HTTP = 'Http'\r\n    SERVER = 'Server'\r\n    DATA = 'Data'\r\n    SOFTWARE_INFRASTRUCTURE = 'SoftwareInfrastructure'\r\n    OPERATING_SYSTEM = 'OperatingSystem'\r\n    HARDWARE_INFRASTRUCTURE = 'HardwareInfrastructure'\r\n    THIRD_PARTY_SERVICES = 'ThirdPartyServices'\r\n\r\nclass Frequency(IntEnum):\r\n    DAILY = 1\r\n    WEEKLY = 7\r\n    MONTHLY = 30\r\n    QUARTERLY = 90\r\n\r\n# @Route(\"/technology/search\")\r\n@dataclass_json(letter_case=LetterCase.CAMEL, undefined=Undefined.EXCLUDE)\r\n@dataclass\r\nclass FindTechnologies(QueryDb2[Technology, TechnologyView], IReturn[QueryResponse[TechnologyView]], IGet):\r\n    ids: Optional[List[int]] = None\r\n    name: Optional[str] = None\r\n    vendor_name: Optional[str] = None\r\n    name_contains: Optional[str] = None\r\n    vendor_name_contains: Optional[str] = None\r\n    description_contains: Optional[str] = None\r\n\r\n# @Route(\"/orgs/{Id}\", \"PUT\")\r\n@dataclass_json(letter_case=LetterCase.CAMEL, undefined=Undefined.EXCLUDE)\r\n@dataclass\r\nclass UpdateOrganization(IReturn[UpdateOrganizationResponse], IPut):\r\n    id: int = 0\r\n    slug: Optional[str] = None\r\n    name: Optional[str] = None\r\n    description: Optional[str] = None\r\n    color: Optional[str] = None\r\n    text_color: Optional[str] = None\r\n    link_color: Optional[str] = None\r\n    background_color: Optional[str] = None\r\n    background_url: Optional[str] = None\r\n    logo_url: Optional[str] = None\r\n    hero_url: Optional[str] = None\r\n    lang: Optional[str] = None\r\n    delete_posts_with_report_count: int = 0\r\n    disable_invites: Optional[bool] = None\r\n    default_post_type: Optional[str] = None\r\n    default_subscription_post_types: Optional[List[str]] = None\r\n    post_types: Optional[List[str]] = None\r\n    moderator_post_types: Optional[List[str]] = None\r\n    technology_ids: Optional[List[int]] = None\r\n\r\n@dataclass_json(letter_case=LetterCase.CAMEL, undefined=Undefined.EXCLUDE)\r\n@dataclass\r\nclass UpdateOrganizationResponse:\r\n    response_status: Optional[ResponseStatus] = None\r\n```\r\n\r\nThe smart Python `JsonServiceClient` available in the [servicestack](https://pypi.org/project/servicestack/) pip and conda packages enabling the same \r\nproductive, typed API development experience available in our other 1st-class supported client platforms. \r\n\r\nUsing [dataclasses](https://docs.python.org/3/library/dataclasses.html) enables DTOs to be populated using a single constructor expression utilizing named parameters which together with the generic `JsonServiceClient` enables end-to-end typed API Requests in a single LOC:\r\n\r\n```python\r\nfrom .dtos import *\r\nfrom servicestack import JsonServiceClient\r\n\r\nclient = JsonServiceClient(\"https://test.servicestack.net\")\r\n\r\nresponse: HelloResponse = client.get(Hello(name=\"World\"))\r\n```\r\n\r\n> The `HelloResponse` optional type hint doesn't change runtime behavior but enables static analysis tools and IDEs like PyCharm to provide rich intelli-sense and development time feedback.\r\n\r\n## Installation\r\n\r\nThe only requirements for Python apps to perform typed API Requests are the generated Python DTOs and the generic `JsonServiceClient` which can be installed globally or in a virtual Python environment using [Python's pip](https://pypi.org/project/pip/):\r\n\r\n    $ pip install servicestack\r\n\r\nOr if preferred can be installed with [conda](https://conda.io):\r\n\r\n    $ conda install conda-build.\r\n\r\n - Add conda-forge as channel using `conda config --add channels conda-forge`\r\n - On root directory run `conda build .`\r\n\r\n### PyCharm ServiceStack Plugin\r\n\r\nPython developers of [PyCharm](https://www.jetbrains.com/pycharm/) Professional and [FREE Community Edition](https://www.jetbrains.com/pycharm/features/#chooseYourEdition) can get a simplified development experience for consuming ServiceStack Services by installing the [ServiceStack Plugin](https://plugins.jetbrains.com/plugin/7749-servicestack) from the JetBrains Marketplace:\r\n\r\n[![](https://docs.servicestack.net/img/pages/servicestack-reference/pycharm-servicestack-plugin.png)](https://plugins.jetbrains.com/plugin/7749-servicestack)\r\n\r\nWhere you'll be able to right-click on a directory and click on **ServiceStack Reference** on the context menu:\r\n\r\n![](https://docs.servicestack.net/img/pages/servicestack-reference/pycharm-add-servicestack-reference.png)\r\n\r\nTo launch the **Add Python ServiceStack Reference** dialog where you can enter the remote URL of the ServiceStack endpoint you wish to call to generate the Typed Python DTOs for all APIs which by default will saved to `dtos.py`:\r\n\r\n![](https://docs.servicestack.net/img/pages/servicestack-reference/pycharm-add-servicestack-reference-dialog.png)\r\n\r\nThen just import the DTOs and `JsonServiceClient` to be able to consume any of the remote ServiceStack APIs:\r\n\r\n```python\r\nfrom .dtos import *\r\nfrom servicestack import JsonServiceClient\r\n\r\nclient = JsonServiceClient(\"https://techstacks.io\")\r\n\r\nresponse = client.send(FindTechnologies(\r\n    ids=[1, 2, 4, 6],\r\n    vendor_name=\"Google\",\r\n    take=10))\r\n```\r\n\r\nIf any of the the remote APIs change their DTOs can be updated by right-clicking on `dtos.py` and clicking **Update ServiceStack Reference**:\r\n\r\n![](https://docs.servicestack.net/img/pages/servicestack-reference/pycharm-update-servicestack-reference.png)\r\n\r\n### Simple command-line utility for Python\r\n\r\nDevelopers using other Python IDEs and Text Editors like VS Code can utilize the cross-platform [`x` command line utility](https://docs.servicestack.net/dotnet-tool) for generating Python DTOs from the command-line.\r\n\r\nTo install first install the [latest .NET SDK](https://dotnet.microsoft.com/download) for your OS then install the [`x` dotnet tool](https://docs.servicestack.net/dotnet-tool) with:\r\n\r\n    $ dotnet tool install --global x \r\n\r\n### Adding a ServiceStack Reference\r\n\r\nTo Add a Python ServiceStack Reference just call `x python` with the URL of a remote ServiceStack instance:\r\n\r\n    $ x python https://techstacks.io\r\n\r\nResult:\r\n\r\n    Saved to: dtos.py\r\n\r\nCalling `x python` with just a URL will save the DTOs using the Host name, you can override this by specifying a FileName as the 2nd argument:\r\n\r\n    $ x python https://techstacks.io Tech\r\n\r\nResult:\r\n\r\n    Saved to: Tech.dtos.py\r\n\r\n### Updating a ServiceStack Reference\r\n\r\nTo Update an existing ServiceStack Reference, call `x python` with the Filename:\r\n\r\n    $ x python dtos.py\r\n\r\nResult:\r\n\r\n    Updated: dtos.py\r\n\r\nWhich will update the File with the latest Python Server DTOs from [techstacks.io](https://techstacks.io). You can also customize how DTOs are generated by uncommenting the [Python DTO Customization Options](https://docs.servicestack.net/#dto-customization-options) and updating them again.\r\n\r\n### Updating all Python DTOs\r\n\r\nCalling `x python` without any arguments will update all Python DTOs in the current directory:\r\n\r\n    $ x python\r\n\r\nResult:\r\n\r\n    Updated: Tech.dtos.py\r\n    Updated: dtos.py\r\n\r\n### Smart Generic JsonServiceClient\r\n\r\nThe generic `JsonServiceClient` is a 1st class client with the same rich featureset of the smart ServiceClients in other [1st class supported languages](https://docs.servicestack.net/add-servicestack-reference#supported-languages) sporting a terse, typed flexible API with support for additional untyped params, custom URLs and HTTP Methods, dynamic response types including consuming API responses in raw text and binary data formats. Clients can be decorated to support generic functionality using instance and static Request, Response and Exception Filters.\r\n\r\nIt includes built-in support for a number of [ServiceStack Auth options](https://docs.servicestack.net/authentication-and-authorization) including [HTTP Basic Auth](https://en.wikipedia.org/wiki/Basic_access_authentication) and stateless Bearer Token Auth Providers like [API Key](https://docs.servicestack.net/api-key-authprovider) and [JWT Auth](https://docs.servicestack.net/jwt-authprovider) as well as [stateful Sessions](https://docs.servicestack.net/sessions) used by the popular **credentials** Auth Provider and an `on_authentication_required` callback for enabling custom authentication methods. The built-in auth options include auto-retry support for transparently authenticating and retrying authentication required requests as well as [Refresh Token Cookie](https://docs.servicestack.net/jwt-authprovider#refresh-token-cookies-supported-in-all-service-clients) support where it will transparently fetch new JWT Bearer Tokens automatically behind-the-scenes for friction-less stateless JWT support.\r\n\r\nA snapshot of these above features is captured in the high-level public API below:\r\n\r\n```python\r\nclass JsonServiceClient:\r\n    base_url: str\r\n    reply_base_url: str\r\n    oneway_base_url: str\r\n    headers: Optional[Dict[str, str]]\r\n    bearer_token: Optional[str]\r\n    refresh_token: Optional[str]\r\n    refresh_token_uri: Optional[str]\r\n    username: Optional[str]\r\n    password: Optional[str]\r\n\r\n    on_authentication_required: Callable[[], None]\r\n\r\n    global_request_filter: Callable[[SendContext], None]  # static\r\n    request_filter: Callable[[SendContext], None]\r\n\r\n    global_response_filter: Callable[[Response], None]  # static\r\n    response_filter: Callable[[Response], None]\r\n\r\n    exception_filter: Callable[[Response, Exception], None]\r\n    global_exception_filter: Callable[[Response, Exception], None]\r\n\r\n    def __init__(self, base_url)\r\n\r\n    def set_credentials(self, username, password)\r\n    @property def token_cookie(self)\r\n    @property def refresh_token_cookie(self)\r\n\r\n    def get(self, request: IReturn[T], args: Dict[str, Any] = None) -> T\r\n    def post(self, request: IReturn[T], body: Any = None, args: Dict[str, Any] = None) -> T\r\n    def put(self, request: IReturn[T], body: Any = None, args: Dict[str, Any] = None) -> T\r\n    def patch(self, request: IReturn[T], body: Any = None, args: Dict[str, Any] = None) -> T\r\n    def delete(self, request: IReturn[T], args: Dict[str, Any] = None) -> T\r\n    def options(self, request: IReturn[T], args: Dict[str, Any] = None) -> T\r\n    def head(self, request: IReturn[T], args: Dict[str, Any] = None) -> T\r\n    def send(self, request, method: Any = None, body: Any = None, args: Dict[str, Any] = None)\r\n\r\n    def get_url(self, path: str, response_as: Type, args: Dict[str, Any] = None)\r\n    def delete_url(self, path: str, response_as: Type, args: Dict[str, Any] = None)\r\n    def options_url(self, path: str, response_as: Type, args: Dict[str, Any] = None)\r\n    def head_url(self, path: str, response_as: Type, args: Dict[str, Any] = None)\r\n    def post_url(self, path: str, body: Any = None, response_as: Type = None, args: Dict[str, Any] = None)\r\n    def put_url(self, path: str, body: Any = None, response_as: Type = None, args: Dict[str, Any] = None)\r\n    def patch_url(self, path: str, body: Any = None, response_as: Type = None, args: Dict[str, Any] = None)\r\n    def send_url(self, path: str, method: str = None, response_as: Type = None, body: Any = None,\r\n                 args: Dict[str, Any] = None)\r\n\r\n    def send_all(self, request_dtos: List[IReturn[T]])  # Auto Batch Reply Requests\r\n    def send_all_oneway(self, request_dtos: list)       # Auto Batch Oneway Requests\r\n```\r\n\r\n### Change Default Server Configuration\r\n\r\nThe above defaults are also overridable on the ServiceStack Server by modifying the default config on the `NativeTypesFeature` Plugin, e.g:\r\n\r\n```csharp\r\nvar nativeTypes = this.GetPlugin<NativeTypesFeature>();\r\nnativeTypes.MetadataTypesConfig.AddResponseStatus = true;\r\n...\r\n```\r\n\r\nPython specific functionality can be added by `PythonGenerator`\r\n\r\n```python\r\nPythonGenerator.DefaultImports.Add(\"requests\");\r\n```\r\n\r\n### Customize DTO Type generation\r\n\r\nAdditional Python specific customization can be statically configured like `PreTypeFilter`, `InnerTypeFilter` & `PostTypeFilter` (available in all languages) can be used to inject custom code in the generated DTOs output. \r\n\r\nUse the `PreTypeFilter` to generate source code before and after a Type definition, e.g. this will append the `Decorator` class decorator on non enum & interface types:\r\n\r\n```csharp\r\nPythonGenerator.PreTypeFilter = (sb, type) => {\r\n    if (!type.IsEnum.GetValueOrDefault() && !type.IsInterface.GetValueOrDefault())\r\n    {\r\n        sb.AppendLine(\"@Decorator\");\r\n    }\r\n};\r\n```\r\n\r\nThe `InnerTypeFilter` gets invoked just after the Type Definition which can be used to generate common members for all Types and interfaces, e.g:\r\n\r\n```csharp\r\nPythonGenerator.InnerTypeFilter = (sb, type) => {\r\n    sb.AppendLine(\"id:str = str(random.random())[2:]\");\r\n};\r\n```\r\n\r\nThere's also `PrePropertyFilter` & `PostPropertyFilter` for generating source before and after properties, e.g:\r\n\r\n```csharp\r\nPythonGenerator.PrePropertyFilter = (sb , prop, type) => {\r\n    if (prop.Name == \"Id\")\r\n    {\r\n        sb.AppendLine(\"@IsInt\");\r\n    }\r\n};\r\n```\r\n\r\n### Emit custom code\r\n\r\nTo enable greater flexibility when generating complex Typed DTOs, you can use `[Emit{Language}]` attributes to generate code before each type or property.\r\n\r\nThese attributes can be used to generate different attributes or annotations to enable client validation for different validation libraries in different languages, e.g:\r\n\r\n```csharp\r\n[EmitCode(Lang.Python, \"# App User\")]\r\n[EmitPython(\"@Validate\")]\r\npublic class User : IReturn<User>\r\n{\r\n    [EmitPython(\"@IsNotEmpty\", \"@IsEmail\")]\r\n    [EmitCode(Lang.Swift | Lang.Dart, new[]{ \"@isNotEmpty()\", \"@isEmail()\" })]\r\n    public string Email { get; set; }\r\n}\r\n```\r\n\r\nWhich will generate `[EmitPython]` code in Python DTOs:\r\n\r\n```python\r\n# App User\r\n@Validate\r\n@dataclass_json(letter_case=LetterCase.CAMEL, undefined=Undefined.EXCLUDE)\r\n@dataclass\r\nclass User:\r\n    @IsNotEmpty\r\n    @IsEmail\r\n    email: Optional[str] = None\r\n```\r\n\r\nWhilst the generic `[EmitCode]` attribute lets you emit the same code in multiple languages with the same syntax.\r\n\r\n### Python Reference Example\r\n\r\nLets walk through a simple example to see how we can use ServiceStack's Python DTO annotations in our Python JsonServiceClient. Firstly we'll need to add a Python Reference to the remote ServiceStack Service by **right-clicking** on a project folder and clicking on `ServiceStack Reference...` (as seen in the above screenshot).\r\n\r\nThis will import the remote Services dtos into your local project which looks similar to:\r\n\r\n```python\r\n\"\"\" Options:\r\nDate: 2021-08-14 15:33:39\r\nVersion: 5.111\r\nTip: To override a DTO option, remove \"//\" prefix before updating\r\nBaseUrl: https://techstacks.io\r\n\r\n#GlobalNamespace: \r\n#MakePropertiesOptional: False\r\n#AddServiceStackTypes: True\r\n#AddResponseStatus: False\r\n#AddImplicitVersion: \r\n#AddDescriptionAsComments: True\r\n#IncludeTypes: \r\n#ExcludeTypes: \r\n#DefaultImports: datetime,decimal,marshmallow.fields:*,servicestack:*,typing:*,dataclasses:dataclass/field,dataclasses_json:dataclass_json/LetterCase/Undefined/config,enum:Enum/IntEnum\r\n#DataClass: \r\n#DataClassJson: \r\n\"\"\"\r\n\r\n@dataclass_json(letter_case=LetterCase.CAMEL, undefined=Undefined.EXCLUDE)\r\n@dataclass\r\nclass GetTechnologyResponse:\r\n    created: datetime.datetime = datetime.datetime(1, 1, 1)\r\n    technology: Optional[Technology] = None\r\n    technology_stacks: Optional[List[TechnologyStack]] = None\r\n    response_status: Optional[ResponseStatus] = None\r\n\r\n# @Route(\"/technology/{Slug}\")\r\n@dataclass_json(letter_case=LetterCase.CAMEL, undefined=Undefined.EXCLUDE)\r\n@dataclass\r\nclass GetTechnology(IReturn[GetTechnologyResponse], IRegisterStats, IGet):\r\n    slug: Optional[str] = None\r\n```\r\n\r\nIn keeping with idiomatic style of local `.py` sources, generated types are not wrapped within a module by default. This lets you reference the types you want directly using normal import destructuring syntax:\r\n\r\n```python\r\nfrom .dtos import GetTechnology, GetTechnologyResponse\r\n```\r\n\r\nOr import all Types into your preferred variable namespace with:\r\n\r\n```python\r\nfrom .dtos import *\r\n\r\nrequest = GetTechnology()\r\n```\r\n\r\n### Making Typed API Requests\r\n\r\nMaking API Requests in Python is the same as all other [ServiceStack's Service Clients](https://docs.servicestack.net/clients-overview) by sending a populated Request DTO using a `JsonServiceClient` which returns typed Response DTO.\r\n\r\nSo the only things we need to make any API Request is the `JsonServiceClient` from the `servicestack` package and any DTO's we're using from generated Python ServiceStack Reference, e.g:\r\n\r\n```python\r\nfrom .dtos import GetTechnology, GetTechnologyResponse\r\nfrom servicestack import JsonServiceClient\r\n\r\nclient = JsonServiceClient(\"https://techstacks.io\")\r\n\r\nrequest = GetTechnology()\r\nrequest.slug = \"ServiceStack\"\r\n\r\nr: GetTechnologyResponse = client.get(request)  # typed to GetTechnologyResponse\r\ntech = r.technology                             # typed to Technology\r\n\r\nprint(f\"{tech.name} by {tech.vendor_name} ({tech.product_url})\")\r\nprint(f\"`{tech.name} TechStacks: {r.technology_stacks}\")\r\n```\r\n\r\n### Constructors Initializer\r\n\r\nAll Python Reference dataclass DTOs also implements **__init__** making them much nicer to populate using a constructor expression with named params syntax we're used to in C#, so instead of:\r\n\r\n```python\r\nrequest = Authenticate()\r\nrequest.provider = \"credentials\"\r\nrequest.user_name = user_name\r\nrequest.password = password\r\nrequest.remember_me = remember_me\r\nresponse = client.post(request)\r\n```\r\n\r\nYou can populate DTOs with a single constructor expression without any loss of Python's Typing benefits:\r\n\r\n```python\r\nresponse = client.post(Authenticate(\r\n    provider='credentials',\r\n    user_name=user_name,\r\n    password=password,\r\n    remember_me=remember_me))\r\n```\r\n\r\n### Sending additional arguments with Typed API Requests\r\n\r\nMany AutoQuery Services utilize [implicit conventions](https://docs.servicestack.net/autoquery-rdbms#implicit-conventions) to query fields that aren't explicitly defined on AutoQuery Request DTOs, these can be queried by specifying additional arguments with the typed Request DTO, e.g:\r\n\r\n```python\r\nrequest = FindTechStacks()\r\n\r\nr:QueryResponse[TechnologyStackView] = client.get(request, args={\"vendorName\": \"ServiceStack\"})\r\n```\r\n\r\n### Making API Requests with URLs\r\n\r\nIn addition to making Typed API Requests you can also call Services using relative or absolute urls, e.g:\r\n\r\n```python\r\nclient.get(\"/technology/ServiceStack\", response_as=GetTechnologyResponse)\r\n\r\nclient.get(\"https://techstacks.io/technology/ServiceStack\", response_as=GetTechnologyResponse)\r\n\r\n# https://techstacks.io/technology?Slug=ServiceStack\r\nargs = {\"slug\":\"ServiceStack\"}\r\nclient.get(\"/technology\", args=args, response_as=GetTechnologyResponse) \r\n```\r\n\r\nas well as POST Request DTOs to custom urls:\r\n\r\n```python\r\nclient.post_url(\"/custom-path\", request, args={\"slug\":\"ServiceStack\"})\r\n\r\nclient.post_url(\"http://example.org/custom-path\", request)\r\n```\r\n\r\n### Raw Data Responses\r\n\r\nThe `JsonServiceClient` also supports Raw Data responses like `string` and `byte[]` which also get a Typed API once declared on Request DTOs using the `IReturn<T>` marker:\r\n\r\n```csharp\r\npublic class ReturnString : IReturn<string> {}\r\npublic class ReturnBytes : IReturn<byte[]> {}\r\n```\r\n\r\nWhich can then be accessed as normal, with their Response typed to a JavaScript `str` or `bytes` for raw `byte[]` responses:\r\n\r\n```python\r\nstr:str = client.get(ReturnString())\r\n\r\ndata:bytes = client.get(ReturnBytes())\r\n```\r\n\r\n### Authenticating using Basic Auth\r\n\r\nBasic Auth support is implemented in `JsonServiceClient` and follows the same API made available in the C# Service Clients where the `userName/password` properties can be set individually, e.g:\r\n\r\n```python\r\nclient = JsonServiceClient(baseUrl)\r\nclient.username = user\r\nclient.password = pass\r\n\r\nresponse = client.get(SecureRequest())\r\n```\r\n\r\nOr use `client.set_credentials()` to have them set both together.\r\n\r\n### Authenticating using Credentials\r\n\r\nAlternatively you can authenticate using userName/password credentials by \r\n[adding a Python Reference](#add-python-reference) \r\nto your remote ServiceStack Instance and sending a populated `Authenticate` Request DTO, e.g:\r\n\r\n```python\r\nrequest = Authenticate()\r\nrequest.provider = \"credentials\"\r\nrequest.user_name = user_name\r\nrequest.password = password\r\nrequest.remember_me = true\r\n\r\nresponse:AuthenticateResponse = client.post(request)\r\n```\r\n\r\nThis will populate the `JsonServiceClient` with [Session Cookies](https://docs.servicestack.net/sessions#cookie-session-ids) \r\nwhich will transparently be sent on subsequent requests to make authenticated requests.\r\n\r\n### Authenticating using JWT\r\n\r\nUse the `bearer_token` property to Authenticate with a [ServiceStack JWT Provider](https://docs.servicestack.net/jwt-authprovider) using a JWT Token:\r\n\r\n```python\r\nclient.bearer_token = jwt\r\n```\r\n\r\nAlternatively you can use just a [Refresh Token](https://docs.servicestack.net/jwt-authprovider#refresh-tokens) instead:\r\n\r\n```python\r\nclient.refresh_token = refresh_token\r\n```\r\n\r\nWhere the client will automatically fetch a new JWT Bearer Token using the Refresh Token for authenticated requests.\r\n\r\n### Authenticating using an API Key\r\n\r\nUse the `bearer_token` property to Authenticate with an [API Key](https://docs.servicestack.net/api-key-authprovider):\r\n\r\n```python\r\nclient.bearer_token = api_key\r\n```\r\n\r\n### Transparently handle 401 Unauthorized Responses\r\n\r\nIf the server returns a 401 Unauthorized Response either because the client was Unauthenticated or the \r\nconfigured Bearer Token or API Key used had expired or was invalidated, you can use `onAuthenticationRequired`\r\ncallback to re-configure the client before automatically retrying the original request, e.g:\r\n\r\n```python\r\nauth_client = JsonServiceClient(AUTH_URL)\r\n\r\nclient.on_authentication_required = lambda c=client, a=auth_client: [\r\n    a.set_credentials(username, password),\r\n    client.set_bearer_token(cast(AuthenticateResponse, a.get(Authenticate())).bearer_token)\r\n]\r\n\r\n# Automatically retries requests returning 401 Responses with new bearerToken\r\nresponse = client.get(Secured())\r\n```\r\n\r\n### Automatically refresh Access Tokens\r\n\r\nWith the [Refresh Token support in JWT](https://docs.servicestack.net/jwt-authprovider#refresh-tokens) \r\nyou can use the `refresh_token` property to instruct the Service Client to automatically fetch new JWT Tokens behind the scenes before automatically retrying failed requests due to invalid or expired JWTs, e.g:\r\n\r\n```python\r\n# Authenticate to get new Refresh Token\r\nauth_client = JsonServiceClient(AUTH_URL)\r\nauth_client.username = username\r\nauth_client.password = password\r\nauth_response = auth_client.get(Authenticate())\r\n\r\n# Configure client with RefreshToken\r\nclient.refresh_token = auth_response.refresh_token\r\n\r\n# Call authenticated Services and clients will automatically retrieve new JWT Tokens as needed\r\nresponse = client.get(Secured())\r\n```\r\n\r\nUse the `refresh_token_uri` property when refresh tokens need to be sent to a different ServiceStack Server, e.g:\r\n\r\n```python\r\nclient.refresh_token = refresh_token\r\nclient.refresh_token_uri = AUTH_URL + \"/access-token\"\r\n```\r\n\r\n## DTO Customization Options \r\n\r\nIn most cases you'll just use the generated Python DTO's as-is, however you can further customize how the DTO's are generated by overriding the default options.\r\n\r\nThe header in the generated DTO's show the different options Python native types support with their defaults. Default values are shown with the comment prefix of `//`. To override a value, remove the `#` and specify the value to the right of the `:`. Any uncommented value will be sent to the server to override any server defaults.\r\n\r\nThe DTO comments allows for customizations for how DTOs are generated. The default options that were used to generate the DTO's are repeated in the header comments of the generated DTOs, options that are preceded by a Python comment `#` are defaults from the server, any uncommented value will be sent to the server \r\nto override any server defaults.\r\n\r\n```python\r\n\"\"\" Options:\r\nDate: 2021-08-15 08:26:46\r\nVersion: 5.111\r\nTip: To override a DTO option, remove \"#\" prefix before updating\r\nBaseUrl: https://techstacks.io\r\n\r\n#GlobalNamespace: \r\n#MakePropertiesOptional: False\r\n#AddServiceStackTypes: True\r\n#AddResponseStatus: False\r\n#AddImplicitVersion: \r\n#AddDescriptionAsComments: True\r\n#IncludeTypes: \r\n#ExcludeTypes: \r\n#DefaultImports: datetime,decimal,marshmallow.fields:*,servicestack:*,typing:*,dataclasses:dataclass/field,dataclasses_json:dataclass_json/LetterCase/Undefined/config,enum:Enum/IntEnum\r\n#DataClass: \r\n#DataClassJson: \r\n\"\"\"\r\n```\r\n\r\nWe'll go through and cover each of the above options to see how they affect the generated DTO's:\r\n\r\n### Change Default Server Configuration\r\n\r\nThe above defaults are also overridable on the ServiceStack Server by modifying the default config on the `NativeTypesFeature` Plugin, e.g:\r\n\r\n```csharp\r\n//Server example in C#\r\nvar nativeTypes = this.GetPlugin<NativeTypesFeature>();\r\nnativeTypes.MetadataTypesConfig.AddResponseStatus = true;\r\n...\r\n```\r\n\r\nWe'll go through and cover each of the above options to see how they affect the generated DTO's:\r\n\r\n### GlobalNamespace\r\n\r\nAs Python lacks the concept of namespaces this just emits a comment with the namespace name:\r\n\r\n```python\r\n# module dtos\r\n```\r\n\r\n### AddResponseStatus\r\n\r\nAutomatically add a `response_status` property on all Response DTO's, regardless if it wasn't already defined:\r\n\r\n```python\r\nclass GetTechnologyResponse:\r\n    ...\r\n    response_status: Optional[ResponseStatus] = None\r\n```\r\n\r\n### AddImplicitVersion\r\n\r\nLets you specify the Version number to be automatically populated in all Request DTO's sent from the client: \r\n\r\n```python\r\nclass GetTechnology(IReturn[GetTechnologyResponse], IRegisterStats, IGet):\r\n    version: int = 1\r\n    ...\r\n```\r\n\r\nThis lets you know what Version of the Service Contract that existing clients are using making it easy to implement ServiceStack's [recommended versioning strategy](http://stackoverflow.com/a/12413091/85785). \r\n\r\n### IncludeTypes\r\n\r\nIs used as a Whitelist to specify only the types you would like to have code-generated:\r\n\r\n```\r\n\"\"\" Options:\r\nIncludeTypes: GetTechnology,GetTechnologyResponse\r\n```\r\n\r\nWill only generate `GetTechnology` and `GetTechnologyResponse` DTO's:\r\n\r\n```python\r\nclass GetTechnologyResponse:\r\n    ...\r\nclass GetTechnology:\r\n    ...\r\n```\r\n\r\n#### Include Generic Types\r\n\r\nUse .NET's Type Name to include Generic Types, i.e. the Type name separated by the backtick followed by the number of generic arguments, e.g:\r\n\r\n```\r\nIncludeTypes: IReturn`1,MyPair`2\r\n```\r\n\r\n#### Include Request DTO and its dependent types\r\n\r\nYou can include a Request DTO and all its dependent types with a `.*` suffix on the Request DTO, e.g:\r\n\r\n```\r\n\"\"\" Options:\r\nIncludeTypes: GetTechnology.*\r\n```\r\n\r\nWhich will include the `GetTechnology` Request DTO, the `GetTechnologyResponse` Response DTO and all Types that they both reference.\r\n\r\n#### Include All Types within a C# namespace\r\n\r\nIf your DTOs are grouped into different namespaces they can be all included using the `/*` suffix, e.g:\r\n\r\n```\r\n\"\"\" Options:\r\nIncludeTypes: MyApp.ServiceModel.Admin/*\r\n```\r\n\r\nThis will include all DTOs within the `MyApp.ServiceModel.Admin` C# namespace. \r\n\r\n#### Include All Services in a Tag Group\r\n\r\nServices [grouped by Tag](https://docs.servicestack.net/api-design#group-services-by-tag) can be used in the `IncludeTypes` where tags can be specified using braces in the format `{tag}` or `{tag1,tag2,tag3}`, e.g:\r\n\r\n```\r\n\"\"\" Options:\r\nIncludeTypes: {web,mobile}\r\n```\r\n\r\nOr individually:\r\n\r\n```\r\n\"\"\" Options:\r\nIncludeTypes: {web},{mobile}\r\n```\r\n\r\n### ExcludeTypes\r\nIs used as a Blacklist to specify which types you would like excluded from being generated:\r\n\r\n```\r\n\"\"\" Options:\r\nExcludeTypes: GetTechnology,GetTechnologyResponse\r\n```\r\n\r\nWill exclude `GetTechnology` and `GetTechnologyResponse` DTOs from being generated.\r\n\r\n### DefaultImports\r\n\r\nThe `module:Symbols` short-hand syntax can be used for specifying additional imports in your generated Python DTO. There are 3 different syntaxes for specifying different Python imports:\r\n\r\n```python\r\n\"\"\" Options:\r\n...\r\nDefaultImports: datetime,typing:*,enum:Enum/IntEnum\r\n\"\"\"\r\n```\r\n\r\nWhich will generate the popular import form of:\r\n\r\n```python\r\nimport datetime\r\nfrom typing import *\r\nfrom enum import Enum, IntEnum\r\n```\r\n\r\n### DataClass\r\n\r\nChange what `dataclass` decorator is used, e.g:\r\n\r\n```python\r\n\"\"\" Options:\r\n...\r\nDataClass: init=False\r\n\"\"\"\r\n```\r\n\r\nWill decorate every DTO with:\r\n\r\n```python\r\n@dataclass(init=False)\r\nclass GetTechnology(IReturn[GetTechnologyResponse], IRegisterStats, IGet):\r\n    slug: Optional[str] = None\r\n```\r\n\r\n\r\n### DataClassJson\r\n\r\nChange what `dataclass_json` decorator is used, e.g:\r\n\r\n```python\r\n\"\"\" Options:\r\n...\r\nDataClassJson: letter_case=LetterCase.PASCAL\r\n\"\"\"\r\n```\r\n\r\nWill decorate every DTO with:\r\n\r\n```python\r\n@dataclass_json(letter_case=LetterCase.PASCAL)\r\nclass GetTechnology(IReturn[GetTechnologyResponse], IRegisterStats, IGet):\r\n    slug: Optional[str] = None\r\n```\r\n\r\nWhich will result in each type being serialized with PascalCase.\r\n\r\n## Customize Serialization\r\n\r\nThe `servicestack` client lib allows for flexible serialization customization where you can change how different .NET Types are serialized and deserialized into native Python types.\r\n\r\nTo illustrate this we'll walk through how serialization of properties containing binary data to Base64 is implemented.\r\n\r\nFirst we specify the Python DTO generator to emit `bytes` type hint for the popular .NET binary data types:\r\n\r\n```csharp\r\nPythonGenerator.TypeAliases[typeof(byte[]).Name] = \"bytes\";\r\nPythonGenerator.TypeAliases[typeof(Stream).Name] = \"bytes\";\r\n```\r\n\r\nIn the Python app we can then specify the serializers and deserializers to use for deserializing properties with the `bytes` data type which converts binary data to/from Base64:\r\n\r\n```python\r\nfrom servicestack import TypeConverters\r\n\r\ndef to_bytearray(value: Optional[bytes]):\r\n    if value is None:\r\n        return None\r\n    return base64.b64encode(value).decode('ascii')\r\n\r\ndef from_bytearray(base64str: Optional[str]):\r\n    return base64.b64decode(base64str)\r\n\r\nTypeConverters.serializers[bytes] = to_bytearray\r\nTypeConverters.deserializers[bytes] = from_bytearray\r\n```\r\n\r\n## Inspect Utils\r\n\r\nTo help clients with inspecting API Responses the `servicestack` library also includes a number of helpful utils to quickly visualizing API outputs.\r\n\r\nFor a basic indented object graph you can use `dump` to capture and `printdump` to print the output of any API Response, e.g:\r\n\r\n```python\r\nfrom dataclasses import dataclass\r\nfrom dataclasses_json import dataclass_json, Undefined\r\nfrom typing import Optional\r\nfrom servicestack import printdump, printtable\r\n\r\n@dataclass_json(undefined=Undefined.EXCLUDE)\r\n@dataclass\r\nclass GithubRepo:\r\n    name: str\r\n    description: Optional[str] = None\r\n    homepage: Optional[str] = None\r\n    lang: Optional[str] = field(metadata=config(field_name=\"language\"),default=None)\r\n    watchers: Optional[int] = 0\r\n    forks: Optional[int] = 0\r\n\r\nresponse = requests.get(f'https://api.github.com/orgs/python/repos')\r\norgRepos = GithubRepo.schema().loads(response.text, many=True)\r\norgRepos.sort(key=operator.attrgetter('watchers'), reverse=True)\r\n\r\nprint(f'Top 3 {orgName} Repos:')\r\nprintdump(orgRepos[0:3])\r\n```\r\n\r\nOutput:\r\n\r\n```\r\nTop 3 python Repos:\r\n[\r\n    {\r\n        name: mypy,\r\n        description: Optional static typing for Python 3 and 2 (PEP 484),\r\n        homepage: http://www.mypy-lang.org/,\r\n        lang: Python,\r\n        watchers: 9638,\r\n        forks: 1564\r\n    },\r\n    {\r\n        name: peps,\r\n        description: Python Enhancement Proposals,\r\n        homepage: https://www.python.org/dev/peps/,\r\n        lang: Python,\r\n        watchers: 2459,\r\n        forks: 921\r\n    },\r\n    {\r\n        name: typeshed,\r\n        description: Collection of library stubs for Python, with static types,\r\n        homepage: ,\r\n        lang: Python,\r\n        watchers: 1942,\r\n        forks: 972\r\n    }\r\n]\r\n```\r\n\r\nFor tabular resultsets you can use `table` to capture and `printtable` to print API resultsets in a human-friendly markdown table with an optional `headers` parameter to specify the order and columns to display, e.g:\r\n\r\n```python\r\nprint(f'\\nTop 10 {orgName} Repos:')\r\nprinttable(orgRepos[0:10],headers=['name','lang','watchers','forks'])\r\n```\r\n\r\nOutput:\r\n\r\n```\r\nTop 10 python Repos:\r\n+--------------+-----------+------------+---------+\r\n| name         | lang      |   watchers |   forks |\r\n|--------------+-----------+------------+---------|\r\n| mypy         | Python    |       9638 |    1564 |\r\n| peps         | Python    |       2459 |     921 |\r\n| typeshed     | Python    |       1942 |     972 |\r\n| pythondotorg | Python    |       1038 |     432 |\r\n| asyncio      |           |        945 |     178 |\r\n| typing       | Python    |        840 |     130 |\r\n| raspberryio  | Python    |        217 |      38 |\r\n| typed_ast    | C         |        171 |      43 |\r\n| planet       | Python    |        100 |     145 |\r\n| psf-salt     | SaltStack |         87 |      50 |\r\n+--------------+-----------+------------+---------+\r\n```\r\n\r\nAlternatively you can use `htmldump` to generate API responses in a HTML UI which is especially useful in [Python Jupyter Notebooks](https://docs.servicestack.net/jupyter-notebooks-python) to easily visualize API responses, e.g:\r\n\r\n[![](https://docs.servicestack.net/img/pages/apps/jupyterlab-mybinder-techstacks.png)](https://github.com/ServiceStack/jupyter-notebooks/blob/main/techstacks.io-FindTechnologies.ipynb)\r\n",
    "bugtrack_url": null,
    "license": "BSD-3-Clause",
    "summary": "ServiceStack Python Service Clients",
    "version": "0.1.3",
    "project_urls": {
        "Homepage": "https://github.com/ServiceStack/servicestack-python"
    },
    "split_keywords": [
        "servicestack",
        "client",
        "dotnet"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "6880d2864385fef7859843595020c131a32ae6c21df69adf43cae4377cb1d966",
                "md5": "454f7d1b1c7eb4b5f6374a9db4578ffd",
                "sha256": "8663018a3995cb4e8bbd326465f9271e2cd375a4cc6ef76f5108cf4e224ce8bf"
            },
            "downloads": -1,
            "filename": "servicestack-0.1.3-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "454f7d1b1c7eb4b5f6374a9db4578ffd",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.7",
            "size": 52841,
            "upload_time": "2024-02-02T14:08:52",
            "upload_time_iso_8601": "2024-02-02T14:08:52.453922Z",
            "url": "https://files.pythonhosted.org/packages/68/80/d2864385fef7859843595020c131a32ae6c21df69adf43cae4377cb1d966/servicestack-0.1.3-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "7e8486f137be988023166712b67c15f13d26f5aae3697421e5ff133bccbec2de",
                "md5": "96553d935cf21decda4bf45ba46ef40e",
                "sha256": "9feba3a7fb30f435dde21dc823275c16275f7441dba12925c1aad4ee571a3ebc"
            },
            "downloads": -1,
            "filename": "servicestack-0.1.3.tar.gz",
            "has_sig": false,
            "md5_digest": "96553d935cf21decda4bf45ba46ef40e",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.7",
            "size": 67372,
            "upload_time": "2024-02-02T14:08:55",
            "upload_time_iso_8601": "2024-02-02T14:08:55.176982Z",
            "url": "https://files.pythonhosted.org/packages/7e/84/86f137be988023166712b67c15f13d26f5aae3697421e5ff133bccbec2de/servicestack-0.1.3.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-02-02 14:08:55",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "ServiceStack",
    "github_project": "servicestack-python",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "requirements": [
        {
            "name": "typing_extensions",
            "specs": [
                [
                    ">=",
                    "3.7.4"
                ]
            ]
        },
        {
            "name": "requests",
            "specs": [
                [
                    ">=",
                    "2.23.0"
                ]
            ]
        },
        {
            "name": "dataclasses",
            "specs": [
                [
                    ">=",
                    "0.6"
                ]
            ]
        },
        {
            "name": "dataclasses-json",
            "specs": [
                [
                    ">=",
                    "0.5.4"
                ]
            ]
        },
        {
            "name": "marshmallow",
            "specs": [
                [
                    ">=",
                    "3.12.2"
                ]
            ]
        },
        {
            "name": "setuptools",
            "specs": [
                [
                    ">=",
                    "57.1.0"
                ]
            ]
        }
    ],
    "lcname": "servicestack"
}
        
Elapsed time: 0.19518s