Re: subprocess problem
On 09.02.2017 01:56, Andreas Paeffgen wrote: The Problem with the subprocess code is: Using the sourcecode functioning as normal. The frozen app with cx_freeze on every platform just returns an empty result Here is the code in short: def get_path_pandoc(): settings = QSettings('Pandoc', 'PanConvert') path_pandoc = settings.value('path_pandoc','') if not os.path.isfile(path_pandoc): if platform.system() == 'Darwin' or os.name == 'posix': args = ['which', 'pandoc'] p = subprocess.Popen( args, stdin=subprocess.PIPE, stdout=subprocess.PIPE) path_pandoc = str.rstrip(p.communicate(path_pandoc.encode('utf-8'))[0].decode('utf-8')) The whole problematic code can be checked on http://github.com/apaeffgen/panconvert in source/converters/interface_pandoc.py Checking your repo I found that get_path_pandoc, the function from which you took the code snippet above, will always return None if os.path.isfile(path_pandoc). This is probably not what you are intending. Do you know if path_pandoc is maybe set to an existing file in your frozen code already so the whole 'which' or 'where' branch is never executed? Best, Wolfgang -- https://mail.python.org/mailman/listinfo/python-list
Re: subprocess problem
On 09.02.2017 01:56, Andreas Paeffgen wrote: The Problem with the subprocess code is: Using the sourcecode functioning as normal. The frozen app with cx_freeze on every platform just returns an empty result Here is the code in short: def get_path_pandoc(): settings = QSettings('Pandoc', 'PanConvert') path_pandoc = settings.value('path_pandoc','') if not os.path.isfile(path_pandoc): if platform.system() == 'Darwin' or os.name == 'posix': args = ['which', 'pandoc'] p = subprocess.Popen( args, stdin=subprocess.PIPE, stdout=subprocess.PIPE) path_pandoc = str.rstrip(p.communicate(path_pandoc.encode('utf-8'))[0].decode('utf-8')) The whole problematic code can be checked on http://github.com/apaeffgen/panconvert in source/converters/interface_pandoc.py Checking your repo I found that get_path_pandoc, the function from which you took the code snippet above, will always return None if os.path.isfile(path_pandoc). This is probably not what you are intending. Do you know if path_pandoc is maybe set to an existing file in your frozen code already so the whole 'which' or 'where' branch is never executed? Best, Wolfgang -- https://mail.python.org/mailman/listinfo/python-list
Re: How to store properties
Cecil Westerhof writes: > ... >> If you only want to read the configuration, just use an ordinary >> file you import. For example config.py contains the lines: >> username=myuser >> server=myserver >> password=secret >> >> In your script: >> >> import config >> >> Now you can referenc all the variables via config., e.g. >> config.username > > That I know, but it is a security risk. It is a security risk if you allow potential attackers to modify the Python files. Then, however, those attackers could also modify the Python code itself (rather than the config file). Thus, the risk may not much increase (depending on how different the protection for the config file is compared to that for other Python source code). > ... >> Another method would be a dictionary for your config. You could >> pickle and unpickle it. > > Is pickle not discouraged? Better to use a JSON file I think. "pickle", too, has a potential security risk -- if you allow unpickling from untrusted source. Usually, however, configuration comes from trusted sources. However, if JSON has sufficient data type support for you, go for it. -- https://mail.python.org/mailman/listinfo/python-list
Re: Decorator
On Thu, 09 Feb 2017 08:03:32 +0100, ast wrote: > Hi > > In python courses I read, it is explained that > > @decor > def f(): > pass > > is equivalent to: > > def f(): > pass > > f = decor(f) > > But that's not always true. See this code [...] > any comment ? Congratulations, you've found a microscopic corner of the language where the two different ways of applying decorators are different. Are you just sharing with us, or do you think there is a problem that needs to be solved? You're absolutely correct that when using `property`, trying to apply it by hand instead of using the @ syntax is tricky. So don't apply it by hand, use the @ syntax. -- Steve -- https://mail.python.org/mailman/listinfo/python-list
Re: How to store properties
On Wednesday 8 Feb 2017 12:26 CET, Cecil Westerhof wrote: > In Java you (can) use a properties file store configuration. What is > the best way to do something like that in Python? > I saw ConfigParser, but have the feeling that it is not really used. > Would a JSON file be a good idea? Thanks for all the input. I think I go for configparser (as it is called in python3). It looks very promising. -- Cecil Westerhof Senior Software Engineer LinkedIn: http://www.linkedin.com/in/cecilwesterhof -- https://mail.python.org/mailman/listinfo/python-list
Re: How to store properties
On Thu, Feb 9, 2017 at 7:43 PM, dieter wrote: > "pickle", too, has a potential security risk -- if you allow > unpickling from untrusted source. Usually, however, configuration > comes from trusted sources. Pickle's other downside is that it's an opaque binary file, unlike ConfigParser, JSON, and Python code, which are human-readable text. Letting the end user edit your configs is often a feature, not a bug. ChrisA -- https://mail.python.org/mailman/listinfo/python-list
Re: Decorator
"Steven D'Aprano" a écrit dans le message de news:589c2cdc$0$1584$c3e8da3$54964...@news.astraweb.com... On Thu, 09 Feb 2017 08:03:32 +0100, ast wrote: Congratulations, you've found a microscopic corner of the language where the two different ways of applying decorators are different. Are you just sharing with us, or do you think there is a problem that needs to be solved? I just wanted to have a confirmation. It's OK with Chris Angelico's detailed answer. Ty -- https://mail.python.org/mailman/listinfo/python-list
Re: Rename file without overwriting existing files
On Mon, 30 Jan 2017 09:39 pm, Peter Otten wrote: def rename(source, dest): > ... os.link(source, dest) > ... os.unlink(source) > ... rename("foo", "baz") os.listdir() > ['bar', 'baz'] rename("bar", "baz") > Traceback (most recent call last): > File "", line 1, in > File "", line 2, in rename > FileExistsError: [Errno 17] File exists: 'bar' -> 'baz' Thanks Peter! That's not quite ideal, as it isn't atomic: it is possible that the link will succeed, but the unlink won't. But I prefer that over the alternative, which is over-writing a file and causing data loss. So to summarise, os.rename(source, destination): - is atomic on POSIX systems, if source and destination are both on the same file system; - may not be atomic on Windows? - may over-write an existing destination on POSIX systems, but not on Windows; - and it doesn't work across file systems. os.replace(source, destination) is similar, except that it may over-write an existing destination on Windows as well as on POSIX systems. The link/unlink trick: - avoids over-writing existing files on POSIX systems at least; - but maybe not Windows? - isn't atomic, so in the worst case you end up with two links to the one file; - but os.link may not be available on all platforms; - and it won't work across file systems. Putting that all together, here's my attempt at a version of file rename which doesn't over-write existing files: import os import shutil def rename(src, dest): """Rename src to dest only if dest doesn't already exist (almost).""" if hasattr(os, 'link'): try: os.link(src, dest) except OSError: pass else: os.unlink(src) return # Fallback to an implementation which is vulnerable to a # Time Of Check to Time Of Use bug. # Try to reduce the window for this race condition by minimizing # the number of lookups needed between one call and the next. move = shutil.move if not os.file.exists(dest): move(src, dest) else: raise shutil.Error("Destination path '%s' already exists" % dest) Any comments? Any bugs? Any cross-platform way to slay this TOCTOU bug once and for all? -- Steve “Cheer up,” they said, “things could be worse.” So I cheered up, and sure enough, things got worse. -- https://mail.python.org/mailman/listinfo/python-list
Re: Rename file without overwriting existing files
On Tue, 31 Jan 2017 11:17 am, Ben Finney wrote: > Peter Otten <__pete...@web.de> writes: > >> http://stackoverflow.com/questions/3222341/how-to-rename-without-race-conditions >> >> and from a quick test it appears to work on Linux: > > By “works on Linux”, I assume you mean “works on filesystems that use > inodes and hard links”. That is not true for all filesystems, even on > Linux. Indeed it is not, and we're often very sloppy about describing file system differences as if they were OS differences. -- Steve “Cheer up,” they said, “things could be worse.” So I cheered up, and sure enough, things got worse. -- https://mail.python.org/mailman/listinfo/python-list
Re: Rename file without overwriting existing files
Steve D'Aprano writes: > On Mon, 30 Jan 2017 09:39 pm, Peter Otten wrote: > > def rename(source, dest): >> ... os.link(source, dest) >> ... os.unlink(source) >> ... > rename("foo", "baz") > os.listdir() >> ['bar', 'baz'] > rename("bar", "baz") >> Traceback (most recent call last): >> File "", line 1, in >> File "", line 2, in rename >> FileExistsError: [Errno 17] File exists: 'bar' -> 'baz' > > > Thanks Peter! > > That's not quite ideal, as it isn't atomic: it is possible that the link > will succeed, but the unlink won't. But I prefer that over the alternative, > which is over-writing a file and causing data loss. > > So to summarise, os.rename(source, destination): > > - is atomic on POSIX systems, if source and destination are both on the > same file system; > > - may not be atomic on Windows? > > - may over-write an existing destination on POSIX systems, but not on > Windows; > > - and it doesn't work across file systems. > > os.replace(source, destination) is similar, except that it may over-write an > existing destination on Windows as well as on POSIX systems. > > > The link/unlink trick: > > - avoids over-writing existing files on POSIX systems at least; > > - but maybe not Windows? > > - isn't atomic, so in the worst case you end up with two links to > the one file; > > - but os.link may not be available on all platforms; > > - and it won't work across file systems. > > > Putting that all together, here's my attempt at a version of file rename > which doesn't over-write existing files: > > > import os > import shutil > > def rename(src, dest): > """Rename src to dest only if dest doesn't already exist (almost).""" > if hasattr(os, 'link'): > try: > os.link(src, dest) > except OSError: > pass > else: > os.unlink(src) > return > # Fallback to an implementation which is vulnerable to a > # Time Of Check to Time Of Use bug. > # Try to reduce the window for this race condition by minimizing > # the number of lookups needed between one call and the next. > move = shutil.move > if not os.file.exists(dest): > move(src, dest) > else: > raise shutil.Error("Destination path '%s' already exists" % dest) > > > > Any comments? Any bugs? Any cross-platform way to slay this TOCTOU bug once > and for all? To claim the filename before crossing a filesystem boundary, how about: 1) create a temporary file in the target directory (tempfile.mkstemp) 2) link the temporary file to the target name (in the same directory) 3) unlink the temporary name 4) now it should be safe to move the source file to the target name 5) set permissions and whatever other attributes there are? Or maybe copy the source file to the temporary name, link the copy to the target name, unlink the temporary name, unlink the source file; failing the link step: unlink the temporary name but do not unlink the source file. -- https://mail.python.org/mailman/listinfo/python-list
Re: Rename file without overwriting existing files
On Thu, Feb 9, 2017 at 11:46 AM, Steve D'Aprano wrote: > > So to summarise, os.rename(source, destination): > > - is atomic on POSIX systems, if source and destination are both on the > same file system; > - may not be atomic on Windows? > - may over-write an existing destination on POSIX systems, but not on > Windows; > - and it doesn't work across file systems. On Windows in 2.7 and prior to 3.3, os.rename will silently copy and delete when the destination isn't on the same volume. It may even silently leave the original file in place in some cases -- e.g. when the file is read-only and the user isn't allowed to modify the file attributes. If the destination is on the same volume, renaming should be atomic via the system calls NtOpenFile and NtSetInformationFile. Ultimately it depends on the file system implementation of IRP_MJ_SET_INFORMATION, FileRenameInformation [1]. > The link/unlink trick: > - avoids over-writing existing files on POSIX systems at least; > - but maybe not Windows? This works for renaming files on Windows as long as the file system supports hard links (e.g. NTFS). It's not documented on MSDN, but WinAPI CreateHardLink is implemented by calling NtSetInformationFile to set the FileLinkInformation, with ReplaceIfExists set to FALSE, so it fails if the destination exists. Note that this does not allow renaming directories. See the note for FileLinkInformation [1]; NTFS doesn't allow directory hard links. But why bother with this 'trick' on Windows? [1]: https://msdn.microsoft.com/en-us/library/ff549366 -- https://mail.python.org/mailman/listinfo/python-list
Re: subprocess problem
Maybe i could use another trick to circumvent the problems in the frozen app? The frozen apps can be downloaded here: https://sourceforge.net/projects/panconvert/files/Newest/ @Cameron: 1. I use PyQT5 for a creating a gui app. To run the app on other systems, where no QT5 and PyQT5 is installed, a bundle is created with all relevant libraries, so it will start independently. This app bundle, is called a frozen app. Not only the source code, but all it dependencies are distributed including python3 itself. 2. In the test-environment pandoc is installed in /usr/local/bin/pandoc (Mac) or /bin/pandoc (Linux). Which returns the path correctly, at the terminal (shell), in Python and in the Gui-App Panconvert. 3. I am aware of the limitations of which. There is a fallback to manually insert the path. So the app will function anyway. And i want to avoid to search the whole filesystem. This takes minutes on my test machines, so this is no option. 4. I suppose that something is different from executing the code in the frozen state. The app e.g. on Mac is not started from a python shell or a comand shell. But even on linux, when started from a shell it does not work. 5. I will try the hint with dev.null and the p.check_returncode() @Wolfgang 1. The function should be executed only, if the path is unknown. If the user enters the path manually in the settings and pandoc exists, the function should not be executed to save computation time. 2. Only if the manually entered path is not correct or empty the function should be executed, hence 'if not os.path.isfile(path_pandoc)' 3. The function fills in the path automatically if which returns a value. This works in the source code -- https://mail.python.org/mailman/listinfo/python-list
Re: subprocess problem
I guess which does not return an error code. If it does not find anything, the return is just blank. If it finds something, the path is returned. So the change of code did not help, because there is just no error message. Could there be a $path problem in the subprocess started inside the binary? -- https://mail.python.org/mailman/listinfo/python-list
Re: subprocess problem
On Thu, 09 Feb 2017 11:16:18 -0600, Andreas Paeffgen wrote: > I guess which does not return an error code. If it does not find > anything, the return is just blank. If it finds something, the path is > returned. > > So the change of code did not help, because there is just no error message. > Could there be a $path problem in the subprocess started inside the binary? Here is a method I frequently use to replace the which command. (air code) import os pathlist = os.environ["PATH"].split(":") def which(target) for p in pathlist: fullpath = p + "/" + target if os.path.isfile(fullpath): return fullpath, True return "", False target, found = which("pandoc") if found: target will contain the full path to pandoc else: pandoc was not found -- GNU/Linux user #557453 The cow died so I don't need your bull! -- https://mail.python.org/mailman/listinfo/python-list
Re: subprocess problem
Am 09.02.17 um 18:16 schrieb Andreas Paeffgen: > I guess which does not return an error code. In fact, id does return a return code. Here an example: | honk:~ gdie$ which bash; echo $? | /bin/bash | 0 | honk:~ gdie$ which wzlbrmpf; echo $? | 1 It is 0 on success, 1 for a failure. Exactly the result I would expect from an unixoid program. On Ubuntu 16.04, 'man which' tells of three possible exit states: 0, 1 and 2. On Mac OS, the return codes are not documented. It seems, there are only 0 (success) and 1 (failure). Normally, on unixoid operating systems, return code 0 indicates success, anything else non-success, failure or error. > If it does not find > anything, the return is just blank. If it finds something, the path is > returned. That is the result on STDOUT. It is _not_ the return code! > So the change of code did not help, because there is just no error message. Do you expect an error message, or a return code? An error message would -- normally -- appear on STDERR. > Could there be a $path problem in the subprocess started inside the binary? That's for sure. I already had this problem with py2exe. I solved it by passing a directory containing a suitable PATH entry to the env argument of subprocess.Popen(). Problem gone. If you call 'python myscript.py' on the shell command line, the python script will inherit a copy the shell's environment. If you start a frozen python script, there is no shell's environment, it could inherit. It is up to the tool you used to freeze the script (cx_freeze, py2exe, etc.), which environment contents it will see. Best regards, Günther -- https://mail.python.org/mailman/listinfo/python-list
Re: subprocess problem
On 09Feb2017 11:16, Andreas Paeffgen wrote: I guess which does not return an error code. If it does not find anything, the return is just blank. If it finds something, the path is returned. So the change of code did not help, because there is just no error message. Could there be a $path problem in the subprocess started inside the binary? You're confusing the error code (an integer returned from _every_ exiting process) and the process' stdout and stderr, which are data streams. This is why I suggested the check_returncode() method, which examines the error code. Cheers, Cameron Simpson -- https://mail.python.org/mailman/listinfo/python-list
Re: subprocess problem
On 09Feb2017 11:59, Wildman wrote: Here is a method I frequently use to replace the which command. (air code) import os pathlist = os.environ["PATH"].split(":") def which(target) for p in pathlist: fullpath = p + "/" + target if os.path.isfile(fullpath): return fullpath, True return "", False Cleaner is to return the path if found, or None if not. target, found = which("pandoc") if found: target will contain the full path to pandoc else: pandoc was not found You want to check for execute permssion too. Cheers, Cameron Simpson -- https://mail.python.org/mailman/listinfo/python-list
Re: Decorator
On 2/9/2017 2:03 AM, ast wrote: Hi In python courses I read, it is explained that @decor def f(): pass is equivalent to: def f(): pass f = decor(f) But that's not always true. See this code Which is why the official docs now say 'roughly equivalent' ''' For example, the following code @f1(arg) @f2 def func(): pass is roughly equivalent to def func(): pass func = f1(arg)(f2(func)) except that the original function is not temporarily bound to the name func. ''' Perhaps "There are also cases in which evaluating 'fi(arg)' before rather than after the def statement makes a difference." should be added. -- Terry Jan Reedy -- https://mail.python.org/mailman/listinfo/python-list
Re: Decorator
On Fri, Feb 10, 2017 at 10:18 AM, Terry Reedy wrote: > Perhaps "There are also cases in which evaluating 'fi(arg)' before rather > than after the def statement makes a difference." should be added. Perhaps not. The word "roughly" covers the odd edge cases, and Python has a general principle of evaluating top-to-bottom, left-to-right [1], which covers this situation. ChrisA [1] if not a conditional expression, else inside-to-outside -- https://mail.python.org/mailman/listinfo/python-list
The Dominion
A video ad for Anaconda from its maker (satirizing a well know data-related film). I found it amusing, in a good way. https://www.youtube.com/watch?v=0XDqc5wTve0 PS. I don't use Anaconda and I am not posting this to promote it, nor do I necessarily agree with everything said, but I do appreciate it as a creative Python-related product, of a sort I would like to see more of. -- Terry Jan Reedy -- https://mail.python.org/mailman/listinfo/python-list
Re: subprocess problem
On Thu, Feb 9, 2017 at 10:50 PM, Cameron Simpson wrote: > This is why I suggested the check_returncode() method, which examines the > error code. You must be thinking of the returncode attribute, which isn't a method. check_returncode() is a method of the CompletedProcess object that's returned by subprocess.run(), which was added in 3.5. The OP is using both 3.4 and 3.5, so run() isn't a practical option. The older check_output() function also checks the return code and raises a subprocess.CalledProcessError if the command fails. For example: >>> subprocess.check_output(['which', 'ls']) b'/bin/ls\n' >>> subprocess.check_output(['which', 'pandoc']) Traceback (most recent call last): File "", line 1, in File "/usr/lib/python3.5/subprocess.py", line 626, in check_output **kwargs).stdout File "/usr/lib/python3.5/subprocess.py", line 708, in run output=stdout, stderr=stderr) subprocess.CalledProcessError: Command '['which', 'pandoc']' returned non-zero exit status 1 -- https://mail.python.org/mailman/listinfo/python-list
Re: subprocess problem
On Fri, 10 Feb 2017 09:53:32 +1100, Cameron Simpson wrote: > On 09Feb2017 11:59, Wildman wrote: >>Here is a method I frequently use to replace the which >>command. (air code) >> >>import os >>pathlist = os.environ["PATH"].split(":") >> >>def which(target) >>for p in pathlist: >>fullpath = p + "/" + target >>if os.path.isfile(fullpath): >>return fullpath, True >>return "", False > > Cleaner is to return the path if found, or None if not. I don't see this as an important issue but you are right. >>target, found = which("pandoc") >>if found: >>target will contain the full path to pandoc >>else: >>pandoc was not found > > You want to check for execute permssion too. For my uses of the above code, it is unlikely that the 'target' would not have the exec bit set. But, your suggestion is valid due to the fact that I should not take anything for granted. > Cheers, > Cameron Simpson Corrected code: def which(target) for p in pathlist: fullpath = p + "/" + target if os.path.isfile(fullpath) and os.access(fullpath, os.X_OK): return fullpath, True return None, False Thanks. -- GNU/Linux user #557453 Keyboard not detected! Press any key to continue... -- https://mail.python.org/mailman/listinfo/python-list
Re: subprocess problem
On 2017-02-10 00:05, Wildman via Python-list wrote: On Fri, 10 Feb 2017 09:53:32 +1100, Cameron Simpson wrote: On 09Feb2017 11:59, Wildman wrote: Here is a method I frequently use to replace the which command. (air code) import os pathlist = os.environ["PATH"].split(":") def which(target) for p in pathlist: fullpath = p + "/" + target if os.path.isfile(fullpath): return fullpath, True return "", False Cleaner is to return the path if found, or None if not. I don't see this as an important issue but you are right. target, found = which("pandoc") if found: target will contain the full path to pandoc else: pandoc was not found You want to check for execute permssion too. For my uses of the above code, it is unlikely that the 'target' would not have the exec bit set. But, your suggestion is valid due to the fact that I should not take anything for granted. Cheers, Cameron Simpson Corrected code: def which(target) for p in pathlist: fullpath = p + "/" + target if os.path.isfile(fullpath) and os.access(fullpath, os.X_OK): return fullpath, True return None, False Thanks. The implication was that you don't need the True/False, just the string/None. -- https://mail.python.org/mailman/listinfo/python-list
Re: subprocess problem
On Fri, Feb 10, 2017 at 12:05 AM, Wildman via Python-list wrote: > > Corrected code: > > def which(target) > for p in pathlist: > fullpath = p + "/" + target > if os.path.isfile(fullpath) and os.access(fullpath, os.X_OK): > return fullpath, True > return None, False Use shutil.which: https://docs.python.org/3/library/shutil.html#shutil.which -- https://mail.python.org/mailman/listinfo/python-list
Re: subprocess problem
On 10Feb2017 00:03, eryk sun wrote: On Thu, Feb 9, 2017 at 10:50 PM, Cameron Simpson wrote: This is why I suggested the check_returncode() method, which examines the error code. You must be thinking of the returncode attribute, which isn't a method. check_returncode() is a method of the CompletedProcess object that's returned by subprocess.run(), which was added in 3.5. The OP is using both 3.4 and 3.5, so run() isn't a practical option. The communicate method mentioned it; I hadn't realised it was new with 3.5, good point. The older check_output() function also checks the return code and raises a subprocess.CalledProcessError if the command fails. For example: [...] Cool, Cameron Simpson -- https://mail.python.org/mailman/listinfo/python-list
int vs. float
Hello, My computer programming professor challenged me to figure out a way to manipulate my program to display one error message if the user input is a zero or a negative number, and a separate error message if the user input is a decimal number. My program starts out: number_purchases_str = int(input("Enter the number of packages you're buying:")) number_purchases = int(number_purchases_str) format(number_purchases, "12,") So if the user input is, for example, -9 or 0, the program will result with: Sorry, you must order at least one package." What I cannot figure out is how to write it so that if my user input is, for example, 1.5, the program will result with: Sorry, you can only order whole packages. I understand that because I am starting out by assigning my number_purchases_str to be an int, when the user enters a float that is a conflict and will crash. My professor apparently believes there is a way to accomplish this. Any help or advice would be greatly appreciated. Thank you. -- https://mail.python.org/mailman/listinfo/python-list
Re: int vs. float
On Fri, Feb 10, 2017 at 1:33 PM, wrote: > I understand that because I am starting out by assigning my > number_purchases_str to be an int, when the user enters a float that is a > conflict and will crash. > > My professor apparently believes there is a way to accomplish this. Any help > or advice would be greatly appreciated. What's actually happening is that you're converting a string to an integer. You can play with this at the interactive prompt: >>> int("1") 1 >>> int("9") 9 >>> int("-3") -3 >>> int("1.5") Traceback (most recent call last): File "", line 1, in ValueError: invalid literal for int() with base 10: '1.5' >>> int("hello") Traceback (most recent call last): File "", line 1, in ValueError: invalid literal for int() with base 10: 'hello' The user always enters a string. Fundamentally, people don't type numbers - they type strings. What you're looking for is a way to let the user type digits that you interpret as an integer. Fortunately, "crash" in Python really means "raise an exception". Explore exception handling and you'll find out how you can *catch* those exceptions you understand. I won't give you the whole solution, but you should be able to research it from there. To distinguish between "1.5" and "hello", you could attempt to convert the digits to a float - if that succeeds, the user entered a fractional number of packages. Or maybe you don't care about that difference. Enjoy Pythonning! ChrisA -- https://mail.python.org/mailman/listinfo/python-list
Re: gmail api
On Tuesday, 7 February 2017 14:22:32 UTC+8, Kelvid Pang wrote: > hi, > > I am trying to gmail api with reference to this URL: > https://developers.google.com/gmail/api/quickstart/python > > But I couldn't find the 'gmail-python-quickstart.json' file. Any one can > help? thanks. First of all, I have figured out the gmail api. thanks for those who give me the guide, apparently I didn't follow the guide 100%. Side note, why reply in the email doesn't appear at the groups.google here, so other viewers can also know the status of the thread? -- https://mail.python.org/mailman/listinfo/python-list