Skip to content

HansBug/pyspj

Repository files navigation

pyspj

PyPI PyPI - Python Version Loc Comments

Docs Deploy Code Test Badge Creation Package Release codecov

GitHub stars GitHub forks GitHub commit activity GitHub issues GitHub pulls Contributors GitHub license

A light-weighted special support utils.

Installation

You can simply install it with pip command line from the official PyPI site.

pip install pyspj

For more information about installation, you can refer to the installation guide.

Quick Start

Use with CLI

You can use pyspj CLI to judge the running result, the help information is as follows

Usage: pyspj [OPTIONS]

Options:
  -v, --version                   Show package's version information.
  -i, --input TEXT                Input content of special judge.
  -o, --output TEXT               Output content of special judge
  -I, --input_file FILE           Input file of special judge (if -i is given,
                                  this will be ignored).

  -O, --output_file FILE          Output file of special judge (if -o is
                                  given, this will be ignored).

  -t, --type [free|simple|continuity]
                                  Type of the final result.  [default: free]
  -s, --spj TEXT                  Special judge script to be used.  [required]
  -p, --pretty                    Use pretty mode to print json result.
  -h, --help                      Show this message and exit.

Here is a simple example, a spj file namedtest_spj.py

import io


def spj_func(stdin: io.StringIO, stdout: io.StringIO):
    inputs = [int(item.strip()) for item in stdin.read().strip().split(' ') if item]
    _correct_sum = sum(inputs)

    outputs = stdout.read().strip().split(' ', maxsplit=2)
    if len(outputs) >= 1:
        _result = int(outputs[0])
    else:
        return False, 'No output found.'

    if _result == _correct_sum:
        return True, 'Correct result.', 'Oh yeah, well done ^_^.'
    else:
        return False, 'Result {correct} expected but {actual} found.'.format(
            correct=repr(_correct_sum), actual=repr(_result)
        )


__spj__ = spj_func

You can use CLI to judge the result

# input: 1 2 3 4 5
# output: 15
pyspj -i '1 2 3 4 5' -o '15' -s test_spj:spj_func

It means import special judge function spj_func from package test_spj, the output result should be

{"correctness": true, "detail": "Oh yeah, well done ^_^.", "message": "Correct result."}

Besides, a simpler command line can be used due to the definition of __spj__ variable

pyspj -i '1 2 3 4 5' -o '15' -s test_spj

This command is equivalent to the above command.

Input & Output from File

When the scale of input or output is huge, you can load them from -I and -E option.

Here is an exmaple, a input file namedtest_input.txt

1 2 3 4 5

Output file namedtest_output.txt

15

You can use CLI to judge the result in the txt files

pyspj -I test_input.txt -O test_output.txt -s test_spj

The output should be

{"correctness": true, "detail": "Oh yeah, well done ^_^.", "message": "Correct result."}

Actually, -I and -o can be used together, so are the -i and -E options. There will be nothing different.

Pretty Json Output

If you need pretty print the result (especially when you are debugging), you can use -p option.

pyspj -i '1 2 3 4 5' -o '15' -s test_spj -p

The output should be

{
    "correctness": true,
    "detail": "Oh yeah, well done ^_^.",
    "message": "Correct result."
}

Additional Arguments

Sometimes, you can use additional arguments to support more complex cases.

Such as the special judge function below

import io


def spj_func(stdin: io.StringIO, stdout: io.StringIO, fxxk=None):
    inputs = [int(item.strip()) for item in stdin.read().strip().split(' ') if item]
    _correct_sum = sum(inputs)

    if not fxxk:
        outputs = stdout.read().strip().split(' ', maxsplit=2)
        if len(outputs) >= 1:
            _result = int(outputs[0])
        else:
            return False, 'No output found.'

        if _result == _correct_sum:
            return True, 'Correct result.', 'Oh yeah, well done ^_^.'
        else:
            return False, 'Result {correct} expected but {actual} found.'.format(
                correct=repr(_correct_sum), actual=repr(_result)
            )
    else:
        return False, 'Result error because {value} detected in fxxk.'.format(value=repr(fxxk))


__spj__ = spj_func

An extra fxxk argument is used, so the following command line can be used to set the value of argument fxxk to 2 (string)

pyspj -i '1 2 3 4 5' -o '15' -s test_spj -p -V fxxk=2

The output should be

{
    "correctness": false,
    "detail": "Result error because '2' detected in fxxk.",
    "message": "Result error because '2' detected in fxxk."
}

ATTENTION:

  • Addtional argument should has a default value, otherwise when the value is not provided by command line, it will raise error.
  • The default type of addtional arguments are string, you need to convert it to the type you actually need in your special judge function.

Use Special Judge in Python

pyspj can be used in native Python by importing package

from pyspj import execute_spj_from_string

if __name__ == '__main__':
    result = execute_spj_from_string('test_spj', '1 2 3 4 5', '15')
    print(result.to_json())

The output should be

{'correctness': True, 'message': 'Correct result.', 'detail': 'Oh yeah, well done ^_^.'}

File input or file output are supported as well, like the following code

from pyspj import execute_spj_from_file

if __name__ == '__main__':
    result = execute_spj_from_file('test_spj', 'test_input.txt', 'test_output.txt')
    print(result.to_json())

The output should be the same as the abovementioned code.

Addtional arguments are also supported like the CLI.

import codecs
import io

from pyspj import execute_spj

if __name__ == '__main__':
    with codecs.open('test_input.txt') as stdin, \
            io.StringIO('15') as stdout:
        result = execute_spj('test_spj', stdin, stdout, arguments={'fxxk': 2})
    print(result.to_json())

The output should be

{'correctness': False, 'message': 'Result error because 2 detected in fxxk.', 'detail': 'Result error because 2 detected in fxxk.'}

Make My Special Judge Runnable

You can add entry for your special judge function by using pyspj_entry function and call it in __main___

import io

from pyspj import pyspj_entry


def spj_func(stdin: io.StringIO, stdout: io.StringIO):
    inputs = [int(item.strip()) for item in stdin.read().strip().split(' ') if item]
    _correct_sum = sum(inputs)

    outputs = stdout.read().strip().split(' ', maxsplit=2)
    if len(outputs) >= 1:
        _result = int(outputs[0])
    else:
        return False, 'No output found.'

    if _result == _correct_sum:
        return True, 'Correct result.', 'Oh yeah, well done ^_^.'
    else:
        return False, 'Result {correct} expected but {actual} found.'.format(
            correct=repr(_correct_sum), actual=repr(_result)
        )


if __name__ == '__main__':
    pyspj_entry('test_spj', spj_func, version='0.1.1')()

Save the code above to test_spj.py, and then you can run it like pyspj cli.

python test_spj.py -h

The output should be

Usage: test_spj.py [OPTIONS]

  Test_spj - test a pair of given input and output.

Options:
  -v, --version           Show special judge's version information.
  -i, --input TEXT        Input content of special judge.
  -o, --output TEXT       Output content of special judge
  -I, --input_file FILE   Input file of special judge (if -i is given, this
                          will be ignored).
  -O, --output_file FILE  Output file of special judge (if -o is given, this
                          will be ignored).
  -V, --value TEXT        Attached values for special judge (do not named as
                          "stdin" or "stdout").
  -p, --pretty            Use pretty mode to print json result.
  -h, --help              Show this message and exit.

And test the input

python test_spj.py -i '1 2 3 4 5' -o 15
{"correctness": true, "detail": "Oh yeah, well done ^_^.", "message": "Correct result."}

Besides, if the target environment does not have python, you can build this script with pyinstaller

pip install pyspj[build]
pyinstaller -D -F -n test_spj -c test_spj.py

A standalone executable file will be created.

License

pyspj released under the Apache 2.0 license.