python / cpython

The Python programming language
https://www.python.org/
Other
59.98k stars 29.02k forks source link

Add shutil.open #47427

Open f601c944-163b-4aa4-8d5d-9c031a35257c opened 15 years ago

f601c944-163b-4aa4-8d5d-9c031a35257c commented 15 years ago
BPO 3177
Nosy @ronaldoussoren, @tebeka, @pitrou, @larryhastings, @giampaolo, @benjaminp, @mcepl, @merwok, @bitdancer, @smarnach, @Fak3, @danpla
Files
  • os_startfile.diff: patch that implemented os.startfile()
  • shutil_open.py: implementation sketch
  • shutil_launch.py: The last 1/3rd of Rebert's implementation of shutil.open()
  • shutil_open.patch: Implementation of shutil_open feature, untested on Windows
  • shutil_open.patch
  • shutil_open.patch: provides shutil.launch() to do os.startfile() cross-platform
  • shutil_open.patch: another round of improvement
  • shutil_open.patch: revised patch
  • issue3177-os_startfile_macosx.txt
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields: ```python assignee = None closed_at = None created_at = labels = ['type-feature', 'library'] title = 'Add shutil.open' updated_at = user = 'https://bugs.python.org/ganadist' ``` bugs.python.org fields: ```python activity = actor = 'Socob' assignee = 'none' closed = False closed_date = None closer = None components = ['Library (Lib)'] creation = creator = 'ganadist' dependencies = [] files = ['10715', '25310', '25311', '25312', '25315', '25317', '25319', '25332', '26624'] hgrepos = [] issue_num = 3177 keywords = ['patch'] message_count = 62.0 messages = ['68623', '68650', '68664', '140059', '140275', '140276', '140280', '140283', '140415', '140416', '140418', '140419', '157216', '157246', '157247', '157258', '159000', '159001', '159004', '159005', '159006', '159007', '159008', '159009', '159010', '159017', '159020', '159029', '159030', '159034', '159037', '159038', '159039', '159043', '159044', '159051', '159056', '159058', '159059', '159062', '159063', '159064', '159065', '159068', '159069', '159121', '159505', '159507', '161569', '161613', '161631', '161687', '161688', '161837', '161852', '161853', '161854', '161858', '167011', '310214', '311549', '311552'] nosy_count = 19.0 nosy_names = ['ronaldoussoren', 'tebeka', 'pitrou', 'larry', 'giampaolo.rodola', 'benjamin.peterson', 'mcepl', 'eric.araujo', 'ganadist', 'Arfrever', 'r.david.murray', 'cvrebert', 'rosslagerwall', 'smarnach', 'Roman.Evstifeev', 'Hobson.Lane', 'plakhotich', 'Socob', 'amirjn'] pr_nums = [] priority = 'low' resolution = None stage = None status = 'open' superseder = None type = 'enhancement' url = 'https://bugs.python.org/issue3177' versions = ['Python 3.3'] ```

    f601c944-163b-4aa4-8d5d-9c031a35257c commented 15 years ago

    Currently, os.startfile is implemented in Win32 only, but there are command line tools in Unix and MacOSX that have same behavior.

    As a result of http://portland.freedesktop.org, unix desktop has command line tool named "xdg-open" (http://portland.freedesktop.org/xdg-utils-1.0/xdg-open.html).

    And MacOSX has 'open' (http://developer.apple.com/documentation/Darwin/Reference/ManPages/man1/open.1.html) command, and it can be used in same condition.

    benjaminp commented 15 years ago

    Those commands can be easily used through the subprocess module. However, if a patch is provided, it could be accepted.

    f601c944-163b-4aa4-8d5d-9c031a35257c commented 15 years ago

    I implemented os.startfile on posix and MacOSX as you said.

    but it need more work to handle error.

    a04be92c-af4e-4c3d-ab01-017f3a697ce8 commented 12 years ago

    Closed bpo-12522 as a duplicate.

    It contains a link to a discussion on python-ideas requesting the feature.

    merwok commented 12 years ago

    I’m not sure we want to copy the Windows startfile call for other OSes. The os module is designed to wrap system-level calls, masking OS differences (for sendfile, for example) but not going further; it’s up to other modules (like shutil) to build more convenient APIs on top of what os provides. xdg-open is a program that’s used to open files or URIs, but it does not provide other actions like Windows’ startfile does (edit, print, etc.), not is it backed by a system call. For these reasons, I think it’s inappropriate to implement os.startfile for non-Windows systems. People can use subprocess to run open or xdg-open.

    giampaolo commented 12 years ago

    +1 on what Eric just said. See bpo-10882 and msg 126049

    merwok commented 12 years ago

    So, unless someone wants to turn this request into “Add shutil.open”, I’ll close it in a few days. (I haven’t found the original discussion; if someone could add a link to the archives on mail.python.org or copy relevant quotes, it could help.)

    06547701-06a2-4e4a-b672-16a33475101e commented 12 years ago

    Eric, I have no problem with this function being placed in shutil instead of os, as long as it's implemented and it's in the standard library, and people don't have to use subprocess to run open or xdg-open themselves as I currently do.

    So I have no problem with renaming this bug to "Add shutil.open".

    merwok commented 12 years ago

    as long as it's implemented and it's in the standard library, and people don't have to use subprocess to run open or xdg-open themselves as I currently do.

    This new function would call os.startfile on Windows, xdg-open where applicable, and open on Mac OS X (using a subprocess for these last two).

    I found the python-ideas thread: http://mail.python.org/pipermail/python-ideas/2011-July/010674.html There was only limited support.

    vstinner commented 12 years ago

    dependencies: + Finding programs in PATH, adding shutil.which

    Why did you add this dependency? For example, subprocess is able to locate a program if the program has no full path. We don't need a which function.

    merwok commented 12 years ago

    See also lengthy discussion on bpo-1301512.

    merwok commented 12 years ago

    > dependencies: + Finding programs in PATH, adding shutil.which Why did you add this dependency? For example, subprocess is able to locate a program if the program has no full path. We don't need a which function.

    While the Windows API call is part of Windows and the open program always present on Mac OS X, xdg-open is an optional program on free OSes, so I thought we’d need shutil.which to look before we leap. The alternative is to call Popen(['xdg-open', etc.]) and check if we get ENOENT, but I don’t know if this would be non-ambiguous (for example, do we get ENOENT if xdg-open exists but not the file?).

    A related question: what to do when we’re not on Windows nor Mac and xdg-open doesn’t exist? Raise NotImplemented?

    77411a08-770c-471e-ba30-9528530a8d45 commented 12 years ago

    The alternative is to call Popen(['xdg-open', etc.]) and check if we get ENOENT, but I don’t know if this would be non-ambiguous (for example, do we get ENOENT if xdg-open exists but not the file?).

    It's unambiguous. Python itself never opens the target file, it just passes the filepath string along to the xdg-open command. If Popen raises EnvironmentError, then xdg-open could not be executed. If the target file is nonexistent, then xdg-open will exit with status 2 (see aforelinked manpage). Entirely different error mechanisms.

    A related question: what to do when we’re not on Windows nor Mac and xdg-open doesn’t exist? Raise NotImplemented?

    Seems reasonable to me.

    So, the failure cases are: (1) Platform doesn't support this feature -> raise NotImplemented (2) Target file doesn't exist (3) Target file is inaccessible (4) No application is associated with the file type in question

    OS X and xdg-open report (2) and (4), does Windows? OS X reports (3) indirectly/vaguely [generic exit status 1 w/ possibly unstable error message]; don't know what Windows and xdg-open do here.

    vstinner commented 12 years ago

    (1) Platform doesn't support this feature -> raise NotImplemented

    It's better to not define the function if the platform doesn't support the feature.

    merwok commented 12 years ago

    > [...] do we get ENOENT if xdg-open exists but not the file?). It's unambiguous. Python itself never opens the target file, it just passes the filepath string along to the xdg-open command. If Popen raises EnvironmentError, then xdg-open could not be executed. If the target file is nonexistent, then xdg-open will exit with status 2 (see aforelinked manpage). Entirely different error mechanisms.

    You are right, I was confusing the layers! Good then.

    So, the failure cases are: (1) Platform doesn't support this feature -> raise NotImplemented

    Actually the exception is NotImplementedError. Its doc says that it’s to be used in a method that is intended to be overriden in subclasses, but I think it’s not wrong to

    (2) Target file doesn't exist (3) Target file is inaccessible (4) No application is associated with the file type in question

    I think that instead of mapping error codes to custom exceptions, which is fragile and not trivial to maintain, we should just catch stderr and raise something like OSError(stderr).

    [Victor]

    > It's better to not define the function if the platform doesn't support the feature. That’s easy to do if we can say detect the availability of a function in the libc, but here the function would depend on a program which could get removed or added between two calls to the function, so we have no choice.

    77411a08-770c-471e-ba30-9528530a8d45 commented 12 years ago

    > (2) Target file doesn't exist > (4) No application is associated with the file type in question I think that instead of mapping error codes to custom exceptions, which is fragile and not trivial to maintain, we should just catch stderr and raise something like OSError(stderr)

    It runs counter to the goal of a cross-platform API if *all the errors are platform-specific. I grant that a generic API cannot wrap *every possible error, but (2) and (4) are amongst the most common+obvious failure modes and are (FWICT) explicitly reported by all 3 native interfaces. If we don't consolidate them, we'll basically be condemning non-trivial users to copying (or writing themselves, probably inferiorly) a chunk of boilerplate recipe code, and if we're fine with that, then why bother having (this in) the std lib at all?

    I don't think the handling code for them would be particularly fragile/onerous; we're talking a mere \~2 constants per platform, all tied to pretty-unlikely-to-change native interfaces. For context, here would be (AFAICT; I only have a Mac ATM) the constants in question:

    Windows: function return value: ERROR_FILE_NOT_FOUND, ERROR_PATH_NOT_FOUND SE_ERR_NOASSOC

    xdg-open (*nix): exit code: 2 3

    Mac OS X: exit code 1 w/ stderr output: "The file XXX does not exist." "No application knows how to open XXX."

    74fe1871-4e48-417c-83e3-88f645c364c2 commented 12 years ago

    @eric.araujo, @giampaolo.rodola, (http://bugs.python.org/issue3177#msg140275)

    I'm not sure I understand why this was moved to shutil.open. It seems appropriate to try to accomplish what os.startfile() does in a cross-platform way. Don't many of the other os. calls do this--check os.name and then "do the right thing". This is the first os. call I've found that doesn't work on linux (though I'm sure there are many others). Is the reason because the name 'startfile' is a Windows creation and sounds Windowsy? If so, shouldn't os.startfile() be renamed to something generic like os.launch() or .launchfile()? But then you'd have reverse-compatibility issues.

    Why not just enhance os.startfile() so it doesn't barf if you try to use it on posix/mac? I'll try to contribute to the shutil.open() effort too.

    77411a08-770c-471e-ba30-9528530a8d45 commented 12 years ago

    Here's a quick stab at 2/3rds of an implementation, and some docs.

    74fe1871-4e48-417c-83e3-88f645c364c2 commented 12 years ago

    Test passes on Ubuntu Oneiric Linux and 'open' action appropriately defaults to launching an editor for my particular OS settings.

    Tests on Windows in work.

    74fe1871-4e48-417c-83e3-88f645c364c2 commented 12 years ago

    Implement shutil.launch() & fix minor shutil.disk_usage() doctext typo

    Name changed from shutil.open to shutil.launch due to namespace conflict with open() builtin within the shutil module and for users that do

        from shutil import *

    On Ubuntu Oneiric Linux shutil.launch() doctest passes and ./python -m test -j3 doesn't change (OS-appropriate tests all pass).

    Windows tests in work. Need Mac testing too.

    77411a08-770c-471e-ba30-9528530a8d45 commented 12 years ago

    or os.name == 'mac' ???

    Nope, that refers to retro Mac OS 9 (and probably lower). Mac OS X is 'posix' for os.name purposes.

    77411a08-770c-471e-ba30-9528530a8d45 commented 12 years ago

    operation seems questionable. IMO, the verbs seem stronger / more important than mere optional suggestions (particularly "open" vs. "edit" for files with read-only viewers), and only Windows supports them (so anyone requiring that feature might as well just use startfile() directly). By virtue of this function being cross-platform, we're kinda limited to just supporting the lowest common denominator.

    Hobs, can you explain gui?

    Also, does startfile() raise exceptions for either of the basic error conditions ("no such file" and "no associated application")? If not, I believe using the lower-level ShellExecute (http://msdn.microsoft.com/en-us/library/windows/desktop/bb762153%28v=vs.85%29.aspx ) or similar Windows API function would allow us to report such errors, as the other platform implementations currently do.

    bitdancer commented 12 years ago

    Is the error raising PEP-3151 compliant?

    77411a08-770c-471e-ba30-9528530a8d45 commented 12 years ago

    No, it isn't. Changing the IOError(errno.ENOENT, "...s to FileNotFoundError("...s would half fix it.

    The other half, the OSError(errno.ENOSYS)s, has a FIXME for what's the right error to raise in that case ("no application associated with files of this type"). I have no idea myself. None of the new PEP-3151 errors apply. Nor did any of the errnos strictly speaking AFAICT; ENOSYS was the closest approximation I could find. Thoughts? Custom error class? Different errno? Something else?

    pitrou commented 12 years ago

    ENOSYS was the closest approximation I could find. Thoughts? Custom error class? Different errno? Something else?

    Why not ValueError?

    merwok commented 12 years ago

    Thanks for relaunching this!

    I'm not sure I understand why this was moved to shutil.open. It seems appropriate to try to accomplish what os.startfile() does in a cross-platform way. Don't many of the other os.* calls do this--check os.name and then "do the right thing". They don’t. The os module is a thin wrapper on top of system functions. Cross-platform compat is not achieved with os.name checks but with platform-specific code in the C files. As Windows provides a call named startfile, it is exposed. When we want to provide a higher-level API on top of system calls, we use other modules such as shutil.

    fix minor shutil.disk_usage() doctext typo Would you report this on another bug report or simply with a mail to the docs@python.org mailing list? Thanks.

    Name changed from shutil.open to shutil.launch due to namespace conflict with open() builtin within the shutil module and for users that do from shutil import I don’t think these are good arguments. A lot of modules expose a function named open: tarfile, codecs, tokenize... Python has namespaces, let’s use them. The argument about import is not strong either in my opinion, because all our docs recommend against this idiom.

    One argument against open is that the other open functions I mention above return a file object, like the builtin open. With this in mind I agree that a better name should be found. I dislike launch though because it brings to my mind the idea of running/executing a program, not opening it in the appropriate program.

    bitdancer commented 12 years ago

    Launch is far better than open for this, I think. If someone can come up with an even better name, that would be good. But I would not like to use open for this function, because it does not behave like other open functions.

    The one exception I know of is webbrowser. Webbrowser uses open, but the recommended way to call it is webbrowser.open(), which makes it clear you are opening it in the webbrowser (and opening the webbrowser if needed). shutil.open would convey no such connotation, to my mind. (Only windows does extension based application opening from the *shell* as far as I know.)

    Perhaps 'wmopen' (for Window Manager Open)?

    74fe1871-4e48-417c-83e3-88f645c364c2 commented 12 years ago

    Does no one like "os.startfile" as a home for this? Besides myself and the original 2008 proposer, of course. Can anyone explain to us newbies why it's a bad idea to have the cross-platform module do things identically across platforms?

    @David,

    shutils.wmopen locks you into never implementing the shell application launching option (gui=False in my crude implementation) that so many projects need. Each project currently implements it in their own nonstandard way (e.g. Mercurial and Bazaar), sometimes with not so nice consequences.

    You're right that only launching from Linux/Mac shell requires manual selection of an app, but that's exactly the inconvenience that I was hoping to solve. Many Ubuntu GUI apps use extensions and MIME-types (associated with extensions) to recognize their files rather than probing magic headers. Why shouldn't their shell apps be allowed a standard way to do the same?

    If I implemented exactly os.startfile() functionality across the 3 major platforms, would that be enough to interest the community in an os.startfile() refinement rather than a new shutils.launch()? I'd drop the distracting gui option to make it completely identical, if that helps. Or, if the community preferred I could add the gui option to startfile() across the board so that even Windows users could have the option of choosing to edit a file within their shell (if they've installed such an editor, of course).

    @Chris,

    Thanks for the tip on where to find low level exception information in Windows. Sounds like a good idea to try to be as identical to os.startfile() as possible. But that's why I thought the operation option would be attractive to the community.

    I'll test on windows (unless someone else chimes in with Windows experience) and see what I can learn about exceptions and what it would take to make os.startfile() truly OS-agnostic, all the way down to each exception raised.

    gui allows the user to chose to launch a shell-based text editor (emacs, vi/vim, nano, $EDITOR, based on user settings). It standardizes what bzr, hg and other popular cross-platform python projects that launch shell editors do already.

    On Mon, Apr 23, 2012 at 10:12 PM, R. David Murray \report@bugs.python.org\wrote:

    R. David Murray \rdmurray@bitdance.com\ added the comment:

    Launch is far better than open for this, I think. If someone can come up with an even better name, that would be good. But I would not like to use open for this function, because it does not behave like other open functions.

    The one exception I know of is webbrowser. Webbrowser uses open, but the recommended way to call it is webbrowser.open(), which makes it clear you are opening it in the webbrowser (and opening the webbrowser if needed). shutil.open would convey no such connotation, to my mind. (Only windows does extension based application opening from the *shell* as far as I know.)

    Perhaps 'wmopen' (for Window Manager Open)?

    ----------


    Python tracker \report@bugs.python.org\ \http://bugs.python.org/issue3177\


    merwok commented 12 years ago

    Please trust us that this is our policy. os is a thin wrapper only.

    74fe1871-4e48-417c-83e3-88f645c364c2 commented 12 years ago

    @Éric

    Thanks for clearing up my misunderstanding of os and shutil. I get it now.

    I'm sure you know this, and it's clear you agree with changing the name, but just to add fire to your resolve, the difference between shutil.open() and the other *.open() modules you mention is that most of the others began their life with open() in their namespace (I think). A new open() in shutil, this late in its life, would break a lot of old code, sometimes invisibly. Apps might launch invisibly on servers with X-windows configured to display remotely, fail to raise exceptions, and leave a lot of admins dumbfounded and cursing the python standard library migration. Seems like pretty draconian punishment for bad (but not forbidden or deprecated) idioms. I'd rather not have my code be one of the rocks in that stoning. A few would surely fly my way.

    On Mon, Apr 23, 2012 at 9:58 PM, Éric Araujo \report@bugs.python.org\ wrote:

    Éric Araujo \merwok@netwok.org\ added the comment:

    Thanks for relaunching this!

    > I'm not sure I understand why this was moved to shutil.open. It seems appropriate to try to accomplish what > os.startfile() does in a cross-platform way. Don't many of the other os.* calls do this--check os.name and > then "do the right thing". They don’t. The os module is a thin wrapper on top of system functions. Cross-platform compat is not achieved with os.name checks but with platform-specific code in the C files. As Windows provides a call named startfile, it is exposed. When we want to provide a higher-level API on top of system calls, we use other modules such as shutil.

    > fix minor shutil.disk_usage() doctext typo Would you report this on another bug report or simply with a mail to the docs@python.org mailing list? Thanks.

    > Name changed from shutil.open to shutil.launch due to namespace conflict with open() builtin within the shutil > module and for users that do from shutil import * I don’t think these are good arguments. A lot of modules expose a function named open: tarfile, codecs, tokenize... Python has namespaces, let’s use them. The argument about import * is not strong either in my opinion, because all our docs recommend against this idiom.

    One argument against open is that the other open functions I mention above return a file object, like the builtin open. With this in mind I agree that a better name should be found. I dislike launch though because it brings to my mind the idea of running/executing a program, not opening it in the appropriate program.

    ----------


    Python tracker \report@bugs.python.org\ \http://bugs.python.org/issue3177\


    74fe1871-4e48-417c-83e3-88f645c364c2 commented 12 years ago

    New patch incorporates improvements from pitrou, cvrebert, r.david.murray, eric.araujo, cool-RR

    bitdancer commented 12 years ago

    Initially this issue was about implementing a startfile-equivalent on posix. But if you have to add a gui option to startfile to not lanuch a GUI, and your real goal is a consistent way to launch non-gui programs on posix, then I don't see that this is about implementing startfile, and the enhancement should *definitely* not go in os.

    Setting that aside for a moment, let me say something about the wrapper argument. There *is* a lot of compatibility code in os. We do have to jump through hoops to get posix equivalent functionality on Windows. So doing the reverse to get windows-equivalent functionality on posix would seem fair turnabout.

    However, it is also true that those hoops we jump through for windows involve calling Windows APIs (the equivalent of the posix system calls we are wrapping). So while the hoops aren't necessarily all that "thin", they are wrappers around APIs at the OS level (thus the name of the module). In this case the hoops are not system calls. So even disregarding my initial comments above, while I don't think the argument is quite as clear cut as Éric does, I do think in this case the code, which is *not* operating at the C API level, does not belong in OS.

    Finally, I'm still against shutil.open as the name. It does not suggest to me that an application is being run. (Neither does 'startfile', by the way).

    ebb240bb-32de-4457-bc38-fcb38b847f9c commented 12 years ago

    The semantics of "associated application" change considerably from operating system to operating system. As an example, os.startfile("a.py") will usually run a.py in the Python interpreter, while xdg-open a.py it will usually open the source code in an editor on Linux. This might reduce the overall usefulness of the proposed shutil.launch() function.

    merwok commented 12 years ago

    The semantics of "associated application" change considerably from operating system to operating system. As an example, os.startfile("a.py") will usually run a.py in the Python interpreter, while xdg-open a.py it will usually open the source code in an editor on Linux.

    Outch. I think the behavior should be more similar than that, i.e. that the function should use startfile with the edit action on Windows.

    About the name: I thought about “edit”; it really means open_file_in_editor. BTW shutil feels the wrong place for this but I don’t think we have anything better.

    74fe1871-4e48-417c-83e3-88f645c364c2 commented 12 years ago

    Last patch was invalid and untested.

    New patch passes make patchtest, but still doing the full test suite on Windows and Linux.

    Still unsure if I raised the right exceptions with the right arguments.

    74fe1871-4e48-417c-83e3-88f645c364c2 commented 12 years ago

    I'll be happy to code, test, and use the new .() function wherever it ends up and whatever it is named... but...

    Initially this issue was about implementing a startfile-equivalent on posix. But if you have to add a gui option to startfile to not lanuch > a GUI, and your real goal is a consistent way to launch non-gui programs on posix

    Actually, my real goal was a consistent way of launching any editor or viewer (or even interpreter) on any platform with graceful fallback from the caller's preferred action to the others. I wanted my application that called the new idiomatic standard library function to do something smarter (in my mind) than what OSes do by default and more consistent and robust than what hg and bzr do by design. Perhaps the fallback should only be within the read/write/execute "silos", but that should be configurable as well, defaulting to do the safe thing (fallback within editors or within viewers only).

    GUI viewer (IE, then Firefox, then Chrome, then Safari)
    GUI editor (notepad, then ...)
    shell editor ($EDITOR, then vim, then vi, then nano, etc)
    shell viewer (less, then more, then cat)

    Obviously this isn't feasible. At least not for my first patch.

    77411a08-770c-471e-ba30-9528530a8d45 commented 12 years ago

    > ENOSYS was the closest approximation I could find. Thoughts? Custom > error class? Different errno? Something else?

    Why not ValueError?

    Because the value they provided was perfectly valid (the file/directory *did* exist), so the caller's request was reasonable. It's the system(/ its (lack of) configuration) that failed the caller in finding an opener application. The "fix" after encountering the exception is to add an association to the system configuration (and/or install a new application), not to pass a different path to the function.

    IMO, it feels like an EnvironmentError or RuntimeError of some sort; hence the current use of OSError. (Or NotImplementedError, but we're already using that exception to indicate a different failure condition, so that's out.)

    77411a08-770c-471e-ba30-9528530a8d45 commented 12 years ago

    Hobs, why is exit code 4 of xdg-open (which the manpage describes as the extremely generic "The action failed.") interpreted as FileNotFoundError in your new version?

    74fe1871-4e48-417c-83e3-88f645c364c2 commented 12 years ago

    Because that's how I caused the exception in Ubuntu--shutil.launch('file_that_doesnt_exist'). That's why I changed the message to "file may not exist" for both 2 and 4, but should probably prove that 2 sometimes happens when the file does exist (like with permission or visiblity/hidden errors in some OSes).

    Interestingly I got it to quietly, insidiously fail on Ubuntu by passing it a path to an empty file named empty.exe with the executeable bit set (but permissions and executable bit didn't seem to make a difference). No app was launched (or too quickly disappeared for me to see) and shutil.launch() did not complain.

    On Tue, Apr 24, 2012 at 1:58 AM, Chris Rebert \report@bugs.python.org\wrote:

    Chris Rebert \pybugs@rebertia.com\ added the comment:

    Hobs, why is exit code 4 of xdg-open (which the manpage describes as the extremely generic "The action failed.") interpreted as FileNotFoundError in your new version?

    ----------


    Python tracker \report@bugs.python.org\ \http://bugs.python.org/issue3177\


    77411a08-770c-471e-ba30-9528530a8d45 commented 12 years ago

    Also:

    The FileNotFoundErrors quote the path twice:
        Python 2.7.1 (r271:86832, Jul 31 2011, 19:30:53) 
        >>> path = "/foo/bar"
        >>> print "Path '%s' may not exist" % repr(path)
        Path ''/foo/bar'' may not exist

    The ValueError error message isn't grammatically correct and doesn't account for the possibility that the path is a directory (consider the case of a Unix system where the GUI file manager has been uninstalled; directories would then fail to open). May I suggest my original message?: "No application is associated with files/directories of the given type"

    77411a08-770c-471e-ba30-9528530a8d45 commented 12 years ago

    The xdg-open source code (http://cgit.freedesktop.org/xdg/xdg-utils/tree/scripts/xdg-open ) shows that exit code 4 is used whenever an invocation of another opener script (e.g. kde-open, gnome-open) fails for any reason besides said script not being installed. So I'm not so sure we can jump to the conclusion that 4 automatically means FileNotFound.

    74fe1871-4e48-417c-83e3-88f645c364c2 commented 12 years ago

    Yea, I hosed up the path quoting in a misguided attempt at shortening for 80-col line-wrapping. Yours is better, will revert.

    On Tue, Apr 24, 2012 at 2:09 AM, Chris Rebert \report@bugs.python.org\wrote:

    Chris Rebert \pybugs@rebertia.com\ added the comment:

    Also:

    The FileNotFoundErrors quote the path twice: Python 2.7.1 (r271:86832, Jul 31 2011, 19:30:53) >>> path = "/foo/bar" >>> print "Path '%s' may not exist" % repr(path) Path ''/foo/bar'' may not exist

    The ValueError error message isn't grammatically correct and doesn't account for the possibility that the path is a directory (consider the case of a Unix system where the GUI file manager has been uninstalled; directories would then fail to open). May I suggest my original message?: "No application is associated with files/directories of the given type"

    ----------


    Python tracker \report@bugs.python.org\ \http://bugs.python.org/issue3177\


    77411a08-770c-471e-ba30-9528530a8d45 commented 12 years ago

    The semantics of "associated application" change considerably from operating system to operating system. As an example, os.startfile("a.py") will usually run a.py in the Python interpreter, while xdg-open a.py it will usually open the source code in an editor on Linux.

    Outch. I think the behavior should be more similar than that, i.e. that the function should use startfile with the edit action on Windows.

    It's a universal problem on all 3 platforms. Given a script file argument, a generic "open" (as opposed to "edit") procedure will either run the script or open it in an editor, depending entirely upon the user's system configuration. Same thing happens when double-clicking a script in the file manager, which is IMO what we're trying to emulate here.

    It sounds like some people want a generic "(text) edit" procedure, which IMO is different enough to warrant a separate bug since there are different/more design issues to tackle (e.g. if someone edit()s an image file (or a file of uncertain type) on Unix, what application is opened, and how is that determined?). And no peeking at Mercurial's code; it's under GPLv2, whereas Python is under BSD/MIT-like licensing, making them incompatible.

    bitdancer commented 12 years ago

    I'm not a lawyer (duh), but my understanding is that *looking* at GPL code (as opposed to proprietary code, where someone might sue you about it and not looking is a good defense) is OK, you just can't copy it.

    pitrou commented 12 years ago

    I'm not a lawyer (duh), but my understanding is that *looking* at GPL code (as opposed to proprietary code, where someone might sue you about it and not looking is a good defense) is OK, you just can't copy it.

    You could probably copy a one- or two-liner, especially if it's not a very creative one. By that I mean that putting "i = i + 1" under the GPL is not enough to prevent anyone else to write the same line of code :-)

    74fe1871-4e48-417c-83e3-88f645c364c2 commented 12 years ago

    I can see why this partial implementation of operation in this ver seems useless. But it is a placeholder for eventually providing Linux/Mac users with the same functionality as windows. The os.startfile() or shutil.launch() function can easily fill the gap left by the OS, which is what os does for lots of other missing OS features on one platform or another.

    I'll delete the OS9 ('mac') test comment and leave an implementation for those platforms up to others?

    gui is for software that intends to launch user's $EDITOR, vi, nano, emacs, etc. This is intended to generalize startfile to encompass a common pattern, e.g. in bzr, hg. Perhaps it doesn't belong in ver1 until we sort out all the other uncomfortable things about this patch.

    I'll test all the windows and linux exception possabilities and get back to you on what exceptions startfile() normally raises, and whether this implementation of shutil.launch() raises comparable exceptions.

    Cheers, H On Apr 23, 2012 7:53 PM, "Chris Rebert" \report@bugs.python.org\ wrote:

    Chris Rebert pybugs@rebertia.com added the comment:

    operation seems questionable. IMO, the verbs seem stronger / more important than mere optional suggestions (particularly "open" vs. "edit" for files with read-only viewers), and only Windows supports them (so anyone requiring that feature might as well just use startfile() directly). By virtue of this function being cross-platform, we're kinda limited to just supporting the lowest common denominator.

    Hobs, can you explain gui?

    Also, does startfile() raise exceptions for either of the basic error conditions ("no such file" and "no associated application")? If not, I believe using the lower-level ShellExecute ( http://msdn.microsoft.com/en-us/library/windows/desktop/bb762153%28v=vs.85%29.aspx) or similar Windows API function would allow us to report such errors, as the other platform implementations currently do.

    ----------


    Python tracker \report@bugs.python.org\ \http://bugs.python.org/issue3177\


    daf46b87-a9e9-4381-bf23-8c373c9135e6 commented 12 years ago

    Just to note there's http://pypi.python.org/pypi/desktop/0.4 out there.

    74fe1871-4e48-417c-83e3-88f645c364c2 commented 12 years ago

    Had no idea. Sounds like a good place for it. On Apr 28, 2012 6:54 AM, "Miki Tebeka" \report@bugs.python.org\ wrote:

    Miki Tebeka \miki.tebeka@gmail.com\ added the comment:

    Just to note there's http://pypi.python.org/pypi/desktop/0.4 out there.

    ---------- nosy: +tebeka


    Python tracker \report@bugs.python.org\ \http://bugs.python.org/issue3177\


    larryhastings commented 11 years ago

    As an example, os.startfile("a.py") will usually run a.py in the Python interpreter, while xdg-open a.py it will usually open the source code in an editor on Linux.

    Well, so how about on UNIX shutil.launch (or whatever it's called) first checks to see if we're referring to a file. If we are, check to see if it's marked executable. If it is, execute it under a shell. Failing *that* we could run xdg-open where available.

    74fe1871-4e48-417c-83e3-88f645c364c2 commented 11 years ago

    Could even add an operation parameter to let the caller select actions, including 'auto' implemented as Larry suggests. Sometimes you feel like trusting the user's xdg-open preferences/settings. Sometimes you don't. Easy enough to let the caller choose, rather than the OS.

    operation in ['auto', 'run', 'edit', 'display', 'browse', 'explore',

    'share', 'send', 'like', 'email', 'open', 'xdg-open', ...] # can be incrementally added/implemented

    Each op requires 1 conditional and gives a lot more utility without requiring much more launch/action code that hasn't already been tested/debugged on all relevant platforms. And the operation parameter is a semi-standard used by MS, easing the transition for Win-devs migrating gui code to python and linux (or cross-platform implementations).

    On Fri, May 25, 2012 at 4:40 AM, Larry Hastings \report@bugs.python.org\wrote:

    Larry Hastings larry@hastings.org added the comment:

    As an example, os.startfile("a.py") will usually run a.py in the Python interpreter, while xdg-open a.py it will usually open the source code in an editor on Linux.

    Well, so how about on UNIX shutil.launch (or whatever it's called) first checks to see if we're referring to a file. If we are, check to see if it's marked executable. If it is, execute it under a shell. Failing that we could run xdg-open where available.

    ---------- nosy: +larry


    Python tracker \report@bugs.python.org\ \http://bugs.python.org/issue3177\