plr(python-leetcode-runner) is a tool to fetch LeetCode problems (using the problem title slug) and then to test your solutions.
A lot of code logic has been lifted from the wonderful leetcode-runner project.
fetcher.py: To execute the GraphQL query on the public API and get the problem details.models.py: Pydantic models for the problem data obtained.generator.py: To generate the template for the python solution file that's created.
Some of my improvements include,
- A new
testsubcommand instead of calling the class method in the solution file. - Supports testing with multiple solutions for a problem.
- Specify your own custom methods for more complex testing scenarios required for certain problems.
- Shorter name 😉
Use uv to install and manage plr.
uv tool install git+https://github.com/dashmage/plr.gitFrom the LeetCode problem URL, obtain the title slug name. For the two sum problem, that would be two-sum.
Now run,
$ plr pull two-sum
# Or even directly with: uv run plr pull two-sum
1-two-sum.py has been created! Happy solvingThis fetches the problem description and python starter code and adds into the newly created 1-two-sum.py python file. 1 is the problem ID for the two sum problem.
After coding up a solution and adding it to the Solution class, run the plr test command with the path to the problem file to validate it against the example test cases.
$ plr test 1-two-sum.pyThis will test the Solution class method(s) with the examples automatically parsed from the problem description in the docstring.
You can even provide multiple solution methods in the Solution class and each of them would be validated with the example test cases.
=== twoSum_1 ===
[ OK ]
nums = [2,7,11,15], target = 9
Expected: [0, 1]
Actual : [0, 1]
------------------------------
[ OK ]
nums = [3,2,4], target = 6
Expected: [1, 2]
Actual : [1, 2]
------------------------------
[ OK ]
nums = [3,3], target = 6
Expected: [0, 1]
Actual : [0, 1]
------------------------------
Passed: 3/3
=== twoSum_2 ===
[ FAILED ]
nums = [2,7,11,15], target = 9
Expected: [0, 1]
Actual : [1, 2, 3]
------------------------------
[ FAILED ]
nums = [3,2,4], target = 6
Expected: [1, 2]
Actual : [1, 2, 3]
------------------------------
[ FAILED ]
nums = [3,3], target = 6
Expected: [0, 1]
Actual : [1, 2, 3]
------------------------------
Passed: 0/3
Extra test cases can easily be added by appending a new "Example" in the problem description. This additional test will be picked up by the test validator.
Example 5:
Input: nums = [1,2,3], k = 2
Output: [1,2]
Certain problems require more steps to be performed either while evaluating and returning the actual results from the solution method or while validating whether the results are as expected.
For these situations, you can optionally define two methods outside the Solution class, namely evaluate and validate.
The evaluate method comes in handy when you need to alter the results returned by the solution method. This can happen when the expected results also check the value of the input array which changes in-place.
For example, in Problem #26, duplicates are to be removed from a sorted array. For testing solutions to this problem, we need to evaluate the number of unique elements and return that along with the input array as a tuple.
Here is what a sample input and output look like,
Input: nums = [1,1,2]
Output: 2, nums = [1,2,_]
Explanation: Your function should return k = 2, with the first two elements of nums being 1 and 2 respectively.
It does not matter what you leave beyond the returned k (hence they are underscores).
We can then define our evaluate method accordingly.
def evaluate(method, kwargs):
result = method(**kwargs)
return result, kwargs["nums"][:result]The validate method can be defined when you need to explicitly specify how to compare the actual and expected test case results. By default, this is checked simply by running actual == expected. But in some problems, say, where the order of elements in the expected array can be ignored, you cannot directly compare their values.
For example, in Problem #347, we're expected to return the top k frequent elements as a list in any order. So Counters can be used to ignore the sort order but still preserve duplicates during the comparison between the lists.
Here is what a sample input and output look like,
Input: nums = [1,1,1,2,2,3], k = 2
Output: [1,2]
We can then define our validate method accordingly.
def validate(actual, expected):
from collections import Counter
return Counter(actual) == Counter(expected)Take a look at the solved LeetCode problems provided in the repo some of which utilize these methods for testing.
Do an editable install of the tool into your local venv.
uv pip install -e .Now any code changes will automatically reflect while using the executable.