Skip to content

Commit b4c54f3

Browse files
authored
Merge pull request #231 from opentensor/fix/thewhaleking/bug-fixes-1.5.10
bug fixes 1.5.10
2 parents 58ee561 + 4ee7a0f commit b4c54f3

File tree

3 files changed

+117
-50
lines changed

3 files changed

+117
-50
lines changed

.github/workflows/check-btcli-tests.yml

Lines changed: 41 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,10 @@ jobs:
6161
echo "Current labels: $LABELS"
6262
if echo "$LABELS" | grep -q "run-bittensor-cli-tests"; then
6363
echo "run-cli-tests=true" >> $GITHUB_ENV
64-
echo "::set-output name=run-cli-tests::true"
64+
echo "run-cli-tests=true" >> $GITHUB_OUTPUT
6565
else
6666
echo "run-cli-tests=false" >> $GITHUB_ENV
67-
echo "::set-output name=run-cli-tests::false"
67+
echo "run-cli-tests=false" >> $GITHUB_OUTPUT
6868
fi
6969
env:
7070
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -91,7 +91,7 @@ jobs:
9191
id: get-tests
9292
run: |
9393
test_files=$(find ${{ github.workspace }}/btcli/tests/e2e_tests -name "test*.py" | jq -R -s -c 'split("\n") | map(select(. != ""))')
94-
echo "::set-output name=test-files::$test_files"
94+
echo "test-files=$test_files" >> $GITHUB_OUTPUT
9595
shell: bash
9696

9797
pull-docker-image:
@@ -147,45 +147,47 @@ jobs:
147147
- name: Check-out repository
148148
uses: actions/checkout@v4
149149

150-
- name: Install dependencies
150+
- name: Install system dependencies
151151
run: |
152152
sudo apt-get update &&
153153
sudo apt-get install -y clang curl libssl-dev llvm libudev-dev protobuf-compiler
154154
155-
- name: Create Python virtual environment
156-
working-directory: ${{ github.workspace }}
157-
run: python3 -m venv ${{ github.workspace }}/venv
155+
- name: Set up Python
156+
uses: actions/setup-python@v5
157+
with:
158+
python-version: '3.13'
159+
160+
- name: Install uv
161+
uses: astral-sh/setup-uv@v4
158162

159163
- name: Clone Bittensor CLI repo
160-
working-directory: ${{ github.workspace }}
161164
run: git clone https://github.com/opentensor/btcli.git
162165

163-
- name: Setup Bittensor-cli from cloned repo
166+
- name: Checkout btcli staging branch
164167
working-directory: ${{ github.workspace }}/btcli
165168
run: |
166-
source ${{ github.workspace }}/venv/bin/activate
167169
git checkout staging
168170
git fetch origin staging
169-
python3 -m pip install --upgrade pip uv
170-
uv pip install '.[dev]'
171-
uv pip install pytest
171+
172+
- name: Install btcli dependencies
173+
working-directory: ${{ github.workspace }}/btcli
174+
run: uv pip install --system '.[dev]'
172175

173176
- name: Clone async-substrate-interface repo
174177
run: git clone https://github.com/opentensor/async-substrate-interface.git
175178

176-
- name: Checkout PR async-substrate-interface repo
179+
- name: Checkout PR branch in async-substrate-interface
177180
working-directory: ${{ github.workspace }}/async-substrate-interface
178181
run: |
179182
git fetch origin ${{ github.event.pull_request.head.ref }}
180183
git checkout ${{ github.event.pull_request.head.ref }}
181184
echo "Current branch: $(git rev-parse --abbrev-ref HEAD)"
182185
183-
- name: Install async-substrate-interface package
186+
- name: Install async-substrate-interface with dev dependencies
184187
working-directory: ${{ github.workspace }}/async-substrate-interface
185188
run: |
186-
source ${{ github.workspace }}/venv/bin/activate
187-
python3 -m pip uninstall async-substrate-interface -y
188-
uv pip install .
189+
uv pip uninstall --system async-substrate-interface || true
190+
uv pip install --system '.[dev]'
189191
190192
- name: Download Cached Docker Image
191193
uses: actions/download-artifact@v4
@@ -195,10 +197,8 @@ jobs:
195197
- name: Load Docker Image
196198
run: docker load -i subtensor-localnet.tar
197199

198-
- name: Run tests
199-
run: |
200-
source ${{ github.workspace }}/venv/bin/activate
201-
pytest ${{ matrix.test-file }} -s
200+
- name: Run e2e tests
201+
run: pytest ${{ matrix.test-file }} -s
202202

203203

204204
run-unit-test:
@@ -210,46 +210,47 @@ jobs:
210210
- name: Check-out repository
211211
uses: actions/checkout@v4
212212

213-
- name: Install dependencies
213+
- name: Install system dependencies
214214
run: |
215215
sudo apt-get update &&
216216
sudo apt-get install -y clang curl libssl-dev llvm libudev-dev protobuf-compiler
217217
218-
- name: Create Python virtual environment
219-
working-directory: ${{ github.workspace }}
220-
run: python3 -m venv venv
218+
- name: Set up Python
219+
uses: actions/setup-python@v5
220+
with:
221+
python-version: '3.13'
222+
223+
- name: Install uv
224+
uses: astral-sh/setup-uv@v4
221225

222226
- name: Clone Bittensor CLI repo
223-
working-directory: ${{ github.workspace }}
224227
run: git clone https://github.com/opentensor/btcli.git
225228

226-
- name: Setup Bittensor SDK from cloned repo
229+
- name: Checkout btcli staging branch
227230
working-directory: ${{ github.workspace }}/btcli
228231
run: |
229-
source ${{ github.workspace }}/venv/bin/activate
230232
git checkout staging
231233
git fetch origin staging
232-
python3 -m pip install --upgrade pip uv
233-
uv pip install '.[dev]'
234+
235+
- name: Install btcli dependencies
236+
working-directory: ${{ github.workspace }}/btcli
237+
run: uv pip install --system '.[dev]'
234238

235239
- name: Clone async-substrate-interface repo
236240
run: git clone https://github.com/opentensor/async-substrate-interface.git
237241

238-
- name: Checkout PR branch in async-substrate-interface repo
242+
- name: Checkout PR branch in async-substrate-interface
239243
working-directory: ${{ github.workspace }}/async-substrate-interface
240244
run: |
241245
git fetch origin ${{ github.event.pull_request.head.ref }}
242246
git checkout ${{ github.event.pull_request.head.ref }}
243247
echo "Current branch: $(git rev-parse --abbrev-ref HEAD)"
244248
245-
- name: Install /async-substrate-interface package
249+
- name: Install async-substrate-interface with dev dependencies
246250
working-directory: ${{ github.workspace }}/async-substrate-interface
247251
run: |
248-
source ${{ github.workspace }}/venv/bin/activate
249-
pip uninstall async-substrate-interface -y
250-
uv pip install .
252+
uv pip uninstall --system async-substrate-interface || true
253+
uv pip install --system '.[dev]'
251254
252-
- name: Run SDK unit tests
253-
run: |
254-
source ${{ github.workspace }}/venv/bin/activate
255-
pytest ${{ github.workspace }}/btcli/tests/unit_tests
255+
- name: Run BTCLI unit tests
256+
run: pytest ${{ github.workspace }}/btcli/tests/unit_tests

async_substrate_interface/async_substrate.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -793,7 +793,7 @@ async def _handler(self, ws: ClientConnection) -> Union[None, Exception]:
793793

794794
async def __aexit__(self, exc_type, exc_val, exc_tb):
795795
if self.shutdown_timer is not None:
796-
if not self.state != State.CONNECTING:
796+
if self.state != State.CONNECTING:
797797
if self._exit_task is not None:
798798
self._exit_task.cancel()
799799
try:
@@ -802,6 +802,7 @@ async def __aexit__(self, exc_type, exc_val, exc_tb):
802802
pass
803803
if self.ws is not None:
804804
self._exit_task = asyncio.create_task(self._exit_with_timer())
805+
self._attempts = 0
805806

806807
async def _exit_with_timer(self):
807808
"""
@@ -952,7 +953,7 @@ async def unsubscribe(
952953
original_id = get_next_id()
953954
while original_id in self._in_use_ids:
954955
original_id = get_next_id()
955-
del self._received_subscriptions[subscription_id]
956+
self._received_subscriptions.pop(subscription_id, None)
956957

957958
to_send = {
958959
"jsonrpc": "2.0",
@@ -1000,11 +1001,12 @@ async def retrieve(self, item_id: str) -> Optional[dict]:
10001001
elif isinstance((e := self._send_recv_task.result()), Exception):
10011002
logger.exception(f"Websocket sending exception: {e}")
10021003
raise e
1003-
await asyncio.sleep(0.01)
10041004
return None
10051005

10061006

10071007
class AsyncSubstrateInterface(SubstrateMixin):
1008+
ws: "Websocket"
1009+
10081010
def __init__(
10091011
self,
10101012
url: str,

tests/e2e_tests/test_substrate_addons.py

Lines changed: 71 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import subprocess
22
import time
3+
import sys
34

45
import pytest
56

@@ -13,6 +14,63 @@
1314
from tests.helpers.settings import ARCHIVE_ENTRYPOINT, LATENT_LITE_ENTRYPOINT
1415

1516

17+
def wait_for_output(process, target_string, timeout=60):
18+
"""
19+
Wait for a specific string to appear in the subprocess stdout.
20+
21+
Args:
22+
process: subprocess.Popen object
23+
target_string: String to wait for in stdout
24+
timeout: Maximum time to wait in seconds
25+
26+
Returns:
27+
bool: True if string was found, False if timeout occurred
28+
"""
29+
import time
30+
31+
start_time = time.time()
32+
33+
# Make stdout non-blocking on Unix systems
34+
if sys.platform != "win32":
35+
import fcntl
36+
import os
37+
38+
flags = fcntl.fcntl(process.stdout, fcntl.F_GETFL)
39+
fcntl.fcntl(process.stdout, fcntl.F_SETFL, flags | os.O_NONBLOCK)
40+
41+
buffer = ""
42+
while time.time() - start_time < timeout:
43+
try:
44+
# Read available data
45+
chunk = process.stdout.read(1024)
46+
if chunk:
47+
chunk_str = chunk.decode("utf-8", errors="ignore")
48+
buffer += chunk_str
49+
print(chunk_str, end="", flush=True) # Echo output for visibility
50+
51+
if target_string in buffer:
52+
return True
53+
else:
54+
# No data available, sleep briefly
55+
time.sleep(0.1)
56+
except (BlockingIOError, TypeError):
57+
# No data available yet
58+
time.sleep(0.1)
59+
60+
# Check if process has terminated
61+
if process.poll() is not None:
62+
# Process ended, read remaining output
63+
remaining = process.stdout.read()
64+
if remaining:
65+
remaining_str = remaining.decode("utf-8", errors="ignore")
66+
print(remaining_str, end="", flush=True)
67+
if target_string in remaining_str:
68+
return True
69+
return False
70+
71+
return False
72+
73+
1674
@pytest.fixture(scope="function")
1775
def docker_containers():
1876
processes = (
@@ -39,7 +97,12 @@ def single_local_chain():
3997

4098

4199
def test_retry_sync_substrate(single_local_chain):
42-
time.sleep(10)
100+
# Wait for the Docker container to be ready
101+
if not wait_for_output(single_local_chain.process, "Imported #1", timeout=60):
102+
raise TimeoutError(
103+
"Docker container did not start properly - 'Imported #1' not found in output"
104+
)
105+
43106
with RetrySyncSubstrate(
44107
single_local_chain.uri, fallback_chains=[LATENT_LITE_ENTRYPOINT]
45108
) as substrate:
@@ -52,13 +115,14 @@ def test_retry_sync_substrate(single_local_chain):
52115
time.sleep(2)
53116

54117

55-
@pytest.mark.skip(
56-
"There's an issue with this running in the GitHub runner, "
57-
"where it seemingly cannot connect to the docker container. "
58-
"It does run locally, however."
59-
)
60118
def test_retry_sync_substrate_max_retries(docker_containers):
61-
time.sleep(10)
119+
# Wait for both Docker containers to be ready
120+
for i, container in enumerate(docker_containers):
121+
if not wait_for_output(container.process, "Imported #1", timeout=60):
122+
raise TimeoutError(
123+
f"Docker container {i} did not start properly - 'Imported #1' not found in output"
124+
)
125+
62126
with RetrySyncSubstrate(
63127
docker_containers[0].uri, fallback_chains=[docker_containers[1].uri]
64128
) as substrate:

0 commit comments

Comments
 (0)