Skip to content

Commit ddfcb62

Browse files
committed
refactor: add HTTP/2 sync support, reorganize modules, and migrate docstrings to Google style
1 parent e0685d2 commit ddfcb62

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

79 files changed

+8928
-4014
lines changed

.github/workflows/license-check.yaml

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,7 @@
11
name: License Template Check
22

3-
on:
4-
pull_request:
5-
types:
6-
- opened
7-
- synchronize
8-
- reopened
9-
push:
3+
on: [push, pull_request]
4+
105

116

127
jobs:

.github/workflows/publish.yml

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,37 @@
1-
name: Publish
1+
name: Publish to PyPI
2+
23
on:
34
release:
5+
types: [released]
46
branches: [main]
5-
types: [created]
67

78

89
jobs:
910
build:
10-
name: Build
11+
name: Build Python Package
1112
runs-on: ubuntu-latest
1213
steps:
1314
- uses: actions/checkout@v4
1415
with:
1516
persist-credentials: false
16-
- name: Set up Python 3.12
17+
18+
- name: Set up Python
1719
uses: actions/setup-python@v5
1820
with:
19-
python-version: "3.12"
21+
python-version-file: ".python-version"
22+
2023
- name: Set up uv
2124
uses: astral-sh/setup-uv@v6
2225
with:
2326
version: "0.7.4"
2427
enable-cache: true
25-
- name: Sync build environment
28+
29+
- name: Sync build dependencies
2630
run: "uv sync --only-group build"
31+
2732
- name: Build distribution
2833
run: "uv run hatch build"
34+
2935
- name: Upload distribution artifacts
3036
uses: actions/upload-artifact@v4
3137
with:
@@ -34,19 +40,22 @@ jobs:
3440

3541
publish-to-pypi:
3642
name: Publish to PyPI
37-
needs:
38-
- build
43+
needs: build
3944
runs-on: ubuntu-latest
45+
4046
environment:
4147
name: pypi
4248
url: https://pypi.org/project/apache-dubbo/
49+
4350
permissions:
44-
id-token: write # IMPORTANT: mandatory for trusted publishing
51+
id-token: write # Required for Trusted Publishing
52+
4553
steps:
4654
- name: Download distribution artifacts
4755
uses: actions/download-artifact@v4
4856
with:
4957
name: python-package-distributions
5058
path: dist/
51-
- name: Publish to PyPI
59+
60+
- name: Upload to PyPI
5261
uses: pypa/gh-action-pypi-publish@release/v1

.github/workflows/test.yaml

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,37 @@
11
name: Lint and Test
2+
23
on:
3-
pull_request:
4-
types:
5-
- opened
6-
- synchronize
7-
- reopened
84
push:
5+
pull_request:
96

107

118
jobs:
129
lint:
13-
name: Lint code
10+
name: Lint Code
1411
runs-on: ubuntu-latest
1512
steps:
1613
- uses: actions/checkout@v4
17-
- name: Set up Python 3.12
14+
15+
- name: Set up Python
1816
uses: actions/setup-python@v5
1917
with:
20-
python-version: "3.12"
18+
python-version-file: ".python-version"
19+
2120
- name: Set up uv
2221
uses: astral-sh/setup-uv@v6
2322
with:
2423
version: "0.7.4"
2524
enable-cache: true
25+
2626
- name: Sync development environment
27-
run: "uv sync --group dev"
28-
- name: Run Lint
27+
run: "uv sync"
28+
29+
- name: Run Linter
2930
run: "scripts/lint.sh"
3031

32+
3133
tests:
32-
name: "Tests (Python ${{ matrix.python-version }} on ${{ matrix.os }})"
34+
name: Test on ${{ matrix.os }} / Python ${{ matrix.python-version }}
3335
runs-on: ${{ matrix.os }}
3436
strategy:
3537
fail-fast: false
@@ -38,16 +40,20 @@ jobs:
3840
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
3941
steps:
4042
- uses: actions/checkout@v4
43+
4144
- name: Set up Python
4245
uses: actions/setup-python@v5
4346
with:
4447
python-version: "${{ matrix.python-version }}"
48+
4549
- name: Set up uv
4650
uses: astral-sh/setup-uv@v6
4751
with:
4852
version: "0.7.4"
4953
enable-cache: true
50-
- name: Sync environment
51-
run: "uv sync --all-extras --group dev"
52-
- name: Run tests
54+
55+
- name: Sync environment with all extras
56+
run: " uv sync --all-extras"
57+
58+
- name: Run Tests with Coverage
5359
run: "uv run pytest --cov=src/dubbo --cov-report=term-missing"

docs/CONTRIBUTING.md

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,20 @@ To report a bug or request a feature, use the [GitHub Issue templates](https://g
3939

4040
Our Python code follows the [PEP 8 style guide](https://peps.python.org/pep-0008/) with these adjustments:
4141

42-
1. **Maximum Line Length:** Up to 120 characters.
43-
2. **Docstrings and Comments:** Use reStructuredText format.
42+
1. **Maximum Line Length:** Limit lines to 120 characters.
43+
2. **Docstrings and Comments:** Use Google-style docstrings for all public functions and methods.
44+
- Example:
45+
```python
46+
def example_method(param1: str, param2: int) -> None:
47+
"""Example method that does something.
48+
49+
Args:
50+
param1 (str): Description of the first parameter.
51+
param2 (int): Description of the second parameter.
52+
"""
53+
# This is an inline comment explaining a specific line
54+
print(param1, param2)
55+
```
4456
3. **Type Hints:** All public functions and methods must include type annotations consistent with [PEP 484](https://peps.python.org/pep-0484/).
4557
4. **Imports:** Grouped in the order: standard library, third-party, local imports, each separated by a blank line.
4658
5. **Indentation:** 4 spaces; no tabs.

pyproject.toml

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ dependencies = [
5959
"anyio>=4.9.0",
6060
"h2>=4.1.0",
6161
"psutil>=6.0.0",
62+
"typing-extensions>=4.13.2; python_version < '3.10'",
6263
]
6364

6465

@@ -72,12 +73,6 @@ Issues = "https://github.com/apache/dubbo/issues"
7273
zookeeper = [
7374
"kazoo>=2.10.0",
7475
]
75-
logging-color = [
76-
"colorlog>=6.9.0",
77-
]
78-
loguru = [
79-
"loguru>=0.7.3",
80-
]
8176

8277

8378
[dependency-groups]
@@ -91,6 +86,7 @@ dev = [
9186
"mypy>=1.15.0",
9287
"pytest>=8.3.5",
9388
"pytest-cov>=6.1.1",
89+
"pytest-mock>=3.14.1",
9490
]
9591

9692

@@ -130,7 +126,6 @@ replacement = "[$1](https://github.com/apache/dubbo-python/blob/main/$2)"
130126
# ------------- Ruff settings -------------
131127
# Top-level
132128
[tool.ruff]
133-
target-version = "py39"
134129
line-length = 120
135130
extend-exclude = ["**/*_pb2.py"]
136131

src/dubbo/bootstrap.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#
2+
# Licensed to the Apache Software Foundation (ASF) under one or more
3+
# contributor license agreements. See the NOTICE file distributed with
4+
# this work for additional information regarding copyright ownership.
5+
# The ASF licenses this file to You under the Apache License, Version 2.0
6+
# (the "License"); you may not use this file except in compliance with
7+
# the License. You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
from dubbo.common.classes import SingletonBase
18+
19+
20+
class Dubbo(SingletonBase):
21+
"""
22+
The main entry point for the Dubbo framework.
23+
"""
24+
25+
pass
26+
27+
28+
class AsyncDubbo(SingletonBase):
29+
"""
30+
The main entry point for the Dubbo framework.
31+
"""
32+
33+
pass

src/dubbo/client.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#
2+
# Licensed to the Apache Software Foundation (ASF) under one or more
3+
# contributor license agreements. See the NOTICE file distributed with
4+
# this work for additional information regarding copyright ownership.
5+
# The ASF licenses this file to You under the Apache License, Version 2.0
6+
# (the "License"); you may not use this file except in compliance with
7+
# the License. You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
18+
class Client:
19+
"""
20+
The main entry point for the Dubbo client.
21+
"""
22+
23+
pass

src/dubbo/cluster/loadbalance/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,6 @@
1414
# See the License for the specific language governing permissions and
1515
# limitations under the License.
1616

17-
from ._base import LoadBalance
17+
from .base import LoadBalance
1818

1919
__all__ = ["LoadBalance"]

src/dubbo/cluster/loadbalance/_base.py renamed to src/dubbo/cluster/loadbalance/base.py

Lines changed: 27 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -24,37 +24,36 @@
2424

2525

2626
def get_weight(invoker: Invoker, invocation: Invocation) -> int:
27-
"""
28-
Get the weight of the invoker with warmup capability.
29-
30-
This method calculates weight based on URL parameters and warming up time.
31-
New services need warmup time to be fully functional, during this period
32-
their weight is gradually increased.
33-
34-
:param invoker: The service invoker.
35-
:type invoker: Invoker
36-
:param invocation: The service invocation context
37-
:type invocation: Invocation
38-
:return: Calculated weight value (minimum 0)
39-
:rtype: int
27+
"""Get the weight of the invoker with warmup capability.
28+
29+
Calculates weight based on URL parameters and warmup time. New services
30+
need warmup time to be fully functional, during which their weight is
31+
gradually increased from 1 to the configured value.
32+
33+
Args:
34+
invoker: The service invoker containing URL configuration.
35+
invocation: The service invocation context with method information.
36+
37+
Returns:
38+
Calculated weight value, minimum 0.
4039
"""
4140
url = invoker.get_url()
4241
# TODO: Multiple registry scenario, load balance among multiple registries.
4342
is_multiple = False
4443

4544
# Determine weight based on URL parameters
4645
if is_multiple:
47-
weight = url.get_param_int(constants.WEIGHT_KEY, constants.DEFAULT_WEIGHT)
46+
weight = url.get_param_int(constants.WEIGHT_KEY, constants.DEFAULT_WEIGHT_VALUE)
4847
else:
49-
weight = url.get_method_param_int(invocation.method_name, constants.WEIGHT_KEY, constants.DEFAULT_WEIGHT)
48+
weight = url.get_method_param_int(invocation.method_name, constants.WEIGHT_KEY, constants.DEFAULT_WEIGHT_VALUE)
5049

5150
# Apply warmup adjustment for positive weights only
5251
if weight > 0:
5352
timestamp = url.get_param_int(constants.TIMESTAMP_KEY, 0)
5453
if timestamp > 0:
5554
# Calculate service uptime in milliseconds
5655
uptime = max(int(time.time() * 1000) - timestamp, 1)
57-
warmup = url.get_param_int(constants.WARMUP_KEY, constants.DEFAULT_WARMUP)
56+
warmup = url.get_param_int(constants.WARMUP_KEY, constants.DEFAULT_WARMUP_VALUE)
5857

5958
# Adjust weight during warmup period
6059
if 0 < uptime < warmup:
@@ -67,22 +66,22 @@ def get_weight(invoker: Invoker, invocation: Invocation) -> int:
6766

6867

6968
class LoadBalance(abc.ABC):
70-
"""
71-
The load balance interface.
69+
"""Base class for load balancing strategies.
7270
71+
Defines the interface for selecting an invoker from a list of available
72+
invokers based on the load balancing algorithm implementation.
7373
"""
7474

7575
@abc.abstractmethod
7676
def select(self, invokers: list[Invoker], url: URL, invocation: Invocation) -> Optional[Invoker]:
77-
"""
78-
Select an invoker from the list.
79-
:param invokers: The invokers.
80-
:type invokers: List[Invoker]
81-
:param url: The URL.
82-
:type url: URL
83-
:param invocation: The invocation.
84-
:type invocation: Invocation
85-
:return: The selected invoker. If no invoker is selected, return None.
86-
:rtype: Optional[Invoker]
77+
"""Select an invoker from the available invokers list.
78+
79+
Args:
80+
invokers: List of available service invokers.
81+
url: The request URL with configuration parameters.
82+
invocation: The service invocation context.
83+
84+
Returns:
85+
The selected invoker, or None if no suitable invoker is found.
8786
"""
8887
raise NotImplementedError()

0 commit comments

Comments
 (0)