Skip to content

Instantly share code, notes, and snippets.

@ecnerwala
Last active December 30, 2024 11:43
Show Gist options
  • Save ecnerwala/ffc9b8c3f61e87ca043393a135d7794d to your computer and use it in GitHub Desktop.
Save ecnerwala/ffc9b8c3f61e87ca043393a135d7794d to your computer and use it in GitHub Desktop.
ecnerwala's CP template system
#!/usr/bin/env python3
"""Download and setup problems from Competitive Companion
Usage:
download_prob.py --echo
download_prob.py [<name>... | -n <number> | -b <batches> | --timeout <timeout>] [--dryrun]
Options:
-h --help Show this screen.
--echo Just echo received responses and exit.
--dryrun Don't actually create any problems
Download limit options:
-n COUNT, --number COUNT Number of problems.
-b COUNT, --batches COUNT Number of batches. (Default 1 batch)
-t TIME, --timeout TIME Timeout for listening to problems. in seconds
"""
from docopt import docopt
import sys
import http.server
import json
from pathlib import Path
import subprocess
import re
# Returns unmarshalled or None
def listen_once(*, timeout=None):
json_data = None
class CompetitiveCompanionHandler(http.server.BaseHTTPRequestHandler):
def do_POST(self):
nonlocal json_data
json_data = json.load(self.rfile)
with http.server.HTTPServer(('127.0.0.1', 10046), CompetitiveCompanionHandler) as server:
server.timeout = timeout
server.handle_request()
if json_data is not None:
print(f"Got data {json.dumps(json_data)}")
else:
print("Got no data")
return json_data
def listen_many(*, num_items=None, num_batches=None, timeout=None):
if num_items is not None:
res = []
for _ in range(num_items):
cur = listen_once(timeout=None)
res.append(cur)
return res
if num_batches is not None:
res = []
batches = {}
while len(batches) < num_batches or any(need for need, tot in batches.values()):
print(f"Waiting for {num_batches} batches:", batches)
cur = listen_once(timeout=None)
res.append(cur)
cur_batch = cur['batch']
batch_id = cur_batch['id']
batch_cnt = cur_batch['size']
if batch_id not in batches:
batches[batch_id] = [batch_cnt, batch_cnt]
assert batches[batch_id][0] > 0
batches[batch_id][0] -= 1
return res
res = [listen_once(timeout=None)]
while True:
cnd = listen_once(timeout=timeout)
if cnd is None:
break
res.append(cnd)
return res
NAME_PATTERN = re.compile(r'^(?:Problem )?([A-Z][0-9]*)\b')
def get_prob_name(data):
if 'USACO' in data['group']:
if 'fileName' in data['input']:
names = [data['input']['fileName'].rstrip('.in'), data['output']['fileName'].rstrip('.out')]
if len(set(names)) == 1:
return names[0]
if 'url' in data and data['url'].startswith('https://www.codechef.com'):
return data['url'].rstrip('/').rsplit('/')[-1]
patternMatch = NAME_PATTERN.search(data['name'])
if patternMatch is not None:
return patternMatch.group(1)
print(f"For data: {json.dumps(data, indent=2)}")
return input("What name to give? ")
def save_samples(data, prob_dir):
with open(prob_dir / 'problem.json', 'w') as f:
json.dump(data, f)
for i, t in enumerate(data['tests'], start=1):
with open(prob_dir / f'sample{i}.in', 'w') as f:
f.write(t['input'])
with open(prob_dir / f'sample{i}.out', 'w') as f:
f.write(t['output'])
# Providing name = '.'
def make_prob(data, name=None):
if name is None:
name = get_prob_name(data)
prob_dir = Path('.')/name
if name == '.':
print("Using current directory...")
pass
elif prob_dir.exists() and prob_dir.is_dir():
# Skip making it
print(f"Already created problem {name}...")
else:
print(f"Creating problem {name}...")
MAKE_PROB = Path(sys.path[0]) / 'make_prob.sh'
try:
subprocess.check_call([MAKE_PROB, name], stdout=sys.stdout, stderr=sys.stderr)
except subprocess.CalledProcessError as e:
print(f"Got error {e}")
return
print("Saving samples...")
save_samples(data, prob_dir)
print()
def main():
arguments = docopt(__doc__)
if arguments['--echo']:
while True:
print(listen_once())
else:
dryrun = arguments['--dryrun']
def run_make_prob(*args, **kwargs):
nonlocal dryrun
if dryrun:
print(f"make_prob(*args={args}, **kwargs={kwargs})")
return
make_prob(*args, **kwargs)
if names := arguments['<name>']:
datas = listen_many(num_items=len(names))
for data, name in zip(datas, names):
run_make_prob(data, name)
elif cnt := arguments['--number']:
cnt = int(cnt)
datas = listen_many(num_items=cnt)
for data in datas:
run_make_prob(data)
elif batches := arguments['--batches']:
batches = int(batches)
datas = listen_many(num_batches=batches)
for data in datas:
run_make_prob(data)
elif timeout := arguments['--timeout']:
timeout = float(timeout)
datas = listen_many(timeout=timeout)
for data in datas:
run_make_prob(data)
else:
datas = listen_many(num_batches=1)
for data in datas:
run_make_prob(data)
if __name__ == '__main__':
main()
#!/usr/bin/env bash
DIR=$(dirname $0)
search_up ()
(
while [[ $PWD != "/" ]]; do
if [[ -e "$1" ]]; then
pwd
if [[ ! -e "$1/$2" ]]; then
break
fi
fi
cd ..
done
)
TEMPLATE_DIR='.template'
PARENT_FILE='$PARENT'
IFS=$'\n'
TEMPLATE_DIRS=($(search_up "$TEMPLATE_DIR" "$PARENT_FILE" | tac))
unset IFS
TEMPLATE_DIRS=(${TEMPLATE_DIRS[@]/%/\/"$TEMPLATE_DIR"})
if hash rename.ul 2>/dev/null; then
RENAME=rename.ul
else
RENAME=rename
fi
for filepath in "$@"; do
PROBLEM_NAME=$(basename "$filepath")
if [[ -e "$filepath" ]]; then
echo "$filepath already exists. Remove it and retry."
continue
fi
# Copy files in
mkdir -p "$filepath"
for CURRENT_TEMPLATE_DIR in "${TEMPLATE_DIRS[@]}"; do
cp -r -T "$CURRENT_TEMPLATE_DIR" "$filepath/"
done
rm -f "$filepath/$PARENT_FILE"
# Rename PROBLEM_NAME in file names
find $filepath -type f -print0 | xargs -0 ${RENAME} "\$PROBLEM_NAME" "$PROBLEM_NAME"
# Envsubst PROBLEM_NAME in files
export PROBLEM_NAME
REPLACE_STRING='${PROBLEM_NAME}'
find $filepath -type f -print0 | xargs -0 -I{} bash -c\
'TEMP=$(mktemp) && cat "$1" > "$TEMP" && envsubst '"'$REPLACE_STRING'"' < "$TEMP" > "$1" && rm "$TEMP"'\
-- {}
pushd $filepath > /dev/null
if [[ -e "setup" ]]; then
echo "Running setup"
./setup
fi
popd > /dev/null
done
@BryanMauricio
Copy link

cmd

@BryanMauricio
Copy link

maybe should i add download_prob and make_prob to the path ?

@tanushbanerjee
Copy link

Ok,
Which version of python are you using?

@BryanMauricio
Copy link

3.8.3

@tanushbanerjee
Copy link

No,
Thats not necessary you can just change the permissions and run it via the shell

@tanushbanerjee
Copy link

Oh, so try to upgrade your python

@BryanMauricio
Copy link

Hey still the same problem :(

**_Got data {"name": "A. Avoid Trygub", "group": "Codeforces - Codeforces Global Round 12", "url": "https://codeforces.com/contest/1450/problem/A", "interactive": false, "memoryLimit": 256, "timeLimit": 1000, "tests": [{"input": "3\n11\nantontrygub\n15\nbestcoordinator\n19\ntrywatchinggurabruh\n", "output": "bugyrtnotna\nbestcoordinator\nbruhtrywatchinggura\n"}], "testType": "single", "input": {"type": "stdin"}, "output": {"type": "stdout"}, "languages": {"java": {"mainClass": "Main", "taskClass": "AAvoidTrygub"}}}

Creating problem n3...
Traceback (most recent call last):
File "C:\Users\admin\Downloads\ffc9b8c3f61e87ca043393a135d7794d-60857c014aa8f76ec654d8dccbcca81f426ef3cc\ffc9b8c3f61e87ca043393a135d7794d-60857c014aa8f76ec654d8dccbcca81f426ef3cc\download_prob.py", line 130, in
main()
File "C:\Users\admin\Downloads\ffc9b8c3f61e87ca043393a135d7794d-60857c014aa8f76ec654d8dccbcca81f426ef3cc\ffc9b8c3f61e87ca043393a135d7794d-60857c014aa8f76ec654d8dccbcca81f426ef3cc\download_prob.py", line 115, in main
make_prob(data, name)
File "C:\Users\admin\Downloads\ffc9b8c3f61e87ca043393a135d7794d-60857c014aa8f76ec654d8dccbcca81f426ef3cc\ffc9b8c3f61e87ca043393a135d7794d-60857c014aa8f76ec654d8dccbcca81f426ef3cc\download_prob.py", line 88, in make_prob
subprocess.check_call([MAKE_PROB, name], stdout=sys.stdout, stderr=sys.stderr)
File "C:\Users\admin\AppData\Local\Programs\Python\Python39\lib\subprocess.py", line 368, in check_call
retcode = call(*popenargs, **kwargs)
File "C:\Users\admin\AppData\Local\Programs\Python\Python39\lib\subprocess.py", line 349, in call
with Popen(*popenargs, kwargs) as p:
File "C:\Users\admin\AppData\Local\Programs\Python\Python39\lib\subprocess.py", line 947, in init
self._execute_child(args, executable, preexec_fn, close_fds,
File "C:\Users\admin\AppData\Local\Programs\Python\Python39\lib\subprocess.py", line 1416, in _execute_child
hp, ht, pid, tid = winapi.CreateProcess(executable, args,

@BryanMauricio
Copy link

and this

OSError: [WinError 193] %1 is not a valid Win32 application

@rishabhdeepsingh
Copy link

@BryanMauricio you can try WSL

Copy link

ghost commented Dec 26, 2020

and this

OSError: [WinError 193] %1 is not a valid Win32 application

download_prob.py is meant to be run on a linux system. However if you are using a windows system (like me).. You can install Windows Subsystem for Linux. Link for reference - https://docs.microsoft.com/en-us/windows/wsl/install-win10

Then install Ubuntu or any other distro via microsoft store.

After doing all this.....

  1. Install Competitive Companion and change port to 10046.
  2. Open Cmd and run the command "wsl"
  3. navigate to your folder where u have your download_prob.py script.
  4. run the script with python3 ./download_prob.py and click on the green plus.
  5. Get back with any questions if you face any problem

@egolesss
Copy link

I faced this error but i do all things, what is a problem ?
Got data {"name": "C. Peaceful Rooks", "group": "Codeforces - Codeforces Round #692 (Div. 2, based on Technocup 2021 Elimination Round 3)", "url": "https://codeforces.com/contest/1465/problem/C", "interactive": false, "memoryLimit": 256, "timeLimit": 1000, "tests": [{"input": "4\n3 1\n2 3\n3 2\n2 1\n1 2\n5 3\n2 3\n3 1\n1 2\n5 4\n4 5\n5 1\n2 2\n3 3\n", "output": "1\n3\n4\n2\n"}], "testType": "single", "input": {"type": "stdin"}, "output": {"type": "stdout"}, "languages": {"java": {"mainClass": "Main", "taskClass": "CPeacefulRooks"}}} Creating problem a... Traceback (most recent call last): File "/home/laniakea/programming/download_prob.py", line 130, in <module> main() File "/home/laniakea/programming/download_prob.py", line 115, in main make_prob(data, name) File "/home/laniakea/programming/download_prob.py", line 88, in make_prob subprocess.check_call([MAKE_PROB, name], stdout=sys.stdout, stderr=sys.stderr) File "/usr/lib/python3.8/subprocess.py", line 359, in check_call retcode = call(*popenargs, **kwargs) File "/usr/lib/python3.8/subprocess.py", line 340, in call with Popen(*popenargs, **kwargs) as p: File "/usr/lib/python3.8/subprocess.py", line 854, in __init__ self._execute_child(args, executable, preexec_fn, close_fds, File "/usr/lib/python3.8/subprocess.py", line 1702, in _execute_child raise child_exception_type(errno_num, err_msg, err_filename) PermissionError: [Errno 13] Permission denied: PosixPath('/home/laniakea/programming/make_prob.sh')

Copy link

ghost commented Dec 27, 2020

Try this :

  1. Run sudo python3 download_prob.py -n6 (and get all problems) --> Do this in WSL
  2. If that dosen't work... run chmod +x download_prob.py --> Do this in WSL
  3. Make sure you have the .template directory, make_prob.sh, download_prob.py in the same folder.. Eg -> Have them all in yr programming directory.
  4. Close the file in the python IDLE and then run the program
  5. Get back with any questions if you face any problem

@geekypandey
Copy link

Thank you for the script! I will build my own using it! :-)

@Akash671
Copy link

Akash671 commented Jan 2, 2021

how to use it in linux
please help me.....

Copy link

ghost commented Jan 3, 2021

Do the same thing but in terminal

Copy link

ghost commented Jan 5, 2021

I faced this error but i do all things, what is a problem ?
Got data {"name": "C. Peaceful Rooks", "group": "Codeforces - Codeforces Round #692 (Div. 2, based on Technocup 2021 Elimination Round 3)", "url": "https://codeforces.com/contest/1465/problem/C", "interactive": false, "memoryLimit": 256, "timeLimit": 1000, "tests": [{"input": "4\n3 1\n2 3\n3 2\n2 1\n1 2\n5 3\n2 3\n3 1\n1 2\n5 4\n4 5\n5 1\n2 2\n3 3\n", "output": "1\n3\n4\n2\n"}], "testType": "single", "input": {"type": "stdin"}, "output": {"type": "stdout"}, "languages": {"java": {"mainClass": "Main", "taskClass": "CPeacefulRooks"}}} Creating problem a... Traceback (most recent call last): File "/home/laniakea/programming/download_prob.py", line 130, in <module> main() File "/home/laniakea/programming/download_prob.py", line 115, in main make_prob(data, name) File "/home/laniakea/programming/download_prob.py", line 88, in make_prob subprocess.check_call([MAKE_PROB, name], stdout=sys.stdout, stderr=sys.stderr) File "/usr/lib/python3.8/subprocess.py", line 359, in check_call retcode = call(*popenargs, **kwargs) File "/usr/lib/python3.8/subprocess.py", line 340, in call with Popen(*popenargs, **kwargs) as p: File "/usr/lib/python3.8/subprocess.py", line 854, in __init__ self._execute_child(args, executable, preexec_fn, close_fds, File "/usr/lib/python3.8/subprocess.py", line 1702, in _execute_child raise child_exception_type(errno_num, err_msg, err_filename) PermissionError: [Errno 13] Permission denied: PosixPath('/home/laniakea/programming/make_prob.sh')

Hey,
Even I faced this error on a new computer.
run : chmod +x make_prob.sh
run : chmod +x download_prob.py

@Ahmedsabib
Copy link

I didn't get the settings of :make!test. How can i do this?

@pnchinmay
Copy link

You can do it as it is simply a python script

Hey
Could you help me with an error
I tried debugging myself but there's one error still left

Global symbol "$PROBLEM_NAME" requires explicit package name (did you forget to declare "my $PROBLEM_NAME"?) at (user-supplied code) line 3.
xargs: rename: exited with status 255; aborting

Also, I've to manually copy the Makefile and $PROBLEM_NAME.cpp to the problem directory and then make changes to problem name section in the Makefile
It can work as desired if the above errors are removed.

Any clue to make it work ?
Appreciate your time

@pnchinmay
Copy link

pnchinmay commented May 4, 2021

Nevermind
I made it work by using cat, echo and sed commands instead of the lines 46-54 in make_prob.sh

 cat ~/programming/template.cpp > ./$filepath/"$PROBLEM_NAME".cpp; echo "created '$PROBLEM_NAME'.cpp file"; cp ~/programming/Makefile ./$filepath/; sed -i '1s/^/PROBLEM_NAME := '$PROBLEM_NAME'\n/' ./$filepath/Makefile;

I'm adding my make_prob.sh here, in case anyone finds it useful

#!/usr/bin/env bash

DIR=$(dirname $0)
search_up ()
(
    while [[ $PWD != "/" ]]; do
        if [[ -e "$1" ]]; then
            pwd
            if [[ ! -e "$1/$2" ]]; then
                break
            fi
        fi
        cd ..
    done
)
TEMPLATE_DIR='.template'
PARENT_FILE='$PARENT'
IFS=$'\n'
TEMPLATE_DIRS=($(search_up "$TEMPLATE_DIR" "$PARENT_FILE" | tac))
unset IFS
TEMPLATE_DIRS=(${TEMPLATE_DIRS[@]/%/\/"$TEMPLATE_DIR"})

if hash rename.ul 2>/dev/null; then
    RENAME=rename.ul
else
    RENAME=rename
fi

for filepath in "$@"; do
    PROBLEM_NAME=$(basename "$filepath")

    if [[ -e "$filepath" ]]; then
        echo "$filepath already exists. Remove it and retry."
        continue
    fi

    # Copy files in
    mkdir -p "$filepath"
    for CURRENT_TEMPLATE_DIR in "${TEMPLATE_DIRS[@]}"; do
        cp -r -T "$CURRENT_TEMPLATE_DIR" "$filepath/"
    done
    rm -f "$filepath/$PARENT_FILE"
    cat ~/programming/template.cpp > ./$filepath/"$PROBLEM_NAME".cpp; echo "created '$PROBLEM_NAME'.cpp file"; cp ~/programming/Makefile ./$filepath/; sed -i '1s/^/PROBLEM_NAME := '$PROBLEM_NAME'\n/' ./$filepath/Makefile;

    pushd $filepath > /dev/null
    if [[ -e "setup" ]]; then
        ./setup
    fi
    popd > /dev/null
done

@berg223
Copy link

berg223 commented Oct 5, 2021

Hi there, I'm confused by $PARENT since it's empty in mac. What exact meaning it is? Is it the folder name like "Codeforces 746"?

@jjiangly
Copy link

jjiangly commented Aug 7, 2022

Screenshot from 2022-08-08 01-07-37
Can anyone help me to fix that, when i use download_pro.py and it always shows like this.

@ecnerwala
Copy link
Author

Very weird, someone else reported something like that too. I verified that it's the same code as on my computer, so I'm not sure what the difference is. Maybe there's something with docopt versions or something? (By the way, the right usage is ./download_prob.py A B C to download 3 problems named A B C)

@jjiangly
Copy link

jjiangly commented Aug 9, 2022

Excuse me, docopt version to install? I tried it on a Mac but it gives me the same error, I think my docopt version is wrong.

@ecnerwala
Copy link
Author

It's just the newest one (0.6.2 I think).

@resident-1
Copy link

For anyone with the same issue, add a new line after Usage ends. Here is the link where I found the solution:
https://stackoverflow.com/questions/31901138/docopt-on-python-3-only-prints-help-screen-and-does-not-execute-the-function

@ecnerwala
Copy link
Author

For anyone with the same issue, add a new line after Usage ends. Here is the link where I found the solution: https://stackoverflow.com/questions/31901138/docopt-on-python-3-only-prints-help-screen-and-does-not-execute-the-function

Huh, isn't there already a newline? Strange

@resident-1
Copy link

resident-1 commented Oct 21, 2022

For anyone with the same issue, add a new line after Usage ends. Here is the link where I found the solution: https://stackoverflow.com/questions/31901138/docopt-on-python-3-only-prints-help-screen-and-does-not-execute-the-function

Huh, isn't there already a newline? Strange

That is really strange. For some reason when I copied the contents of download_prob.py the newline after Usage was gone ...

@ecnerwala
Copy link
Author

ecnerwala commented Oct 21, 2022

Hm, that happens to me if I copy from this page (with syntax highlighting), but not if I copy from the Raw version. I guess there's some funny HTML/CSS going on. I guess that explains it then.

@utkarsh-shrivastav77
Copy link

#ecnerwala can you share your setup file and the whole process how to setup nvim

@tungduong150105
Copy link

tungduong150105 commented Feb 22, 2024

image
Can anyone help me, when I use download_prob.py and get this error, but I created make_pro.sh file directly, I don't know how to fix that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment