Skip to content

Commit

Permalink
Merge pull request #74 from geowurster/ci
Browse files Browse the repository at this point in the history
Add GitHub Actions CI
  • Loading branch information
geowurster authored Dec 12, 2023
2 parents 0d37902 + 3312169 commit 52a7faf
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 32 deletions.
52 changes: 52 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
name: Tests

on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]

jobs:

test:

runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]

steps:

- uses: actions/checkout@v4

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
cache: 'pip'

- name: Install dependencies
shell: bash
run: |
python3 -m pip install --upgrade pip setuptools wheel
python3 -m pip install ".[test]"
# Be sure to actually test the package, not the local 'pyin.py' file.
rm pyin.py
- name: Report environment information
shell: bash
run: |
python3 --version
python3 -m pip --version
python3 -m pip show pip setuptools wheel pyin
python3 -m pyin --version
python3 -c "import pyin; print(pyin.__version__)"
- name: Run tests
shell: bash
run: |
python3 -W error -m pytest \
--cov pyin \
--cov-report term-missing \
--cov-fail-under 100
20 changes: 4 additions & 16 deletions docs.rst
Original file line number Diff line number Diff line change
Expand Up @@ -689,22 +689,10 @@ is equivalent to:

Entrypoint to the CLI for use within Python. Does not catch all exceptions.
A compliant argument parser is available via the ``argparse_parser()``
function.

.. code::
>>> import pyin
>>> parser = pyin.argparse_parser()
>>> args = parser.parse_args(['--gen', 'range(3)', 'i + 1'])
>>> assert pyin.main(**vars(args)) == 0
1
2
3
While not part of the official API, the ``_cli_entrypoint()`` function may be
worth referencing. It contains an additional layer of error handling for the
``$ pyin`` utility and exists to bridge the gap between the shell and
``main()``.
function. While not part of the official API, the ``_cli_entrypoint()``
function may be worth referencing. It contains an additional layer of error
handling for the ``$ pyin`` utility and exists to bridge the gap between the
shell and ``main()``.

``pyin.argparse_parser()``
--------------------------
Expand Down
21 changes: 17 additions & 4 deletions pyin.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,22 @@


import abc
from collections.abc import Iterable
import argparse
import builtins
from collections import deque
from collections.abc import Iterable
import builtins
import csv
import functools
import importlib.util
import inspect
import io
import itertools as it
import json
import sys
import signal
import operator as op
import os
import re
import signal
import sys
import traceback


Expand Down Expand Up @@ -1246,6 +1247,18 @@ def _cli_entrypoint(rawargs=None):
print("ERROR:", str(e), file=sys.stderr)
exit_code = 1

# If the input and/or file points to a file descriptor and is not 'stdin',
# close it. Avoids a Python warning about an unclosed resource.
for attr in ('infile', 'outfile'):
f = getattr(args, attr)
try:
fileno = getattr(f, 'fileno', lambda: None)()
except io.UnsupportedOperation:
continue

if fileno not in (None, 0, 1, 2):
f.close()

exit(exit_code)


Expand Down
5 changes: 4 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -53,5 +53,8 @@ legacy_tox_ini = """
deps =
.[test]
commands =
pytest --cov pyin --cov-report term-missing --cov-fail-under 100
python3 -W error -m pytest \
--cov pyin \
--cov-report term-missing \
--cov-fail-under 100
"""
24 changes: 13 additions & 11 deletions tests/test_pyin.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,27 +164,29 @@ def test_KeyboardInterrupt():
# into a thread where '_cli_entrypoint()' is running. It probably is
# possible with some awful hackery though.

_, stdin = pty.openpty()
_, fd = pty.openpty()

proc = subprocess.Popen(
['pyin', '--gen', 'range(10)', '(time.sleep(0.5), i)[1]'],
stdin=stdin,
stdin=fd,
stderr=subprocess.PIPE,
stdout=subprocess.PIPE
)

# Sleep long enough for things to hit the main loop, otherwise we may
# kill the process before it enters the right context.
time.sleep(0.5)
with proc as proc:

# Send SIGINT into the process.
proc.send_signal(signal.SIGINT)
# Sleep long enough for things to hit the main loop, otherwise we may
# kill the process before it enters the right context.
time.sleep(0.5)

# Wait for it to shut down, which should not take long at all.
proc.wait(1)
# Send SIGINT into the process.
proc.send_signal(signal.SIGINT)

assert proc.returncode == 130
assert not proc.stderr.read()
# Wait for it to shut down, which should not take long at all.
proc.wait(1)

assert proc.returncode == 130
assert not proc.stderr.read()


def test_main_sys_path(runner):
Expand Down

0 comments on commit 52a7faf

Please sign in to comment.