Re: [Tutor] Chunking list/array data?
On 21Aug2019 21:26, Sarah Hembree wrote: How do you chunk data? We came up with the below snippet. It works (with integer list data) for our needs, but it seems so clunky. def _chunks(lst: list, size: int) -> list: return [lst[x:x+size] for x in range(0, len(lst), size)] What do you do? Also, what about doing this lazily so as to keep memory drag at a minimum? This looks pretty good to me. But as you say, it constructs the complete list of chunks and returns them all. For many chunks that is both slow and memory hungry. If you want to conserve memory and return chunks in a lazy manner you can rewrite this as a generator. A first cut might look like this: def _chunks(lst: list, size: int) -> list: for x in range(0, len(lst), size): yield lst[x:x+size] which causes _chunk() be a generator function: it returns an iterator which yields each chunk one at a time - the body of the function is kept "running", but stalled. When you iterate over the return from _chunk() Python runs that stalled function until it yields a value, then stalls it again and hands you that value. Modern Python has a thing called a "generator expression". Your original function is a "list comprehension": it constructs a list of values and returns that list. In many cases, particularly for very long lists, that can be both slow and memory hungry. You can rewrite such a thing like this: def _chunks(lst: list, size: int) -> list: return ( lst[x:x+size] for x in range(0, len(lst), size) ) Omitting the square brackets turns this into a generator expression. It returns an iterator instead of a list, which functions like the generator function I sketched, and generates the chunks lazily. Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Is nesting functions only for data hiding overkill?
On 22Aug2019 00:53, James Hartley wrote: Yes, nesting functions is valuable & necessary for closures and wrapping functions for creating properties. But is nesting, simply for hiding data, a preferred solution? I have a number of member functions which are prefaced with underscores pointing out that they should not I think you're not using "nesting" the way I think of it. Can you provide an example bit of code illustrating what you're thinking of and explaining your concerns? Also, your paragraph looks a little truncated. Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] class functions/staticmethod?
On 14Aug2019 11:15, Steven D'Aprano wrote: On Wed, Aug 14, 2019 at 09:58:35AM +1000, Cameron Simpson wrote: On 11Aug2019 22:58, James Hartley wrote: >I am lacking in understanding of the @staticmethod property. >Explanation(s)/links might be helpful. I have not found the descriptions >found in the Internet wild to be particularly instructive. You have received some answers; to me they seem detailed enough to be confusing. Its only confusing if you don't work your way through it carefully and systematically. There's a lot to understand, but if you don't understand it, Python's behaviour in this case seems counter-intuitive and hard to follow. Yeah, but it helps to understand the objective: function context. A deep dive into the mechanisms used to achieve that is a load to ingest. High levels of detail tend to swamp one's view of the larger picture, particularly when learning. [...] I think of things this way: what context does a method require? Not everything needs the calling instance. Here endeth the lesson. Given that you go on to write almost another 150 lines of explanation, I think a better description would be "Here *begins* the lesson" *wink* Well, maybe, but I really wanted to highlight the objective: @classmethod and @staticmethod dictate the context provided to the method. All the examples that follow aim, however vaguely, to show those contexts in action. Your lesson, I think, assumes that it is obvious that staticmethods don't have access to the calling instance, or its class. No, it aims to make that point clear. EVerything else is example or mechanism. But if you look at James' code, I think you will agree that he's assuming that staticmethods *do* have access to the calling class, and is perplexed by the fact that the look-up of class variables (class attributes) fails. Because nobody had said that @staticmethod and @classmethod _define_ the provided context. Your lesson gives us no clue why James' first method, "dimensions()", which he describes as a "class method", isn't a class method and doesn't actually work correctly, even though it appears to at first glance. I didn't try to tackle his code. I think it is better to get the intended use of @classmethod and @staticmethod clear. Digging into whatever weird consequences there might be to his slightly wrong code just brings confusion. Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] class functions/staticmethod?
er use the forms of "area2" and "area3" because it is clear that I'm getting an area function from a nicely named class. (Also, I wouldn't have to import the area function explicitly - it comes along with the class nicely.) So the static method is used to associate it with the class it supports, for use when the caller doesn't have an instance to hand. Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] HELP PLEASE
On 12Aug2019 15:11, Marissa Russo wrote: This is my code: Thank you. This is the output of my updated code: Traceback (most recent call last): File "/Applications/Python 3.7/exercises .py", line 37, in main() File "/Applications/Python 3.7/exercises .py", line 33, in main m = mean(data[0]) File "/Applications/Python 3.7/exercises .py", line 29, in mean return(sum(nums)/len(nums)) TypeError: unsupported operand type(s) for +: 'int' and 'str' Thank you for this as well, it makes things much clearer. So, to your code: import math Just a remark: you're not using anything from this module. I presume you intend to later. def get_numbers(): print("This program will compute the mean and standard deviation") file1 = input("Please enter the first filename: ") file2 = input("Please enter the second filename: ") x = open(file1, "r") y = open(file2, "r") nums = x.readlines() nums2 = y.readlines() As has been mentioned in another reply, readlines() returns a list of strings, one for each line of text in the file. In order to treat these as numbers you need to convert them. return nums, nums2 def to_ints(strings): num_copy = [] for num in nums: num_copy.append(float(num)) return num_copy This returns a list of floats. You might want to rename this function to "to_floats". Just for clarity. return to_ints(nums), to_ints(nums2) This isn't reached. I _think_ you need to put this line at the bottom of the get_numbers function in order to return two lists of numbers. But it is down here, not up there. def mean(nums): _sum = 0 return(sum(nums)/len(nums)) This is the line raising your exception. The reference to "+" is because sum() does addition. It starts with 0 and adds the values you give it, but you're handing it "nums". Presently "nums" is a list of strings, thus the addition of the initial 0 to a str in the exception message. If you move your misplaced "return to_ints(nums), to_ints(nums2)" statement up into the get_numbers function you should be better off, because then it will return a list of numbers, not strings. Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Error terminal
On 07Aug2019 13:08, Richard Rizk wrote: I wanted to send you this email to ask if you would have someone that can solve the problem I'm having with python. I'm having issues with terminal on mac, is there someone that can help with this? I probably can. Is this a Python problem, a Terminal problem, or some kind of mix? Anyway, followup and describe your issue and we'll see. Remember that this list drops attachments, so all your description should be text in the message, including and cut/paste of terminal output (which we usually want for context, and it is more precise than loose verbal descriptions alone). Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Name for this type of class?
On 02Aug2019 17:47, Malcolm Greene wrote: They same naming is one of the two biggest challenges when it comes to software. Or one of three if you count the "off-by-one" joke :) Anyways, I'm looking for help coming up for the proper name for a class that collects the following type of telemetry data that we use for operational analysis. We use various combinations of these attributes depending on context. event_type event_step file_count line_count byte_count row_count batch_count job_count error_count warning_count duration Here are the ways we've come up with to describe a class that collects this info: JobMetrics JobStats or JobStatistics JobTelemetry None of these feel right and of course everyone on our team has a different opinion. Well they could all subclass types.SimpleNamespace, and I personally think JobTelemetry or Telemetry sound fine given your description. Unless they're snapshots/samples, in which case "Telemetric" ?-) Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Difference between decorator and inheritance
On 02Aug2019 11:26, bob gailer wrote: And now for something completely different... Decorators are not required to return a function! I use them to create a dictionary that maps function names to the corresponding function object. That is an interesting idea! But I want to counter it, briefly. This is very useful when associating actions with user-entered commands. Example: def collect(func=None, d={}): if not func: return d d[func.__name__] = func @collect def add(a,b): return a+b # adds item to dictionary d (key = 'add', value = func) # repeat for other user-command functions # finally: cmd_dict = collect() # returns the dictionary cmd = input('enter a command>') func = cmd_dict.get(cmd) I think you're conflating 2 things: having the decorator have a side effect outside the bare "do stuff around the call of an inner function", and returning a callable. The feature of your remark is the side effect, which is useful. Not returning a callable is orthognal, and a misfeature. Let me show you why: Python 3.7.4 (default, Jul 11 2019, 01:07:48) [Clang 8.0.0 (clang-800.0.42.1)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> d={} >>> def collect(f): d[f.__name__]=f ... >>> def g(x): print(x*2) ... >>> @collect ... def h(x): print(x*3) ... >>> g(8) 16 >>> h(8) Traceback (most recent call last): File "", line 1, in TypeError: 'NoneType' object is not callable The return value of the decorator is bound to the function name in the current scope,typically the current module for a normal function or the enclosing class for a method. Your decorator returns None (I'm ignoring the d={} funkiness for now). Therefore a side effect of using the decorator is that every function "foo" you use with this decorator defines the name "foo" in the current scope as None. As you can see in the example above, that makes the h() function not usable on its own. (And litters the namespace with a useless "h" name whose value is None.) Had my version of your decorator looked like this: def collect(f): d[f.__name__] = f return f then h() would have remained independently useful, at no cost to the functionality of your decorator. So I'm arguing that while you _can_ return None from a decorator (which is what is actually happening in your "not returning" phrasing), it remains _useful_ and _easy_ to return the decorated function itself unchanged. I've concerns about your d={} trick too, but we can discuss those in another subthread if you like. I'm hoping to convince you that your otherwise nifty @collect decorator could do with returning the function unchanged after doing its work. Finally, there is another important reason to return the function (or another callable): nesting decorators. Look at this piece of code from a project I'm working on: @classmethod @auto_session @require(lambda console: isinstance(console, Console)) @require(lambda top_node: isinstance(top_node, DirTreeNode)) @require(lambda top_node: not hasattr(top_node, 'can_uuid')) def from_fstree(cls, console, top_node, *, session): This is a method, but otherwise the situation is no different. Each of these decorators does a little task and returns a callable, ready for further decoration by outer decorators. So every one of them returns a suitable callable. If your @collect decorator returned the function, it too could be happily placed in such a nesting of decorators and everyone is happy. Because it does not, it does not play well with others, because an outer decorator would not have a callable to work with; it would get the None that your @collect returns. This is the other argument for always returning a callable: to interoperate with other decorators, or of course anything else which works with a callable. Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Python code
On 01Aug2019 15:23, Spencer Wannemacher wrote: I'm new to python and I was trying to perform a simple one code. All that is included in the code is print(61). I save it as 61.py and change the directory before typing in python 61.py and I don't get an output. There is no error and the output is blank. Please let me know what I'm doing wrong. Thank you so much! Can you confirm that your entire "61.py" file is this: print(61) That should print a "61" on the output, as I think you expected. Can you confirm your operating system? I'm guessing Windows, but a detailed description would be helpful. Are you are typing "python 61.py" at the shell prompt (I presume Windows' CMD.EXE prompt)? And not to some other interface? It is my recollection that "python" isn't a command under windows, there's a "py" command (I'm not on Windows here). So it may be that when you issue the command "python" it isn't running the Python interpreter but something else. Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] raising exceptions in constructor code?
On 16Jul2019 23:49, Alan Gauld wrote: On 16/07/2019 22:56, Mats Wichmann wrote: thrown. This gets watered down to the mantra "Don't throw exceptions from within constructors." Does this carry over to Python? If you mean __init__, that's not a constructor, so you should set your mind at rest :) It's more properly an "initializer", the instance has already been constructed when it's called. FWIW The true constructor is __new__() and its quite rarely overridden by application programmers. But if you do, it's not common that you'd do anything that would merit an exception. __new__ pretty much just sets up the structure of the object ready for initialisation by __init__. Incidentally, this two stage construction/initialisation is also found in other OOP languages like Smalltalk and Objective C (and Lisp?). And to return to the OP's question: The __init__ method (and arguably __new__ if you touch it - very rare) is like other Python code: resource allocation should normally get unwound as objects become unreferenced. So raising an exception should be a pretty safe thing to do. That is a simplification. Of course if you implement an object with side effects _outside_ the Python object space (maybe it opened a scratch file to support something), it is your responsibility to ensure release in the object's __del__ method. But an object that just allocates a bunch of lists or dicts or the like? Python will clean that up for you. That said, I try to do cheap initialisation before exspensive initialisation. So allocating locks, opening files, starting worker threads: these come at the bottom of the __init__ method. Also, it is _ROUTINE_ to raise exceptions from __init__: like any other method we _expect_ you to raise ValueError if the initialiser parameters are insane (negatively sized arrays, etc etc). So in Python, raising exceptions in __init__ is normal: it shouldn't happen when you programme is running correctly of course, but it is the _preferred_ action when your initialiser cannot complete correctly. Consider: x = Foo() After this assignment we expect "x" to be a usable instance of Foo. We don't put special checks; what would such checks look like? (There are some answers for that, but they're all poor.) So raising an exception is what happens if __init__ fails. Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Multiprocessing with many input input parameters
On 11Jul2019 15:40, Mike Barnett wrote: If you're passing parameters as a list, then you need a "," at the end of the items. Otherwise if you have something like a string as the only item, the list will be the string. list_with_one_item = ['item one',] Actually, this isn't true. This is a one element list, no trailing coma required: [5] Mike has probably confused this with tuples. Because tuples are delineated with parentheses, there is ambiguity between a tuple's parentheses and normal "group these terms together" parentheses. So: x = 5 + 4 * (9 + 7) Here we just have parentheses causing the assignment "9 + 7" to occur before the multiplication by 4. And this is also legal: x = 5 + 4 * (9) where the parentheses don't add anything special in terma of behaviour. Here is a 2 element tuple: (9, 7) How does one write a one element tuple? Like this: (9,) Here the trailing comma is _required_ to syntacticly indicate that we intend a 1 element tuple instead of a plain "9 in parentheses") as in the earlier assignment statement. I'm not sure any of this is relevant to Sydney's question though. Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Make a linked list subscriptable?
On 10Jul2019 20:30, Sarah Hembree wrote: How might I best make a linked list subscriptable? Below is skeleton code for a linked list (my actual is much more). I've done __iter__ and __next__ but I would like to be able to do start:stop:stride I just can't figure out how. Suggestions or just hints please? Well, you could write a method to find and return element `n`, counting from 0 (the root Node). For start stop stride you could do the extremely simple approach: iterate over a range() of the start stop stride and call the get-element-n method. This will be very slow though (a complete scan for every element). Instead, you could write a method accepting a start, stop and stride. Call the find-element-n method to get to start, lets call that `n`. While n < stop, step forward `stride` elements and also bump `n` by stride. That steps you along each element indicated by the start:stop:stride. You'll notice that this only works for a positive stride. For a negative stride you're probably better off handing it to range(), getting a list of values back from that as a list, and reversing the list (which then has ascending values). Collect the elements indicated by the list (because you can traverse the linkedlist forwards). Then reverse the collected elements and return them. Now, you _could_ accumulate each element in a list and return that at the end. _Or_ you could make the function a generator and just yield each element as found. To turn all this into a subscriptable list, define the __getitem__ method as a function accepting an index. If that index is an int, just return that element. If the index is a slice (start:stop:stride), call the more complicated function to return multiple elements. Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Environment variables and Flask
On 28Jun2019 09:34, Alan Gauld wrote: Environment variable have fallen out of favour for user settings and config files are now preferred. But some things are a bit easier via en environment variable - especially where you spawn new sub-processes and don't want the sub-process to have to re-read the config file each time. This is something of a simplification. Most programmes consult a few places for configuration information. A programme may want to run in different ways (different places to write files, different language settings or timezones, etc). Environment variables are a convenient and inheritable way to indicate a specific way to run, because they get inherited (as a copy) from parent programme to child programmes and so on. So a flask application will usually be invoked from within a web server, and various things about how it should run _may_ be indicated by environment variables set by the web server. A flexible programme may decide how to run from several places, in a specific order (to ensure predictable controllable behaviour). A normal order would be: command line arguments, environment variables, personal config file ($HOME/.thingrc), system configfile (/etc/thingrc), inbuilt defaults within the programme. The idea here is that this is a simple hierachy of defaults. Anything can be overridden by a command line option. If not supplied, an environment variable may be consulted. Otherwise the personal config file. Otherwise the system default. Otherwise some default within the programme. Programmatically you don't go: for each setting, look at these things in the order above. Instead you has some "settings" structure in the programme, initially filled out with some internal defaults. You read the system file to override the builtin defaults. Then you read the personal file to override that. Then you consult the environment to override that. Then you process the command line and have it override various things. A single pass across all this stuff. Any of it may be missing. Returning to Flask and the environment: because a Flask app is often invoked from within a web server instead of directly, it isn't feasible to pass it "command line" arguments to control it. So the environment becomes the most convenient place for ad hoc special settings. Cheers, Cameron Simpson "How do you know I'm Mad?" asked Alice. "You must be," said the Cat, "or you wouldn't have come here." ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Python and DB
On 27Jun2019 23:20, Brave Heart wrote: I have a little RSS program , I current the out are basically outputted on my screen, but I would like python to write to DB so I can from DB write on a webpage with PHP... Kinda like I want to run a news website .. See the "sqlite3" module with ships with Python. It creates a database in a local file and provides an SQL interface: https://docs.python.org/3/library/sqlite3.html#module-sqlite3 SQLite3 also has a command line tool for interactive access to the database; you might need to install that separately. For the web side you'd need an SQLite library for PHP, but I cannot believe that one does not exist. (Or you could also write your web application in Python instead of PHP.) Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] data structures general query
On 26Jun2019 11:01, Mats Wichmann wrote: On 6/26/19 4:40 AM, mhysnm1...@gmail.com wrote: Link lists I would guess be useful in an index for a database? I believe the "classic" use case is memory management - keeping track of chunks of memory. Flipping this, your typical ordered database index (unless the tech has advanced further) is a B+ tree possibly with a doubly linked list threaded through the leaf nodes. So a B+ tree is a sorted tree structure which is maintained in a balanced way so that the depth is pretty consistent across the tree, in turn so that there is not particularly long branch equivalent to have particular keys which are very expensive to look up. Unlike a binary tree a B+ tree has many keys at each node because this makes for efficient storage of the nodes in "blocks", whatever size is useful, and is also makes the tree shallower, making lookups cheaper. The leaf nodes point at the associated records (or possibly just hold keys if there are no records), and the doubly linked list of leaf nodes means you can traverse forwards or backwards from one leaf to the next in either order. Which makes find ranges of keys efficient: "SELECT ... WHERE key >= value ORDER BY key DESC" and its many variants. As has been pointed out by others, the various computer science basic structures are often built up into something different or more complex depending on what your data access pattern will be. It is important to understand the basic structures so that you can reason about their trade offs, and in turn understand more complex related structures. This goes both ways: in design you choose a structure to support what you're going to do. In use, you might choose to approach a problem differently depending on what data structure is used to arrange the data, because some actions are cheap in some structures and expensive in others, so you choose the efficient action where possible. Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Unexpected result when running flask application.
On 19Jun2019 09:54, Alan Gauld wrote: On 19/06/2019 05:18, Cravan wrote: I am experiencing an unexpected result when I try to run my flask application. The movie.html page prints out nothing except those in the . This appears on my webpage: Note that the mail server does not allow (for security reasons) binary attachments so we lost your image. Cravan, you might find it useful to "View Source" of that page in your browser. You can also use command line tools like "curl" or "wget" to directly fetch the page content. However, your html files are not in HTML. I'm not a Flask expert but every time I've used Flask the html pages have been real HTML. Yours appear to be in some strange pseudo markup language. It is very common in Flask to write HTML pages using Jinja templates, which is what his examples look like. Of course this adds more complexity, if he forgets to use Jinja to render the content to HTML before returning it. If this is something unique to Flask then I suspect you will need to ask on a Flask support page or list. It doesn't seem to be a Python language related issue at this point. He has, as it happens, over in fl...@python.org. Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Differences between while and for
On 15Jun2019 14:53, Sean Murphy wrote: In C, Perl and other languages. While only uses a conditional statement and for uses an iteration. In python while and for seems to be the same and I cannot see the difference. No, they're really much as in other languages. In general (most languages), a for loop is for iterating over some collection or list. A while is not explicitly for iteration over some collection, it is for repeating an action until some condition fails (or the inverse of the condition is achieved). Let's take C's for loop. It really is closely related to a while. That's because C is a pretty low level language. Early C is almost like a structured assembly language (well, it is a lot better, but it is deliberately close to the underlying machine). So C's for loop goes: for (setup; condition; advance) statement-or-block You can leave any of these out. It is equivalent to this while loop: setup while condition: statement-or-block advance but it is almost always used for iteration: s="foo" for (i=0; s[i]; i++) ... which counts "i" along the string "s". You _can_ use of for arbitrary while loops, but idiomatically that is rarely done - it is conceptually useful to use "for" for various kinds of iteration and "while" for more arbitrary repetition. Python is a bit more rigid. The "while" loop is just like "while" in other languages: do something while a condition holds. But a "for" loop in Python is inherently about iteration; it is defined as: for variable in iterable: suite and applies to any "iterable", some object or expression which can be iterated over. Any object which is iterable may be used. So it is very oriented towards collections of various kinds: lists, tuples, dictionary (iterates over the keys) and so on. Python does not have an until (do while) where the test is done at the end of the loop. Permitting a once through the loop block. Am I correct or is there a difference and if so what is it? You're correct. Why doesn't Python have an until statement? Basicly because it isn't necessary. It is usually easy enough to work around the lack that nobody has made a conincing case (meaning nobody has convinced the core developers). It would probably be written: do: ... while condition in some form if it ever came in to avoid using an new keyword ("until"). It does sometimes take a little contortion to make a do/while loop into a Python while - you usually have to perform some kind of hack to make the condition initially true. In the extreme case you just treat the first loop specially: first = True while first or the-actual-condition: ... do stuff ... first = False if you want to use "first" during the "do stuff". Or you could be a bit more reliable and go: first_test = True while first_test or the-actual-condition: first_test = False ... do stuff ... putting the flag up the top next to the condition. Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] deleting elements out of a list.
use the new list for the outer loop. I will receive multiple occurrences of the same text. This could be addressed by a if test. But I am wondering if there is a better method. The common idom is to leave the original unchanged and copy into a new list as in my example above. But taking a copy and iterating over that is also reasonable. You will still have issues with the popping, because the index "i" will no longer be aligned with the modified list. If you really want to modify in place, avoid enumerate. Instead, make "i" an index into the list as you do, but maintain it yourself. Loop from left to right in the list until you come off the end: i = 0 while i < len(description): if ... we want to pop the element ...: description.pop(i) else: i = i + 1 Here we _either_ discard from the list and _do not_ advance "i", or we advance "i". Either way "i" then points at the next word, in the former case because the next word has shuffled down once position and in the latter because "i" has moved forwards. Either way "i" gets closer to the end of the list. We leave the loop when "i" gets past the end. 2nd code example: description = load_files() # returns a list search_txt = description.copy() # I have not verify if this is the right syntax for the copy method.] A quick way is: search_text = description[:] but lists have a .copy method which does the same thing. for text in search_txt: words = text.split() for i in enumerate(words): Word = ' '.join(words[:i]) print (word) answer = input('Keep word (ynq)?') if answer == 'n': continue elif answer = 'q': break for i, v in enumerate(description): if word in description[i]: description.pop[i] The inner for loop still has all the same issues as before. The outer loop is now more robust because you've iterating over the copy. Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Broadcasting using sockets over adhoc wifi
On 11Jun2019 10:35, John Hoeksema wrote: Summer researcher using Raspbian and Python 3.5. I'm trying to use a Raspberry Pi 3 B+ to broadcast a message using the sockets library to other Pis (same model) over their shared ad-hoc network. All of the Pis can ping the others over the ad hoc network. The Pis can also communicate using pretty standard client-server code and the python socket library <https://docs.python.org/3.4/library/socket.html>. However, when I try to *broadcast* a message, the Pis give a "Network is unreachable" message (full error down below). A grad student I'm working with said that the script he provided me expects the server to be run in infrastructure mode, and configuration for ad-hoc mode is required to make it work correctly. This is confirmed, as I have successfully run the code on a desktop. I have poured over man pages and stackoverflow, and can't seem to find resources for how to configure socket broadcasts for ad-hoc networks. Any thoughts? I would start by debugging a bit outside of Python first. And I've never used an ad hoc wifi network, but after setup I _imagine_ that it looks like a normal local network: an IP address and a network mask, so "braodcast" is the usual notion of the IP address with all 1s in the local part. So 1: Does a manual command line "ping" of the broadcast address work? Eg, if the local network were 192.168.3.x/24 and I went: ping 192.168.3.255 (or on Linux): ping -b 192.168.3.255 I'm assuming your '' below is an actualy broadcast address? Or is it a special string? If so, what happens if you hand construct a broadcast IP like the *.255 above? Any different? Does tcpdump show anything useful, either locally or on one of the other Pis? Though given "Network is unreachable" I'd guess no packets get sent at all. I repeat my disclaimer: I've not used an ad hoc wifi network. Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Python printing parentheses and quotes
On 10Jun2019 19:04, Sai Allu wrote: Actually I'm pretty sure what happened was that the "#! usr/bin/python" was in a module that was being imported. So the Python interpreter cached it or somehow crashed randomly, which meant that the print was working as a keyword instead of a function. But when I removed that "#! usr/bin/python" line and then rewrote the print statements, it went back to working normally. My personal suspicision is that what you might have been doing is this (notice the trailing comma): print("",) or maybe: print("this", that") Look: % python Python 2.7.16 (default, Apr 1 2019, 15:01:04) [GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.42.1)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> print("",) ('',) >>> % python3 Python 3.7.3 (default, Mar 30 2019, 03:38:02) [Clang 8.0.0 (clang-800.0.42.1)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> print("",) >>> What is happening? In Python 2, print is a statement unless you use the __future__ import already mentioned. That means that this: print("",) is a "print" of the expression ("",), which is a 1-tuple, and gets printed as a tuple. The more likely scenario is when you're printing mulitple things: print("this", "that") which is still a "print" of a tuple. However, in Python 3 print is a function which means that the brackets are part of the function call. So this: print("") or: print("this", "that") is a call to the "print()" function, passing one or two arguments, which get printed. And printing "" (the former case) is an empty string. Please revisit your code can test this. Subtle issues like this are why we like to receive _exact_ cut/paste of your code and the matching output, not a retype of what you thought you ran. If you encounter something weird like this, it is well worth your time (and ours) if you make a tiny standalone script showing the problem, as small as possible. Then paste it into your message and paste in the output (this list drops attachments). That we we can all run exactly the same code, and solve your actual problem. And start always using: from __future__ import print_function in Python if you're using print. That will make your prints behave the same regardless if whether they are using Python 2 or 3. Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] regular expression query
get back. Untested example sketch: m = re.match('(ROYAL_BANK|COMMONER_CREDIT_UNION) INTERNET BANKING FUNDS TFER TRANSFER (\d+) TO (.*)', line) if m: category = m.match(1) id_number = m.match(2) recipient = m.match(3) else: m = re.match(...) ... more tests here ... ... ... else: ... report unmatched line for further consideration ... 3: You use ".*" a lot. This is quite prone to matching too much. You might find things like "\S+" better, which matches a single nonwhitespace "word". It depends a bit on your input. Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] is this doable
On 01Jun2019 10:02, nathan tech wrote: Now it has been mentioned, I do recall, on linux, briefly playing with psutil to retrieve memory values for a few tasks I keep running on my server. To that end, I think I now know roughly what to do. Something like this: import psutil import os path=os.getcwd()+"\\program.exe" Remark: try: r'\program.exe' instead of: "\\program.exe" because backslash escapes have meaning inside single or double quotes it is generally more reliable to use raw strings (r'') for such strings to avoid accidents. slist=[] for x in psutil.process_iter(): if(x.exe()==path): slist.append([x, x.create_time]_) r.sort() # not sure how to sort by second element, but I'd sort the list by start time list.sort() and sorted() accept an optional key= parameter which is a function that takes an element and returns the sort key. For example (untested): r.sort(key=lambda x: x[1]) to sort on x[1]. if(len(r)>1): Stylisticly we tend to just write: if r: It is a convention in Python that collections (such as lists) are "false" if they are empty. Urr, I see you said >1, not >0; this remark probably isn't relevant. But you could drop the outer brackets, not needed in Python: if len(r) > 1: It sounds like your "task" is then a running instance of "program.exe", yes? In that case the usual practive is to keep a "pid file" around with a distinctive pathname associated with the task. That is just a text file containing the process id of the task program. So rather than iterating over the process list with psutils (which will show you _other_ instances of program.exe, perhaps being run for another purpose), you just read the pid from the pid file and see if it is running. If it is, assume the task is already active. Untested incomplete example: pid_filepath = 'taskname.pid' try: pid = int(open(pid_filepath).read().strip()) os.kill(pid, 0) except (OSError, ValueError): # missing pid file, invalid contents) running = False else: running = True The "os.kill(pid, 0)" is a UNIX specific idiom for testing for a process; you can send signal 0 to a process you own successfully (the process itself never sees it); it will fail if the process doesn't exist or isn't yours. There should be a Windows equivalent for probing a process. The converse part where you start the process includes this: P = subprocess.Popen(.) # start the program with open(pid_filename, 'w') as pidf: print(P.pid, file=pidf) to update the process id file. Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Interactive editing of variables.
On 01Jun2019 12:53, Sean Murphy wrote: Python 3.7, windows 10. I have no clue on how to achieve what I want to do and the code I have creates an hash. As shown below: for row in description: [... get some text and present it for editing ...] I have had a look and cannot find an example where I can interactively edit a content of a variable at the command line. I do not want to use GUI at all. As this is a simple program only requiring CLI. I have no problems showing the prompt, but cannot insert text into the edit (input) area. Any ideas? If I understand you, you've got your target text and you want to user to be given it so they can modify it, rather than having to retype it in full at the prompt. On a UNIX system you'd use the standand "readline" module, and prefill the text buffer with your text. Is it marked as UNIX only, but I believe there are Windows dropins for this facility. Maybe install this package: https://pypi.org/project/pyreadline-ais/ maybe with "python -m pip install pyreadline-ais". Then use it according to the documentation for the stdlib readline module: https://docs.python.org/3/library/readline.html#module-readline Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] is this doable
On 31May2019 19:41, nathan tech wrote: Is it possible, in python, to store a running task id in the registry? I might be using the complete wrong terms here, because I'm only used to doing this with a specific language, but here's what I want to do: python mytest.py: if(registry.taskid==valid_task): print 'already open' send to open program to make a ding noise. I understand that the second part, the "send to program" requires the program to handle being sent a "wake up!" event, which is fine, it's the "is it already running" which I am not sure on. Well, you need to have some kind of persistent storage of tasks and a way to check if some described task is running. I don't know what constitutes a task in your mind here, or what you consider "the registry". There is any number of ways to store persistent values. A simple one is a CSV file: keep one around with a line per task including the taskid and whatever other relevant information is needed. Reread the file when needed. To avoid difficulties with updating an arbitrary record in such a file (which is just a text file with lines of variying lengths) you could treat it like a log: just append more lines containing the new task state. On reading the file, just keep the last line per task. Less simple, but more flexible, might be some kind of database. Python ships with SQLite3 support, which lets you have a little SQL database in a local file. It is hard to be any more specific without knowing what you consider a task, and how you'd check if it was active. Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] File extension against File content
On 31May2019 12:38, ingo wrote: Many file formats have "magic bytes" that you can use for that purpose. https://en.wikipedia.org/wiki/List_of_file_signatures Also, UNIX systems ship with a command called "file" which inspects a file's leading data for such magic numbers to identify their content. And there's a library called libmagic [1,2] which does this work, and there's a PyPI package called python-magic [3] for using this from Python, not to mention various other PyPI modules [4]. 1: https://sourceforge.net/projects/libmagic/ 2: https://github.com/threatstack/libmagic 3: https://pypi.org/project/python-magic/ 4: https://pypi.org/search/?q=magic Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] I'm having a small problem with my code
On 23May2019 15:16, David Lifschitz wrote: I am currently working on a project for myself. The code posted here is supposed to ask the user for an amount of numbers, what those numbers are, and places those numbers in a list. The next job of the code is to sort the list of numbers that were inputted in an ascending fashion. There is no error from the code, Regardless, it clearly isn't doing what you want. In this situation it is helpful (to us, and therefore to you later) to post the output from a run and an example of the output you wanted, and and description of what is deficient in the programme output. You've got the last 2 of these 3. however, when I run the code the first inputted number stays in its place and doesn't get sorted with the rest of the numbers. Comments below the code. emptyList = [] nOFN = int(input("how many numbers do you want to sort: ")) for x in range(nOFN): number1 = int(input("input number: ")) emptyList.append(number1) firstElement = emptyList[0] n = len(emptyList) for j in range(1, n): if emptyList[j-1] > emptyList[j]: (emptyList[j-1], emptyList[j]) = (emptyList[j], emptyList[j-1]) print(emptyList) Well, you only make one pass over the list. So if emptyList[0] <= emptyList[1] _on the first (and only) pass_, it will not move. Try comparing: 2 5 3 and: 3 2 5 and see if the behaviour differs. BTW, what you['re implementing looks like a bubble sort to me (look it up). But a since pass over the list isn't enough to sort the whole thing. Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Two Scripts, Same Commands, One Works, One Doesn't
On 15May2019 08:16, Stephen P. Molnar wrote: I am writing scripts to semi-automate some of my Quantum Chemistry software and have encountered a problem that has me baffled. The two scripts have the same form, the only difference being the commands. As you say, the scripts are the same but for that tiny difference. So let's look: for nvar in ligand: command = ["./pythonsh", "./prepare_ligand4.py", [...] command = ["./pythonsh", "./prepare_pdf4.py", [...] The errors are: runfile('/home/comp/Apps/Models/1-NerveAgents/Ligands/calc_pdf.py', wdir='/home/comp/Apps/Models/1-NerveAgents/Ligands') b'' None /sdc1/Apps/MGLTools2-1.1/bin/python: can't open file './prepare_pdf4.py': [Errno 2] No such file or directory So: first issue: your prepare_pdf4.py file is missing. Is it really missing or are you in the wrong working directory? Might its filename be mistyped? BTW, you shouldn't need the leading "./" on the .py filenames: harmless but also useless. If you copied that usage from the "./pythonsh" incantation, the circumstances are different. You probably need the "./pythonsh" to execute it directly from the current directory, which is not in your $PATH (and indeed it should not be - that way lies subversion). The .py files are just data and do not need this. Then, the second part. This is a totally separate error from your script. Jumping to the bottom... Traceback (most recent call last): [...] File "/home/comp/Apps/Models/1-NerveAgents/Ligands/calc_pdf.py", line 23, in print ('Subprocess FAILED:', proc.command) AttributeError: 'Popen' object has no attribute 'command' Because the prepare_pdf.py file is missing, for whatever reason, your "if proc.returncode" fire. And in that code you access "proc.command", which isn't defined. In the former script it doesn't try to execute this line because pythonsh succeeded. Looking at the subprocess docs, I think that is spelled "cmd", not "command". I have attached the two scripts that are called and a test input file. This is a text only list. Attachments are dropped before your message goes out. Fortunately you have enough information in the main body of the message. Googling has not helped me to find a solution [...] 1: I recommend duckduckgo instead of Google for privacy/tracking reasons. 2: When I search, I tend to find people with the same problem, not necessarily people with answers. But this question might be hard to get good hits on because the problem lies in a spelling error, which others may not have made that way. Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Looking for some direction
On 12May2019 17:19, boB Stepp wrote: On Sun, May 12, 2019 at 1:05 PM David L Neil wrote: I'm using Gnome Terminal under Fedora (Linux). This allows multiple terminals in tabs (and thus Ctrl-Tab rapid-switching). However, it irritates me that whilst I can set "profiles" for particular purposes; there does not seem to be a way to save a 'session'. Thus each time Terminal re-starts, I have to re-build each terminal, manually. (suggestions of other similar tools would be most welcome) I may be mistaken, but I think that a terminal multiplexer like tmux (https://github.com/tmux/tmux/wiki) is capable of session management. I have no personal use of tmux, but have been intrigued enough about others referring to it that eventually I will get around to seriously checking it out. Tmux is great, but I mostly use it for persistent sessions. It has facilities for running multiple panes in one terminal, which could be useful for remote sessions; locally I just use multiple panes in my terminal emulator, and in fact just multiple local panes connected to remote sessions anyway. I do use tmux panes in email though: I invoke mutt in a tmux session and replies start in a subpane, with mutt's index view in the upper (smaller) pane. But otherwise it is almost all persistent (and named) sessions. Now, I am spoilt: on a Mac I have access to iTerm3, which does: multiple tabs _and multiple panes and subpanes. My usual coding layout is a terminal in the left half of the screen running vim (with, usually, two _vim_ windows in it, vertically split). Often, that window gets a horizontal split, with a short and wide terminal pane below the editors, where I have a shell. The right hand half is antoher terminal, usually split intovarious panes, often 2 more evenly split. FOr shells and Python interpreters. But a really good terminal emulator is an outstanding tool. And iTerm3 seems to outshine everything else (Mac only alas - I'd like to find a food X11 equivalent - everything I've tried is deficient). Tabs and multiple panes is hugely flexible. It also has a toggle keystroke to expand a particular pane to the full window for when you want lots of text (diffs, commiting, etc). So unlike Alan, since it is all one Mac app (iTerm3), there's no Alt-TAB to switch apps, and since it does focus-follows-mouse cut/paste is very fast (iTerm3 has a mode like most X11 apps: select implicitly copies, so no Cmd-C copy keystroke for me either). Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Looking for some direction
On 11May2019 14:59, Cranky Frankie wrote: I'm a long time IT professional trying to teach myself object-oriented programming. As such I want to build a traditional PC app using MVC (Model - View - Controller) architecture. Just want to make sure I'm heading about this in the best way so I'm looking for some direction. For the Model or persistence layer I want to use SQLite. That's reasonable. I'm trusting you're aware of SQL injection issues and will be constructing your SQL with '?' parameter placeholders to avoid this? For the View or GUI I want to use wxPython. For the Controller I want to of course use Python. I'm also planning on using Git for source control. All reasonable. 1) For the IDE I'm most comfortable with Netbeans/Java, but I'm forcing myself to try and get comfortable with PyCharm. Is it worth sticking it out with PyCharm, or should I go with the Python module in Netbeans? Or is there another IDE I should look at? I haven't an opinion about IDEs except that unless the IDE doesn't work with Python for whatever reason, there's no reason to switch IDEs unless you want to learn a specific new IDE. Several of us don't really use IDEs and just use editors and terminal windows, though that is less common in the Windows world. Just use what already works unless there's some feature elsewhere which you need. [...] 3) For the O-O part, I'm comfortable with Inheritance and Composition. Do I need to worry about any of the more advanced design patterns? This app will be for vehicle ownership - tracking maintenance, etc. Nothing fancy. I wouldn't worry. Python mostly does inheritance; I suppose mixin classes (inherits) are like composition. The biggest change you'll find coming from Java is likely the typing: Python _values_ are strongly typed, but the variables are not - they can refer to a value of any type. And there aren't really Java interfaces. However, there are lint tools to look for issues like this. Oh yes: more than one class per Python source file - group them by package/module/topic. Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Collating date data from a csv file
On 08May2019 21:04, Dave Hill wrote: I have a csv file which details the results of equipment tests, I carry out PAT testing as a volunteer at a heriatge railway in N. Wales. I want to extract how many items were tested on each test day. So far I have generated a List of test dates, but I am now stalled at how to efficiently count numbers tested on each date. Can I have a list of tuples, where one item is the date and the second the count? Not as such, because you can't modify a tuple (so you can't update the count part). But you could use a 2 element list. or is there a better construct? Oh definitely. The easiest thing would be a defaultdict(int). Example: from collections import defaultdict ... by_date = defaultdict(int) for row in csvdata: timestamp = row[1] # based on your example data # get the date from the timestamp date = ... by_date[date] += 1 A defaultdict is a dict which magicly makes missing elements when they get access, using a factory function you supply. Here we're using "int" as that factory, as int() returns zero. I presume you've got the timestamp => date conversion sorted? Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] pip issue
On 02May2019 17:24, Anil Duggirala wrote: I executed the pip3 install --user -r contrib/requirements/requirements.txt (I actually did sudo before that). Please don't use sudo for this. The notion "install" does not imply being root. The whole point of --user is to install packages in your personal account without troubling with the system packages. Doing that as root only installs the packages for root, generally a useless thing as you shouldn't be running normal stuff as root. Just do pip3 as yourself. I then interrupted the process with Ctrl-C. Now, when I execute the same command I get: Collecting aiorpcX<0.18,>=0.17.0 (from -r contrib/requirements/requirements.txt (line 5)) Could not find a version that satisfies the requirement aiorpcX<0.18,>=0.17.0 (from -r contrib/requirements/requirements.txt (line 5)) (from versions: ) No matching distribution found for aiorpcX<0.18,>=0.17.0 (from -r contrib/requirements/requirements.txt (line 5)) That is odd, though I've seen this kind of complaint from pip before for some packages. Try this (as _yourself_, not as root): pip3 install --verbose --user 'aiorpcX<0.18,>=0.17.0' For me, this just worked. Also, the output includes the location where pip is installing stuff. You could always just clean that area out and retry. Also, try the --ignore-installed option and/or the --force-reinstall, which may cause pip3 to ignore any partial/damaged install and just do it all from scratch. I suspect this has something to do with me interrupting the install process, because I interrupted it precisely when it was fetching the package that it can't find now. Let me know if I should be asking this elsewhere. This is a fine place to ask this question. Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] self.name is calling the __set__ method of another class
On 29Apr2019 23:25, Arup Rakshit wrote: In the following code, class attributes name and email is set to the instances of NonBlank. class NonBlank: def __init__(self, storage_name): self.storage_name = storage_name def __set__(self, instance, value): if not isinstance(value, str): raise TypeError("%r must be of type 'str'" % self.storage_name) elif len(value) == 0: raise ValueError("%r must not be empty" % self.storage_name) instance.__dict__[self.storage_name] = value class Customer: name = NonBlank('name') email = NonBlank('email') def __init__(self, name, email, fidelity=0): self.name = name self.email = email self.fidelity = fidelity def full_email(self): return '{0} <{1}>'.format(self.name, self.email) if __name__ == '__main__': cus = Customer('Arup', 99) Running this code throws an error: Traceback (most recent call last): File "/Users/aruprakshit/python_playground/pycon2017/decorators_and_descriptors_decoded/customer.py", line 25, in cus = Customer('Arup', 99) File "/Users/aruprakshit/python_playground/pycon2017/decorators_and_descriptors_decoded/customer.py", line 18, in __init__ self.email = email File "/Users/aruprakshit/python_playground/pycon2017/decorators_and_descriptors_decoded/customer.py", line 7, in __set__ raise TypeError("%r must be of type 'str'" % self.storage_name) TypeError: 'email' must be of type 'str' Process terminated with an exit code of 1 Now I am not getting how the __set__() method from NonBlank is being called inside the __init__() method. Looks like some magic is going on under the hood. Can anyone please explain this how self.name and self.email assignment is called the __set__ from NonBlank? What is the name of this concept? As Steven has mentioned, it looks like NonBlank is a descriptor, which defined here: https://docs.python.org/3/glossary.html#term-descriptor So NonBlank has a __set__ method. The above text says: When a class attribute is a descriptor, its special binding behavior is triggered upon attribute lookup. Normally, using a.b to get, set or delete an attribute looks up the object named b in the class dictionary for a, but if b is a descriptor, the respective descriptor method gets called. So when your new Customer object runs its __init_ method and goes: self.name = name Since Customer.name is a descriptor, this effectively calls: NonBlank.__set__(self, name) which in turn does some type and value checking and then directly modifies self.__dict__ to effect the assignment. So yes, some magic is occurring - that is what the Python dunder methods are for: to provide the mechanism for particular magic actions. Descriptors are rarely used directly, however the @property decorator is quite ommon, where you define methodlike functions which look like attributes. Untested example: class Foo: def __init__(self): self.timestamp = time.time() @property def age(self): return time.time() - self.timestamp which you'd access directly as: foo = Foo() print("age =", foo.age) @property arranges this using descriptors: in the example above it arranges that the class "age" attribute is a descriptor with a __get__ method. Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Trouble with SUM()
On 20Apr2019 16:51, Ju Bo wrote: Hi, I'm trying to write a program that uses a while loop to ask a user for multiple values then use the program to add all the values, however many there may be, then print the sum. I'm having trouble with the sum() function. My code is below: con = "y" while con == "y": AMT = float(input("What is the price of the item? $")) con = input("Would you like to continue? [y/n]") price = float(sum(AMT + AMT)) We generally would also like to see the output of a run and your explaination of what is wrong with that output, compared to the output you wanted. However, there's an obvious problem in your code above: the value of price is computed entirely from the latest amount, with no reference to any previous amounts. Also, sum() does not take a single numeric vlue, it takes an iterable, such as a list. I suspect what you want to do is append AMT values to a list which is set up as an empty list before the loop. Then _after_ the loop, use sum() to add up all the number in the list and print that. For your reference, here is help(sum): sum(iterable, start=0, /) Return the sum of a 'start' value (default: 0) plus an iterable of numbers When the iterable is empty, return the start value. This function is intended specifically for use with numeric values and may reject non-numeric types. Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Python Django Query
On 29Mar2019 21:18, nitin chandra wrote: Hi Everyone, I need some guidance / corrections to my code. I hosted a demo site on pythonanywhere.com and to test the initial pages I wrote some test code. [...] Hi Nitin, I looks like nobody has replied; this probably means that nobody has the required specialty expertise to help you. (I don't.) Good news, put in 10 hrs, tried so many suggestion given on the net, yet non worked. So finally mailing the list. Might I suggest that you ask on the django-users mailing list, here: https://www.djangoproject.com/community/ You want the "Using Django" list there. There's a guideline to posting here: https://code.djangoproject.com/wiki/UsingTheMailingList but your post looks fairly good on the face of it. Hoping this helps, Cameron Simpson Objective : display main page with multiple links to other pages. Use jQuery plugins, click the link on main page and open other pages. The following path and pages are posted below. Thanks Nitin Chandra ERROR When I click on 'Table' link on 'home' page, the following error is displayed http://selftech.pythonanywhere.com/table.html Page not found (404) Request Method:GET Request URL:http://selftech.pythonanywhere.com/table.html Using the URLconf defined in eduinfra.urls, Django tried these URL patterns, in this order: admin/ [name='home.html'] The current path, table.html, didn't match any of these. You're seeing this error because you have DEBUG = True in your Django settings file. Change that to False, and Django will display a standard 404 page. +++ /home/selfTech/edu/tech/ __init__.py admin.py apps.py models.py tests.py urls.py views.py /home/selfTech/edu/tech/templates/ base.html home.html table.html *** our 'base.html' code below (test code, gets rendered correctly) Navbar Home (current) Link Table Disabled Search * home.html {% extends 'base.html' %} {% block content%} Hello TEAM :) {% endblock %} *** table.html (gives ERROR 404) Name * /home/selfTech/edu/tech/ urls.py from django.urls import path from . import views urlpatterns = [ path('', views.home, name='home'), path('table/', views.table, name='table') ## various combo did not work # path (' ', views.table, name='table') ## nope # path (' ', views.table, name='table.html') # nope ] */// views.py from django.shortcuts import render from django.http import HttpResponse # Create your views here. def home (request): /// correctly renders return render (request, "home.html",{}) def table (request): gives error return HttpResponse ('This is a test Page') # Tried the below code, nada # return render (request, "table.html",{}) *\ ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] operate on files based on comparing filenames to today's date
Before getting to your specific question, a few remarks below: On 28Mar2019 12:08, Matthew Herzog wrote: I have cobbled together this code which gives me regex matches of files whose names either begin with either MMDD_? or erased_YYMMDD_? and whose extensions are exml or ewav. todaystring = date.today().strftime("%Y%m%d") oldest = date.today() - timedelta(days=180) def get_files(extensions): all_files = [] for ext in extensions: all_files.extend(Path('/Users/msh/Python/calls').glob(ext)) return all_files for file in get_files(('*.ewav', '*.exml')): print(re.match("[0-9]{8}|erased_",file.name)) Your regexp in the "print" loop at the bottom does not do what you say. You have: print(re.match("[0-9]{8}|erased_",file.name)) i.e. the regexp is: [0-9]{8}|erased_ (a) That matches 8 digits _or_ the string "erased_". (b) [0-9] can be written as \d for more readability. (c) I'd use: (erased_)?\d{8} which is an optional "erased_" followed by 8 digits. And for your purposes: (erased_)?(\d{8}) which will group the digits together for easy extraction: DATED_FILENAME_re = re.compile(r'(erased_)?(\d{8})') for file in get_files(('*.ewav', '*.exml')): m = DATED_FILENAME_re.match(file) if m: # a suitable filename datepart = m.group(2) # now you can turn that into an actual datetime.date object Now I need to compare the date string (regex match) in the filename to today's date. If the result of the comparison results in YYYMMDD being older than 180 days, I should print something to indicate this. If not, nothing need be done. Should I write another function to compare each matched regex to today's date or is that overkill? Thanks. If you want to figure out the age, you need to convert the MMDD into a datetime.date and then compare _that_ to today's date. Why? Because the datetime.date type knows how to work with dates correctly, avoiding all sorts of bug prone efforts on your own part (because human calendars are irregular tricky things with many special cases). So I would drop the "todaystring" altogether. You're thinking "get the string from the filename and compare it to "todaystring". But what you _want_ it to measure the age, and that requires working with dates, not strings. So instead convert the filename's string in to a date and do straight arithmetic with today(). So you might upgrade that regexp to group the year, month and day individually, pull them out and make a date object: import datetime DATED_FILENAME_re = re.compile(r'(erased_)?(\d\d\d\d)(\d\d)(\d\d)') # get today as a datetime.date object today = datetime.today() for file in ..: m = DATED_FILENAME_re.match(file) if m: prefix, year, month, day = m.group(1,2,3,4) year = int(year) month = int(month) day = int(day) # turn this into a datetime.date object date = datetime.date(year, month, day) # compute a datetime.timedelta object age = today - date if age.days > 180: print("old!") I think you're right: make a function to return the datetime.date of the filename, so this portion: m = DATED_FILENAME_re.match(file) if m: prefix, year, month, day = m.group(1,2,3,4) year = int(year) month = int(month) day = int(day) # turn this into a datetime.date object date = datetime.date(year, month, day) and return the computed date. Then just keep this in the for loop so it is obvious what's going on; it is too small to hide in a function without a better reason. # compute a datetime.timedelta object age = today - date if age.days > 180: print("old!") Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] How to avoid "UnboundLocalError: local variable 'goal_year' referenced before assignment"?
On 24Mar2019 14:33, boB Stepp wrote: On 23Mar2019 22:15, boB Stepp wrote: The lambda is just a single line function definition, and doesn't get a function name. So your get_input name now accepts a "date_constructor" parameter and you would change the input step from this: try: identifier = int(input(input_prompt)) if date_value_err_ck: date(*date_value_err_ck) except ValueError: to this: try: value = int(input(input_prompt)) date = date_constructor(value) except ValueError: You could not know this from the code I showed (As I pared it down to illustrate my problem.), but I am also using get_input() to pull in from the user non-date values, too, but they are also all integers: pages_read and total_pages_to_read. Because of this, for these latter two items, "date_value_err_ck" will be assigned "None", which is why I have the "if date_value_err_ck:". Ok. So I realised later that you're not using the date from date_constructor; you're just calling it to see if it raises ValueError as a sanity check. Why not make that a condition, and drop date_value_err_ck altogether? 'conditions': [ (lambda goal_year: datetime.date(goal_year, 1, 1), "This doesn't look like a valid date year to datetime.date()."), and make the condition checking code more robust: for bad_condition, message in conditions: try: badness = bad_condition(input_value) except ValueError as e: print("Invalid goal_year, cannot even run the condition check! " + str(e)) else: if badness: print(message) That reduces your opening try/except to just checking that the input is a valid int, a lot simpler. Well, when you define the goal_month constructor lambda function, goal_year _is_ a local variable. And _because_ it is not a parameter of the lambda, the lambda finds it in the scope where it was defined: the scope at the bottom of your programme. This is called a "closure": functions has access to the scope they are define in for identifiers not locally defined (eg in the parameters or the function local variables - which are those assigned to in the code). This is so cool and useful! I recall seeing this mentioned for nested functions, but did not know it worked for lambdas as well. Lambda are functions. Same rules. Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] How to avoid "UnboundLocalError: local variable 'goal_year' referenced before assignment"?
ructor lambda function, goal_year _is_ a local variable. And _because_ it is not a parameter of the lambda, the lambda finds it in the scope where it was defined: the scope at the bottom of your programme. This is called a "closure": functions has access to the scope they are define in for identifiers not locally defined (eg in the parameters or the function local variables - which are those assigned to in the code). This means you get to pass in a lambda which still just takes one parameter (the input value, which it will use for the month) and still have access to the goal_year from the place the lambda was defined. A final note regarding "what is a local variable"? A local variable is one which is assigned to in the function code. Looks: x = 1 y = 2 z = 3 def func(x): y = 5 return x + y + z In "func", "y" is local because of the "y = 5" line. "x" is also local because it is a function parameter (which amounts to assigning a value to "x" when the function is called. However, "z" comes from the scrope where the function was defined. Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] properly propagate problems
ure", this is where we decide that specific failures are in fact valid execution paths, and None is a valid function return, indicating some kind of null result. You might still raise exceptions of various types for invalid input in this case; the None is only for a well defined expected non-answer. Regarding uncaught exceptions: As you say, you don't want your whole app to abort. So while you may catch specific exception types at some inner layer, you might want to catch _all_ exceptions at the very outermost layer and log them (with a stack trace), but not abort. So: try: ... process client request ... except Exception as e: # log exception and stack trace to the application log error("handler failed: %s", e, exc_info=True) return 500 series web response to client here ... This is one of those situaions where you might use the normally reviled "catch all exceptions" anti-pattern: at the outermost layer of some kind of service programme such as a daemon or web app handling requests: report the exception and carry on with the application. Remember the Zen: errors should not pass silently. Always log something when you catch an exception. Note that a primary reason to hate "catch all" is that such code often then proceeds to do more work with the bogus results. In a daemon or a web app, you're aborting _that request_. Any further work is shiny and new from a new request, not continuing with nonsensical data left around by a catch-all. Fortunately web frameworks like Flask or CherryPy usually embed such a catch-everything in their handler logic, outside you own code (after all, what if you own catch-everything was buggy?) So you don't normally need to write one of these things yourself. Which is good really, most of the time - they are a recipe for accidentally hiding errors. Let the framework do that one - it has been debugged for you. Another issue is the distinction between what to log and what to show the client. You usually DO NOT want to let the nitty gritty of the exception get to the end user: that way lies accidental leaking of credentials or private implementation details. So log details, but return fairly bland information to the client. Try to write your code so that this is the default behaviour. Again, web frameworks generally do just this in their outermost catch-all handler: only if you turn on some kind of DEBUG mode does it splurge private stuff over the web page for ease of debugging in development. Finally, I'm sure you've thought to yourself: if I catch an exception a long way from where it happened, won't the exception message lack all sorts of useful context about what happened? How useful is a log entry like this (from the outermost "OCR the document" level): error("OCR failed: %s", e) producing: OCR failed: permission denied because of a permission issue on a specific (but here, unnamed) file? My own solution to this issue is my cs.pfx module (you can install this with "pip install cs.pfx"). This provides a context manager named Pfx which adorns exceptions with call stack information, totally under your control. It also has various .error and .warning etc methods which produce prefixed log messages. Example: from cs.pfx import Pfx def read_file(input_file): with Pfx("read_file(%r)", input_file): with open(input_file, 'rb') as f: return io.BytesIO(f.read()) and outer calls might look like: def produce_image(image_name): with Pfx("produce_image(%r)", image_name): filename = path_to_image_file(image_name) buffer = read_file(filename) ... do stuff with the buffer ... If the inner open fails, the exception message, which is originally like this: [Errno 2] No such file or directory: 'f' becomes: produce_image('image_name'): read_file("/path/to/image_name.png"): [Errno 2] No such file or directory: '/path/to/image_name.png' How much context you get depends on where you put the "with Pfx(...):" statements. It also furthers simple code, because you no longer need to pepper your own exceptions with annoying repetitive context, just the core message: def read_file(input_file): with Pfx("read_file(%r)", input_file): if not input_file.startswith('/'): raise ValueError("must be an absolute path") with open(input_file, 'rb') as f: return io.BytesIO(f.read()) Because of the Pfx the ValueError gets the input_file value in question prefixed automatically, so you don't need to include it in your raise statement. Hoping all this helps. Short takeaway: decide what's mechanism and what is policy, and try to put policy further out in higher level code. Cheers, Cameron Simpson Go not to the elves for counsel, for they will say both no and yes. - Frodo, The Fellowship of the Ring ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] (no subject)
On 22Mar2019 17:45, Matthew Herzog wrote: I have a Python3 script that reads the first eight characters of every filename in a directory in order to determine whether the file was created before or after 180 days ago based on each file's name. The file names all begin with MMDD or erased_MMDD_etc.xls. I can collect all these filenames already. I need to tell my script to ignore any filename that does not conform to the standard eight leading numerical characters, example: 20180922 or erased_20171207_1oIkZf.so. Here is my code. if name.startswith('scrubbed_'): fileDate = datetime.strptime(name[9:17], DATEFMT).date() else: fileDate = datetime.strptime(name[0:8], DATEFMT).date() I need logic to prevent the script from 'choking' on files that don't fit these patterns. The script needs to carry on with its work and forget about non-conformant filenames. Do I need to add code that causes an exception or just add an elif block? Just an elif. Untested example: for name in all_the_filenames: if name.startswith('erased_') and has 8 digits after that: extract date after "erased" ... elif name starts with 8 digits: extract date at the start else: print("skipping", repr(name)) continue ... other stuff using the extracted date ... The "continue" causes execution to go straight to the next loop iteration, effectively skipping the rest of the loop body. An exception won't really do what you want (well, not neatly). Alan's suggestion of a regexp may be a sensible way to test filenames for conformance to your rules. \d{8} matches 8 digits. It doesn't do any tighter validation such as sane year, month or day values: would be accepted. Which may be ok, and it should certainly be ok for your first attempt: tighten things up later. Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] directory structure with tests?
On 06Mar2019 23:41, Alan Gauld wrote: On 06/03/2019 22:38, Mats Wichmann wrote: "It depends". ... How's that for a definitive answer? :) Pretty good! and I agree with all of it :-) Although personally I always use a test subdirectory and then, for building a distributable, use a file filter (eg find in *nix) to prune those out. All version controlled of course! There are those who argue that it is better to include the test files in the distribution. Aside from transparency and completeness, it may also aid bug reports as a test might only fail in the end user's environment and not that of the developer. Being able to get the error output from the end user running the tests is a win there. Q: How many user support people does it take to change a light bulb? A: We have an exact copy of the light bulb here and it seems to be working fine. Can you tell me what kind of system you have? For variety, in my own code I keep the tests for foo.py in foo_tests.py, the better to be seen next to foo.py in listings and file completion. Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] systemd
On 03Mar2019 16:01, Alan Gauld wrote: On 03/03/2019 14:46, Dave Hill wrote: python3 /home/pi/Code/TestVideo#6.py CLIP0026.MP4 20 DEBUG To be honest I'm surprised that works. I'd expected bash to interpret the # as a comment delimiter! But I tried it and it seems ok, you live and learn... The octothorpe is only a comment marker at the start of a word. Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Is this the preferred way to change terminal screen color using curses?
On 02Mar2019 22:32, boB Stepp wrote: BTW, my Linux Mint installation did *not* have the man pages for ncurses, even though it was installed. I had to manually fetch the man pages myself. Maybe they're in a separate -dev or -doc package? Sometimes the base package (eg "libncurses") contains only the library, not header files or doco wanted for development. Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Is this the preferred way to change terminal screen color using curses?
On 02Mar2019 15:16, boB Stepp wrote: I wanted to be able to change the background screen color of a terminal window using curses. My weak Google-Foo did not turn up a clear example of how to do this despite much searching. The two _obvious_curses methods to attempt this seemed to be window.bkgdset(ch, attr) to initially set a window's background attributes and window.bkgd(ch, attr) to change them to new values. The thing that has puzzled me is that "ch" is a mandatory parameter to supply. Remember that the Python curses module is a shim for the curses (or ncurses) C library. So "man 3 curses" gets you the main library page, and there are distinct manual entries for the various functions. On my machine (a Mac) the curses(3) manual entry has a section named "Routine Name Index" thus: Routine Name Index The following table lists each curses routine and the name of the man‐ ual page on which it is described. Routines flagged with “*” are ncurses-specific, not described by XPG4 or present in SVr4. and then there's a long table of functions and the match manual entry name. bkgdset is listed as in the curs_bkgd(3) entry, so run "man curs_bkgd" to view that manual entry. It describes the bkgdset, wbkgdset, bkgd, wbkgd, getbkgd functions in some detail. Also, the curs_color manual entry talks about terminal colours in detail. So "man curs_color". So after a variety of experimental efforts I came up with the following approach which seems to do what I want to do -- just change the terminal's background color at will. But since I did *not* locate any clear examples online on how to do this, I cannot help but wonder if there is an easier approach to do what I want to do? I would be inclined to call getbkgd() and then modify what it gives you as desired, then call bkgdset(). Untested. My code follows. As always I am open to any constructive criticism even if it is off this email's topic, though this code is not meant to be a polished product. [...] # Fill screen with spaces to color screen background: for y in range(max_height): try: stdscr.addstr(y, 0, ' ' * max_width) except curses.error as error: if y == max_height - 1: # Ignore error from writing to lower right-hand screen corner: pass else: raise error Is the painting of the screen with spaces actually required? I would have thought not (again, untested). The main window (stdscr) should start filled with spaces. [Reads more closely...] probably you want to call bkgd() or wbkgd() instead. "man curs_bkgd" says: bkgd The bkgd and wbkgd functions set the background property of the current or specified window and then apply this setting to every character position in that window: · The rendition of every character on the screen is changed to the new background rendition. · Wherever the former background character appears, it is changed to the new background character. Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Exception not working as expected?
On 02Mar2019 00:05, Alan Gauld wrote: On 01/03/2019 19:23, Chip Wachob wrote: I'm not sure what you mean by putting the except close to the int(). He means you should have a try/except for the int conversion, typically something like: # wait for it... try: num_items = int(raw_input(": ")) except ValueError: # try a second time. if num_items == 0: # individual testing print "\nIndividual testing requested" That means the user has a chance of continuing without errors and you don;t need to use recursion to restart the menu system. Just further to this remark of Alan's: you should make try/except clauses as small as is reasonable i.e. containing as little code as possible between "try" and "except". Not only does this have the advantage Alan mentioned, of making it possible to offset the user the chance to continue after an error, it _also_ means you have more confidence about what caused the exception. In you programme, you have a try/except around the entire main body of your loop. This means that the "except ValueError" clause will intercept _any_ ValueError issued by the code, not just the one from the int() call, so it needn't indicate bad user input, it could as easily indicate some subsequent bug in your code, as many functions can raise ValueError if they are handed something unsatisfactory. Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Only appending one object to list, when I am expecting more than 1
Thank you for a well formed problem description. However, as Steven has remarked the code you've included doesn't run. Can you follow up/reply with your actual working script, and also include some of the output you get. That said, I've a few small remarks about the code you have posted: On 26Feb2019 09:09, AdamC wrote: I'm creating lots of objects from json in a file. Part of reading the json back means that it iterates over the file and loads a json object and then creates the object from the dictionary. This is my file: {"name": "Dwarf Fortress", "platform": "steam", "dateAdded": "2019:02:25:16:56:1551113768", "tpe": "2019:02:21:13:49:1550756942"} {"name": "Jaws", "platform": "Netflix", "dateAdded": "2019:02:25:16:56:1551113768", "tpe": "2019:02:21:13:49:1550756960"} {"name": "Wargames", "platform": "CLI", "dateAdded": "2019:02:25:16:59:1551113984", "tpe": "Game"} BTW, I notice that only one of these rows has the "tpe" field set to "Game" or "Film", specificly the last one. So based on your code below, only one of these rows gets appended to the media array. Remarks below on writing code which is less prone to hiding this kind of problem. and these are the functions that help load that file: media = [] def loadFile(): filename = input('Filename? ') f = open(filename, 'r') createObjects(f) This f=open code would normally be written like this: with open(filename, 'r') as f: createObjects(f) That construction ensures that the file gets closed after running "createObjects()". As it is in your code the file is not explicitly closed; the CPython interpreter will, as it happens, close the file pretty promptly when "f" goes out of scope, but the language definition doesn't require such immediacy. def createObjects(f): '''Takes a file object and iterates through entries, passing them to create object, depending on what object it is.''' for line in f: count = count + 1 data = json.loads(line) print(type(data['tpe'])) name = data['name'] platform = data['platform'] dateAdded = data['dateAdded'] tpe = data['tpe'] if data['tpe'] == 'Game': a = createGame(name, platform, dateAdded,tpe) game = {a: tpe} media.append(game) if data['tpe'] == 'Film': a = createFilm(name, platform, dateAdded,tpe) film = {a: tpe} media.append(film) These if statements don't cover the case when "tpe" isn't "Game" or "Film", and (in other circumstances) could conceivably add two objects. If you construct it like this instead: if data['tpe'] == 'Game': a = createGame(name, platform, dateAdded,tpe) game = {a: tpe} media.append(game) elif data['tpe'] == 'Film': a = createFilm(name, platform, dateAdded,tpe) film = {a: tpe} media.append(film) else: print("Unhandled tpe value:", repr(tpe)) then (a) only 1 branch can ever apply and (b) reports any unexpected values which would otherwise _silently_ get ignored. By always having a final "else" in an if/elif//else chain you can catch/observe these unhandled situations. def createGame(name, platform, dateAdded, tpe): return Game(name, platform, dateAdded) def createFilm(name, platform, dateAdded, tpe): return Film(name, platform, dateAdded) Unless there's more stuff happening in these functions which you've stripped out for clarity you could just call the object constructors directly from the if statements: if data['tpe'] == 'Game': a = Game(name, platform, dateAdded) game = {a: tpe} media.append(game) Why would I only get one object in media, even though all three are created? As you may gather, all three input lines are processed, but only one gets turned into an object to add to media. Change the if/if into an if/elif/else and see if things become more obvious. Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] How to use "curses.resizeterm(nlines, ncols)"
On 24Feb2019 17:48, boB Stepp wrote: On Sun, Feb 24, 2019 at 2:52 PM Mats Wichmann wrote: If it's snippets you want, I always look at programcreek. These are always part of something bigger so they may not fit your request to have them be something you can run. https://www.programcreek.com/python/example/57429/curses.is_term_resized Thanks for the link! It looks useful for future research! Seconded. I did not know about this either! However, in the context of the current discussion, especially after Cameron's revelations, I cannot help but wonder if the writers of the three code snippets did not truly understand resizeterm()? Especially the first example is very similar to my testing script. But I did not go to the full-fledge programs to see if there was something unusual going on, so I may be overly harsh is my first impression. I think the first two snippets definitely don't. The third I'm less sure about. resizeterm is easy to misunderstand. Anyway, I should add a few remarks: 1: the use case for resizeterm() is for when curses has not noticed a resize. This can happen in remote terminal environments or where for some very weird reason the curses programme isn't in the terminal's control group. Most remote facilities (eg ssh and telnet) try to propagate terminal resize information, so remote curses stays informed. 2: much more useful is is_term_resized(). Many curses programmes need to know the termianl size (from getmaxyx()) in order to size their output (crop long lines, scale subwindows, what have you). So you might reasonably keep a copy of the result of getmaxyx() at the start of the programme: tty_y, tty_x = getmaxyx() and then call: if is_term_resized(tty_y, tty_x): # update size tty_y, tty_x = getmaxyx() # recompute the sizes for various displayed things # redisplay everything... at suitable times, because is_term_resized() is exactly for checking if the actual size (known by curses) matches some notional size (tty_y, tty_x, known by you, the programmer). All is is_term_resized, resizeterm and the "internal" resize_term functions are recent additions :-) From "man 3 resizeterm": This extension of ncurses was introduced in mid-1995. It was adopted in NetBSD curses (2001) and PDCurses (2003). Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] How to use "curses.resizeterm(nlines, ncols)"
On 24Feb2019 22:51, Mark Lawrence wrote: As I know squat about the curses module is this a time when a bug report could be put into the docs to clarify things, or do you have to know something about curses before you try using the Python wrapper? Well, both. The Python curses module is mostly a thin shim around the curses(3) C library. So the real semantics come from that; the Python module doco test closely resembles the text from the curses(3) manual entry (what you get from the "man 3 curses" command). The curses(3) manual entry (well, ncurses on my Mac here) says: The ncurses library includes facilities for responding to window resizing events, e.g., when running in an xterm. See the resizeterm(3X) and wresize(3X) manual pages for details. In addition, the library may be configured with a SIGWINCH handler. and resizeterm(3) says in part: resizeterm The function resizeterm resizes the standard and current windows to the specified dimensions, and adjusts other bookkeeping data used by the ncurses library that record the window dimensions such as the LINES and COLS variables. However, since people using the Python module might reasonably be expected to know less than those using the C library directly it would be useful to make it more clear that resizeterm() is essentailly "tell curses the terminal size" function, not a "make the terminal a specific size" function, and that because curses normally notices changes automatically then it is uncommon to need to call resizeterm(). Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] How to use "curses.resizeterm(nlines, ncols)"
On 24Feb2019 14:30, boB Stepp wrote: On Sun, Feb 24, 2019 at 1:39 AM Cameron Simpson wrote: It looks like the resizeterm() function updates the curses _internal_ records of what it believes the physcial terminal size to be. When you physically resize a terminal the processes within it receive a SIGWINCH signal, and those which pay attention to that signal should then consult the terminal to find out its new size. The curses library notices this signal, and calls resizeterm() to update its own internal idea of the terminal size so that it knows how to draw correctly on the screen. It does _not_ change the terminal; it changes curses' beliefs _about_ the terminal. [...] The is_term_resized() function looks up the current physical size and reports False if that matches curses current beliefs, and True if it does not match, meaning that the physical size has changed since curses last set up its beliefs [...] What you say makes sense and supports much of what I had concluded from my coding experiments. However, I still cannot get the function call, curses.resizeterm(), to do anything meaningful, which suggests that I still do not truly understand its usage. Likely so. The important thing you may be missing is that curses _itself_ calls resizeterm() automatically when it gets a SIGWINCH, so in normal situations you do not need to call this function. Because of this, getmaxyx() is always correct for the size of the terminal. Secondarily, resizeterm() does not make a change to the terminal itself. Note that is_term_resized(y,x) is a _test_: it asks whether curses' idea of the screen size does not match (y,x). (y,x) is a pair of numbers that _you_, the programmer, is keeping track of. If you set it once at the start of the programme: max_y, max_x = stdscr.getmaxyx() and never update it then is_term_resized(max_y, max_x) will report True if the terminal has changed size. If you update the (max_y,max_x) values regularly from getmaxyx() then they will always match and is_term_resized will always report False. I created the following script to test things out: [...] I've modified your script. Please try the script appended below. The short answer is that resizeterm() is _not_ normally useful to you, the programmer; it will only be useful if curses does not get to notice terminal size changes - _then_ you could use it to provide that facility. The script below is like yours: 'q' to quit, other keys to refresh and retest. Notice that the version below does not update (max_y,max_x) or call resizeterm(); initially you want to see what is_term_resized() does. It also shows you what got tested. Cheers, Cameron Simpson #!/usr/bin/env python3 import curses def start_cli(stdscr): max_y, max_x = stdscr.getmaxyx() stdscr.clear() stdscr.border() stdscr.addstr(2, 2, "This is the beginning!") stdscr.refresh() while True: char = chr(stdscr.getch()) if char in 'Qq': return tested = "is_term_resized(max_x=%d, max_y=%d)" % (max_x, max_y) internal = "getmaxyx() => y=%d, x=%d" % stdscr.getmaxyx() resized = curses.is_term_resized(max_y, max_x) result = "%s => %s" % (tested, resized) stdscr.clear() stdscr.addstr(max_y//2, max_x//2, result) stdscr.addstr(max_y//2 + 1, max_x//2, internal) if curses.is_term_resized(max_y, max_x): ##max_y, max_x = stdscr.getmaxyx() stdscr.addstr(max_y//2 + 2, max_x//2, "You resized the terminal!") ##stdscr.addstr(max_y//2 + 2, max_x//2, "Resizing your window -- NOW!") ##curses.resizeterm(max_y, max_x) else: stdscr.addstr(max_y//2 + 2, max_x//2, "Not resized.") stdscr.border() stdscr.refresh() if __name__ == '__main__': curses.wrapper(start_cli) ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] How to use "curses.resizeterm(nlines, ncols)"
On 23Feb2019 23:00, boB Stepp wrote: I am trying to understand the functionality that the Python module, curses, provides. But I am stuck on how to use the command, curses.resizeterm(nlines, ncols). At https://docs.python.org/3/library/curses.html#curses.resizeterm it says: curses.resizeterm(nlines, ncols)¶ Resize the standard and current windows to the specified dimensions, and adjusts other bookkeeping data used by the curses library that record the window dimensions (in particular the SIGWINCH handler). After much experimentation -- to no good effect -- I have concluded that "resizeterm" does *not* mean resize the terminal window that the curses program is running within. Can someone give me a working example of how to use this command? I think you might misunderstand the purpose of the function; I have to say the doco doesn't help you much here. It looks like the resizeterm() function updates the curses _internal_ records of what it believes the physcial terminal size to be. When you physically resize a terminal the processes within it receive a SIGWINCH signal, and those which pay attention to that signal should then consult the terminal to find out its new size. The curses library notices this signal, and calls resizeterm() to update its own internal idea of the terminal size so that it knows how to draw correctly on the screen. It does _not_ change the terminal; it changes curses' beliefs _about_ the terminal. If you call resizeterm() yourself you will cause curses to act from then on as though the physcial terminal has the size you supplied. That may make for bad rendering if that size does not match reality (consider cursor motions "from the right edge" or "from the bottom edge" - their sizes are computed from where curses thinks those edges are). Test the function curses.is_term_resized(nlines,ncols), whose doco says: Return True if resize_term() would modify the window structure, False otherwise. The is_term_resized() function looks up the current physical size and reports False if that matches curses current beliefs, and True if it does not match, meaning that the physical size has changed since curses last set up its beliefs (for example, in some environment where the resize _doesn't_ propagate a SIGWINCH to the process using curses, so it hasn't noticed). Does this clarify things for you? Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] python - files
On 27Jan2019 10:30, Peter Otten <__pete...@web.de> wrote: Cameron Simpson wrote: Mats has mentioned the modules getopt and argparse etc. These are primarily aimed at option parsing ("-v", "-o foo"). Your situation occurs _after_ the option parsing (in your case, there are no options). Not argparse. The main advantage over optparse is its handling of positional arguments. I stand corrected. Your custom logic [...] can roughly be replicated with the two lines parser.add_argument("first") parser.add_argument("second", nargs="?") [... extended example ...] Thank you! Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] python - files
Mats has mentioned the modules getopt and argparse etc. These are primarily aimed at option parsing ("-v", "-o foo"). Your situation occurs _after_ the option parsing (in your case, there are no options). Alan has talked about explicitly checking the length of sys.argv, much as you are doing, or accessing the (missing) argument and catching an exception. There's a middle ground, which is a little more flexible, which is to _consume_ the command line arguments. The argv array is a list, and can be modified. So: def main(argv): cmd = argv.pop(0) # collect the command word badopts = False # mandatory first argument if not argv: print("%s: missing first argument" % cmd, file=sys.stderr) badopts = True else: first = argv.pop(0) # optional second argument if argv: second = argv.pop(0)# explicit argument 2, use it else: second = None # or some otherdefault if argv: print("%s: extra arguments: %r" % (cmd, argv), file=sys.stderr) badopts = true if badopts: print("%s: invalid invocation, aborting" % cmd, file=sys.stderr) return 2 ... work with first and second ... You can see here that we process the arguments from left to right, consuming the valid ones as we find them, and setting a flag for incorrect arguments. At the end we test the flag and abort if it is set. otherwise we process knowing we have valid values. One important aspect of the above code is that you do not wire in an explicit length for sys.argv such as 2 or 3. That way you can easily change your code later if you want more arguments without running around adjusting such fixed numbers. The other important aspect is usability: the above code complains about each issue it encounters, and finally quits with an additional message. In a real programme that addition message would include a "usage" message which describes the expected arguments. Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Debugging a sort error.
On 14Jan2019 09:29, mhysnm1...@gmail.com wrote: Once again thanks for all the suggestions. It was the input data after all. As I am importing three sheets into python. One of the sheets had one less column. Semantic nit: "fewer". "less" is for continuous values. I've had to deal with loosely defined spreadsheets in the past year, and ended up with some mapping classes for reading "heading based" CSV and Excel sheets, where the first column contains column headings. It reads the rows and constructs a namedtuple class for the rows with field names based on the headings and then fills in the fields for each subsequent row. The advantage here is that then you can access the column data by name, eg: row.description provided the column heading remains the same. See the xl_import function from the cs.csvutils module: https://pypi.org/project/cs.csvutils/ The code is here: https://bitbucket.org/cameron_simpson/css/src/tip/lib/python/cs/csvutils.py Right at the bottom of that file is an example use of xl_import() for a worksheet where row 1 is a title and the column names are in row 2. On and forward to start working on text pattern exercise which I always have struggled with. Last language I did this in was Perl and had all sorts of headaches. Python seems cleaner from the reading I have done thus far. Lets see what challenges wait in front of me. I used to use Perl extensively. I put off moving to Python for too long. Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Debugging a sort error.
Discussion inline below. On 13Jan2019 13:16, mhysnm1...@gmail.com wrote: I am hoping someone can help with the below error using Python3.5 in the Windows 10 bash environment. I found the below link which I am not sure if this is related to the issue or not. As I don't fully understand the answer. https://github.com/SethMMorton/natsort/issues/7 I'm not sure that URL is very relevant, except to the extent that it points out that Python 3 issues an error when comparing incomparable types. In Python 2 this problem could go unnoticed, and that just leads to problems later, much farther from the source of the issue. Issue, following error is generated after trying to sort a list of strings. description.sort() TypeError: unorderable types: float() < str() Each list items (elements) contain a mixture of alpha chars, numbers, punctuation chars like / and are in a string type. Below is an example extract of the data from the list. ['Description', 'EFTPOS WOOLWORTHS 1294 ", "withdrawal Hudson street 3219"] The error message says that some of these values are not strings. One at least is a float. My expectation is that the openpyxl module is reading a floating point value into your description array. This might be openpxyl being too clever, or it might be (more likely IMO) be Excel turning something that looked like a float into a float. Spreadsheets can be ... helpful like that. There is over 2000 such entries. This used to work and now doesn't. You'll need to examine the values. But I see that you're trying to do this. I've snipped the data loading phase. Here: description = data['Description'] for i in description: if not str(i): print "not a string") This is not a valid check that "i" is a string. That expression: str(i) tries to convert "i" into a string (via its __str__ method). Most objects have such a method, and str() of a float is the textual representation of the float. So the if statement doesn't test what you want to test. Try this: if not isinstance(i, str): print("not a string:", i, type(i)) description.sort() I am suspecting it is something to do with the data but cannot track down the cause. Any suggestions on how to debug this? Your exception is in here, but as you expect you want to inspect the description types first. If the description column does contain a float in the original data then you could convert it to a string first! Note that this may not match visually what was in the spreadsheet. (BTW, your cited code never fills out the description list, not it cannot be current.) But first, fine out what's wrong. Try the type test I suggest and see how far you get. Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] decomposing a problem
On 26Dec2018 01:06, Alan Gauld wrote: On 26/12/2018 00:00, Avi Gross wrote: great. Many things in python can be made to fit and some need work. Dumb example is that sorting something internally returns None and not the object itself. This is one of my few complaints about Python. In Smalltalk the default return value from any method is self. In Python it is None. self allows chaining of methods, None does not. [...] Smalltalk uses this technique so much it has its own code layout idiom (Pythonised as follows): object .method1() .method2() .method3() .lastone() While I see your point, the Python distinction is that methods returning values tend to return _independent_ values; the original object is not normally semanticly changed. As you know. To take the builtin sorted() example, let us soppose object is a collection, such as a list. I would not want: object.sort() to return the list because that method has a side effect on object. By contract, I'd be happy with a: object.sorted() method returning a new list because it hasn't changes object, and it returns a nice chaining capable object for continued use. But that way lies a suite of doubled methods for most classes: one to apply some operation to an object, modifying it, and its partner to produce a new object (normally of the same type) being a copy of the first object with the operation applied. To me it is the side effect on the original object which weighs against modification methods returning self. Here's a shiny counter example for chaining. thread1: print(object.sorted()) thread2: print(object.sorted(reverse=True)) The above employs composable methods. And they conflict. When methods return a copy the above operation is, loosely speaking, safe: thread1: print(sorted(object)) thread2: print(sorted(object,reverse=True)) Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Trouble in dealing with special characters.
On 07Dec2018 21:20, Steven D'Aprano wrote: On Fri, Dec 07, 2018 at 02:06:16PM +0530, Sunil Tech wrote: I am using Python 2.7.8 That is important information. Python 2 unfortunately predates Unicode, and when it was added some bad decisions were made. For example, we can write this in Python 2: txt = "abcπ" but it is a lie, because what we get isn't the string we typed, but the interpreters *bad guess* that we actually meant this: txt 'abc\xcf\x80' Wow. I did not know that! I imagined Python 2 would have simply rejected such a string (out of range characters -- ordinals >= 256 -- in a "byte" string). Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] To check for empty string after a portion of the string in python 3.6
Again, _please_ use just one list: tutor or python-list. I've have directed replies to the tutor list. - Cameron On 04Dec2018 04:05, srinivasan wrote: Thanks a lot for your quick responses, Could you please let me know when the device is not enabled I get the error " I get the below error saying "IndexError: list index out of range"" Code snippet: [...] res = self._helper.execute_cmd_output_string(cmd) print("The value of res", res) res = self._helper.execute_cmd_output_string(cmd).split("\n", 2) print("the value", res) print("the value", res[1]) if __name__ == "__main__": m = Bt() print(m.bluetooth_scan()) 1. Output when device is enabled: The value of res Scanning ... 64:A2:F9:06:63:79 OnePlus 6 the value ['Scanning ...', '\t64:A2:F9:06:63:79\tOnePlus 6'] the value 64:A2:F9:06:63:79 OnePlus 6 None The "None" is because your bluetooth_scan method has no return value (I think), which in Python it means it returns None. 2. Output when device is not enabled When the device is not connected, I get the below error saying "IndexError: list index out of range" The value of res Scanning ... Traceback (most recent call last): the value ['Scanning ...'] File "/home/srinivasan/Downloads/bt_tests/qa/test_library/Bt.py", line 96, in print(m.bluetooth_scan()) File "/home/srinivasan/Downloads/bt_tests/qa/test_library/Bt.py", line 74, in bluetooth_scan print("the value", res[1]) IndexError: list index out of range Well, you've printed your list: ['Scanning ...'] It is a single element list. So it has an element at index 0. There is no element 1. Therefor Python raises an IndexError if you try to access that element. Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] To check for empty string after a portion of the string in python 3.6
Note: post returned to the tutor list. Please DO NOT cross post to multiple lists (i.e. tutor and python-list, as you have). This makes things difficult for people who are not on both lists. Pick a _single_ list, and use that. On 04Dec2018 02:46, srinivasan wrote: Could you please help me, as am still learning python syntax, how can I add conditional check for empty string after running "hcitool scan" (ie., when there is no Bluetooth devices discovered) ie., after the word "Scanning..." , when there are no Bluetooth discover-able devices and then return False in the below python code snippet? Command: ~$ sudo hcitool scan Scanning ... --> When there are no BT devices ~$ sudo hcitool scan Scanning ... 64:A2:F9:06:63:79 OnePlus 6 ---> When there are BT devices ~$ Python code snippet: def bluetooth_scan(self): """ Start bluetooth scanning process. :return: Return device info by mac address and name. """ cmd = "sudo hciconfig hci0 up" self._helper.execute_cmd_return_code(cmd) cmd = "sudo hcitool scan" res = self._helper.execute_cmd_output_string(cmd) return res Well you document your function as returning device info by MAC. So part the output if "hcitool scan" and for MAC address and name and store that in a dictionary (key MAC, value the name). Return the dictionary. If the dictionary is empty, there were no devices. Not that like almost all collections, empty dictionaries are "false", so you can go: bluetooth_devices = scanner.bluetooth_scan() if not bluetooth_devices: ... no devices found ... Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] I need help with my project
Avi and Alan and Sibylle, you're making this a bit hard on the OP (Treyton). Yes he's supplied no context, but it is easy to make some suggestions. Each of yours suggests he design a much wider system (menu entry, web interface, some kind of GUI). All of which is (a) beyond him and (b) irrelevant. Why not pretend he _has_ the existing order, from wherever. Suggest ways to store that order (in a list, or a dict mapping ordable items to counts, or something). Then ask him to write a little Python, or even detailed English prose. Treyton: you seem to have recitied a homework question: If the user selected a sandwich, french fries, and a beverage, reduce the total cost of the order by $1.00. This is what I have to do and I don't know where to start. Ok, this is clear: Treyton can't get off the ground, very common for beginning programmers. The core challenge is to break your problem into a sequence of tasks. How would _you_, a person, do this if you had a food order given to you? Think about a food order. It is usually a list of standard food items, a count of how many of each. And each item will have a cost. The total cost is the sum of (each item's cost * its price * its count), for each item in the order. Or for all possible items, by presuming that unordered items just have a count of 0. So you need: A label for each item, so you can talk about it. You can just use a string for this, eg "sandwich" or "fries". Make the strings simple to start with to avoid spelling mistakes. You can always associate better names with the short strings later. You need a table of items and their costs. It is normal to make a mapping for this, such a Python's dict type. You can write dicts literally: costs = { "sandwich": 200, "fries": 100, } In the example above, I'm imagining you have dollars and cents, and making prices in cents. You also need a representation of the order, being the item type and the count. You could use a Python list for this. Example: [ "fries", 2 ] The whole order might be a list of those, example: [ ["fries", 2 ], [ "sandwich", 3 ] ] So, a list of lists. For purposes of your program you can just set all this stuff up at the beginning, not worrying about GUIs or input forma or any complication. whole_order = [ ["fries", 2 ], [ "sandwich", 3 ] ] Now comes the part you need to do: - write some Python code to compute the total cost of the order (item cost * item count), summed for all the items. Print this raw total so that you can see it is correct. - write some totally separate code to look at the order and decide if the client met your special condition (sandwich, fries, beverage) and get a true/false result. Print this, too. - write a Python statement to subtract $1.00 (or 100 cents) from the total if that condition is true. Print that. Then fiddle the order and run your programme several times to check that it is behaving the way it should. If you find difficulties you cannot surmount, come back here (by replying directly to one of the messages in your discussion) with: - your complete code - your expected output, and the output from your programme - a complete transcript of any error message, for example if your programme raised an exception Make sure these are inline in your message, _not_ attachments. We drop attachments in this list. Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Error Python version 3.6 does not support this syntax.
On 30Nov2018 02:19, srinivasan wrote: Thanks a lot for your quick responses, again the below line seems to be throwing the same error, is that should I again decode the line where am facing the issue to str? or could you please let me if there is any alternative solution for the same or workaround in python 3.6? Code Snippet: def parse_device_info(self, info_string): """Parse a string corresponding to a device.""" device = {} block_list = ["[\x1b[0;", "removed"] string_valid = not any(keyword in info_string for keyword in block_list) ---> Again this line seems to be the same issue [...] def get_paired_devices(self): """Return a list of tuples of paired devices.""" try: out = self.get_output("paired-devices") except BluetoothctlError as e: print(e) return None else: paired_devices = [] for line in out: device = self.parse_device_info(line) [...] Your problem is basicly that reading from command output gets you bytes data, not text (str) data. This is because pipes transfer bytes; that the command may issue text simply means that those bytes are an encoding of the text. Your entire process treats the output as text, because the commands issue textual output. Therefore, the most sensible thing to do at this point is to _decode_ the bytes into text as soon as you get them from the command, and then the rest of your programme can work in text (str) from then on. So I would be inclined to change: for line in out: device = self.parse_device_info(line) into (untested): for line_b in out: line = line_b.decode(errors='replace') device = self.parse_device_info(line) That will turn line_b (a bytes object holding the line) into text before you try to do any parsing. From that point onward, everything is text (str) and you do not need to put any bytes->str stuff elsewhere in your programme. Some remarks: That decode line above uses the default bytes->str decoding, which is 'utf-8'. That is probably how your system works, but if it is not you need to adjust accordingly. If the command ussues pure ASCII you'll be fine regardless. The decode uses "errors='replace'", which means that if the bytes data are _not_ correct UTF-8 encoded text, the decoder will put some replacement characters in the result instead of raising an exception. This simplifies your code, and since you're parsing the output anyway for infomation the replacements should show up to your eye. The default decode mode is 'strict', which would raise an exception on an invalid encoding. Purists might decode the output stream ("out") before the for-loop, but in most encodings including UTF-8, you can split on newlines (byte code 10, ASCII NL) safely anyway, so we just split first and decode each "bytes" line individually. In the loop I deliberately iterate over "line_b", and have the decoded text in "line", instead of doing something like: for line in out: line = line.decode() That way I am always sure that I intend to talk about bytes in one place (line_b) and text (line) in another. Having variable that might contain bytes _or_ text leads to confusion and difficult debugging. The core takeaway here is that you want to keep in mind whether you're working in bytes or text (str). Keep the division clean, that way all you other code can be written appropriately. So: the command pipe output is bytes. COnvert it to text before passing to your text parsing code. That way all the parsing code can work in text (str) and have no weird conversion logic. Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Issue in using "subprocess.Popen" for parsing the command output
On 26Nov2018 09:03, Steven D'Aprano wrote: On Sun, Nov 25, 2018 at 10:43:10PM +0530, srinivasan wrote: 1. Am trying to improve the below code with "try" and "exception", could you please help me how "try" and "exception" can be used on the below code snippet. I hope in my code with try and exception, seems to be a bug. As a beginner, you should normally not use try...except to report errors. You should learn how to diagnose errors by reading the traceback. Covering up the traceback with try...except makes debugging harder. Very true, but... Your use here: *try:* *cmd = "nmcli device wifi connect '%s' password '%s'" % (ssid, pw)* *proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, universal_newlines=True)* *stdout, stderr = proc.communicate()* *retcode = proc.returncode* *print("printing stdout!!", stdout)* *print("printing retcode!!", retcode)* *except subprocess.CalledProcessError as e:* *s = """While executing '{}' something went wrong.* *Return code == '{}'* *Return output:\n'{}'* *""".format(cmd, e.returncode, e.output, shell=enable_shell)* *raise AssertionError(s)* [...] But even if it doesn't fail, the next line: raise AssertionError(s) is an abuse of exceptions. The failure here is *not* an assertion, and you shouldn't use AssertionError. You wouldn't use TypeError or UnicodeEncodeError or AttributeError. "AssertionError" should not be used for "some arbitrary error". [...] My opinion is, you should remove that try...except altogether. I don't think that it helps your code, even if it worked. Calls to Popen can fail in many, many ways, and it seems pointless to single out just one of them and to replace the useful traceback and error message with a less accurate one. I'd add one qualificaion here: it may be that he wants to report this exception in particular, while still not "handling it". In which case I'd advocate something like: try: ... Popen stuff ... except subprocess.CalledProcessError as e: s = print(s, file=sys.stderr) raise i.e. report some special message, then _reraise_ the original exception. In this way he gets to keep the original exception and traceback for debugging, which still making whatever special message he wanted to make. Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] [Python 3] Threads status, join() and Semaphore queue
On 24Nov2018 16:08, Dimitar Ivanov wrote: Your explanation definitely clears up quite a bit of my misunderstanding, thank you for that! There was a reason why I shy away from using Queue, but for the life of me I can't remember right now what that reason was. I will have to modify my code using your example and give it another try, I will make sure to let you know if I run into any issues or additional questions. :) Questions are welcome. Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] [Python 3] Threads status, join() and Semaphore queue
] for id in ids: thread = threading.Thread(target=file2.runStuff, name=str(id), args=(id, q)) threadsPool.append(thread) and modify runStuff thus: def runStuff(id, q): sem.aquire() ... sem.release() q.put(id) After the threads are started, collect completed ids: for count in range(len(ids)): id = q.get() print("completed work on id %r" % (id,)) You'll notice no .join() there. Getting the id off the queue "q" implies that the Thread has completed. I have the feeling I'm using a very wrong approach in trying to extract that information in the .join() loop, since it only goes back to it once a thread has finished, but at the same time it feels like the perfect timing. You're collecting specific threads. If other threads complete earlier than that specific thread, they don't get reported immediately. You're reporting threads in the order you made them, not in the order they complete. Using a Queue and not worrying about the threads themselves lets you gets ids as they're done, in whatever order. And just in case you are wondering why I have my threads starting in file1.py and my Semaphore queue in file2.py, it's because I wanted to split the runStuff(id) function in a separate module due to its length. I don't know if it's a good way to do it, but thankfully the Python interpreter is smart enough to see through my ignorance. I usually split modules based on function, not size. Put related things in the same module. Often in classes, but let us not go there yet. If you want to get a little funky, separate the runStuff code which works on the id from the control code (the semaphore use). You could then run the queue collection in its own thread. Have the main control code also manage the semaphore: q = Queue() threadsPool = [] for id in ids: thread = threading.Thread(target=file2.runStuff, name=str(id), args=(id, q)) threadsPool.append(thread) collector = Thread(target=collect, args=(q, ids)) collector.start() for thread in threadPool: sem.acquire() thread.start() # wait for collection to complete collector.join() def collect(q, ids): for count in range(len(ids)): id = q.get() sem.release() so that you acquire the semaphore before starting each thread, and release the semaphore as threads complete and report their id values. Because these things need to happen in parallel (acquire, start versus q.get, release) you run the collector in its own thread. Does this clear anything up? Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] GPA calculator
On 14Nov2018 13:51, Whitney Eichelberger wrote: I need help creating a weighted GPA calculator. I attempted to create one but I was unable to incorporate different leveled classes (College Prep, Honors, and AP). How can I incorporate those leveled classes into the calculator in order to get a final GPA Please always include your code, and some sample data and the output, and explain what isn't as you want it. Past that into your message - this list does not do attachments. Also, please explain terms like "GPA". I imagine it may mean "Grade Point Average", but really it might mean almost anything. On the tutor list we're happy to help with code by expalining problems and suggesting solutions, but we don't write things outright - you need to do that yourself in order to learn. Finally, I put a better description in the Subject: line above. It is useful so that people know what various discussions are about. Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Example for read and readlines() (Asad)
On 12Nov2018 07:24, Asad wrote: Thanks for the reply . I am building a framework for the two error conditions, therefore I need to read and readlines because in one only regex is required and in other regex+ n-1 line is required to process : #Here we are opening the file and substituting space " " for each \n encountered f3 = open (r"D:\QI\log.log", 'r') string = f3.read() string1 = f3.readlines() My first remark is that both these lines read _and_ _consume_ the file content. So "string" gets the entire file content, and "string1" gets an empty array of lines, because the file is already at the end, where there is no more data. It is also better to use this idiom to read and then close a file: with open(r"D:\QI\log.log", 'r') as f3: string = f3.read() This reliably closes f3 once the "with" suite completes, even if there's some kind of exception. You need 2 copies of the file data. You can do this 2 ways. The first way is to read the file twice: with open(r"D:\QI\log.log", 'r') as f3: string = f3.read() with open(r"D:\QI\log.log", 'r') as f3: string1 = f3.readlines() The efficient way is to read the file once, then make string from string1, or string1 from string. For example: with open(r"D:\QI\log.log", 'r') as f3: string1 = f3.readlines() string = ''.join(string1) regex = re.compile ( "\n" ) st = regex.sub ( " ", string ) Using a regular expression to replace a fixed string such as "\n" is overkill. Consider: st = string.replace("\n", " ") Python strings have a bunch of handy methods for common simple things. Have a read of the docs for further detail. if re.search('ERR1',st): y=re.findall("[A-Z][a-z][a-z] [ 123][0-9] [012][0-9]:[0-5][0-9]:[0-5][0-9] [0-9][0-9][0-9][0-9]",st) print y On the other hand, a regexp is a good tool for something like the above. patchnumber = re.compile(r'(\d+)\/(\d+)')==> doesnot work it only works if I use #string = f3.read() This may be because "string" is a single string (the whole file text as one string). "string1" is a _list_ of individual strings, one for each line. Personally, i would call this "strings" or "lines" or some other plural word; your code will be easier to read, and easier to debug. Conversely, a misleading name makes debugging harder because you expect the variable to contain what its name suggests, and if it doesn't this will impede you in finding problems, because you will be thinking the whrong thing about what your program is doing. for j in range(len(string1)): if re.search ( r'ERR2', string1[j] ): print "Error line \n", string1[j - 1] mo = patchnumber.search (string1[j-1]) a = mo.group() print a print os.getcwd() break Please advice how to proceed. mo.group() returns the whole match. The above seems to look for the string 'ERR2' in a line, and look for a patch number in the previous line. Is that what is it supposed to do? If the above isn't working, it would help to see the failing output and a description of what good output is meant to look like. Finally, please consider turning off "digest mode" in your list subscription. It will make things easier for everyone. Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Displaying Status on the Command Line
On 08Nov2018 10:00, Steven D'Aprano wrote: Note that I need this to be platform agnostic. That's hard, even on a single platform like Linux. Most, nearly all, terminal honour carriage return and backspace. That is technically enough. Even terminals with a destructive backspace (rare - it is normally just a cursor motion) can get by (backspace, overwrite the new text). Most xterminal windows use either the xterm or vt1000 set of commands, which are broadly similar, but that's not guaranteed. If somebody happens to be running a different terminal type, they'll see something weird. And I have no idea what happens on Windows. I'd sort of expect Windows terminals, even cmd.exe, to accept the ANSI sequences, which is what vt100 and xterms use. But that is expectation, not knowledge. Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Displaying Status on the Command Line
On 07Nov2018 11:22, Chip Wachob wrote: I'm sure that this is simple and my searches have just not used the correct words. What I would like to do is display, on a single line, in the terminal / command line a progress percentage, or, simply a sequence of - / - \, etc.. or even, accumulating period characters. What would the escape codes be, or is there a better way to handle this? Note that I need this to be platform agnostic. I'e got a module 'cs.upd' on PyPI which does this. "pip install cs.upd" to obtain it. Typical usage: import sys import time from cs.upd import Upd upd = Upd(sys.stdout) for percentage in range(1,100): upd.out("Progress: %d%%", percentage) if percentage % 10 == 0: upd.nl("completed %d%%", percentage) time.sleep(0.1) upd.out("Complete!") time.sleep(1.0) That example is obviously contrived, and the sleeps are so you can see it all happen. But you can slot this into simple terminal based programmes to present dynamic progress. Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Request for help with code
On 06Nov2018 15:50, Joseph Gulizia ", count) You should see that the expected code is actually reached and run, and if it isn't, the corresponding print()s do not happen. Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Request for help with code
On 06Nov2018 15:50, Joseph Gulizia I'm using the bookazine "The Python Book" First Edition on pages 13-14 it gives the code (listed further below). It asks for user to state a given number of integers (for example 4)...then user enters integers. It doesn't stop seeking input after the number requested thereby creating an infinite loop. It is vital to preserve the indenting when pasting in code. Indent level is critical to Python's control flow. I'm going to look anyway, but without the indenting I may misinterpret the logic. [...snip...] # creates a collection (list) called ints ints=list() # keeps track of number of intergers count=0 # Keep asking for an interger until we have the required number while countHere is where I imagine the problem may lie, but it depends critically on the indenting. Your while loop should look something like this: while count < target_int: ... read the int ... if isint == True: ints.append(new_int) count += 1 However, consider this: while count < target_int: ... read the int ... if isint == True: ints.append(new_int) count += 1 All I have changed is the indent. This means that the increment of count is _outside_ the while loop body. Which means that it never happens inside the loop, and therefore count never increases, and therefore the end of loop condition is never reached. Infinite loop. The other likelihood is that isint somehow does not become true. If that is the case, the count also never increments. I suggest that you put several print() statements into the loop at strategic points (note the indenting - the same as the block they're embedded in): while count < target_int: print("loop: count =", count, "target_int =", target_int) ... read the int ... if isint == True: print("isint is true!") ints.append(new_int) count += 1 print("count =>", count) You should see that the expected code is actually reached and run, and if it isn't, the corresponding print()s do not happen. Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Regex for Filesystem path
On 06Nov2018 18:10, Alan Gauld wrote: >On 06/11/2018 13:13, Asad wrote: > >> Can you provide some advice and code for the following problem : > >The first thing is to go read the documentation for the os.path module. >It is designed for reliable path manipulation. > >> /a/b/c/d/test/test_2814__2018_10_05_12_12_45/logA.log >> >> f3 = open ( r"/a/b/c/d/test/test_2814__2018_10_05_12_12_45/logA.log", 'r' ) >> st1 = f3.readlines () > >You hardly ever need readlines() any more, just iterate >over the file, its much easier. > >> for j in range ( len ( st1 ) ): > >for line in f3: Not to mention cheaper in memory usage. [...snip...] >>a = mo.group() ## 123456/789 >>=== >>How to do I traverse to the required directory which is >> /a/b/c/d/test/123456/789 ? > >You can use relative paths in os.chdir. >So a payth of '..' will be one level up from the current >directory. Of course you need to chdir to that directory first >but os.path will tell you the dir you need. It is better to just construct the required path. Chdir there requires a chdir back, and chdir affects all the relative paths your programme may be using. I'd use os.path.dirname to get '/a/b/c/d/test' and then just append to it with os.path.join to contruct each directory path. [...] >But I'm guessing that's too obvious so the path may vary? >>1) First I need to extract /a/b/c/d/test/ from >> /a/b/c/d/test/test_2814__2018_10_05_12_12_45/logA.log ? Use os.path.dirname: # up the top from os.path import dirname, join # later testdir = dirname(logfile_path) >get the dir then chdir to .. from there. > >>2) Then add 123456/789 and create directory location as >> /a/b/c/d/test/123456/789 > >Simple string manipulation or use the os.path functions. Eg dirpath = join(testdir, '123456/789') >>3) cd /a/b/c/d/test/123456/789 > >os.chdir() I still recommend avoiding this. Just construct the full path to what you need. >>4) look for the latest file in the directory /a/b/c/d/test/123456/789 > >Slightly more complex, you need the creation timestamp. >You can find that with os.path.getctime() (or several >other options, eg os.stat) Do not use ctime, it is _not_ "creation" time. It is "last change to inode" time. It _starts_ as creation time, but a chmod or even a link/unlink can change it: anything that changes the metadata. Generally people want mtime (last nmodified time), which is the last time the file data got changed. It is more meaningful. Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Can tempfile.NamedTemporaryFile(delete=False) be used to create *permanent* uniquely named files?
On 23Oct2018 11:24, Peter Otten <__pete...@web.de> wrote: Cameron Simpson wrote: The doco for mktemp (do not use! use mkstemp or the NamedTemporaryFile classes instead!) explicitly mentions using delete=False. Well, "permanent temporary file" does sound odd. By the way, NamedTemporaryFile returns a proxy instead of the file itself. In some rare cases that could be a problem. Would mktemp() really be dangerous if you used it like this, def new_game(directory): for _retry in range(3): filename = mktemp("game_", ".json", dir=directory) try: return open(filename, "x") except FileExistsError: pass raise FileExistsError with the "x" mode? In terms of a race, maybe not. But in terms of security? Probably. Consider: the issue with mktemp is that it can be switched out before use. So: Alice: mktemp() -> filename Mallory: guess filename, put a symlink there pointing at a file which doesn't exist, but which has an effect if it does. For example, in ancient windows, an autorun.ini file. Or cooler, on UNIX, a file in /etc/cron.d. Alice: write to filename, not accidentally _creating_ the target of the symlink, now writing a file somewhere unwanted. Now, the examples above pretend that Alice has root privileges so that Mallory affects a root run system. But for Alice, it is just as bad if Mallory just subverts her personal account via some other pathname. Also, there's the issue of privacy: open(), in your example, will use the default umask, which may be more open than one wants. And so on... Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] What is the best way for a program suite to know where it is installed?
On 22Oct2018 19:26, boB Stepp wrote: On Mon, Oct 22, 2018 at 9:47 AM Mats Wichmann wrote: As you've concluded by now, this isn't a completely trivial exercise, and you'll possibly get asked the question "why do you think you need to know that?". Actually no one has yet asked me this question, and you have me intrigued. Importing the various program modules/module contents is no issue. Where I believe I need to know the paths to things are to get to data folders, config files, and occasionally utility programs that I have written that are on my hard drive, but not copied to my current program suite. Data folders inbuilt to your app? (I'm going to call it an "app" purely for convenience.) Not sure there's a universally good answer for this. You can include data files in your package I think (haven't tried this, as far as PyPI/pip goes), which means you could locate them from your source code. Happy to hear more on this from others. Config files: I'm coming to be of the opinion, based on a couple of things I'm writiing at the moment, that apps should (a) come with a builtin default config (possibly computed form the environment the find themselves executed in) and that (b) that config should be expressed in a class instance which can transcribe itself to a file in the right format. Why? It solves the "where is it" problem: it is in the code, as some function which constructs the app's config instance in the absense of a config file. It solves the "how does the user get their first config file for later hacking/customisation"? If the config file is not in the well known place (~/.your-apprc or ~/.config/something, etc) then having made your default config you can transcribe it to the default place. Now the user has a file they can modify. It also solves the "incomplete config file" problem: if you can construct a default config, you can usually handle an incomplete config as "construct the default, then alter based on the contents of the config file". Which lets the user keep a tiny config file modifying only the stuff which needs tweaking. Utilities: I my opinion, unless they shift with you app it is the end user's job to have these in the execution path ($PATH on UNIX). If you app/package provides them you need a bin directory, with the same issues as your data files. Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Can tempfile.NamedTemporaryFile(delete=False) be used to create *permanent* uniquely named files?
On 21Oct2018 10:55, Peter Otten <__pete...@web.de> wrote: boB Stepp wrote: So I am now wondering if using tempfile.NamedTemporaryFile(delete=False) would solve this problem nicely? As I am not very familiar with this library, are there any unforeseen issues I should be made aware of? Would this work equally well on all operating systems? I think this is cool thinking outside of the box. I would not have "dared" this, but now you suggest it I cannot see anything wrong with your approach. The doco for mktemp (do not use! use mkstemp or the NamedTemporaryFile classes instead!) explicitly mentions using delete=False. Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Can tempfile.NamedTemporaryFile(delete=False) be used to create *permanent* uniquely named files?
On 21Oct2018 01:13, boB Stepp wrote: Use case: I want to allow a user of my Solitaire Scorekeeper program to be able to give any name he wants to each game of solitaire he wishes to record. My thought for permanent storage of each game's parameters is to use a dictionary to map the user-chosen game names to a unique json filename. This way I hope no shenanigans can occur with weird characters/non-printing characters. My initial thought was to just have a sequence of game names with incrementing numerical suffixes: game_0, game_1, ... , game_n. But this would require the program to keep track of what the next available numerical suffix is. Additionally, if a user chooses to delete a game, then there would be a gap in the numerical sequence of the game filenames. I find such a gap aesthetically displeasing and would probably go to additional efforts to reuse such deleted filenames, so there would be no such "gaps". So I am now wondering if using tempfile.NamedTemporaryFile(delete=False) would solve this problem nicely? As I am not very familiar with this library, are there any unforeseen issues I should be made aware of? Would this work equally well on all operating systems? The doco reads that way to me. However, NamedTemporaryFile is a (nice) wrapper for tempfile.mkstemp(). Why not use that directly? Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] How to find optimisations for code
On 19Oct2018 23:07, Alan Gauld wrote: On 19/10/18 17:12, Pat Martin wrote: TLDR; How do you figure out if code is inefficient (if it isn't necessarily obvious) and how do you find a more efficient solution? Others have addressed most of the issues but I'd just add the caveat that you can spend forever trying to make your code "more efficient". Usually, in the real world, you don't need to. So how do you figure out if your code is inefficient? Run it and if it doesn't work fast enough for your purpose then try to speed it up. If it does then move onto the next project. how do I go about finding a more efficient solution? Google, a good reference book and experience. Particularly, get some knowledge of the cost of various algorithms and data structures. There are outright inefficient things to do, but many others have costs and benefits: things fast in time but costly in space, and vice versa, and things efficient for some kinds of data but known to be bad for others. Have a quick read of this: https://en.wikipedia.org/wiki/Big_O_notation which talks about a common notation for costs. Skip the formal section with the math and go to the Orders of Common Functions section. https://en.wikipedia.org/wiki/Big_O_notation#Orders_of_common_functions You'll find people talk about big O notation a lot with algorithms and their efficiency. For example, a dict _lookup_ is O(1): constant time per lookup. But that doesn't mean always use a dict, because there's a cost to creating one in the first place. What you use it for matters. But always, always, measure because there has been more time wasted on unnecessary optimisations than on any other feature of programming. I just want to add a little nuance to all of this, because it to me it reads a little like (a) if it works and you get things done in a timely manner it is efficient and (b) if it isn't fast enough you can always make it faster. Alan hasn't actually said that, but one could get that impression. To my mind: Alan's point about "fast enough" is perfectly valid: in the real world, if your problem has been solved then further work on efficiency might cost more to implement than you gain after doing it. His other point about measurement is also very important. It is possible to guess incorrectly about where performance problems lie, particularly with higher level languages because their internals has costs not apparent to the eye (because you can't see the internals). So from an engineering point of view, it is important to measure where a problematic programme spends its time and devote effort to those parts consuming the most time. The standard example is the tight loop: for a in sequence1: for b in sequence2: do thing A do thing B The cost of "do thing A" is more important than the cost of "do thing B" because likely A runs many many times more often than B. So even if B has some known inefficiency you can see, which will take some work to improve, effort spent on A will probably be more useful (if that's feasible). With a complex programme this isn't always obvious; in the example above the 2 pieces of code are side by side. The point about measurement is that profiling tools are useful here: when you _don't_ have an obvious primary target to improve but do need to improve efficiency, a profiling tool can measure where a programme spends its time in aggregate. That can point the way to code more beneficial to inspect. It at least gets you objective information about where your programme spends its time. It is limited by the data you give your programme: toy example input data are not as good as real world data. Finally, some things are as efficient as they get. You _can't_ always make things even more efficient. Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Shifting arrays as though they are a 'word'
On 05Oct2018 16:17, Chip Wachob wrote: I have an array of bytes. Up to 64, which makes for 512 bits. I am reading these bytes in serially, and once I have a collection of them, I want to shift them by 'n' bits. The size of the array and the number of bits are both variable up to the limit of 64/512. Now, I've played around with looping through the bytes and taking the LSByte and shifting it by 'n' bits using >> or << and that works for the first byte. But then I need to take the next byte in the sequence and shift it in the opposite direction by 8-n bits using << or >> (opposite the LSByte direction), respectively. Shifting adjacent byte in opposite directions seems a little odd. Is that really what you need to do? Then I OR the two bytes and save them into the location of the LSByte and then move to the next byte in the sequence and so on. While this works most of the time, I sometimes get strange behavior at the 'fringes' of the bytes. Sometimes I end up with zero, or the shift seems to 'roll over'. I'm thinking that maybe there's a way to treat the array / list and shift allowing the bits to transfer from byte to byte as needed. Maybe by concatenating the bytes into one huge word and then breaking it apart again? Yes, not too hard. Python ints are bigints, so you can do operations on values of arbitrary size. So if you can convert your array of bytes into a single int, you can shift it: Python 3.6.4 (default, Dec 28 2017, 14:20:21) [GCC 5.4.0 20160609] on linux Type "help", "copyright", "credits" or "license" for more information. >>> 100 <<17 13107200 >>> Then convert back into bytes. The easy way is to just accrue the bytes into a value as you read them: n = 0 for b in the_bytes: n = n<<8 + b if you're reading "big endian" data (high ordinal bytes come first). So read them in, accruing the value into "n". Shift. Write them back out by decomposing "n" with successive division or successive shifts. Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Help understanding base64 decoding
On 13Sep2018 08:23, Ryan Smith wrote: [...] I'm still getting familiar with all of the different encodings at play. For example the way I currently understand things is that python supports unicode which ultimately defaults to being encoded in UTF-8. Hence I'm guessing is the reason for converting strings to a bytes object in the first place. Yeah. "str" is text, using Unicode code points. To store this in a file, the text must be transcribed in some encoding. The default encoding in Python is UTF-8, which has some advantages: the bottom 128 values are one to one with ASCII, and it is fairly compact when the source text live in or near that range. Windows often works with UTF-16, which is why your source bytes look the way they do. So the path is: base64 text (which fits in a conservative subset of ASCII) => bytes holding a UTF-16 encoding of your target text => decode to a Python str Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Help with building bytearray arrays
On 10Sep2018 10:23, Chip Wachob wrote: So, without all the fluff associated with wiggling lines, my function now looks like this: def RSI_size_the_loop(): results = [] all_together = [] # not certain if I need this, put it in in an attempt to fix the incompatibility if it existed You don't need this. all_together doesn't need to be mentioned until you initiate it with your bytearray.join. for x in range (0, MAX_LOOP_COUNT, slice_size): results.append(my_transfer(disp, data_out, slice_size) print " results ", x, " = ", results # show how results grows on each iteration all_together = bytearray().join(results) print " all together ", all_together I can observe results increasing in size and the last time through the loop: results 48 = [[bytearray(b'\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')], [bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')], [bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')], [bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')]] Peter has pointed out that you have a list of list-of-bytearray instead of a flat list-of-bytearray. The inference here is that your my_transfer function is returning a single element list-of-bytearray. So, now when I hit the line: all_together = bytearray().join(results) I'm getting the Traceback : [...] Traceback (most recent call last): File "SW8T_5.py", line 101, in # this is my main script loop_size = RSI_size_the_loop(Print) File "/home/temp/Python_Scratch/examples/RSI.py", line 359, in RSI_size_the_loop all_together = bytearray().join(results) TypeError: can only join an iterable of bytes (item 0 has type 'list') So because you have a list-of-list, item[0] is indeed a list, not a bytearray. If you change this: results.append(my_transfer(disp, data_out, slice_size) into: result = my_transfer(disp, data_out, slice_size) print("result =", repr(result)) results.append(result) this should be apparent. So this issue lies with your my_transfer function; the main loop above now looks correct. I've even added in print statements for the types, so I could double check, and I get: results returns all_together returns So both are type 'list' which is referred to here : https://infohost.nmt.edu/tcc/help/pubs/python/web/sequence-types.html as a valid sequence type but apparently there's a detail I'm still missing... Yeah. bytearray().join wants bytes or bytearrays in the list/iterable you hand it. You've got lists, with the bytearrays further in. Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Help with building bytearray arrays
On 09Sep2018 23:00, Chip Wachob wrote: On Sat, Sep 8, 2018 at 9:14 PM, Cameron Simpson wrote: Actually he's getting back bytearray instances from transfer and wants to join them up (his function does a few small transfers to work around an issue with one big transfer). His earlier code is just confused. So he wants: bytearray().join(results) Hacked example: >>> bytearray().join( (bytearray("foo"),bytearray("bah")) ) bytearray(b'foobah') I understand this example and I can replicate it in the interpreter.. But, I'm still missing something here. I presume that I need to instantiate an array of slice_size-sized bytearrays. But no! So, when I'm looping through, I can do: for i in range (0, slice_count): results[i] = spi.transfer(data_out) Python lists are a variable size data structure, so our example goess: results = [] which allocates an empty list. Then: for i in range(slice_count): results.append(spi.transfer(data_out)) suitably adjusted (data_out will be different pieces of the larger data, yes?) which grows the array by one item with each append. Your spi.transfer function allocates a new bytearray for each return value, so you end up with a list of distinct bytearrays. Then I can : all_together = butearray().join(results) Yes. But I can't seem to be able to find the proper syntax to create the initial array. And any attempt at filling the arrays to test some stand-alone code only give me errors. You _can_ allocate a presized list, but there's almost no benefit and it isn't what people normally do. Here's my code (all of it) [...] #results = bytearray( (bytearray(slice_size)*slice_count) ) results = bytearray(slice_size)# why isn't this 16 bytes long? It is 16 bytes long when I do it: >>> bs=bytearray(16) >>> bs bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') res_list = (results)*slice_count This is a single 64 byte bytearray. You may have intended to make a single element tuple with "(results)", but that is just the same as "results" (rundundant brackets). To make a single element tuple you go "(results,)" - see the trailing comma? Example of each: >>> bs*16 bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x 00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') >>> (bs,)*16 (bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'), bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'), bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'), bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'), bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'), bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'), bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'), bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'), bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'), bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'), bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'), bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'), bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'), bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'), bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'), bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')) But you don't need any of that. First, the list "results" can start empty and just get things appended to it and second, you don't need to preallocate any bytearrays because the internal, primary, transfer allocates a new bytearray for each return chunk. Cheers, Cameron Si
Re: [Tutor] Help with building bytearray arrays
horoughly. [...] # Send command and length. self._assert_cs() I would guess that this raises a control signal. Ah, RS-232? So clear-to-send then. This is actually a chip select line that electrically wiggles a pin on a device telling it 'Hey, I'm talking to YOU". Ah, hence the "assert". Ok, thanks. self._ft232h._write(str(bytearray((command, len_low, len_high Ok, it looks like this is Python 2, not Python 3. Let's unpack it. Yes, Adafruit insists that this work has to be done in Python 2.7. I started working on this and tried to use Python 3.x but things were failing all over the place. Unfortunately, at the time I didn't understand that Python 3 wasn't backward compatible with Python 2.x, 1.x, etc.. Lesson learned. Python 3 was the big break to the language to make a swathe of changes which broke backward compatibility, all for the good as far as I can see. Previous to that changes worked hard to remain backward compatible and not break code. The idea with Python 3 was to make several breaking changes which had been bubbling away for years, and hopefully never make that break again in future. Bytes versus strings versus unicode was a big change with Python 2/3, and code working at the hardware levewl like your tends to notice it. So the library is working with bytearrays (because Python 2 and 3 have them and they look like buffers of bytes) but still having to convert these into str to write them to "files". In Python 2 the "str" type is 8 bit characters (or no specified character set, btw) that look like characters (yea, even unto characters really just being strings of length 1) and there's a separate "unicode" type for decent strings which support Unicode text. In Python 3 "str" is Unicode, and there's a bytes types for bytes, which looks like a list if integers with values 0..255. "(command, len_low, len_high)" is a tuple of 3 values. A tuple is like a read only list. We're passing that to the bytearray() constructor, which will accept an iterable of values and make a bytes buffer. And we want to write that to "self._ft232h". Which expects a str, which is why I think this is Python 2. In Python 2 there's no "bytes" type and str is an immutable array of 8-bit character values. So writing bytes uses str. Okay, so in Python 2 (the world I'm left to live within) if I want to handle bytes, they actually have to be strings? This sort of makes sense. Well, yes and no. File I/O .write methods tend to accept str. Which is 8-bit character values, so you can use them for bytes. Thing genuinely using bytes (as small integers, as you do when assemble a flags value etc) can get by with bytearrays, which look like arrays of bytes (because they are). But for historic reasons these interfaces will be writing "str" because that's what they expect to get. When I try to display the contents of my arrays via a print statement, I will get \xnn for my values, but at some point the nn becomes what appears to be ASCII characters. Sometimes I get, what I would call, extended ASCII 'art' when I try to print the arrays. Interesting art, but not very helpful in the information department. Yeah, not so great. Python's trying to be slightly nice here. Values with printable ASCII correspondents get prints as that character and other values get the \xnn treatment. Handy if you're working with text (because many many character sets has the 128 ASCII values as their lower portion, so this is usually not insane), less handy for nontext. Try importing the hexlify function from the binascii module: from binascii import hexlify bs = bytearray( (1,2,3,65,66) ) print(repr(bs)) print(hexlify(bs)) [...] faffing is a new term, but given the context I'm guessing it is equivalent to 'mucking about' or more colorful wording which I won't even attempt to publish here. You are correct: https://en.wikipedia.org/wiki/Glossary_of_British_terms_not_widely_used_in_the_United_States#F Why this faffing about with str and bytearray? Probably for Python 2/3 compatibility, and because you want to deal with bytes (small ints) instead of characters. Ignore it: we're dealing with bytes. More questions in the next installment since the reconstruction methods are discussed there.. Excellent. Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Help with building bytearray arrays
On 08Sep2018 11:40, Alan Gauld wrote: On 08/09/18 03:15, Chip Wachob wrote: Ideally, I'd like to take the slice_size chunks that have been read and concatenate them back togetjer into a long MAX_LOOP_COUNT size array to pass back to the rest of my code. Eg: You need to create a list of read_ary results = [] then after creating each read_ary value append it to results. results.append(read_ary) Then, at the very end, return the summation of all the lists in results. return sum(results,[]) Actually he's getting back bytearray instances from transfer and wants to join them up (his function does a few small transfers to work around an issue with one big transfer). His earlier code is just confused. So he wants: bytearray().join(results) Hacked example: >>> bytearray().join( (bytearray("foo"),bytearray("bah")) ) bytearray(b'foobah') And he's working with bytearrays because the target library is Python 2, where there's no bytes type. Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Help with building bytearray arrays
On 08Sep2018 20:01, Cameron Simpson wrote: So, if I'm understanding the transfer() function correctly, the function takes and returns a bytearray type. It would be good to see the specification for the transfer function. They we can adhere to its requirements. Can you supply a URL? I see you supplied the whole transfer function in your first message :-( I'll recite it here and walk through its contents to explain: def transfer(self, data): Ok, this is a method, a particular type of function associated with a class instance. (All objects are class instances, and the class is their type.) So to call this you would normally have a control object of some kind. [...] Ah, it looks like you should have an SpiDev instance, inferring from this code: https://github.com/adafruit/Adafruit_Python_GPIO/blob/master/Adafruit_GPIO/SPI.py So suppose you've got such an object and a variable referring to it, let's say it is named "spi". You'd normally call the transfer function like this: spi.transfer(some_data) instead of calling transfer() "bare", as it were. When you call a Python method, the instance itself is implicitly passed as the parameter "self" (well, the first parameter - in Python we always call this "self" like C++ uses "this"). """Full-duplex SPI read and write. The specified array of bytes will be clocked out the MOSI line, while simultaneously bytes will be read from the MISO line. Read bytes will be returned as a bytearray object. """ This is a docstring. It is like a comment but it gets attached to the function and can be inspected. Not your problem. # Build command to read and write SPI data. command = 0x30 | (self.lsbfirst << 3) | (self.read_clock_ve << 2) | self.write_clock_ve This constructs a value just as you would in C. logger.debug('SPI transfer with command {0:2X}.'.format(command)) Write a debugging message. # Compute length low and high bytes. # NOTE: Must actually send length minus one because the MPSSE engine # considers 0 a length of 1 and a length of 65536 length = len(data) len_low = (length-1) & 0xFF len_high = ((length-1) >> 8) & 0xFF All just like C. # Send command and length. self._assert_cs() I would guess that this raises a control signal. Ah, RS-232? So clear-to-send then. self._ft232h._write(str(bytearray((command, len_low, len_high Ok, it looks like this is Python 2, not Python 3. Let's unpack it. "(command, len_low, len_high)" is a tuple of 3 values. A tuple is like a read only list. We're passing that to the bytearray() constructor, which will accept an iterable of values and make a bytes buffer. And we want to write that to "self._ft232h". Which expects a str, which is why I think this is Python 2. In Python 2 there's no "bytes" type and str is an immutable array of 8-bit character values. So writing bytes uses str. So this tabkes a tuple of values, to be bytes, makes those into a bytearray and makes that into a str, and writes that str to the serial line. self._ft232h._write(str(bytearray(data))) We write that data itself. self._ft232h._write('\x87') self._deassert_cs() And here we lower the control signal. # Read response bytes. return bytearray(self._ft232h._poll_read(length)) This calls the _poll_read method, presumably requesting "length" bytes, the same length as the supplied data. I presume we get a str back: we make a new bytearray with those bytes in it and return it. So you do get a new bytearray back from each call, so we can accumulate them into a list and then join them together later to make a single bytearray. Why this faffing about with str and bytearray? Probably for Python 2/3 compatibility, and because you want to deal with bytes (small ints) instead of characters. Ignore it: we're dealing with bytes. Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Help with building bytearray arrays
Please try to adopt the inline reply style; we prefer it here. It lets us reply point by point and makes messages read like conversations. Anyway... On 07Sep2018 23:57, Chip Wachob wrote: Point taken on 'bytes'.. thanks. the scratch_ary = bytearray() was my attempt at 'setting' the type of the variable. I had hoped that it would help resolve the error messages telling me that the types didn't go together. Coming from a 'C' background, I find the lack of typing in Python to be confusing. I'm used to working with bytes / words signed and unsigned for a reason. Ok. Variables aren't typed. Variables are references to objects, which _are_ typed. So pointing a variable at a bytearray doesn't set its type in any persistent sense. Thus: x = 1 x = "a string" x = bytearray() All just point "x" at different objects. If you'd like a C metaphor, variables are _like_ (void*) pointers: they can reference any kind of object. Aside: they're not pointers, avoid the term - people will complain. As far as the language spec goes they're references. Which may in a particular implementation be _implemented internally_ using pointers. So, if I'm understanding the transfer() function correctly, the function takes and returns a bytearray type. It would be good to see the specification for the transfer function. They we can adhere to its requirements. Can you supply a URL? You mentioned about constructing a bytearray if I need one. Can you expand on how I approach that? Well, you were getting several bytes or bytearray objects back from transfer and wanted to join them together. The efficient way is to accumulate them in a list and then join them all together later using the bytearry (or bytes) .join method: https://docs.python.org/3/library/stdtypes.html#bytearray.join So: data_list = [] for # send some data, get some data back data = transfer(...) # add that buffer to the data_list data_list.append(data) # make a single bytes object being the concatenation of all the smaller data # chunks all_data = bytes.join(data_list) It looks to me like your transfer() function is handed a bytes or bytearray and returns one. Normally that would be a separate bytes or bytearray. Aside: bytes and bytearray objects are generally the way Python 3 deals with chunks of bytes. A "bytes" is readonly and a bytearray may have its contents modified. From a C background, they're like an array of unsigned chars. I'm going to try the experiment you mentioned in hopes of it giving me a better understanding of the 'types' and what happens with the variables. Sounds good. Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Help with building bytearray arrays
On 07Sep2018 15:45, Chip Wachob wrote: Basically I'm trying to write a block of unsigned bytes to the device and read back an equal sized block of unsigned bytes. There's a function that is provided called transfer(data_to_send, num_of_bytes) that handles the heavy lifting. Unfortunately there seems to be a bug in the part and if I attempt to send the entire block of bytes (64), the device will lock up. I've been able to determine that if I send 16 bytes at a time, I'm okay. So, I take my bytearray(64) and step through it 16 bytes at a time like this: my function's main pieces are: def transfer_byte_array(): MAX_LOOP_COUNT = 64 slice_size = 16 read_ary = bytearray(MAX_LOOP_COUNT) scratch_ary = bytearray() for step in range (0, MAX_LOOP_COUNT, slice_size): scratch_ary = transfer(data_to_send, slice_size) for bytes in range (0, slice_size): read_ary = scratch_ary[bytes] return(read_ary) Ideally, I'd like to take the slice_size chunks that have been read and concatenate them back togetjer into a long MAX_LOOP_COUNT size array to pass back to the rest of my code. Eg: read_ary = ary_slice[0] + ary_slice[1] + ary_slice[2] + ary_slice[3] Minor remark: don't use the name "bytes" for a variable, it is a builtin type name and you're shadowing it. It looks to me like "transfer" hands you back a buffer with the read data, so this: scratch_ary = bytearray() don't do anything (it gets discarded). If you're getting back a bytes or bytearray object from transfer, just gather them all up in an list: returned_buffers = [] for .. response = transfer(data_to_send, slice_size) returned_buffers.append(response) ... read_ary = b''.join(returned_buffers) Note that that makes a new bytes object for read_ary to refer to. You don't need the earlier initialisation of read_ary. Also note that the bytes object is read only; if that is a problem you'll need to construct a bytearray instead. [...] The problem that I repeatedly run into is with the line: read_ary = scratch_ary[bytes] (or variants thereof) The traceback is this: Traceback (most recent call last): File "SW8T_5.py", line 101, in loop_size = RSI_size_the_loop(Print) File "/home/temp/Python_Scratch/examples/RSI.py", line 350, in RSI_size_the_loop read_ary.append(scratch_ary[singles]) TypeError: an integer or string of size 1 is required Yeah I thought that looked weird to me too. or, one of the other common ones that I've seen is TypeError: can't concat bytearray to list This one is confusing because both of the operands are bytearry types.. or at least I thought they should be... No, one will be a list :-) putting a bunch of: print(repr(foo)) replacing "foo" with relevant variables will be illuminating to you; you can see immediately where this are not what you expected. I'm obviously missing something fundamental here. Problem is I can't seem to find any examples of people asking this question before on the inter-webs.. You have the opposite of my problem. I can often find people asking the same question, but less often an answer. Or a decent answer, anyway. Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Writing for loop output to csv
On 06Sep2018 12:32, Brandon Creech wrote: Hi, I am working to forecast the temperatures for the next 5 days using an API and a for loop. I would like write the output of this loop to a csv in this format:: Columns: City, min1, max1, min2, max2,min3,max3,min4,max4,min5,max5 data: Athens,Greece 25.4,26.7etc. Nantou,Taiwan 16.18, ..etc the data prints out on top of each other like this: Nantou, Taiwan 29.49 20.79 Nantou, Taiwan 30. 49 21.56 Normally there would be more commas in CSV output, eg: Nantou, Taiwan,29.49,20.79 and because "Nantou, Taiwan" is a single string, it would typically look like this: "Nantou, Taiwan",29.49,20.79 to make that clear, otherwise the embedded comma would make it two CSV columns. Code I have: from forecastiopy import * import csv I see you're importing the csv module, but not using it. [...] [...snip...] for city, coords in cities.items(): weather = ForecastIO.ForecastIO( api_key, latitude=coords[0], longitude=coords[1] ) daily = FIODaily.FIODaily(weather) for day in range(2,7): print(str(city) + " " + str(daily.get_day(day)['temperatureMax']) + " " + str(daily.get_day(day)['temperatureMin'])) First a small suggestion. Change this: print(str(city) + " " + str(daily.get_day(day)['temperatureMax']) + " " + str(daily.get_day(day)['temperatureMin'])) like this: day_data = daily.get_day(day) print(str(city) + " " + str(day_data['temperatureMax']) + " " + str(day_data['temperatureMin'])) It fetches the daily data just once and makes your subsequent code easily to read and debug. Second, your actual problem. Your loop is basicly sound, but you're using a print call for the output. The csv module provides a writer object which does all the heavy lifting for you: turns strings into quotes strings, puts in commas, etc. Try this change: csvw = csv.writer(sys.stdout) for city, coords in cities.items(): weather = ForecastIO.ForecastIO( api_key, latitude=coords[0], longitude=coords[1] ) daily = FIODaily.FIODaily(weather) for day in range(2,7): day_data = daily.get_day(day) csvw.writerow([city, day_data['temperatureMax'], day_data['temperatureMin']]) You'll also need to "import sys" up the top to use the name "sys.stdout". See how now you're just passing a list of the values to the csv writer? Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] localhosting
Note: replies inline below, and irrelevant verbiage trimmed. We prefer this format on this list: it makes it easy to respond point by point and makes the reply read like a conversation. Please consider adopting this style here. Anyway, to your message: On 06Sep2018 12:09, Roger Lea Scherer wrote: Thank you all for your help. I am still chugging away at this problem. I've switched to Windows PowerShell Version 5.1 since I can select, copy, and paste more easily in PowerShell. (I can't figure out how to do that in Anaconda and I get the same errors in PowerShell.) I removed the "3" in "python3" and it works; along with moving the "www" folder to where python resides. Thanks for the help. Now switch back to python3 and see if it still works, even temporarily. You want to isolate what was the fix and what was irrelevant. So it appears the local host is running correctly, but when I run this code: print("Hello World") Chrome does not render and I get an error message in PowerShell: 127.0.0.1 - - [06/Sep/2018 11:22:46] "GET /cgi-bin/hello.py HTTP/1.1" 200 - 127.0.0.1 - - [06/Sep/2018 11:22:46] command: C:\Users\Roger\AppData\Local\Programs\Python\Python37-32\python.exe -u C:\Users\Roger\documents\roger\python\www\cgi-bin\hello.py "" 127.0.0.1 - - [06/Sep/2018 11:22:46] b' File "C:\\Users\\Roger\\documents\\roger\\python\\www\\cgi-bin\\hello.py", line 1\r\nprint ""\r\n ^\r\nSyntaxError: Missing parentheses in call to \'print\'. Did you mean print("")?\r\n' 127.0.0.1 - - [06/Sep/2018 11:22:46] CGI script exit status 0x1 I'm guessing you "Hello World" print was after the start of the tag. Look at the rrror message you've recited above: it is talking about line 1 of your hello.py file, which has this: print "" That is an old-style print _statement_, which will not work in Python 3. So your other print isn't the source of this error message: likely it is never reached. Edit your python files to start with this import: from __future__ import print_function That will cause python 2 to expect print to be a function (needing brackets) and not a statement, meaning the same syntax will be required for both python 2 and 3, providing you with consistent behaviour. Then change the print statement into a print function call: print("") BUT when I run this code: def fib(n): if n < 2: return n return fib(n-1) + fib(n-2) print(fib(15)) Note: python 3 print function. Chrome does not render but I DON'T get an error message, I get this: 127.0.0.1 - - [06/Sep/2018 11:33:30] "GET /cgi-bin/recursive%20fibonacci.py HTTP/1.1" 200 - 127.0.0.1 - - [06/Sep/2018 11:33:30] command: C:\Users\Roger\AppData\Local\Programs\Python\Python37-32\python.exe -u "C:\Users\Roger\documents\roger\python\www\cgi-bin\recursive fibonacci.py" "" 127.0.0.1 - - [06/Sep/2018 11:33:30] CGI script exited OK There should be more than a bare number in the output. CGI scripts require one to provide HTTP response headers before the body text: that way they can return other stuff than HTML (eg an image or CSV data etc). Try putting these print calls at the start of that script: print('Content-Type: text/html') print() which mark the rest of the script output as HTML and then provide a blank line to indicate the end of the headers. The objective is that your script produces this output: Content-Type: text/html 325 That's a made up number, I haven't bothered to compute fib(15), sorry. So I'm confused about 2 things: 1. Why does the one file cause an error in PowerShell (and Anaconda actually) when it seems to be the same as the other file which appears to run with no error, but just not render? and, Because you're running the file with Python 2 by hand and Python 3 from the web server (see the "Python\Python37-32\python.exe" in the log?) Apply the suggested __future__ import and you'll get consistent behaviour. 2. What am I missing: why won't it render since the instructions I have at the very beginning of this email say, basically, this is all I have to do to get it to render? I know this second question is maybe a little bit outside this forum, but I am struggling to make sense out of what little I know and, truly, this forum seems the nicest and most helpful I've encountered. The output of a CGI script should be a valid HTTP response: you need some HTTP headers describing the output format and _then_ the core programme output. The minimal header is a Content-Type: header to denote the program result format. See above for how to stick one at the top of any of your CGI scripts. Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] REG : Pexpect timeout issue
On 02Sep2018 14:29, Steven D'Aprano wrote: On Sun, Sep 02, 2018 at 10:01:02AM +1000, Cameron Simpson wrote: On 02Sep2018 00:31, Steven D'Aprano wrote: >On Sat, Sep 01, 2018 at 11:41:42AM +, krishna chaitanya via Tutor >wrote: >>Below is my code, i am frequently hitting timeout issue to login to linux >>or router. > >Timeout issues are a network problem. Perhaps your network is too busy, >or the cable is faulty, or your router is being hammered by attackers >and can't respond. No, timeout issues are "the target input didn't arrive in this timeframe". All his commands are _local_. Krishna wrote: "i am frequently hitting timeout issue to login to linux or router." Given that Krishna says he's trying to login to a router, what tells you that it is local? His script, which goes: import pexpect from pexpect import * child = spawn('su x',timeout = 50) child.expect('Password:',timeout = 50) child.sendline('XXX') #child.sendline('ls -l')# chasis = child.before.decode('utf-8') child.expect('krishna@krishna-desktop:~/python_excercises$',timeout = 50) child.sendline('ls -l') chasis = child.before.decode('utf-8') print(chasis) Error : raise TIMEOUT(msg)pexpect.exceptions.TIMEOUT: Timeout exceeded. All his commands are local, with no remote login. He's probably just slightly misusing the term "timeout issue to login to linux" when tallking about "su". The expect stuff matches command outputs against an expression. Any command which issues a prompt and pauses indefinitely, and whose prompt isn't matched by the expression, will inherently stall the output and cause a timeout if the expect() call has a timeout setting. It could easily be that the su is working and that his pattern for his shell prompt is incorrect ("python_excercises" looks misspelled to me). Same situation and same symptom. Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] REG : Pexpect timeout issue
On 02Sep2018 00:31, Steven D'Aprano wrote: On Sat, Sep 01, 2018 at 11:41:42AM +, krishna chaitanya via Tutor wrote: Below is my code, i am frequently hitting timeout issue to login to linux or router. Timeout issues are a network problem. Perhaps your network is too busy, or the cable is faulty, or your router is being hammered by attackers and can't respond. No, timeout issues are "the target input didn't arrive in this timeframe". All his commands are _local_. Krishna: if you're blocking waiting for a pattern (eg "Password:") and it times out, even for big timeouts, then maybe the pattern is wrong. A command like "su" will prompt for a password and then wait indefinitely. If your prompt pattern is incorrect, you will wait indefinitely waiting for the pattern to show up, because it never will. Run an interactive "su" and see if it matches your pattern. And so on. Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] REG : Pexpect timeout issue
On 01Sep2018 20:33, Alan Gauld wrote: On 01/09/18 12:41, krishna chaitanya via Tutor wrote: child = spawn('su x',timeout = 50) What is the timeout interval? If its in milliseconds then 50 is much too short, try 5000. If its in seconds then you have a problem... How long does it take to connect manually using ssh? He's not using ssh - it is all local. Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] OT: How to automate the setting of file permissions for all files in a collection of programs?
On 30Aug2018 09:08, Alan Gauld wrote: On 30/08/18 04:44, boB Stepp wrote: [...] 4) FTP this back to Solaris for code repair, testing, etc. [...] This process has changed all of the Unix file permissions That is inherent in using version control systems. Not really. I suspect FTP may not be preserving permissions across the transfer (no proof though). But git doesn't preserve file permissions as pat of the state. Personally I use mercurial which does include the permissions in the state. But there's also the issue of Windows permissions versus UNIX permissions. [...] If there is a way in this CuteFTP software to maintain file permissions in this back-and-forth transferring between a Windows and CuteFTP's web site says it can use SFTP (ssh's ftp-ish protocol, which can preserve permissions). https://www.globalscape.com/cuteftp I don't know CuteFTP but rsync definitely can. One of its zillions of options. The option is -p (permissions). software package in the Solaris environment, I am not allowed to do so. I am not allowed to use Python pip either. Strange rules ... Not that odd in a corporate environment, I was still using Python 1.3 in 2002 for similar reasons on one of our work servers. But there is a 50/5-0 chance the latest Solaris upgrade will have included rsync. Even if it hasn't, if you can mount a Solaris drive on your PC then you can still use rsync from your PC (via cygwin). Is that an option? If he can mount a Solaris drive (NFS or SMB) he can just copy the files :-) Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] OT: How to automate the setting of file permissions for all files in a collection of programs?
On 29Aug2018 22:44, boB Stepp wrote: So as to not lose the benefits of a version control system, I have installed Git on my windows PC. My current workflow now has gotten more complex, and I'm sure can be improved by those thinking more clearly than I (And surely more knowledgeable!), and is as follows: 1) Using CuteFTP copy all of my original working code (Now with problems due to the planning software upgrade.) to my windows PC. 2) Put this code under Git version control. 3) Create a development branch. 4) FTP this back to Solaris for code repair, testing, etc. BUT! This process has changed all of the Unix file permissions on what are (For me.) many files, some planning system proprietary scripting files, some Perl files, some shell script files and some Python files. So before I can do anything further I must go through all of these files and change their permissions to the values I need them to be. This is quite tedious and error prone. So I wish to either fix the process, or, failing that, automate the process of correcting the file permissions. If there is a way in this CuteFTP software to maintain file permissions in this back-and-forth transferring between a Windows and Solaris environment, I have yet to find it in the software's help (Though I have not yet had much time to invest in this search, so I may not have found it yet.). It occurs to me that in theory it should be possible to automate this either with a shell script or a Python program. Is there a standard way of handling this sort of thing? Bear in mind that if a typical solution would require the installation of a software package in the Solaris environment, I am not allowed to do so. I am not allowed to use Python pip either. Strange rules ... Does rsync exist on your Solaris system? Can you get rsync and ssh on your Windows system? The "standard" UNIX solution to reproduce a directory somewhere is rsync these days, which will work over ssh (by default) if the target is remote. IIRC, git doesn't track file permissions, so you can't just "export" from your WIndows git (or some mirror elsewhere). So: do you have rsync? Do you have ssh from your PC to the Solaris box? Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] need help generating table of contents
On 24Aug2018 17:55, Peter Otten <__pete...@web.de> wrote: Albert-Jan Roskam wrote: I have Ghostscript files with a table of contents (toc) and I would like to use this info to generate a human-readable toc. The problem is: I can't get the (nested) hierarchy right. import re toc = """\ [ /PageMode /UseOutlines /Page 1 /View [/XYZ null null 0] /DOCVIEW pdfmark [ /Title (Title page) /Page 1 /View [/XYZ null null 0] /OUT pdfmark [ /Title (Document information) /Page 2 /View [/XYZ null null 0] /OUT pdfmark [...] What is the best approach to do this? The best approach is probably to use some tool/library that understands postscript. Just to this: I disagree. IIRC, there's no such thing as '/Title' etc in PostScript - these will all be PostScript functions defined by whatever made the document. So a generic tool won't have any way to extract semantics like titles from a document. The OP presumably has the specific output of a particular tool with this nice well structured postscript, so he needs to write his/her own special parser. Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Query: lists
On 14Aug2018 18:11, Deepti K wrote: when I pass ['bbb', 'ccc', 'axx', 'xzz', 'xaa'] as words to the below function, it picks up only 'xzz' and not 'xaa' def front_x(words): # +++your code here+++ a = [] b = [] for z in words: if z.startswith('x'): words.remove(z) b.append(z) print 'z is', z print 'original', sorted(words) print 'new', sorted(b) print sorted(b) + sorted(words) That is because you are making a common mistake which applies to almost any data structure, but is particularly easy with lists and loops: you are modifying the list _while_ iterating over it. After you go: words.remove(z) all the elements _after_ z (i.e. those after 'xzz' i.e. ['xaa']) are moved down the list. In your particular case, that means that 'xaa' is now at index 3, and the next iteration of the loop would have picked up position 4. Therefore the loop doesn't get to see the value 'xaa'. A "for" loop and almost anything that "iterates" over a data structure does not work by taking a copy of that structure ahead of time, and looping over the values. This is normal, because a data structure may be of any size - you do not want to "make a copy of all the values" by default - that can be arbitrarily expensive. Instead, a for loop obtains an "iterator" of what you ask it to loop over. The iterator for a list effectively has a reference to the list (in order to obtain the values) and a notion of where in the list it is up to (i.e. a list index, a counter starting at 0 for the first element and incrementing until it exceeds the length of the list). So when you run "for z in words", the iterator is up to index 3 when you reach "xzz". So z[3] == "xzz". After you remove "xzz", z[3] == "xaa" and in this case there is no longer a z[4] at all because the list is shortened. So the next loop iteration never inspects that value. Even if the list had more value, the loop would still skip the "xaa" value. You should perhaps ask yourself: why am I removing values from "words"? If you're just trying to obtain the values starting with "x" you do not need to modify words because you're already collecting the values you want in "b". If you're trying to partition words into values starting with "x" and values not starting with "x", you're better off making a separate collection for the "not starting with x" values. And that has me wondering what the list "b" in your code was for originally. As a matter of principle, functions that "compute a value" (in your case, a list of the values starting with "x") should try not to modify what they are given as parameters. When you pass values to Python functions, you are passing a reference, not a new copy. If a function modifies that reference's _content_, as you do when you go "words.move(z)", you're modifying the original. Try running this code: my_words = ['bbb', 'ccc', 'axx', 'xzz', 'xaa'] print 'words before =", my_words front_x(my_words) print 'words after =", my_words You will find that "my_words" has been modified. This is called a "side effect", where calling a function affects something outside it. It is usually undesirable. Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Do something on list elements
On 27Jul2018 23:06, Alan Gauld wrote: On 27/07/18 13:56, Valerio Pachera wrote: l = ['unoX', 'dueX'] c = 0 for n in l: l[c] = l[c].replace('X','') c = c + 1 print (l) it works but I wonder if there's a better way to achieve the same. Yes, a much better way. for index, s in l: l[index] = s.replace('X','') print(l) I think you meant: for index, s in enumerate(l): But better still is a list comprehension: l = [s.replace('X','') for s in l) print(l) In Python you very rarely need to resort to using indexes to process the members of a collection. And even more rarely do you need to manually increment the index. I use indices when I need to modify the elements of a list in place. The list comprehension makes a shiny new list. That is usually fine, but not always what is required. I also have (rare) occasions where an item wants know its own index. In that case one wants the index floating around so it can be attached to the item. The other place I use enumerate in a big way is to track line numbers in files, as context for error messages (either now or later). For example: with open(filename) as f: for lineno, line in enumerate(f, 1): if badness: print("%s:%d: badness happened" % (filename, lineno), file=sys.stderr) continue ... process good lines ... Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] changing font
On 13Jul2018 17:42, Talia Koch wrote: Hi, I am trying to figure out a code that would change my text output to 'Arial' font. How would I do this? Thanks. You will need to provide far more context for this question. What are you using to display your text? HTML (eg a web browser)? Then the tag might help you. Some other document format such as roff or LaTeX? A terminal? If this is possible it will be entirely terminal dependent. A GUI of some kind, such as Tk or Qt? You will need to consult its documentation for its text widgets. Cheers, Cameron Simpson (formerly c...@zip.com.au) in rec.moto, jsh wrote: Dan Nitschke wrote: > Ged Martin wrote: > > On Sat, 17 May 1997 16:53:33 +, Dan Nitschke scribbled: > > >(And you stay *out* of my dreams, you deviant little > > >weirdo.) > > Yeah, yeah, that's what you're saying in _public_ > Feh. You know nothing of my dreams. I dream entirely in text (New Century > Schoolbook bold oblique 14 point), and never in color. I once dreamed I > was walking down a flowchart of my own code, and a waterfall of semicolons > was chasing me. (I hid behind a global variable until they went by.) You write code in a proportional serif? No wonder you got extra semicolons falling all over the place. No, I *dream* about writing code in a proportional serif font. It's much more exciting than my real life. /* dan: THE Anti-Ged -- Ignorant Yank (tm) #1, none-%er #7 */ Dan Nitschke pedan...@best.com nitsc...@redbrick.com ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Virtual environment question
On 11Mar2018 15:52, jim <jf_byr...@comcast.net> wrote: It was my understanding that using a virtual environment kept everything isolated in that environment. So I was surprised when I got the following error message. (env) jfb@jims-mint18 ~ $ File "/home/jfb/EVs/env/lib/python3.5/site-packages/selenium/webdriver/remote/remote_connection.py", line 528, in _request resp = opener.open(request, timeout=self._timeout) File "/usr/lib/python3.5/urllib/request.py", line 466, in open response = self._open(req, data) I snipped most of the error msg because for the purpose of this question I am not interested in them. I tried something that I did not think would work and it did not. I am wondering why the path for the first line and every line above it is /home/jfb/EVs/env and the second line and everything after is is /usr/lib/. I didn't think anything from my system python would be involved if I started from a virtual environment. It is possible to make a virtualenv which references the osurce python's library. These days the default is isolation, but older virtualenvs used to hook to the original python by default. This is controlled by virtualenv's --system-site-packages and --no-site-packages. Maybe you should build the env again using --no-site-packages explicitly and see if the behaviour changes. If you're not using the "virtualenv" command to make the environment, please tell use exactly how it was made (there are other tools for the same purpose). In fact, tell us regardless. It aids debugging. Cheers, Cameron Simpson <c...@cskk.id.au> (formerly c...@zip.com.au) ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] help with code
r a valid username and password..." Here's you are admonishing the user for entering an empty username or password. However you don't then do anything about it; instead your code falls through and starts setting up the user. You probably want a loop shapes more like this (totally untested): while True: username = input("Please input your desired username ") if len(username) == 0: print("Empty username rejected.") continue password = input("Please input your desired password ") if len(password) == 0: print("Empty password rejected.") continue break which will keep prompting until both the username and password are acceptable. _Then_ it breaks out of the loop and proceeds. users = c.get_all_users() userList = users['list_users_response']['list_users_result']['users'] if username in userList: print "username already exist" else: This "else" needs to be indented the same as the "if". # I just want to create if fields are not empty and if username dont exist c.create_user(username) file = open("credential.txt","a") file.write(username) file.write(" ") file.write(password) file.close() login() It seems odd to call the "login" function after creating the user. if choice==3: Again, this "if" should be indented for the main loop like the other "choice" "if" statements. def login(): check = open("credential.txt","r") Here you're opening the credential.txt file, but not doing anything with it. username = input("Please enter your username") password = input("Please enter your password") Again, these lines should call raw_input(), not input(). def thank_you(): print("Thank you for signing up at our website!.") You define this function but never call it. elif choice == "q": exit() The call to exit() needs to be indented in order to be inside the "elif". Also, exit() is not a builtin function. I need to import it. Normally you would put this import at the very top of your program, such as: from sys import exit I also notice here that you're expecting the user to be able to enter a "q" instead of a "4". So this doesn't match your menu. But if you do want the user to enter a "q" the you need to use raw_input() instead of input() in your menu prompt, and your other "choice" values need to be strings, such as "1", "2" and so forth. Cheers, Cameron Simpson <c...@cskk.id.au> ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Regex not working as desired
On 26Feb2018 11:01, Roger Lea Scherer <rls...@gmail.com> wrote: The first step is to input data and then I want to check to make sure there are only digits and no other type of characters. I thought regex would be great for this. Many people do :-) They are a reasonable tool for an assortment of text matching tasks, but as you're discovering they can be easy to get wrong and hard to debug when you do. That's not to say you shouldn't use them, but many people use them for far too much. The program works great, but no matter what I enter, the regex part does the same thing. By same thing I mean this: [...] Please enter an integer less than 10,000 greater than 0: 4jkk33 No match Please enter an integer less than 10,000 greater than 0: 4k33 No match Please enter an integer less than 10,000 greater than 0: 4jjk4 No match Please enter an integer less than 10,000 greater than 0: 4334 No match So, "no match regardless of the input". So I don't know what I'm doing wrong. The cipher will still draw, but I want to return an "error message" in this case print("No match"), but it does it every time, even when there are only digits; that's not what I want. Please help. Below is my code: Thank you for the code! Many people forget to include it. I'm going to trim for readability... [...] digits = input("Please enter an integer less than 10,000 greater than 0: ") """ ensure input is no other characters than digits sudocode: if the input has anything other than digits return digits """ #def digit_check(digits): # I thought making it a function might h p = re.compile(r'[^\D]') This seems a slightly obtuse way to match a digit. You're matching "not a nondigit". You could just use \d to match a digit, which is more readable. This regular expression also matches a _single_ digit. m = p.match(digits) Note that match() matches at the beginning of the string. I notice that all your test strings start with a digit. That is why the regular expression always matches. if m: print("No match") This seems upside down, since your expression matches a digit. Ah, I see what you've done. The "^" marker has 2 purposes in regular expressions. At the start of a regular expression it requires the expression to match at the start of the string. At the start of a character range inside [] it means to invert the range. So: \dA digit. \DA nondigit. ^\D A nondigit at the start of the string [^\D] "not a nondigit" ==> a digit The other thing that you may have missed is that the \d, \D etc shortcuts for various common characters do not need to be inside [] markers. So I suspect you wanted to at least start with "a nondigit at the start of the string". That would be: ^\D with no [] characters. Now your wider problem seems to be to make sure your string consists entirely of digits. Since your logic looks like a match for invalid input, your regexp might look like this: \D and you could use .search instead of .match to find the nondigit anywhere in the string instead of just at the start. Usually, however, it is better to write validation code which matches exactly what you actually want instead of trying to think of all the things that might be invalid. You want an "all digits" string, so you might write this: ^\d*$ which matches a string containing only digits from the beginning to the end. That's: ^ start of string \da digit * zero or more of the digit $ end of string Of course you really want at least one or more, so you would use "+" instead of "*". So you code might look like: valid_regexp = re.compile(r'^\d+$') m = valid_regexp.match(digits) if m: # input is valid else: # input is invalid Finally, you could also consider not using a regexp for this particular task. Python's "int" class can be called with a string, and will raise an exception if that string is not a valid integer. This also has the advantage that you get an int back, which is easy to test for your other constraints (less than 1, greater than 0). Now, because int(0 raises an exception for bad input you need to phrase the test differently: try: value = int(digits) except ValueError: # invalid input, do something here else: if value >= 1 or value <= 0: # value out of range, do something here else: # valid input, use it Cheers, Cameron Simpson <c...@cskk.id.au> (formerly c...@zip.com.au) ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] unable to locate python on mac
On 31Jan2018 19:44, Alan Gauld <alan.ga...@yahoo.co.uk> wrote: On 31/01/18 17:42, Megan Zirger wrote: I am completely new to python and trying to learn how to set up and get going. I'm not a Mac expert but v2.7 is usually installed on a Mac by default (although its just a basic version its fine for learning) Yes, the system Python is 2.7: [~]fleet*> /usr/bin/python Python 2.7.10 (default, Oct 23 2015, 19:19:21) [GCC 4.2.1 Compatible Apple LLVM 7.0.0 (clang-700.0.59.5)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> That's from El Capitan, a few OS releases behind. [...] able to work with sublime text. I think that's a text editor right? Or is it more of an IDE? Can you run the code inside sublime? Is that what you are trying to set up? Subblime Text is just an editor. It's got lots of nice stuff but it isn't an IDE. If that's the case you probably need to type in the path to the pyhon3 interpreter in Sublime's settings somewhere. Thats the same path you got from 'which python3' above. My Sublime text seems to be associated as the default app for opening .py files already. A little surprised here, I use vim mostly and thought I'd bound MacVim (the GUI form of vim on a Mac) for .py files. If you need more details you will need to ask more specific questions. Bear in mind that although some folks here use Macs most of us don't. I live on a Mac, I'll watch this thread. But yes, Alan's remark that Python isn't an "app" in the sense of a GUI tool is probably very pertinent. Megan, you may be expecting Python to be a GUI app. It isn't, though it can be used to write them. You also need some sort of arrangement to edit python code and run it. Such arrangements tend to come in 2 basic forms: an IDE (integrated development environment) which is usually a GUI app with both editing and running capabilities, or separate editor and run arrangements. Sublime Text, which I gather you use, is, I thought, just an editor. You also need somewhere to run Python from. Those of use not using IDEs generally run the programmes from a terminal. Personally I use iterm3 for my terminals, lots of nice features. Cheers, Cameron Simpson <c...@cskk.id.au> (formerly c...@zip.com.au) ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Do _all_ Python builtin methods/functions return "None" IF ...
On 27Jan2018 09:18, Alan Gauld <alan.ga...@yahoo.co.uk> wrote: On 27/01/18 02:56, boB Stepp wrote: So my actual question is: For these types of methods/functions, is Python Both versions 2 and 3) consistent throughout and *always* returns None? Mostly, but only for mutable objects. So the string methods return a new string with the modifications because the original string is immutable and cannot be changed. So superficially, list handling methods return none on modification but string methods return the modified string. You need to bear in mind whether the object is mutable or not to understand the expected result. For a big more context, the general rule is: if the method fetches a value from the object eg its length, of course it returns something other than None. But if a method _modifies_ the object (append an element to a list, close a file), just affecting its internal state, then the method will usually return None. These modification methods _could_ return a value, but the general practice is not to. Cheers, Cameron Simpson <c...@cskk.id.au> (formerly c...@zip.com.au) ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] delete strings from specificed words
On 11Jan2018 12:16, YU Bo <tsu.y...@gmail.com> wrote: Hi, Hi, On Thu, Jan 11, 2018 at 11:40:35AM +1100, Cameron Simpson wrote: Do you have the text as above - a single string - or coming from a file? I'll presume a single string. En.., the text is multi-string from str(something) within python. That's a single string in my thinking. I would treat the text as lines, particularly since the diff markers etc are all line oriented. So you might write something like this: interesting = [] for line in the_text.splitlines(): if line.startswith('diff --git '): break interesting.append(line) Now the "interesting" list has the lines you want. Yes, i test your method and it will come to my intend, but maybe cast a few of other steps. I think that the method will offer a similar ways to solve others issues. I personally like peter's method: text.partition("diff --git")[0].strip() Yes, Peter's partition method is very short and direct. Personally I would include a leading newline in the string, thus: text.partition("\ndiff --git ") to make it more precise. Consider a patch which discusses your script; its comment area might well mention the string "diff --git", as this email does. What you end up with may depend on what further things you do with the text. Cheers, Cameron Simpson <c...@cskk.id.au> ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor