Re: [Tutor] Chunking list/array data?

2019-08-22 Thread Cameron Simpson

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?

2019-08-22 Thread Cameron Simpson

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?

2019-08-13 Thread Cameron Simpson

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?

2019-08-13 Thread Cameron Simpson
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

2019-08-13 Thread Cameron Simpson

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

2019-08-07 Thread Cameron Simpson

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?

2019-08-02 Thread Cameron Simpson

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

2019-08-02 Thread Cameron Simpson

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

2019-08-01 Thread Cameron Simpson

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?

2019-07-16 Thread Cameron Simpson

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

2019-07-12 Thread Cameron Simpson

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?

2019-07-11 Thread Cameron Simpson

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

2019-06-28 Thread Cameron Simpson

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

2019-06-27 Thread Cameron Simpson

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

2019-06-26 Thread Cameron Simpson

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.

2019-06-19 Thread Cameron Simpson

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

2019-06-15 Thread Cameron Simpson

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.

2019-06-15 Thread Cameron Simpson
 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

2019-06-13 Thread Cameron Simpson

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

2019-06-10 Thread Cameron Simpson

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

2019-06-09 Thread Cameron Simpson
 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

2019-06-01 Thread Cameron Simpson

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.

2019-06-01 Thread Cameron Simpson

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

2019-05-31 Thread Cameron Simpson

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

2019-05-31 Thread Cameron Simpson

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

2019-05-23 Thread Cameron Simpson

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

2019-05-15 Thread Cameron Simpson

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

2019-05-12 Thread Cameron Simpson

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

2019-05-11 Thread Cameron Simpson

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

2019-05-08 Thread Cameron Simpson

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

2019-05-02 Thread Cameron Simpson

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

2019-04-29 Thread Cameron Simpson

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()

2019-04-20 Thread Cameron Simpson

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

2019-04-01 Thread Cameron Simpson

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

2019-03-28 Thread Cameron Simpson

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"?

2019-03-24 Thread Cameron Simpson

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"?

2019-03-23 Thread Cameron Simpson
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

2019-03-23 Thread Cameron Simpson
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)

2019-03-22 Thread Cameron Simpson

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?

2019-03-06 Thread Cameron Simpson

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

2019-03-03 Thread Cameron Simpson

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?

2019-03-02 Thread Cameron Simpson

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?

2019-03-02 Thread Cameron Simpson

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?

2019-03-01 Thread Cameron Simpson

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

2019-02-26 Thread Cameron Simpson

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)"

2019-02-24 Thread Cameron Simpson

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)"

2019-02-24 Thread Cameron Simpson

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)"

2019-02-24 Thread Cameron Simpson

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)"

2019-02-23 Thread Cameron Simpson

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

2019-01-27 Thread Cameron Simpson

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

2019-01-26 Thread Cameron Simpson
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.

2019-01-14 Thread Cameron Simpson

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.

2019-01-13 Thread Cameron Simpson

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

2018-12-25 Thread Cameron Simpson

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.

2018-12-08 Thread Cameron Simpson

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

2018-12-03 Thread Cameron Simpson
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

2018-12-03 Thread Cameron Simpson

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

2018-11-30 Thread Cameron Simpson
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.

2018-11-29 Thread Cameron Simpson

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

2018-11-25 Thread Cameron Simpson

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

2018-11-24 Thread Cameron Simpson

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

2018-11-19 Thread Cameron Simpson
]
 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

2018-11-14 Thread Cameron Simpson

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)

2018-11-13 Thread Cameron Simpson

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

2018-11-07 Thread Cameron Simpson

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

2018-11-07 Thread Cameron Simpson

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

2018-11-06 Thread Cameron Simpson
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

2018-11-06 Thread Cameron Simpson

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

2018-11-06 Thread Cameron Simpson
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?

2018-10-23 Thread Cameron Simpson

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?

2018-10-22 Thread Cameron Simpson

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?

2018-10-21 Thread Cameron Simpson

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?

2018-10-21 Thread Cameron Simpson

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

2018-10-19 Thread Cameron Simpson

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'

2018-10-05 Thread Cameron Simpson

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

2018-09-13 Thread Cameron Simpson

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

2018-09-10 Thread Cameron Simpson

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

2018-09-10 Thread Cameron Simpson

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

2018-09-09 Thread Cameron Simpson
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

2018-09-08 Thread Cameron Simpson

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

2018-09-08 Thread Cameron Simpson

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

2018-09-08 Thread Cameron Simpson
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

2018-09-07 Thread Cameron Simpson

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

2018-09-06 Thread Cameron Simpson

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

2018-09-06 Thread Cameron Simpson
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

2018-09-01 Thread Cameron Simpson

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

2018-09-01 Thread Cameron Simpson

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

2018-09-01 Thread Cameron Simpson

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?

2018-08-30 Thread Cameron Simpson

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?

2018-08-29 Thread Cameron Simpson

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

2018-08-25 Thread Cameron Simpson

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

2018-08-14 Thread Cameron Simpson

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

2018-07-27 Thread Cameron Simpson

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

2018-07-13 Thread Cameron Simpson

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

2018-03-11 Thread Cameron Simpson

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

2018-03-11 Thread Cameron Simpson
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

2018-02-26 Thread Cameron Simpson

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

2018-01-31 Thread Cameron Simpson

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 ...

2018-01-27 Thread Cameron Simpson

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

2018-01-11 Thread Cameron Simpson

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


  1   2   3   4   >