Skip to content
This repository was archived by the owner on Jun 9, 2025. It is now read-only.

Commit 656585d

Browse files
committed
Option to choose whether to compile sync or / and async clients
1 parent 069975b commit 656585d

File tree

6 files changed

+88
-4
lines changed

6 files changed

+88
-4
lines changed

src/betterproto2_compiler/plugin/parser.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
CodeGeneratorResponseFeature,
1515
CodeGeneratorResponseFile,
1616
)
17-
from betterproto2_compiler.settings import Settings
17+
from betterproto2_compiler.settings import ClientGeneration, Settings
1818

1919
from .compiler import outputfile_compiler
2020
from .models import (
@@ -60,8 +60,24 @@ def _traverse(
6060

6161

6262
def get_settings(plugin_options: list[str]) -> Settings:
63+
# Synchronous clients are suitable for most users
64+
client_generation = ClientGeneration.SYNC
65+
66+
for opt in plugin_options:
67+
if opt.startswith("client_generation="):
68+
name = opt.split("=")[1]
69+
70+
# print(ClientGeneration.__members__, file=sys.stderr)
71+
# print([member.value for member in ClientGeneration])
72+
73+
try:
74+
client_generation = ClientGeneration(name)
75+
except ValueError:
76+
raise ValueError(f"Invalid client_generation option: {name}")
77+
6378
return Settings(
6479
pydantic_dataclasses="pydantic_dataclasses" in plugin_options,
80+
client_generation=client_generation,
6581
)
6682

6783

src/betterproto2_compiler/settings.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,62 @@
11
from dataclasses import dataclass
2+
from enum import StrEnum
3+
4+
5+
class ClientGeneration(StrEnum):
6+
NONE = "none"
7+
"""Clients are not generated."""
8+
9+
SYNC = "sync"
10+
"""Only synchronous clients are generated."""
11+
12+
ASYNC = "async"
13+
"""Only asynchronous clients are generated."""
14+
15+
SYNC_ASYNC = "sync_async"
16+
"""Both synchronous and asynchronous clients are generated.
17+
18+
The asynchronous client is generated with the Async suffix."""
19+
20+
ASYNC_SYNC = "async_sync"
21+
"""Both synchronous and asynchronous clients are generated.
22+
23+
The synchronous client is generated with the Sync suffix."""
24+
25+
SYNC_ASYNC_NO_DEFAULT = "sync_async_no_default"
26+
"""Both synchronous and asynchronous clients are generated.
27+
28+
The synchronous client is generated with the Sync suffix, and the asynchronous client is generated with the Async
29+
suffix."""
30+
31+
@property
32+
def is_sync_generated(self) -> bool:
33+
return self in {
34+
ClientGeneration.SYNC,
35+
ClientGeneration.SYNC_ASYNC,
36+
ClientGeneration.ASYNC_SYNC,
37+
ClientGeneration.SYNC_ASYNC_NO_DEFAULT,
38+
}
39+
40+
@property
41+
def is_async_generated(self) -> bool:
42+
return self in {
43+
ClientGeneration.ASYNC,
44+
ClientGeneration.SYNC_ASYNC,
45+
ClientGeneration.ASYNC_SYNC,
46+
ClientGeneration.SYNC_ASYNC_NO_DEFAULT,
47+
}
48+
49+
@property
50+
def is_sync_prefixed(self) -> bool:
51+
return self in {ClientGeneration.ASYNC_SYNC, ClientGeneration.SYNC_ASYNC_NO_DEFAULT}
52+
53+
@property
54+
def is_async_prefixed(self) -> bool:
55+
return self in {ClientGeneration.SYNC_ASYNC, ClientGeneration.SYNC_ASYNC_NO_DEFAULT}
256

357

458
@dataclass
559
class Settings:
660
pydantic_dataclasses: bool
61+
62+
client_generation: ClientGeneration

src/betterproto2_compiler/templates/service_stub_async.py.j2

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{% extends "service_stub.py.j2" %}
22

33
{# Class definition #}
4-
{% block class_name %}{{ service.py_name }}Stub{% endblock %}
4+
{% block class_name %}{{ service.py_name }}{% if output_file.settings.client_generation.is_async_prefixed %}Async{% endif %}Stub{% endblock %}
55
{% block inherit_from %}betterproto2.ServiceStub{% endblock %}
66

77
{# Methods definition #}

src/betterproto2_compiler/templates/service_stub_sync.py.j2

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{% extends "service_stub.py.j2" %}
22

33
{# Class definition #}
4-
{% block class_name %}{{ service.py_name }}SyncStub{% endblock %}
4+
{% block class_name %}{{ service.py_name }}{% if output_file.settings.client_generation.is_sync_prefixed %}Sync{% endif %}Stub{% endblock %}
55

66
{% block class_content %}
77
{# TODO move to parent class #}

src/betterproto2_compiler/templates/template.py.j2

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,15 @@ default_message_pool.register_message("{{ output_file.package }}", "{{ message.p
8787
{% endfor %}
8888

8989
{% for _, service in output_file.services|dictsort(by="key") %}
90-
{% include "service_stub_async.py.j2" %}
90+
91+
{% if output_file.settings.client_generation.is_sync_generated %}
9192
{% include "service_stub_sync.py.j2" %}
93+
{% endif %}
94+
95+
{% if output_file.settings.client_generation.is_async_generated %}
96+
{% include "service_stub_async.py.j2" %}
97+
{% endif %}
98+
9299
{% endfor %}
93100

94101
{% for i in output_file.imports_end %}

tests/util.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ async def protoc(
6363
f"--plugin=protoc-gen-custom={plugin_path.as_posix()}",
6464
"--experimental_allow_proto3_optional",
6565
"--custom_opt=pydantic_dataclasses",
66+
"--custom_opt=client_generation=async_sync",
6667
f"--proto_path={path.as_posix()}",
6768
f"--custom_out={output_dir.as_posix()}",
6869
*[p.as_posix() for p in path.glob("*.proto")],
@@ -76,6 +77,10 @@ async def protoc(
7677
f"--{python_out_option}={output_dir.as_posix()}",
7778
*[p.as_posix() for p in path.glob("*.proto")],
7879
]
80+
81+
if not reference:
82+
command.insert(3, "--python_betterproto2_opt=client_generation=async_sync")
83+
7984
proc = await asyncio.create_subprocess_exec(
8085
*command,
8186
stdout=asyncio.subprocess.PIPE,

0 commit comments

Comments
 (0)