Re: Data unchanged when passing data to Python in multiprocessing shared memory

2022-02-02 Thread Barry Scott


> On 1 Feb 2022, at 23:40, Jen Kris  wrote:
> 
> Barry, thanks for your reply.  
> 
> On the theory that it is not yet possible to pass data from a non-Python 
> language to Python with multiprocessing.shared_memory, I bypassed the problem 
> by attaching 4 bytes to my FIFO pipe message from NASM to Python:
> 
> byte_val = v[10:14]
> 
> where v is the message read from the FIFO.  Then:
> 
> breakup = int.from_bytes(byte_val, "big")
> print("this is breakup " + str(breakup))
> 
> Python prints:  this is breakup 32894
> 
> Note that I had to switch from little endian to big endian.  Python is little 
> endian by default, but in this case it's big endian.  
> 
> However, if anyone on this list knows how to pass data from a non-Python 
> language to Python in multiprocessing.shared_memory please let me (and the 
> list) know.  

By using the struct module you can control for endian of the data.

Barry

> 
> Thanks.  
> 
> 
> Feb 1, 2022, 14:20 by [email protected]:
> 
> On 1 Feb 2022, at 20:26, Jen Kris via Python-list  
> wrote:
> 
> I am using multiprocesssing.shared_memory to pass data between NASM and 
> Python. The shared memory is created in NASM before Python is called. Python 
> connects to the shm: shm_00 = 
> shared_memory.SharedMemory(name='shm_object_00',create=False). 
> 
> I have used shared memory at other points in this project to pass text data 
> from Python back to NASM with no problems. But now this time I need to pass a 
> 32-bit integer (specifically 32,894) from NASM to Python. 
> 
> First I convert the integer to bytes in a C program linked into NASM:
> 
> unsigned char bytes[4]
> unsigned long int_to_convert = 32894;
> 
> bytes[0] = (int_to_convert >> 24) & 0xFF;
> bytes[1] = (int_to_convert >> 16) & 0xFF;
> bytes[2] = (int_to_convert >> 8) & 0xFF;
> bytes[3] = int_to_convert & 0xFF;
> memcpy(outbuf, bytes, 4);
> 
> where outbuf is a pointer to the shared memory. On return from C to NASM, I 
> verify that the first four bytes of the shared memory contain what I want, 
> and they are 0, 0, -128, 126 which is binary   1000 
> 0110, and that's correct (32,894). 
> 
> Next I send a message to Python through a FIFO to read the data from shared 
> memory. Python uses the following code to read the first four bytes of the 
> shared memory:
> 
> byte_val = shm_00.buf[:4]
> print(shm_00.buf[0])
> print(shm_00.buf[1])
> print(shm_00.buf[2])
> print(shm_00.buf[3])
> 
> But the bytes show as 40 39 96 96, which is exactly what the first four bytes 
> of this shared memory contained before I called C to overwrite them with the 
> bytes 0, 0, -128, 126. So Python does not see the updated bytes, and 
> naturally int.from_bytes(byte_val, "little") does not return the result I 
> want. 
> 
> I know that Python refers to shm00.buf, using the buffer protocol. Is that 
> the reason that Python can't see the data that has been updated by another 
> language? 
> 
> So my question is, how can I alter the data in shared memory in a non-Python 
> language to pass back to Python?
> 
> Maybe you need to use a memory barrier to force the data to be seen by 
> another cpu?
> Maybe use shm lock operation to sync both sides?
> Googling I see people talking about using stdatomic.h for this.
> 
> But I am far from clear what you would need to do.
> 
> Barry
> 
> Thanks,
> 
> Jen
> 
> -- 
> https://mail.python.org/mailman/listinfo/python-list
> 

-- 
https://mail.python.org/mailman/listinfo/python-list


Why dict.setdefault() has value as optional?

2022-02-02 Thread Marco Sulla
Just out of curiosity: why dict.setdefault() has the default parameter
that well, has a default value (None)? I used setdefault in the past,
but I always specified a value. What's the use case of setting None by
default?
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Why dict.setdefault() has value as optional?

2022-02-02 Thread Lars Liedtke

This is a quite philosophical queston if you look at it in general:
"What value do you give a variable, that is not set?"

You are right, at first it seems strange to have a default of None. But 
how do you want to signal that no default is set yet? Especially if you 
think of a dict that can have multiple keys with each different values 
of different types?


Have fun in the rabbithole ;-)

Cheers

Lars

Am 02.02.22 um 13:54 schrieb Marco Sulla:

Just out of curiosity: why dict.setdefault() has the default parameter
that well, has a default value (None)? I used setdefault in the past,
but I always specified a value. What's the use case of setting None by
default?


--
punkt.de GmbH
Lars Liedtke
.infrastructure

Kaiserallee 13a 
76133 Karlsruhe

Tel. +49 721 9109 500
https://infrastructure.punkt.de
[email protected]

AG Mannheim 108285
Geschäftsführer: Jürgen Egeling, Daniel Lienert, Fabian Stein

--
https://mail.python.org/mailman/listinfo/python-list


Re: Data unchanged when passing data to Python in multiprocessing shared memory

2022-02-02 Thread Dennis Lee Bieber
On Wed, 2 Feb 2022 00:40:22 +0100 (CET), Jen Kris 
declaimed the following:

>
> breakup = int.from_bytes(byte_val, "big")
>print("this is breakup " + str(breakup))
>
>Python prints:  this is breakup 32894
>
>Note that I had to switch from little endian to big endian.  Python is little 
>endian by default, but in this case it's big endian.  
>
Look at the struct module. I'm pretty certain it has flags for big or
little end, or system native (that, or run your integers through the
various "network byte order" functions that I think C and Python both
support.

https://www.gta.ufrj.br/ensino/eel878/sockets/htonsman.html


>However, if anyone on this list knows how to pass data from a non-Python 
>language to Python in multiprocessing.shared_memory please let me (and the 
>list) know.  

MMU cache lines not writing through to RAM? Can't find
anything on Google to force a cache flush Can you test on a
different OS? (Windows vs Linux)



-- 
Wulfraed Dennis Lee Bieber AF6VN
[email protected]://wlfraed.microdiversity.freeddns.org/
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Why dict.setdefault() has value as optional?

2022-02-02 Thread Marco Sulla
On Wed, 2 Feb 2022 at 14:34, Lars Liedtke  wrote:
>
> This is a quite philosophical queston if you look at it in general:
> "What value do you give a variable, that is not set?"

Maybe I expressed my question badly. My existential doubt is why
setdefault has an optional parameter for the value and not a required
parameter. I'm not asking why the default is None.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: http.client and dns lookups

2022-02-02 Thread Dieter Maurer
Michael Welle wrote at 2022-2-1 19:28 +0100:
> ...
>That doesn't happen when the 'real' issue occurs. Attaching strace to
>the Python process I can see that resolv.conf is stat'ed and open'ed. I
>guess now I'm more confused than before ;). There must be an additional
>condition that I'm missing.

The DNS service routinely uses caches. Outdated cache values
can cause (apparently non deterministic) failures.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Data unchanged when passing data to Python in multiprocessing shared memory

2022-02-02 Thread Avi Gross via Python-list
I applaud trying to find the right solution but wonder if a more trivial 
solution is even being considered. It ignores big and little endians and just 
converts your data into another form and back.

If all you want to do is send an integer that fit in 32 bits or 64 bits, why 
not convert it to a character string in a form that both machines will see the 
same way and when read back, convert it back to an integer? 

As long as both side see the same string, this can be done in reasonable time 
and portably.

Or am I missing something? Is "1234" not necessarily seen in the same order, or 
"1.234e3" or whatever?

Obviously, if the mechanism is heavily used and multiple sides keep reading and 
even writing the same memory location, this is not ideal. But having different 
incompatible processors looking at the same memory is also not.

-Original Message-
From: Dennis Lee Bieber 
To: [email protected]
Sent: Wed, Feb 2, 2022 12:30 am
Subject: Re: Data unchanged when passing data to Python in multiprocessing 
shared memory


On Wed, 2 Feb 2022 00:40:22 +0100 (CET), Jen Kris 

declaimed the following:



>

> breakup = int.from_bytes(byte_val, "big")

>print("this is breakup " + str(breakup))

>

>Python prints:  this is breakup 32894

>

>Note that I had to switch from little endian to big endian.  Python is little 
>endian by default, but in this case it's big endian.  

>

    Look at the struct module. I'm pretty certain it has flags for big or

little end, or system native (that, or run your integers through the

various "network byte order" functions that I think C and Python both

support.



https://www.gta.ufrj.br/ensino/eel878/sockets/htonsman.html





>However, if anyone on this list knows how to pass data from a non-Python 
>language to Python in multiprocessing.shared_memory please let me (and the 
>list) know.  



    MMU cache lines not writing through to RAM? Can't find

anything on Google to force a cache flush Can you test on a

different OS? (Windows vs Linux)







-- 

    Wulfraed                 Dennis Lee Bieber         AF6VN

    [email protected]    http://wlfraed.microdiversity.freeddns.org/

-- 

https://mail.python.org/mailman/listinfo/python-list

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Data unchanged when passing data to Python in multiprocessing shared memory

2022-02-02 Thread Jen Kris via Python-list
It's not clear to me from the struct module whether it can actually auto-detect 
endianness.  I think it must be specified, just as I had to do with 
int.from_bytes().  In my case endianness was dictated by how the four bytes 
were populated, starting with the zero bytes on the left.  


Feb 1, 2022, 21:30 by [email protected]:

> On Wed, 2 Feb 2022 00:40:22 +0100 (CET), Jen Kris 
> declaimed the following:
>
>>
>> breakup = int.from_bytes(byte_val, "big")
>>
> >print("this is breakup " + str(breakup))
>
>>
>>
> >Python prints:  this is breakup 32894
>
>>
>>
> >Note that I had to switch from little endian to big endian.  Python is 
> >little endian by default, but in this case it's big endian.  
>
>>
>>
> Look at the struct module. I'm pretty certain it has flags for big or
> little end, or system native (that, or run your integers through the
> various "network byte order" functions that I think C and Python both
> support.
>
> https://www.gta.ufrj.br/ensino/eel878/sockets/htonsman.html
>
>
> >However, if anyone on this list knows how to pass data from a non-Python 
> >language to Python in multiprocessing.shared_memory please let me (and the 
> >list) know.  
>
>  MMU cache lines not writing through to RAM? Can't find
> anything on Google to force a cache flush Can you test on a
> different OS? (Windows vs Linux)
>
>
>
> -- 
>  Wulfraed Dennis Lee Bieber AF6VN
>  [email protected]://wlfraed.microdiversity.freeddns.org/
> -- 
> https://mail.python.org/mailman/listinfo/python-list
>

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Data unchanged when passing data to Python in multiprocessing shared memory

2022-02-02 Thread Jen Kris via Python-list
An ASCII string will not work.  If you convert 32894 to an ascii string you 
will have five bytes, but you need four.  In my original post I showed the C 
program I used to convert any 32-bit number to 4 bytes.  


Feb 2, 2022, 10:16 by [email protected]:

> I applaud trying to find the right solution but wonder if a more trivial 
> solution is even being considered. It ignores big and little endians and just 
> converts your data into another form and back.
>
> If all you want to do is send an integer that fit in 32 bits or 64 bits, why 
> not convert it to a character string in a form that both machines will see 
> the same way and when read back, convert it back to an integer? 
>
> As long as both side see the same string, this can be done in reasonable time 
> and portably.
>
> Or am I missing something? Is "1234" not necessarily seen in the same order, 
> or "1.234e3" or whatever?
>
> Obviously, if the mechanism is heavily used and multiple sides keep reading 
> and even writing the same memory location, this is not ideal. But having 
> different incompatible processors looking at the same memory is also not.
>
> -Original Message-
> From: Dennis Lee Bieber 
> To: [email protected]
> Sent: Wed, Feb 2, 2022 12:30 am
> Subject: Re: Data unchanged when passing data to Python in multiprocessing 
> shared memory
>
>
> On Wed, 2 Feb 2022 00:40:22 +0100 (CET), Jen Kris 
>
> declaimed the following:
>
>
>
>>
>>
>> breakup = int.from_bytes(byte_val, "big")
>>
>
> >print("this is breakup " + str(breakup))
>
>>
>>
>
> >Python prints:  this is breakup 32894
>
>>
>>
>
> >Note that I had to switch from little endian to big endian.  Python is 
> >little endian by default, but in this case it's big endian.  
>
>>
>>
>
>     Look at the struct module. I'm pretty certain it has flags for big or
>
> little end, or system native (that, or run your integers through the
>
> various "network byte order" functions that I think C and Python both
>
> support.
>
>
>
> https://www.gta.ufrj.br/ensino/eel878/sockets/htonsman.html
>
>
>
>
>
> >However, if anyone on this list knows how to pass data from a non-Python 
> >language to Python in multiprocessing.shared_memory please let me (and the 
> >list) know.  
>
>
>
>     MMU cache lines not writing through to RAM? Can't find
>
> anything on Google to force a cache flush Can you test on a
>
> different OS? (Windows vs Linux)
>
>
>
>
>
>
>
> -- 
>
>     Wulfraed                 Dennis Lee Bieber         AF6VN
>
>     [email protected]    http://wlfraed.microdiversity.freeddns.org/
>
> -- 
>
> https://mail.python.org/mailman/listinfo/python-list
>
> -- 
> https://mail.python.org/mailman/listinfo/python-list
>

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Data unchanged when passing data to Python in multiprocessing shared memory

2022-02-02 Thread Dennis Lee Bieber
On Wed, 2 Feb 2022 19:16:19 +0100 (CET), Jen Kris 
declaimed the following:

>It's not clear to me from the struct module whether it can actually 
>auto-detect endianness.  I think it must be specified, just as I had to do 
>with int.from_bytes().  In my case endianness was dictated by how the four 
>bytes were populated, starting with the zero bytes on the left. 

Which is why I also suggested maybe looking at the various network/host
translation calls. They are in the socket module of Python, and should also
be available in most C standard libraries...

https://docs.python.org/3/library/socket.html#other-functions

"""

socket.ntohl(x)

Convert 32-bit positive integers from network to host byte order. On
machines where the host byte order is the same as network byte order, this
is a no-op; otherwise, it performs a 4-byte swap operation.

socket.ntohs(x)

Convert 16-bit positive integers from network to host byte order. On
machines where the host byte order is the same as network byte order, this
is a no-op; otherwise, it performs a 2-byte swap operation.

Changed in version 3.10: Raises OverflowError if x does not fit in a
16-bit unsigned integer.

socket.htonl(x)

Convert 32-bit positive integers from host to network byte order. On
machines where the host byte order is the same as network byte order, this
is a no-op; otherwise, it performs a 4-byte swap operation.

socket.htons(x)

Convert 16-bit positive integers from host to network byte order. On
machines where the host byte order is the same as network byte order, this
is a no-op; otherwise, it performs a 2-byte swap operation.

Changed in version 3.10: Raises OverflowError if x does not fit in a
16-bit unsigned integer.
"""

https://docs.python.org/3/library/struct.html
"""
Byte Order, Size, and Alignment

By default, C types are represented in the machine’s native format and byte
order, and properly aligned by skipping pad bytes if necessary (according
to the rules used by the C compiler).

Alternatively, the first character of the format string can be used to
indicate the byte order, size and alignment of the packed data, according
to the following table:

Character   Byte order  SizeAlignment
@   native  native  native
=   native  standardnone
<   little-endian   standardnone
>   big-endian  standardnone
!   network (= big-endian)  <<
standardnone<<

If the first character is not one of these, '@' is assumed.
"""

Since all the programs in your situation are running on the same
machine, it would appear that at least one of them is NOT formatting
integers in native host mode -- and I don't think it is Python.


https://www.tutorialspoint.com/unix_sockets/network_byte_orders.htm
"""
These functions are macros and result in the insertion of conversion source
code into the calling program. On little-endian machines, the code will
change the values around to network byte order. On big-endian machines, no
code is inserted since none is needed; the functions are defined as null.
"""



-- 
Wulfraed Dennis Lee Bieber AF6VN
[email protected]://wlfraed.microdiversity.freeddns.org/
-- 
https://mail.python.org/mailman/listinfo/python-list


Waht do you think about my repeated_timer class

2022-02-02 Thread Cecil Westerhof via Python-list
I need (sometimes) to repeatedly execute a function. For this I wrote
the below class. What do you think about it?
from threading  import Timer



class repeated_timer(object):
def __init__(self, fn, interval, start = False):
if not callable(fn):
raise TypeError('{} is not a function'.format(fn))
self._fn = fn
self._check_interval(interval)
self._interval   = interval
self._timer  = None
self._is_running = False
if start:
self.start()

def _check_interval(self, interval):
if not type(interval) in [int, float]:
raise TypeError('{} is not numeric'.format(interval))
if interval <= 0:
raise ValueError('{} is not greater as 0'.format(interval))

def _next(self):
self._timer = Timer(self._interval, self._run)
self._timer.start()

def _run(self):
self._next()
self._fn()

def set_interval(self, interval):
self._check_interval(interval)
self._interval = interval

def start(self):
if not self._is_running:
self._next()
self._is_running = True

def stop(self):
if self._is_running:
self._timer.cancel()
self._timer  = None
self._is_running = False

-- 
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Waht do you think about my repeated_timer class

2022-02-02 Thread Marco Sulla
You could add a __del__ that calls stop :)

On Wed, 2 Feb 2022 at 21:23, Cecil Westerhof via Python-list
 wrote:
>
> I need (sometimes) to repeatedly execute a function. For this I wrote
> the below class. What do you think about it?
> from threading  import Timer
>
>
>
> class repeated_timer(object):
> def __init__(self, fn, interval, start = False):
> if not callable(fn):
> raise TypeError('{} is not a function'.format(fn))
> self._fn = fn
> self._check_interval(interval)
> self._interval   = interval
> self._timer  = None
> self._is_running = False
> if start:
> self.start()
>
> def _check_interval(self, interval):
> if not type(interval) in [int, float]:
> raise TypeError('{} is not numeric'.format(interval))
> if interval <= 0:
> raise ValueError('{} is not greater as 0'.format(interval))
>
> def _next(self):
> self._timer = Timer(self._interval, self._run)
> self._timer.start()
>
> def _run(self):
> self._next()
> self._fn()
>
> def set_interval(self, interval):
> self._check_interval(interval)
> self._interval = interval
>
> def start(self):
> if not self._is_running:
> self._next()
> self._is_running = True
>
> def stop(self):
> if self._is_running:
> self._timer.cancel()
> self._timer  = None
> self._is_running = False
>
> --
> Cecil Westerhof
> Senior Software Engineer
> LinkedIn: http://www.linkedin.com/in/cecilwesterhof
> --
> https://mail.python.org/mailman/listinfo/python-list
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Data unchanged when passing data to Python in multiprocessing shared memory

2022-02-02 Thread Barry


> On 2 Feb 2022, at 18:19, Jen Kris via Python-list  
> wrote:
> 
> It's not clear to me from the struct module whether it can actually 
> auto-detect endianness. 

It is impossible to auto detect endian in the general case.

> I think it must be specified, just as I had to do with int.from_bytes().  In 
> my case endianness was dictated by how the four bytes were populated, 
> starting with the zero bytes on the left.  

You can specify the endian explicitly in the format strings. It’s all in the 
docs.

Barry
> 
> 
> Feb 1, 2022, 21:30 by [email protected]:
> 
>> On Wed, 2 Feb 2022 00:40:22 +0100 (CET), Jen Kris 
>> declaimed the following:
>> 
>>> 
>>> breakup = int.from_bytes(byte_val, "big")
>>> 
>>> print("this is breakup " + str(breakup))
>> 
>>> 
>>> 
>>> Python prints:  this is breakup 32894
>> 
>>> 
>>> 
>>> Note that I had to switch from little endian to big endian.  Python is 
>>> little endian by default, but in this case it's big endian.  
>> 
>>> 
>>> 
>> Look at the struct module. I'm pretty certain it has flags for big or
>> little end, or system native (that, or run your integers through the
>> various "network byte order" functions that I think C and Python both
>> support.
>> 
>> https://www.gta.ufrj.br/ensino/eel878/sockets/htonsman.html
>> 
>> 
>>> However, if anyone on this list knows how to pass data from a non-Python 
>>> language to Python in multiprocessing.shared_memory please let me (and the 
>>> list) know.  
>> 
>> MMU cache lines not writing through to RAM? Can't find
>> anything on Google to force a cache flush Can you test on a
>> different OS? (Windows vs Linux)
>> 
>> 
>> 
>> -- 
>> Wulfraed Dennis Lee Bieber AF6VN
>> [email protected]://wlfraed.microdiversity.freeddns.org/
>> -- 
>> https://mail.python.org/mailman/listinfo/python-list
>> 
> 
> -- 
> https://mail.python.org/mailman/listinfo/python-list

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Waht do you think about my repeated_timer class

2022-02-02 Thread Barry


> On 2 Feb 2022, at 21:12, Marco Sulla  wrote:
> 
> You could add a __del__ that calls stop :)

Didn’t python3 make this non deterministic when del is called?

I thought the recommendation is to not rely on __del__ in python3 code.

Barry
> 
>> On Wed, 2 Feb 2022 at 21:23, Cecil Westerhof via Python-list
>>  wrote:
>> 
>> I need (sometimes) to repeatedly execute a function. For this I wrote
>> the below class. What do you think about it?
>>from threading  import Timer
>> 
>> 
>> 
>>class repeated_timer(object):
>>def __init__(self, fn, interval, start = False):
>>if not callable(fn):
>>raise TypeError('{} is not a function'.format(fn))
>>self._fn = fn
>>self._check_interval(interval)
>>self._interval   = interval
>>self._timer  = None
>>self._is_running = False
>>if start:
>>self.start()
>> 
>>def _check_interval(self, interval):
>>if not type(interval) in [int, float]:
>>raise TypeError('{} is not numeric'.format(interval))
>>if interval <= 0:
>>raise ValueError('{} is not greater as 0'.format(interval))
>> 
>>def _next(self):
>>self._timer = Timer(self._interval, self._run)
>>self._timer.start()
>> 
>>def _run(self):
>>self._next()
>>self._fn()
>> 
>>def set_interval(self, interval):
>>self._check_interval(interval)
>>self._interval = interval
>> 
>>def start(self):
>>if not self._is_running:
>>self._next()
>>self._is_running = True
>> 
>>def stop(self):
>>if self._is_running:
>>self._timer.cancel()
>>self._timer  = None
>>self._is_running = False
>> 
>> --
>> Cecil Westerhof
>> Senior Software Engineer
>> LinkedIn: http://www.linkedin.com/in/cecilwesterhof
>> --
>> https://mail.python.org/mailman/listinfo/python-list
> -- 
> https://mail.python.org/mailman/listinfo/python-list
> 

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Waht do you think about my repeated_timer class

2022-02-02 Thread Chris Angelico
On Thu, 3 Feb 2022 at 09:33, Barry  wrote:
>
>
>
> > On 2 Feb 2022, at 21:12, Marco Sulla  wrote:
> >
> > You could add a __del__ that calls stop :)
>
> Didn’t python3 make this non deterministic when del is called?
>
> I thought the recommendation is to not rely on __del__ in python3 code.
>

The __del__ method is called when the object is being disposed of.
Aside from some considerations about interpreter shutdown, it's
perfectly reliable... as long as you understand that objects don't get
disposed of when they "go out of scope", but when they run out of
references and get garbage collected. So for instance, you can't
depend on "x = Spam(); x = Ham()" to dispose of the Spam object
instantly, because it might not get garbage collected instantly; but
you can depend on __del__ getting called when the Spam object gets
garbage collected.

With that said, I can guarantee you that a __del__ method is NOT the
right way to call stop, for one simple reason: the object will keep
its own references (via the timer) so long as it is running. So it
won't get garbage collected, and in fact, this is very important to it
being reliable. Consider this simpler example:

def call_soon(func):
t = threading.Timer(10, func)
t.start()

When this function returns, you can no longer refer to the object 't'.
Will the function be called at the appropriate time? Yes, it
absolutely will, and it would be highly surprising if it didn't! So
the thread itself keeps a reference to the important objects.

(Side point: The OP's code is quite inefficient, as it creates a new
thread for each reiteration, but there's nothing wrong with that if
you're looking for something simple.)

The main reason to "not rely on __del__" (and, by the way, that's
nothing to do with whether it's Python 2 or Python 3, this has been
true since early Py2 and possibly earlier) is that you don't know when
the object will be disposed of. So if you want to guarantee that
something is cleaned up, what you need is a way for the object itself
to still exist, but the corresponding resource to be cleaned up. A
classic example is a file object:

def read_then_write(fn):
with open(fn) as read_file:
data = read_file.read()
print(read_file)
# ... transform the data as required ...
with open(fn, "w") as write_file:
write_file.write(data)
print(write_file)

After each 'with' block, the file object is still there. You can refer
to it. Nothing has destroyed the object. But the file has been closed,
guaranteeing that you can safely reopen it in a different mode
(regardless of your OS). The same could be done with this timer; an
__exit__ method would make a lot of sense here, and would allow the
timer to be used in a with block to govern its execution. (It also
isn't really necessary, but if you want a good Pythonic way to show
the beginning and end of its use area, a 'with' block is the way to
go.)

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Waht do you think about my repeated_timer class

2022-02-02 Thread Cecil Westerhof via Python-list
Chris Angelico  writes:

> On Thu, 3 Feb 2022 at 09:33, Barry  wrote:
> (Side point: The OP's code is quite inefficient, as it creates a new
> thread for each reiteration, but there's nothing wrong with that if
> you're looking for something simple.)

It is just something I wrote fast. How could I do this in a better way?


> (regardless of your OS). The same could be done with this timer; an
> __exit__ method would make a lot of sense here, and would allow the
> timer to be used in a with block to govern its execution. (It also
> isn't really necessary, but if you want a good Pythonic way to show
> the beginning and end of its use area, a 'with' block is the way to
> go.)

I will look into that.

-- 
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Waht do you think about my repeated_timer class

2022-02-02 Thread Cecil Westerhof via Python-list
Cecil Westerhof  writes:

>> (regardless of your OS). The same could be done with this timer; an
>> __exit__ method would make a lot of sense here, and would allow the
>> timer to be used in a with block to govern its execution. (It also
>> isn't really necessary, but if you want a good Pythonic way to show
>> the beginning and end of its use area, a 'with' block is the way to
>> go.)
>
> I will look into that.

Implemented:
from threading  import Timer



class repeated_timer(object):
def __init__(self, fn, interval, start = False):
if not callable(fn):
raise TypeError('{} is not a function'.format(fn))
self._fn = fn
self._check_interval(interval)
self._interval   = interval
self._timer  = None
self._is_running = False
if start:
self.start()

def __enter__(self):
return self

def __exit__(self, exc_type, exc_val, exc_tb):
self.stop()

def _check_interval(self, interval):
if not type(interval) in [int, float]:
raise TypeError('{} is not numeric'.format(interval))
if interval <= 0:
raise ValueError('{} is not greater as 0'.format(interval))

def _next(self):
self._timer = Timer(self._interval, self._run)
self._timer.start()

def _run(self):
self._next()
self._fn()

def set_interval(self, interval):
self._check_interval(interval)
self._interval = interval

def start(self):
if not self._is_running:
self._is_running = True
self._next()

def stop(self):
if self._is_running:
self._timer.cancel()
self._timer  = None
self._is_running = False

-- 
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Waht do you think about my repeated_timer class

2022-02-02 Thread Cameron Simpson
You have:

def _check_interval(self, interval):
if not type(interval) in [int, float]:
raise TypeError('{} is not numeric'.format(interval))

This check is better written:

if not isinstance(interval, (int,float)):

which handles subclasses of these types (but note that bool subclasses 
int :-) normally we don't care), or behaviourally:

try:
interval = float(interval)
except ValueError as e:
raise TypeError(
"cannot convert %s:%r to float: %s"
% (type(interval).__name__, interval, e)) from e

which tries to convert to float and fails if that does not work, which 
supports classes with a __float__ method (these classes are rare, but 
decimal.Decimal is one example).

I'd probably use the isinstance() form myself.

Cheers,
Cameron Simpson 
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Waht do you think about my repeated_timer class

2022-02-02 Thread Chris Angelico
On Thu, 3 Feb 2022 at 12:24, Cecil Westerhof via Python-list
 wrote:
>
> Chris Angelico  writes:
>
> > On Thu, 3 Feb 2022 at 09:33, Barry  wrote:
> > (Side point: The OP's code is quite inefficient, as it creates a new
> > thread for each reiteration, but there's nothing wrong with that if
> > you're looking for something simple.)
>
> It is just something I wrote fast. How could I do this in a better way?

I'll answer your question, but first and foremost: Your code was fine,
and if something does what it's supposed to, that is the most
important. Everything else is minor.

But for other ways to do things, I would recommend creating a single
thread function and spawning a single thread to run it, and then
having that function call the target every N seconds. Also, consider
subclassing Thread rather than subclassing object (which, btw, is the
default; you don't need to say "class X(object)"), which will
automatically give your object all the methods of a timer.

If you feel like it, you could even look into ways to do things
without threads, but that would be a much bigger change :)

But remember: when your code does what it's supposed to, it is *fine*,
and doesn't need changing. I'm not saying that your code is bad :)

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Data unchanged when passing data to Python in multiprocessing shared memory

2022-02-02 Thread Avi Gross via Python-list
Jen,

I would not be shocked at incompatibilities in the system described making it 
hard to exchange anything, including text, but am not clear if there is a 
limitation of four bytes in what can be shared. For me, a character string can 
use any number of contiguous bytes in memory that some kind of pointer or table 
lookup provides access to. 

Clearly you could squeeze larger number in by not writing decimals but using 
hexadecimal notation that adds a to f as valid entries, and of course you can 
make your own customized base 32 or if you use more symbols (such as upper and 
lower case as different) you could  add a few symbols and stretch it out to 
base 60 or 64.

Like I said, I may have missed something. If you KNOW that system A will 
interact with systems B and C and so on, and each machine knows what kind it 
is, and especially if it knows which kind of machine left it something in 
shared memory, there has to be a way to coordinate between them. If character 
strings in ASCII or UTF8 or EBCDIC or some kind of raw are allowed, and used 
with just a few characters that can spell out numbers, I would think much is 
possible. If needed, perhaps a fixed size could be set aside and the string use 
a null terminator if shorter. 

Of course if this big-endian issue also scrambles bytes used in strings, forget 
it.

Or, maybe shared memory is not the easy way to go, even it it might be faster.



-Original Message-
From: Jen Kris 
To: Avi Gross 
Cc: [email protected] 
Sent: Wed, Feb 2, 2022 1:27 pm
Subject: Re: Data unchanged when passing data to Python in multiprocessing 
shared memory



An ASCII string will not work.  If you convert 32894 to an ascii string you 
will have five bytes, but you need four.  In my original post I showed the C 
program I used to convert any 32-bit number to 4 bytes.  






Feb 2, 2022, 10:16 by [email protected]:

I applaud trying to find the right solution but wonder if a more trivial 
solution is even being considered. It ignores big and little endians and just 
converts your data into another form and back.



If all you want to do is send an integer that fit in 32 bits or 64 bits, why 
not convert it to a character string in a form that both machines will see the 
same way and when read back, convert it back to an integer? 



As long as both side see the same string, this can be done in reasonable time 
and portably.



Or am I missing something? Is "1234" not necessarily seen in the same order, or 
"1.234e3" or whatever?



Obviously, if the mechanism is heavily used and multiple sides keep reading and 
even writing the same memory location, this is not ideal. But having different 
incompatible processors looking at the same memory is also not.



-Original Message-

From: Dennis Lee Bieber 

To: [email protected]

Sent: Wed, Feb 2, 2022 12:30 am

Subject: Re: Data unchanged when passing data to Python in multiprocessing 
shared memory





On Wed, 2 Feb 2022 00:40:22 +0100 (CET), Jen Kris 



declaimed the following:






breakup = int.from_bytes(byte_val, "big")



>print("this is breakup " + str(breakup))





>Python prints:  this is breakup 32894





>Note that I had to switch from little endian to big endian.  Python is little 
>endian by default, but in this case it's big endian.  





    Look at the struct module. I'm pretty certain it has flags for big or



little end, or system native (that, or run your integers through the



various "network byte order" functions that I think C and Python both



support.







https://www.gta.ufrj.br/ensino/eel878/sockets/htonsman.html











>However, if anyone on this list knows how to pass data from a non-Python 
>language to Python in multiprocessing.shared_memory please let me (and the 
>list) know.  







    MMU cache lines not writing through to RAM? Can't find



anything on Google to force a cache flush Can you test on a



different OS? (Windows vs Linux)















-- 



    Wulfraed                 Dennis Lee Bieber         AF6VN



    [email protected]    http://wlfraed.microdiversity.freeddns.org/



-- 



https://mail.python.org/mailman/listinfo/python-list



-- 

https://mail.python.org/mailman/listinfo/python-list



  

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Data unchanged when passing data to Python in multiprocessing shared memory

2022-02-02 Thread Chris Angelico
On Thu, 3 Feb 2022 at 13:32, Avi Gross via Python-list
 wrote:
>
> Jen,
>
> I would not be shocked at incompatibilities in the system described making it 
> hard to exchange anything, including text, but am not clear if there is a 
> limitation of four bytes in what can be shared. For me, a character string 
> can use any number of contiguous bytes in memory that some kind of pointer or 
> table lookup provides access to.
>
> Clearly you could squeeze larger number in by not writing decimals but using 
> hexadecimal notation that adds a to f as valid entries, and of course you can 
> make your own customized base 32 or if you use more symbols (such as upper 
> and lower case as different) you could  add a few symbols and stretch it out 
> to base 60 or 64.
>
> Like I said, I may have missed something. If you KNOW that system A will 
> interact with systems B and C and so on, and each machine knows what kind it 
> is, and especially if it knows which kind of machine left it something in 
> shared memory, there has to be a way to coordinate between them. If character 
> strings in ASCII or UTF8 or EBCDIC or some kind of raw are allowed, and used 
> with just a few characters that can spell out numbers, I would think much is 
> possible. If needed, perhaps a fixed size could be set aside and the string 
> use a null terminator if shorter.
>
> Of course if this big-endian issue also scrambles bytes used in strings, 
> forget it.
>
> Or, maybe shared memory is not the easy way to go, even it it might be faster.
>

Structs are fine, and are highly unlikely to be the OP's problem.
Switching to a different system won't help.

Unfortunately I can't offer any serious help about the actual problem,
as I don't know what's going on with the shared memory issue.

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Waht do you think about my repeated_timer class

2022-02-02 Thread Cecil Westerhof via Python-list
Cameron Simpson  writes:

> You have:
>
> def _check_interval(self, interval):
> if not type(interval) in [int, float]:
> raise TypeError('{} is not numeric'.format(interval))
>
> This check is better written:
>
> if not isinstance(interval, (int,float)):
>
> which handles subclasses of these types (but note that bool subclasses 
> int :-)

Done, thanks.

-- 
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Waht do you think about my repeated_timer class

2022-02-02 Thread 2QdxY4RzWzUUiLuE
On 2022-02-03 at 12:39:43 +1100,
Cameron Simpson  wrote:

> You have:
> 
> def _check_interval(self, interval):
> if not type(interval) in [int, float]:
> raise TypeError('{} is not numeric'.format(interval))
> 
> This check is better written:
> 
> if not isinstance(interval, (int,float)):
> 
> which handles subclasses of these types (but note that bool subclasses 
> int :-) normally we don't care), or behaviourally:
> 
> try:
> interval = float(interval)
> except ValueError as e:
> raise TypeError(
> "cannot convert %s:%r to float: %s"
> % (type(interval).__name__, interval, e)) from e
> 
> which tries to convert to float and fails if that does not work, which 
> supports classes with a __float__ method (these classes are rare, but 
> decimal.Decimal is one example).

I think this can be simplified for time intervals to the following:

if interval <= 0:
raise ValueError(...)

which accepts non-negative real values; throws ValueError for negative
real values; and TypeError for other stuff, including complex numbers
(pathological types notwithstanding).  One thing that doesn't work right
is NaNs, but I'm sure it's not the only code that acts weirdly when
faced with a NaM (curiously, Timer accepts a NaN, but the text I get
from help(Timer) in Python 3.10.2 is, well, broken).

FWIW, I'd find some way to tell users the units (seconds, milliseconds,
fortnights, etc.) instead of making them wade through your code to find
the call to (and possibly the [broken] help text of) Timer.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Waht do you think about my repeated_timer class

2022-02-02 Thread Chris Angelico
On Thu, 3 Feb 2022 at 14:52, <[email protected]> wrote:
>
> On 2022-02-03 at 12:39:43 +1100,
> Cameron Simpson  wrote:
>
> > You have:
> >
> > def _check_interval(self, interval):
> > if not type(interval) in [int, float]:
> > raise TypeError('{} is not numeric'.format(interval))
> >
> > This check is better written:
> >
> > if not isinstance(interval, (int,float)):
> >
> > which handles subclasses of these types (but note that bool subclasses
> > int :-) normally we don't care), or behaviourally:
> >
> > try:
> > interval = float(interval)
> > except ValueError as e:
> > raise TypeError(
> > "cannot convert %s:%r to float: %s"
> > % (type(interval).__name__, interval, e)) from e
> >
> > which tries to convert to float and fails if that does not work, which
> > supports classes with a __float__ method (these classes are rare, but
> > decimal.Decimal is one example).
>
> I think this can be simplified for time intervals to the following:
>
> if interval <= 0:
> raise ValueError(...)

That's checking something quite different, though. Casting to float
will accept anything that can be, well, cast to float, but checking
for less than or equal to zero demands that it already be some sort of
number. It's debatable which check is more correct, but certainly this
is not a simplification of the other code, it's a distinctly different
validation.

> which accepts non-negative real values; throws ValueError for negative
> real values; and TypeError for other stuff, including complex numbers
> (pathological types notwithstanding).  One thing that doesn't work right
> is NaNs, but I'm sure it's not the only code that acts weirdly when
> faced with a NaM (curiously, Timer accepts a NaN, but the text I get
> from help(Timer) in Python 3.10.2 is, well, broken).

Strange. The text I get in 3.11.0a1 is fine. But in any case, there's
always the docs on the web.

https://docs.python.org/3/library/threading.html#timer-objects

> FWIW, I'd find some way to tell users the units (seconds, milliseconds,
> fortnights, etc.) instead of making them wade through your code to find
> the call to (and possibly the [broken] help text of) Timer.

In anything in Python, assume that the unit is seconds. With anything
that accepts floats (where these can be distinguished from integers),
assume the unit is seconds. If it accepts micro or nanoseconds, it'll
almost certainly be called "high resolution timer" (unless it accepts
two args, sec and us/ns, but that's pretty obvious), so you can
generally exclude those too. The only real question is whether
sleep(int) takes seconds or milliseconds, which isn't a problem here.

Citation: I've slept in many many programming languages and
frameworks. Which sounds seriously weird, but you're all programmers,
you know what I mean :)

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Waht do you think about my repeated_timer class

2022-02-02 Thread 2QdxY4RzWzUUiLuE
On 2022-02-03 at 15:07:22 +1100,
Chris Angelico  wrote:

> On Thu, 3 Feb 2022 at 14:52, <[email protected]> wrote:
> >
> > On 2022-02-03 at 12:39:43 +1100,
> > Cameron Simpson  wrote:
> >
> > > You have:
> > >
> > > def _check_interval(self, interval):
> > > if not type(interval) in [int, float]:
> > > raise TypeError('{} is not numeric'.format(interval))
> > >
> > > This check is better written:
> > >
> > > if not isinstance(interval, (int,float)):
> > >
> > > which handles subclasses of these types (but note that bool subclasses
> > > int :-) normally we don't care), or behaviourally:
> > >
> > > try:
> > > interval = float(interval)
> > > except ValueError as e:
> > > raise TypeError(
> > > "cannot convert %s:%r to float: %s"
> > > % (type(interval).__name__, interval, e)) from e
> > >
> > > which tries to convert to float and fails if that does not work, which
> > > supports classes with a __float__ method (these classes are rare, but
> > > decimal.Decimal is one example).
> >
> > I think this can be simplified for time intervals to the following:
> >
> > if interval <= 0:
> > raise ValueError(...)
> 
> That's checking something quite different, though. Casting to float
> will accept anything that can be, well, cast to float, but checking
> for less than or equal to zero demands that it already be some sort of
> number. It's debatable which check is more correct, but certainly this
> is not a simplification of the other code, it's a distinctly different
> validation.

Okay, "simplified" isn't quite the right word.  Given two examples (with
known deficiencies) and no actual use cases or specifications, I added a
third example, which I believed was simpler (and arguably better in one
or more ways, which I explained), than the others.

> > which accepts non-negative real values; throws ValueError for negative
> > real values; and TypeError for other stuff, including complex numbers
> > (pathological types notwithstanding).  One thing that doesn't work right
> > is NaNs, but I'm sure it's not the only code that acts weirdly when
> > faced with a NaM (curiously, Timer accepts a NaN, but the text I get
> > from help(Timer) in Python 3.10.2 is, well, broken).
> 
> Strange. The text I get in 3.11.0a1 is fine. But in any case, there's
> always the docs on the web.
> 
> https://docs.python.org/3/library/threading.html#timer-objects

help(Timer) is built into my REPL (and likely consumed by development
systems and IDEs everywhere).  No web necessary.

> > FWIW, I'd find some way to tell users the units (seconds, milliseconds,
> > fortnights, etc.) instead of making them wade through your code to find
> > the call to (and possibly the [broken] help text of) Timer.
> 
> In anything in Python, assume that the unit is seconds. With anything
> that accepts floats (where these can be distinguished from integers),
> assume the unit is seconds. If it accepts micro or nanoseconds, it'll
> almost certainly be called "high resolution timer" (unless it accepts
> two args, sec and us/ns, but that's pretty obvious), so you can
> generally exclude those too. The only real question is whether
> sleep(int) takes seconds or milliseconds, which isn't a problem here.
> 
> Citation: I've slept in many many programming languages and
> frameworks. Which sounds seriously weird, but you're all programmers,
> you know what I mean :)

I've slept in enough programming environments to know better than to
assume anything.  ;-)
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Waht do you think about my repeated_timer class

2022-02-02 Thread Chris Angelico
On Thu, 3 Feb 2022 at 15:28, <[email protected]> wrote:
>
> On 2022-02-03 at 15:07:22 +1100,
> Chris Angelico  wrote:
>
> > On Thu, 3 Feb 2022 at 14:52, <[email protected]> wrote:
> > >
> > > On 2022-02-03 at 12:39:43 +1100,
> > > Cameron Simpson  wrote:
> > >
> > > > You have:
> > > >
> > > > def _check_interval(self, interval):
> > > > if not type(interval) in [int, float]:
> > > > raise TypeError('{} is not numeric'.format(interval))
> > > >
> > > > This check is better written:
> > > >
> > > > if not isinstance(interval, (int,float)):
> > > >
> > > > which handles subclasses of these types (but note that bool subclasses
> > > > int :-) normally we don't care), or behaviourally:
> > > >
> > > > try:
> > > > interval = float(interval)
> > > > except ValueError as e:
> > > > raise TypeError(
> > > > "cannot convert %s:%r to float: %s"
> > > > % (type(interval).__name__, interval, e)) from e
> > > >
> > > > which tries to convert to float and fails if that does not work, which
> > > > supports classes with a __float__ method (these classes are rare, but
> > > > decimal.Decimal is one example).
> > >
> > > I think this can be simplified for time intervals to the following:
> > >
> > > if interval <= 0:
> > > raise ValueError(...)
> >
> > That's checking something quite different, though. Casting to float
> > will accept anything that can be, well, cast to float, but checking
> > for less than or equal to zero demands that it already be some sort of
> > number. It's debatable which check is more correct, but certainly this
> > is not a simplification of the other code, it's a distinctly different
> > validation.
>
> Okay, "simplified" isn't quite the right word.  Given two examples (with
> known deficiencies) and no actual use cases or specifications, I added a
> third example, which I believed was simpler (and arguably better in one
> or more ways, which I explained), than the others.

Fair :) I'm unsure which is the best check here, or whether it's worth
having any check at all (you could just let the Timer - or
time.sleep() - do the checks).

> > Strange. The text I get in 3.11.0a1 is fine. But in any case, there's
> > always the docs on the web.
> >
> > https://docs.python.org/3/library/threading.html#timer-objects
>
> help(Timer) is built into my REPL (and likely consumed by development
> systems and IDEs everywhere).  No web necessary.

Agreed, and my primary response is that it's fine in my 3.11, so it's
probably something fixable. The web docs are a good fallback though.

> I've slept in enough programming environments to know better than to
> assume anything.  ;-)

Excellent :)

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Waht do you think about my repeated_timer class

2022-02-02 Thread Cecil Westerhof via Python-list
Chris Angelico  writes:

>> > (Side point: The OP's code is quite inefficient, as it creates a new
>> > thread for each reiteration, but there's nothing wrong with that if
>> > you're looking for something simple.)
>>
>> It is just something I wrote fast. How could I do this in a better way?
>
> I'll answer your question, but first and foremost: Your code was fine,
> and if something does what it's supposed to, that is the most
> important. Everything else is minor.

I like to write efficient code and it never hurts to write better code
as just doing what it is supposed to do. ;-)

And in my case interval is .5 seconds and when someone is going to use
it with an even smaller interval …


> But for other ways to do things, I would recommend creating a single
> thread function and spawning a single thread to run it, and then
> having that function call the target every N seconds. Also, consider

Have to be careful that timing keeps correct when target takes a 'lot'
of time.
Something to ponder about, but can wait.


> subclassing Thread rather than subclassing object (which, btw, is the
> default; you don't need to say "class X(object)"), which will
> automatically give your object all the methods of a timer.

Of-course. I should have thought about that. :'-(

-- 
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Waht do you think about my repeated_timer class

2022-02-02 Thread Chris Angelico
On Thu, 3 Feb 2022 at 15:43, Cecil Westerhof via Python-list
 wrote:
>
> Chris Angelico  writes:
>
> >> > (Side point: The OP's code is quite inefficient, as it creates a new
> >> > thread for each reiteration, but there's nothing wrong with that if
> >> > you're looking for something simple.)
> >>
> >> It is just something I wrote fast. How could I do this in a better way?
> >
> > I'll answer your question, but first and foremost: Your code was fine,
> > and if something does what it's supposed to, that is the most
> > important. Everything else is minor.
>
> I like to write efficient code and it never hurts to write better code
> as just doing what it is supposed to do. ;-)
>
> And in my case interval is .5 seconds and when someone is going to use
> it with an even smaller interval …
>
>
> > But for other ways to do things, I would recommend creating a single
> > thread function and spawning a single thread to run it, and then
> > having that function call the target every N seconds. Also, consider
>
> Have to be careful that timing keeps correct when target takes a 'lot'
> of time.
> Something to ponder about, but can wait.

Ah. In that case, I would recommend a different look at things.
Instead of waiting X time, then firing the event, then waiting X time,
consider instead an interval timer based on monotonic time:

https://docs.python.org/3/library/time.html#time.monotonic

When the timer starts, record the current monotonic time, and sleep
one interval. After the function returns, sleep the remainder of one
interval. It's up to you what happens if you ever find that the next
time point has already passed - do you call the function immediately,
or skip and wait for the next moment?

Interval timers have some complexity to them, but it's worth putting
in the time (pun intended) to figure out how these things work :)

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Waht do you think about my repeated_timer class

2022-02-02 Thread Cecil Westerhof via Python-list
[email protected] writes:

> FWIW, I'd find some way to tell users the units (seconds, milliseconds,
> fortnights, etc.) instead of making them wade through your code to find
> the call to (and possibly the [broken] help text of) Timer.

You mean with docstring?

-- 
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Waht do you think about my repeated_timer class

2022-02-02 Thread Cecil Westerhof via Python-list
Cecil Westerhof  writes:

> I need (sometimes) to repeatedly execute a function. For this I wrote
> the below class. What do you think about it?

I wrote some unit test for the class. Is this the correct way to do
this?
For example in test_correct_params_no_start I check four things. Some
people say you should not check more as one.

By the way it was good that I defined __enter__ and __exit__. :-D


#!/usr/bin/env python3



import unittest

from threading  import Timer



from repeated_timer import repeated_timer


class test_repeated_timer(unittest.TestCase):
   def test_interval_zero(self):
  with self.assertRaises(ValueError):
  rt = repeated_timer(dummy_fn, 0)

   def test_interval_negative(self):
  with self.assertRaises(ValueError):
  rt = repeated_timer(dummy_fn, -1)

   def test_interval_string(self):
  with self.assertRaises(TypeError):
  rt = repeated_timer(dummy_fn, '.4')

   def test_non_function(self):
  with self.assertRaises(TypeError):
  rt = repeated_timer('dummy_fn', .5)

   def test_correct_params_no_start(self):
   rt = repeated_timer(dummy_fn, .5)
   self.assertEqual(rt._fn,   dummy_fn)
   self.assertEqual(rt._interval, .5)
   self.assertEqual(rt._timer,None)
   self.assertFalse(rt._is_running)

   def test_correct_params_do_start(self):
   with repeated_timer(dummy_fn, .375, True) as rt:
   self.assertEqual(rt._fn,   dummy_fn)
   self.assertEqual(rt._interval, .375)
   self.assertTrue (isinstance(rt._timer, Timer), 'There should be 
a timer')
   self.assertTrue (rt._is_running,   'Should be 
running')

   def test__start_later(self):
   with repeated_timer(dummy_fn, .5) as rt:
   self.assertEqual(rt._fn,   dummy_fn)
   self.assertEqual(rt._interval, .5)
   self.assertEqual(rt._timer,None)
   self.assertFalse(rt._is_running)
   rt.start()
   self.assertEqual(rt._fn,   dummy_fn)
   self.assertEqual(rt._interval, .5)
   self.assertTrue (isinstance(rt._timer, Timer), 'There should be 
a timer')
   self.assertTrue (rt._is_running,   'Should be 
running')



def dummy_fn():
pass



if __name__ == '__main__':
unittest.main()


> from threading  import Timer
>
>
>
> class repeated_timer(object):
> def __init__(self, fn, interval, start = False):
> if not callable(fn):
> raise TypeError('{} is not a function'.format(fn))
> self._fn = fn
> self._check_interval(interval)
> self._interval   = interval
> self._timer  = None
> self._is_running = False
> if start:
> self.start()
>
> def _check_interval(self, interval):
> if not type(interval) in [int, float]:
> raise TypeError('{} is not numeric'.format(interval))
> if interval <= 0:
> raise ValueError('{} is not greater as 0'.format(interval))
>
> def _next(self):
> self._timer = Timer(self._interval, self._run)
> self._timer.start()
>
> def _run(self):
> self._next()
> self._fn()
>
> def set_interval(self, interval):
> self._check_interval(interval)
> self._interval = interval
>
> def start(self):
> if not self._is_running:
> self._next()
> self._is_running = True
>
> def stop(self):
> if self._is_running:
> self._timer.cancel()
> self._timer  = None
> self._is_running = False

-- 
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Waht do you think about my repeated_timer class

2022-02-02 Thread Cecil Westerhof via Python-list
Chris Angelico  writes:

> On Thu, 3 Feb 2022 at 15:43, Cecil Westerhof via Python-list
>  wrote:
>>
>> Chris Angelico  writes:
>>
>> >> > (Side point: The OP's code is quite inefficient, as it creates a new
>> >> > thread for each reiteration, but there's nothing wrong with that if
>> >> > you're looking for something simple.)
>> >>
>> >> It is just something I wrote fast. How could I do this in a better way?
>> >
>> > I'll answer your question, but first and foremost: Your code was fine,
>> > and if something does what it's supposed to, that is the most
>> > important. Everything else is minor.
>>
>> I like to write efficient code and it never hurts to write better code
>> as just doing what it is supposed to do. ;-)
>>
>> And in my case interval is .5 seconds and when someone is going to use
>> it with an even smaller interval …
>>
>>
>> > But for other ways to do things, I would recommend creating a single
>> > thread function and spawning a single thread to run it, and then
>> > having that function call the target every N seconds. Also, consider
>>
>> Have to be careful that timing keeps correct when target takes a 'lot'
>> of time.
>> Something to ponder about, but can wait.
>
> Ah. In that case, I would recommend a different look at things.
> Instead of waiting X time, then firing the event, then waiting X time,
> consider instead an interval timer based on monotonic time:
>
> https://docs.python.org/3/library/time.html#time.monotonic
>
> When the timer starts, record the current monotonic time, and sleep
> one interval. After the function returns, sleep the remainder of one
> interval. It's up to you what happens if you ever find that the next
> time point has already passed - do you call the function immediately,
> or skip and wait for the next moment?
>
> Interval timers have some complexity to them, but it's worth putting
> in the time (pun intended) to figure out how these things work :)

I will look into it.

-- 
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof
-- 
https://mail.python.org/mailman/listinfo/python-list