Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 35 additions & 1 deletion .github/workflows/dist.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ jobs:
run: |
pip --disable-pip-version-check install mypy
pip --disable-pip-version-check install -e .
pip --disable-pip-version-check install -r tests/requirements.txt
- name: Run mypy
uses: liskin/gh-problem-matcher-wrap@v2
with:
Expand Down Expand Up @@ -57,9 +58,42 @@ jobs:
name: dist
path: dist

test:
needs: [build]
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: ["ubuntu-22.04", "macos-14", "windows-2022"]

steps:
- uses: actions/checkout@v5

- uses: actions/setup-python@v5
with:
python-version: "3.13"

- name: Download build artifacts
uses: actions/download-artifact@v4
with:
name: dist
path: dist

- name: Install
shell: bash
working-directory: dist
run: python -m pip --disable-pip-version-check install *.whl

- name: Install test dependencies
working-directory: tests
run: python -m pip --disable-pip-version-check install -r requirements.txt

- name: Test wheel
working-directory: tests
run: python run_tests.py

publish:
runs-on: ubuntu-latest
needs: [check, check-mypy, build]
needs: [check, check-mypy, build, test]
permissions:
id-token: write
if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags')
Expand Down
11 changes: 11 additions & 0 deletions robotpy/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,17 @@ def _load_robot_class():
print(f"ERROR: {robot_py_path} is a directory", file=sys.stderr)
sys.exit(1)

# Ensure that it's robot.py and not Robot.py or similar by checking the
# directory entries of its parent
lower_name = robot_py_path.name.lower()
for entry in robot_py_path.parent.iterdir():
if entry.name.lower() == lower_name and entry.name != robot_py_path.name:
print(
f"ERROR: {robot_py_path} must be {robot_py_path.name} (found '{entry.name}')",
file=sys.stderr,
)
sys.exit(1)

# Add that directory to sys.path to ensure that imports work as expected
sys.path.insert(0, str(robot_py_path.parent.absolute()))

Expand Down
1 change: 1 addition & 0 deletions tests/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pytest
13 changes: 13 additions & 0 deletions tests/run_tests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/usr/bin/env python3

import os
from os.path import abspath, dirname, join
import sys
import subprocess

if __name__ == "__main__":
root = abspath(dirname(__file__))
os.chdir(root)

# Run pytest
subprocess.check_call([sys.executable, "-m", "pytest"])
62 changes: 62 additions & 0 deletions tests/test_robot_case.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import sys
import textwrap

import pytest

from robotpy import main


class DummyWpilib:
class RobotBase:
pass


@pytest.fixture(autouse=True)
def mock_wpilib(monkeypatch):
monkeypatch.setitem(sys.modules, "wpilib", DummyWpilib)


def test_load_robot_class_exact_case(tmp_path, monkeypatch, capsys):
# create correct-case file
robot_py = tmp_path / "robot.py"
robot_py.write_text(
textwrap.dedent(
"""
import wpilib
class MyRobot(wpilib.RobotBase):
pass
"""
)
)

monkeypatch.setattr(main, "robot_py_path", robot_py)

# Should pass (exact case)
main._load_robot_class()


def test_load_robot_class_wrong_case(tmp_path, monkeypatch, capsys):
robot_py = tmp_path / "robot.py"
Robot_py = tmp_path / "Robot.py"
Robot_py.write_text(
textwrap.dedent(
"""
import wpilib
class MyRobot(wpilib.RobotBase):
pass
"""
)
)

case_insensitive_fs = robot_py.exists()

monkeypatch.setattr(main, "robot_py_path", robot_py)

with pytest.raises(SystemExit):
main._load_robot_class()
err = capsys.readouterr().err

if case_insensitive_fs:
assert "must be robot.py" in err
else:
assert "does not exist" in err