2

I have the following snippet which I use with every code I run.

import sys
sys.stdin, sys.stdout = open('input', 'r'), open('output', 'w')

Is there any way I can make these two lines run with every .py I run.

Also on Sublime Text this is the build configuration I used to redirect the output to a file, but it is not working.

{
    "cmd": ["/home/jithin/venv/bin/python", "-u", "$file" ,">","/home/jithin/temp/hackerrank/output"],
    "file_regex": "^[ ]*File \"(...*?)\", line ([0-9]*)",
    "selector": "source.python"
}
    

Is there any flags like --stdout to redirect the output of the code to a file.

NB. I cannot use include any lines in the code because I am practising competitive programming, so I usually copy and paste the code from the question to ST. If there was a differemt method I wouldn't need to include the above snippet everytime. Also for pasting back I could simply use Ctrl + A and Ctrl + V.

5
  • 1
    Does this answer your question? How can I run Python commands every time I start Python Commented Jun 22, 2021 at 12:08
  • No because I need to add import os filename = os.environ.get('PYTHONSTARTUP') if filename and os.path.isfile(filename): execfile(filename) in the code. I am looking for a way that resolves the issue by not including any lines of code, so that I can copy and paste easily. Commented Jun 22, 2021 at 12:13
  • Can anything be done in the build configuration ?? Commented Jun 22, 2021 at 12:16
  • 1
    If you'er going to use cmd instead of shell_cmd, you need to add "shell": true, to your build system to tell Sublime that it should get the shell to run the command; otherwise you're giving shell commands (i.e. redirection) as arguments to Python, which it probably does not handle like you would expect Commented Jun 22, 2021 at 17:44
  • I have tried and it's not executing properly, probably an error in the synatx, can you just post the build config? Commented Jun 22, 2021 at 19:40

1 Answer 1

1

As far as I can see, Python has no built in way to allow you to execute arbitrary script commands along with a full on script, so the options available boil down to either manually putting the boilerplate in every file or dynamically adding it there when you run the code.

Generally speaking, my recommendation would be create a snippet that inserts this code for you so that you don't have to manually copy and paste it. To do that, you can choose Tools > Developer > New Snippet... and replace the stub with the following, then save the file as a sublime-snippet file in the location Sublime suggests:

<snippet>
    <content><![CDATA[
import sys
sys.stdin, sys.stdout = open('input', 'r'), open('output', 'w')

]]></content>
    <tabTrigger>stub</tabTrigger>
    <description>Insert IO redirect stubs for competetive coding</description>
    <scope>source.python</scope>
</snippet>

Change the tab trigger as appropriate, but now in a new Python file stubTab will insert the code for you.

It is also possible to construct a build that will automatically add the stub onto the start of every Python file that's executed, if you'd rather do that (but the snippet is much easier).

For that, there is this plugin (see this video on installing plugins if you're not sure how to use one).


import sublime
import sublime_plugin

import os
import tempfile

from Default.exec import ExecCommand


_stub = """
import sys
sys.stdin, sys.stdout = open('input', 'r'), open('output', 'w')

"""


class PythonWithRedirectExecCommand(ExecCommand):
    def run(self, **kwargs):
        view = self.window.active_view()
        if view.file_name() is None or not os.path.exists(view.file_name()):
            return self.window.status_message("Cannot build; no file associated with the current view")

        self.tmp_file = self.get_temp_file(view)

        variables = {"temp_file": self.tmp_file}
        kwargs = sublime.expand_variables(kwargs, variables)

        super().run(**kwargs)

    def get_temp_file(self, view):
        handle, name = tempfile.mkstemp(text=True, suffix=".py")
        with os.fdopen(handle, mode="wt", encoding="utf-8") as handle:
            handle.write(_stub)
            with open(view.file_name()) as source:
                handle.write(source.read())

        return name

    # NOTE: If you are using Sublime Text 3, change this line and the
    #       next use to use finished instead of on_finished.
    def on_finished(self, proc):
        super().on_finished(proc)

        # If the current build didn't finish or it was manually killed, leave.
        if proc != self.proc or proc.killed:
            return

        try:
            # If the build succeeded, delete the temporary file; we will
            # leave it alone if the build fails so that it's possible to
            # navigate to it.
            exit_code = proc.exit_code()
            if exit_code == 0 or exit_code is None:
                os.remove(self.tmp_file)
        finally:
            self.tmp_file = None

This implements a replacement build target which, when executed, will create a temporary file containing the stub content as well as the contents of the current file.

Important note: This was developed in Sublime Text ~~4~~; it will also work in Sublime Text 3, but you need to change both references to on_finished to finished if you're using ST3; otherwise the plugin won't clean up temporary files. Probably also worth noting that for the reasons outlined below, if the run fails the temporary file isn't erased.

To use it, you want a build system similar to this (modify the command as appropriate; this is a generic build):

{
    "target": "python_with_redirect_exec",
    "cancel": {"kill": true},

    "cmd": ["python3", "-u", "\\$temp_file"],
    "file_regex": "^[ ]*File \"(...*?)\", line ([0-9]*)",
    "selector": "source.python",

    "working_dir": "${file_path}",

    "env": {"PYTHONIOENCODING": "utf-8"},

    "windows": {
        "cmd": ["py", "-u", "\\$temp_file"],
    },
}

The important notes here are the target and cancel, which tie the build to the command provided by the plugin, the working_dir which makes sure that the current directory is the directory the current file is in (since that is where the input and output files are expected to be), and that the \\$temp_file is used to reference the temporary output file that contains the resulting code.

As a note on this, if an error occurs, the line numbers will be slightly off in the errors because they are referencing the file that has extra content at top, and if you navigate to it you'll open the temporary file, which is not the one you should probably be editing.

So, all things told, the snippet is probably the safest fastest way to go.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks. I'm following the first method now.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.