From PythonList at DancesWithMice.info Wed Aug 2 18:14:56 2023 From: PythonList at DancesWithMice.info (dn) Date: Thu, 3 Aug 2023 10:14:56 +1200 Subject: isinstance() Message-ID: Can you please explain why a multi-part second-argument must be a tuple and not any other form of collection-type? The signature is: isinstance(object, classinfo) leading to "classinfo" of: 1/ a single class/type, eg int 2/ a tuple of same, eg ( int, str, ) 3/ a union type, eg int | str (v3.10+) A question was asked about this at last night's PUG-meeting. The person was using the union option, but from Python v3.8. Sorting that out, he replaced the union with a list. No-go! Before correcting to a tuple... Why does the second argument need to be a tuple, given that any series of non-keyword arguments is a tuple; and that such a tuple will still need to be delimited by parentheses. In other words, other forms of delimiter/collection, eg list and set; being a series of elements/members would seem no different. Yes, the underlying C operation appears to only accept a single argument (am not C-soned, mea culpa!). There is some discussion about hashability, but isn't it coincidental rather than constructive? (again, maybe I've not understood...) Enquiring minds want to know... Web.Refs: https://docs.python.org/3/library/functions.html?highlight=isinstance#isinstance https://docs.python.org/3/c-api/object.html?highlight=isinstance#c.PyObject_IsInstance https://docs.python.org/3/reference/datamodel.html?highlight=isinstance -- Regards, =dn From cs at cskk.id.au Wed Aug 2 21:14:35 2023 From: cs at cskk.id.au (Cameron Simpson) Date: Thu, 3 Aug 2023 11:14:35 +1000 Subject: isinstance() In-Reply-To: References: Message-ID: On 03Aug2023 10:14, dn wrote: >Can you please explain why a multi-part second-argument must be a >tuple and not any other form of collection-type? > >The signature is: isinstance(object, classinfo) >leading to "classinfo" of: > >1/ a single class/type, eg int >2/ a tuple of same, eg ( int, str, ) >3/ a union type, eg int | str (v3.10+) help(isinstance) (in 3.8) says class_or_tuple. I would speculate that requiring a tuple has two advantages: - it may lend itself to promotion to a set for comparison with the MRO of object (IIRC the "foo in (a,b,c)" is optimised this way also), and this in turn may hint at the Hashable requirement - it is _frugal_ in what we expect there, leaving open a future meaning for something else in that place (for example, isinstance well predates type annotations, and a looser kind of argument might have precluded this new usage) There's similar language in this try/except documentation: file:///Users/cameron/var/doc/python/3.8.0/reference/compound_stmts.html#index-10 For an except clause with an expression, that expression is evaluated, and the clause matches the exception if the resulting object is ?compatible? with the exception. An object is compatible with an exception if it is the class or a base class of the exception object or a tuple containing an item compatible with the exception. To my mind the tuple requirement lends itself to a distinct syntax (the brackets) and frugal use of the meaning of what values can occur there. Cheers, Cameron Simpson From jsf80238 at gmail.com Thu Aug 3 23:34:04 2023 From: jsf80238 at gmail.com (Jason Friedman) Date: Thu, 3 Aug 2023 21:34:04 -0600 Subject: How to find the full class name for a frame Message-ID: import inspect def my_example(arg1, arg2): print(inspect.stack()[0][3]) my_frame = inspect.currentframe() args,_,_,values = inspect.getargvalues(my_frame) args_rendered = [f"{x}: {values[x]}" for x in args] print(args_rendered) my_example("a", 1) The above "works" in the sense it prints what I want, namely the method name (my_example) and the arguments it was called with. My question is: let's say I wanted to add a type hint for my_frame. my_frame: some_class_name = inspect.currentframe() What would I put for some_class_name? "frame" (without quotations) is not recognized, Nor is inspect.frame. From PythonList at DancesWithMice.info Fri Aug 4 01:14:04 2023 From: PythonList at DancesWithMice.info (dn) Date: Fri, 4 Aug 2023 17:14:04 +1200 Subject: How to find the full class name for a frame In-Reply-To: References: Message-ID: <78264357-9277-1394-4239-0ecca17834e1@DancesWithMice.info> On 04/08/2023 15.34, Jason Friedman via Python-list wrote: > import inspect > > def my_example(arg1, arg2): > print(inspect.stack()[0][3]) > my_frame = inspect.currentframe() > args,_,_,values = inspect.getargvalues(my_frame) > args_rendered = [f"{x}: {values[x]}" for x in args] > print(args_rendered) > > my_example("a", 1) > > > The above "works" in the sense it prints what I want, namely the method > name (my_example) and the arguments it was called with. The above didn't 'work' - please copy-paste and ensure that the email-client is respecting indentation. > My question is: let's say I wanted to add a type hint for my_frame. > > my_frame: some_class_name = inspect.currentframe() > > What would I put for some_class_name? > "frame" (without quotations) is not recognized, > Nor is inspect.frame. We know Python code is executed in an execution frame. (https://docs.python.org/3/reference/executionmodel.html?highlight=frame) We are told "Frame objects Frame objects represent execution frames." (https://docs.python.org/3/reference/datamodel.html?highlight=frame). The word "represent" conflicts with the idea of "are". 'Under the hood' inspect calls sys._current_frames() (https://docs.python.org/3/library/sys.html?highlight=frame). That code is: def _getframe(*args, **kwargs): # real signature unknown """ Return a frame object from the call stack. If optional integer depth is given, return the frame object that many calls below the top of the stack. If that is deeper than the call stack, ValueError is raised. The default for depth is zero, returning the frame at the top of the call stack. This function should be used for internal and specialized purposes only. """ pass Which rather suggests that if the sys library doesn't know the signature, then neither typing nor we mere-mortals are going to do so, either. Theory: the concept of a frame does not really exist at the Python-level (remember "represents"). Frames (must) exist at the C-level (https://docs.python.org/3/c-api/frame.html?highlight=frame#c.PyFrameObject) of the virtual-machine - where typing is not a 'thing'. It's an interesting question. Perhaps a better mind than mine can give a better answer? -- Regards, =dn From jsf80238 at gmail.com Fri Aug 4 11:32:40 2023 From: jsf80238 at gmail.com (Jason Friedman) Date: Fri, 4 Aug 2023 09:32:40 -0600 Subject: How to find the full class name for a frame In-Reply-To: <78264357-9277-1394-4239-0ecca17834e1@DancesWithMice.info> References: <78264357-9277-1394-4239-0ecca17834e1@DancesWithMice.info> Message-ID: > My question is: let's say I wanted to add a type hint for my_frame. > > > > my_frame: some_class_name = inspect.currentframe() > > > > What would I put for some_class_name? > > "frame" (without quotations) is not recognized, > > Nor is inspect.frame. > > We know Python code is executed in an execution frame. > (https://docs.python.org/3/reference/executionmodel.html?highlight=frame) > > We are told "Frame objects Frame objects represent execution frames." > (https://docs.python.org/3/reference/datamodel.html?highlight=frame). > The word "represent" conflicts with the idea of "are". > > 'Under the hood' inspect calls sys._current_frames() > (https://docs.python.org/3/library/sys.html?highlight=frame). That code > is: > > def _getframe(*args, **kwargs): # real signature unknown > """ > Return a frame object from the call stack. > > If optional integer depth is given, return the frame object that many > calls below the top of the stack. If that is deeper than the call > stack, ValueError is raised. The default for depth is zero, returning > the frame at the top of the call stack. > > This function should be used for internal and specialized purposes > only. > """ > pass > > Which rather suggests that if the sys library doesn't know the > signature, then neither typing nor we mere-mortals are going to do so, > either. > > > Theory: the concept of a frame does not really exist at the Python-level > (remember "represents"). Frames (must) exist at the C-level > ( > https://docs.python.org/3/c-api/frame.html?highlight=frame#c.PyFrameObject) > > of the virtual-machine - where typing is not a 'thing'. > > > It's an interesting question. Perhaps a better mind than mine can give a > better answer? > > Thank you DN. My ultimate goal is a function I'd put in my main library which other functions could leverage, something like: function_in_another_file(arg): logger.info(my_main_module.render_calling_info(inspect.stack(), inspect.currentframe()) # Now do the work From edmondo.giovannozzi at gmail.com Wed Aug 2 12:54:59 2023 From: edmondo.giovannozzi at gmail.com (Edmondo Giovannozzi) Date: Wed, 2 Aug 2023 09:54:59 -0700 (PDT) Subject: Fallback for operator and other dunder methods In-Reply-To: References: <2D6F0153-5FAE-49A1-A5B0-23CF9AAED4E7@gmail.com> <333FA876-8F7B-42D1-BD5C-6AEB07EE03BB@gmail.com> <9EB0B006-9309-42EE-8D60-A6EF12B0B1BF@gmail.com> Message-ID: Il giorno mercoled? 26 luglio 2023 alle 20:35:53 UTC+2 Dom Grigonis ha scritto: > Tried exactly that and didn?t work. Neither __getattr__, nor __getattribute__ of meta is being invoked. > > On 26 Jul 2023, at 10:01, Chris Angelico via Python-list wrote: > > > > On Wed, 26 Jul 2023 at 16:52, Dom Grigonis wrote: > >> > >> Could you give an example? Something isn?t working for me. > >> > > > > This is a metaclass: > > > > class Meta(type): > > ... > > class Demo(metaclass=Meta): > > ... > > > > In order to catch those kinds of attribute lookups, you'll need the > > metaclass to hook them. And you might need to use __getattribute__ > > rather than __getattr__. However, there may also be some checks that > > simply look for the presence of the attribute (see: slots), so you may > > find that it's even more complicated. It's usually easiest to just > > create the slots you want. > > > > ChrisA > > -- > > https://mail.python.org/mailman/listinfo/python-list For numpy arrays you can find some suggestion at: https://numpy.org/doc/stable/user/basics.dispatch.html From jon+usenet at unequivocal.eu Wed Aug 2 19:38:10 2023 From: jon+usenet at unequivocal.eu (Jon Ribbens) Date: Wed, 2 Aug 2023 23:38:10 -0000 (UTC) Subject: isinstance() References: Message-ID: On 2023-08-02, dn wrote: > Can you please explain why a multi-part second-argument must be a tuple > and not any other form of collection-type? The following comment may hold a clue: if (PyTuple_Check(cls)) { /* Not a general sequence -- that opens up the road to recursion and stack overflow. */ https://github.com/python/cpython/blob/main/Objects/abstract.c#L2684 Plus an almost total lack of demand for change I should think. From dom.grigonis at gmail.com Fri Aug 4 12:07:50 2023 From: dom.grigonis at gmail.com (Dom Grigonis) Date: Fri, 4 Aug 2023 19:07:50 +0300 Subject: Fallback for operator and other dunder methods In-Reply-To: References: <2D6F0153-5FAE-49A1-A5B0-23CF9AAED4E7@gmail.com> <333FA876-8F7B-42D1-BD5C-6AEB07EE03BB@gmail.com> <9EB0B006-9309-42EE-8D60-A6EF12B0B1BF@gmail.com> Message-ID: <3DDEF864-9301-438A-9895-04D8D4A2A614@gmail.com> The issue was more of a wrapping around numpy array. Found the solution already. Unfortunately, there is no equivalent to __getattr__, the only way is to dynamically define them from meta. It seems it?s pretty standard to just have a collection of special method names and using them for similar cases. Well, at least it?s what I got to. __getattr__ feels very hacky for such case, so maybe it?s for the best. > On 2 Aug 2023, at 19:54, Edmondo Giovannozzi via Python-list wrote: > > Il giorno mercoled? 26 luglio 2023 alle 20:35:53 UTC+2 Dom Grigonis ha scritto: >> Tried exactly that and didn?t work. Neither __getattr__, nor __getattribute__ of meta is being invoked. >>> On 26 Jul 2023, at 10:01, Chris Angelico via Python-list > wrote: >>> >>> On Wed, 26 Jul 2023 at 16:52, Dom Grigonis ... at gmail.com > wrote: >>>> >>>> Could you give an example? Something isn?t working for me. >>>> >>> >>> This is a metaclass: >>> >>> class Meta(type): >>> ... >>> class Demo(metaclass=Meta): >>> ... >>> >>> In order to catch those kinds of attribute lookups, you'll need the >>> metaclass to hook them. And you might need to use __getattribute__ >>> rather than __getattr__. However, there may also be some checks that >>> simply look for the presence of the attribute (see: slots), so you may >>> find that it's even more complicated. It's usually easiest to just >>> create the slots you want. >>> >>> ChrisA >>> -- >>> https://mail.python.org/mailman/listinfo/python-list > > > For numpy arrays you can find some suggestion at: > https://numpy.org/doc/stable/user/basics.dispatch.html > -- > https://mail.python.org/mailman/listinfo/python-list From dieter at handshake.de Fri Aug 4 13:41:12 2023 From: dieter at handshake.de (Dieter Maurer) Date: Fri, 4 Aug 2023 19:41:12 +0200 Subject: How to find the full class name for a frame In-Reply-To: References: Message-ID: <25805.14392.436100.67342@ixdm.fritz.box> Jason Friedman wrote at 2023-8-3 21:34 -0600: > ... >my_frame = inspect.currentframe() > ... >My question is: let's say I wanted to add a type hint for my_frame. `my_frame` will be an instance of `Types.FrameType`. From jsf80238 at gmail.com Fri Aug 4 16:38:40 2023 From: jsf80238 at gmail.com (Jason Friedman) Date: Fri, 4 Aug 2023 14:38:40 -0600 Subject: How to find the full class name for a frame In-Reply-To: <25805.14392.436100.67342@ixdm.fritz.box> References: <25805.14392.436100.67342@ixdm.fritz.box> Message-ID: > > Jason Friedman wrote at 2023-8-3 21:34 -0600: > > ... > >my_frame = inspect.currentframe() > > ... > >My question is: let's say I wanted to add a type hint for my_frame. > > `my_frame` will be an instance of `Types.FrameType`. > Confirmed. Thank you! From PythonList at DancesWithMice.info Fri Aug 4 19:07:19 2023 From: PythonList at DancesWithMice.info (dn) Date: Sat, 5 Aug 2023 11:07:19 +1200 Subject: isinstance() In-Reply-To: References: Message-ID: On 03/08/2023 11.38, Jon Ribbens via Python-list wrote: > On 2023-08-02, dn wrote: >> Can you please explain why a multi-part second-argument must be a tuple >> and not any other form of collection-type? > > The following comment may hold a clue: > > if (PyTuple_Check(cls)) { > /* Not a general sequence -- that opens up the road to > recursion and stack overflow. */ > > https://github.com/python/cpython/blob/main/Objects/abstract.c#L2684 > > Plus an almost total lack of demand for change I should think. Thanks for the reference! Am not proposing a change (have learned 'the rule' and accepted life-as-it-is), but was curious about the restriction: why not any (reasonable sequence)? Such pondering continues in my subversive mind, given such thoughts as: - "we're all adults here" (eg frequent justification when arguing about Python not having "private attributes" per-se). So, if we introduce a complexity, on our own heads be it! (hardly likely given that all we are likely to attempt is the application of a simple and short 'list' of [un]acceptable types). NB understood that the quoted-code is applied in many and other 'scalar or tuple' situations. - Python happily enables recursion, which "opens up the road to recursion and stack overflow.". So, why install a 'nanny' to save us from ourselves here? Again: seems on-the-surface that such 'lists' (at the code-line level) will be mono-dimensional 99.9% of the time. NB having said that, the underlying mechanism *is* multi-dimensional: "direct, indirect, or virtual) subclass thereof" (https://docs.python.org/3/library/functions.html#isinstance) Further: the 'rules' say: "classinfo is a tuple of type objects (or recursively, other such tuples)". Thus, can write: >>> target_object = ... >>> inner_tuple = float, complex >>> inner_tuple (, ) >>> isinstance( target_object, ( str, inner_tuple, int, ), ) False I can't say I've ever used such construction in-the-wild - either defining and then using an "inner_tuple", or even nesting. YMMV! Any thoughts? -- Regards, =dn From rosuav at gmail.com Fri Aug 4 19:18:34 2023 From: rosuav at gmail.com (Chris Angelico) Date: Sat, 5 Aug 2023 09:18:34 +1000 Subject: isinstance() In-Reply-To: References: Message-ID: On Sat, 5 Aug 2023 at 09:08, dn via Python-list wrote: > > On 03/08/2023 11.38, Jon Ribbens via Python-list wrote: > > On 2023-08-02, dn wrote: > >> Can you please explain why a multi-part second-argument must be a tuple > >> and not any other form of collection-type? > > > > The following comment may hold a clue: > > > > if (PyTuple_Check(cls)) { > > /* Not a general sequence -- that opens up the road to > > recursion and stack overflow. */ > > > > https://github.com/python/cpython/blob/main/Objects/abstract.c#L2684 > > > > Plus an almost total lack of demand for change I should think. > > Thanks for the reference! > > > Am not proposing a change (have learned 'the rule' and accepted > life-as-it-is), but was curious about the restriction: why not any > (reasonable sequence)? There are quite a few places where the only option is a tuple. >>> "spam".startswith(["sp", "h"]) Traceback (most recent call last): File "", line 1, in TypeError: startswith first arg must be str or a tuple of str, not list >>> try: 1/0 ... except [ValueError, IndexError]: pass ... Traceback (most recent call last): File "", line 1, in ZeroDivisionError: division by zero During handling of the above exception, another exception occurred: Traceback (most recent call last): File "", line 2, in TypeError: catching classes that do not inherit from BaseException is not allowed It simplifies a lot of checks. Either it's a tuple or it's a single thing. A *lot* of values are iterable, but only tuples are tuples. As the C comment notes, this also means you don't have to worry about recursion; otherwise, even core language features like exception handling would have to iterate over a thing while ensuring that they don't get stuck in self-referential objects. (Incidentally, it seems that exception handling doesn't bother with recursion *at all*, and won't catch "(a, (b, c))" - but even if recursion is handled, it can't go infinite, short of some serious messing around in ctypes or the C API.) ChrisA From PythonList at DancesWithMice.info Fri Aug 4 19:35:03 2023 From: PythonList at DancesWithMice.info (dn) Date: Sat, 5 Aug 2023 11:35:03 +1200 Subject: isinstance() In-Reply-To: References: Message-ID: <4cf7e053-95fa-4ece-1a77-3b2b8421a11c@DancesWithMice.info> On 05/08/2023 11.18, Chris Angelico via Python-list wrote: > On Sat, 5 Aug 2023 at 09:08, dn via Python-list wrote: >> >> On 03/08/2023 11.38, Jon Ribbens via Python-list wrote: >>> On 2023-08-02, dn wrote: >>>> Can you please explain why a multi-part second-argument must be a tuple >>>> and not any other form of collection-type? >>> >>> The following comment may hold a clue: >>> >>> if (PyTuple_Check(cls)) { >>> /* Not a general sequence -- that opens up the road to >>> recursion and stack overflow. */ >>> >>> https://github.com/python/cpython/blob/main/Objects/abstract.c#L2684 >>> >>> Plus an almost total lack of demand for change I should think. >> >> Thanks for the reference! >> >> >> Am not proposing a change (have learned 'the rule' and accepted >> life-as-it-is), but was curious about the restriction: why not any >> (reasonable sequence)? > > There are quite a few places where the only option is a tuple. > >>>> "spam".startswith(["sp", "h"]) > Traceback (most recent call last): > File "", line 1, in > TypeError: startswith first arg must be str or a tuple of str, not list >>>> try: 1/0 > ... except [ValueError, IndexError]: pass > ... > Traceback (most recent call last): > File "", line 1, in > ZeroDivisionError: division by zero > > During handling of the above exception, another exception occurred: > > Traceback (most recent call last): > File "", line 2, in > TypeError: catching classes that do not inherit from BaseException is > not allowed > > It simplifies a lot of checks. Either it's a tuple or it's a single > thing. A *lot* of values are iterable, but only tuples are tuples. > > As the C comment notes, this also means you don't have to worry about > recursion; otherwise, even core language features like exception > handling would have to iterate over a thing while ensuring that they > don't get stuck in self-referential objects. (Incidentally, it seems > that exception handling doesn't bother with recursion *at all*, and > won't catch "(a, (b, c))" - but even if recursion is handled, it can't > go infinite, short of some serious messing around in ctypes or the C > API.) Yes. Thanks Chris! The idea that such 'lists' be immutable (even, hashable), and therefore a tuple, makes a certain amount of sense, and @Cameron mentioned 'frugality'. My limitation is thinking only at the Python level (which as @Jon pointed-out, is only part of the story). Faced with a situation where an argument may be a scalar-value or an iterable, I'll presume the latter, eg throw it straight into a for-loop. If that fails (because the argument is a scalar), use try-except to re-route the logic. Alternately, in an OOP situation, utilise polymorphism so that the 'scalar' and 'iterable' instances both include the appropriate method[name]. Accordingly, as long as the argument is an iterable (includes an __iter__() method), the actual type/class is more-or-less irrelevant. However, as observed earlier - and with these additions, having learned the 'rule', ie use a tuple; the brain is still pondering, but have shrugged-shoulders and carried-on regardless... -- -- Regards, =dn From rosuav at gmail.com Fri Aug 4 19:39:16 2023 From: rosuav at gmail.com (Chris Angelico) Date: Sat, 5 Aug 2023 09:39:16 +1000 Subject: isinstance() In-Reply-To: <4cf7e053-95fa-4ece-1a77-3b2b8421a11c@DancesWithMice.info> References: <4cf7e053-95fa-4ece-1a77-3b2b8421a11c@DancesWithMice.info> Message-ID: On Sat, 5 Aug 2023 at 09:36, dn via Python-list wrote: > Faced with a situation where an argument may be a scalar-value or an > iterable, I'll presume the latter, eg throw it straight into a for-loop. > If that fails (because the argument is a scalar), use try-except to > re-route the logic. That's great as long as you aren't expecting to handle strings. The string "spam" is sometimes equivalent to the list ["s", "p", "a", "m"] and sometimes not. ChrisA From grant.b.edwards at gmail.com Fri Aug 4 22:37:37 2023 From: grant.b.edwards at gmail.com (Grant Edwards) Date: Fri, 04 Aug 2023 19:37:37 -0700 (PDT) Subject: isinstance() References: <4cf7e053-95fa-4ece-1a77-3b2b8421a11c@DancesWithMice.info> Message-ID: <64cdb5f1.6b0a0220.e2a02.1c1c@mx.google.com> On 2023-08-04, Chris Angelico via Python-list wrote: > On Sat, 5 Aug 2023 at 09:36, dn via Python-list wrote: > >> Faced with a situation where an argument may be a scalar-value or an >> iterable, I'll presume the latter, eg throw it straight into a for-loop. >> If that fails (because the argument is a scalar), use try-except to >> re-route the logic. > > That's great as long as you aren't expecting to handle strings. If you do that, you're obviously not expecting to handle strings. The problem happens when you're not expecting to handle strings, and you get passed one anyway. It's like the Spanish Inquisition... > The string "spam" is sometimes equivalent to the list ["s", "p", > "a", "m"] and sometimes not. And b"ABCD" is sometimes equivalent to the list [65,66,67,68] and sometimes not. Been there, fell in that hole. More than a few times. :/ Famous Last Words: "I wasn't expecting to handle strings -- but I should have been..." -- Grant From thomas at python.org Sun Aug 6 09:14:21 2023 From: thomas at python.org (Thomas Wouters) Date: Sun, 6 Aug 2023 15:14:21 +0200 Subject: [RELEASE] Python 3.12.0 release candidate 1 released Message-ID: I'm pleased to announce the release of Python 3.12.0rc1: https://www.python.org/downloads/release/python-3120rc1/ This is the first release candidate of Python 3.12.0 This release, *3.12.0rc1*, is the penultimate release preview. Entering the release candidate phase, only reviewed code changes which are clear bug fixes are allowed between this release candidate and the final release. The second candidate (and the last planned release preview) is scheduled for Monday, 2023-09-04, while the official release of 3.12.0 is scheduled for Monday, 2023-10-02. There will be *no ABI changes* from this point forward in the 3.12 series, and the goal is that there will be as few code changes as possible. Call to action We strongly encourage maintainers of third-party Python projects to prepare their projects for 3.12 compatibilities during this phase, and where necessary publish Python 3.12 wheels on PyPI to be ready for the final release of 3.12.0. Any binary wheels built against Python 3.12.0rc1 will work with future versions of Python 3.12. As always, report any issues to the Python bug tracker . Please keep in mind that this is a preview release and while it?s as close to the final release as we can get it, its use is *not* recommended for production environments. Core developers: time to work on documentation now - Are all your changes properly documented? - Are they mentioned in What?s New ? - Did you notice other changes you know of to have insufficient documentation? Major new features of the 3.12 series, compared to 3.11 New features - More flexible f-string parsing , allowing many things previously disallowed (PEP 701 ). - Support for the buffer protocol in Python code (PEP 688 ). - A new debugging/profiling API (PEP 669 ). - Support for isolated subinterpreters with separate Global Interpreter Locks (PEP 684 ). - Even more improved error messages . More exceptions potentially caused by typos now make suggestions to the user. - Support for the Linux perf profiler to report Python function names in traces. - Many large and small performance improvements (like PEP 709 ), delivering an estimated 5% overall performance improvementcitation needed. Type annotations - New type annotation syntax for generic classes (PEP 695 ). - New override decorator for methods (PEP 698 ). Deprecations - The deprecated wstr and wstr_length members of the C implementation of unicode objects were removed, per PEP 623 . - In the unittest module, a number of long deprecated methods and classes were removed. (They had been deprecated since Python 3.1 or 3.2). - The deprecated smtpd and distutils modules have been removed (see PEP 594 and PEP 632 . The setuptools package continues to provide the distutils module. - A number of other old, broken and deprecated functions, classes and methods have been removed. - Invalid backslash escape sequences in strings now warn with SyntaxWarning instead of DeprecationWarning, making them more visible. (They will become syntax errors in the future.) - The internal representation of integers has changed in preparation for performance enhancements. (This should not affect most users as it is an internal detail, but it may cause problems for Cython-generated code.) (Hey, *fellow core developer,* if a feature you find important is missing from this list, let Thomas know .) For more details on the changes to Python 3.12, see What?s new in Python 3.12 . The next pre-release of Python 3.12 will be 3.12.0rc2, the *final release candidate*, currently scheduled for 2023-09-04. More resources - Online Documentation . - PEP 693 , the Python 3.12 Release Schedule. - Report bugs via GitHub Issues . - Help fund Python and its community . We hope you enjoy the new releases! Thanks to all of the many volunteers who help make Python Development and these releases possible! Please consider supporting our efforts by volunteering yourself or through organization contributions to the Python Software Foundation . Your release team, Thomas Wouters Ned Deily Steve Dower ?ukasz Langa -- Thomas Wouters From hjp-python at hjp.at Sun Aug 6 16:41:51 2023 From: hjp-python at hjp.at (Peter J. Holzer) Date: Sun, 6 Aug 2023 22:41:51 +0200 Subject: Where is the error? Message-ID: <20230806204151.rvaspz6iu4w3w5db@hjp.at> Mostly, error messages got a lot better in Python 3.10, but this one had me scratching my head for a few minutes. Consider this useless and faulty script: ------------------------------------------------------------------------ r = { "x": (1 + 2 + 3) "y": (4 + 5 + 6) "z": (7 + 8 + 9) } ------------------------------------------------------------------------ Python 3.9 (and earlier) reports: ------------------------------------------------------------------------ File "/home/hjp/tmp/foo", line 3 "y": (4 + 5 + 6) ^ SyntaxError: invalid syntax ------------------------------------------------------------------------ This isn't great, but experience with lots of programming languages tells me that an error is noticed where or after it actually occurs, so it's easy to see that there is a comma missing just before the "y". Python 3.10 and 3.11 report: ------------------------------------------------------------------------ File "/home/hjp/tmp/foo", line 2 "x": (1 + 2 + 3) ^^^^^^^^^^ SyntaxError: invalid syntax. Perhaps you forgot a comma? ------------------------------------------------------------------------ The error message is now a lot better, of course, but the fact that it points at the expression *before* the error completely threw me. The underlined expression is clearly not missing a comma, nor is there an error before that. My real program was a bit longer of course, so I checked the lines before that to see if I forgot to close any parentheses. Took me some time to notice the missing comma *after* the underlined expression. Is this "clairvoyant" behaviour a side-effect of the new parser or was that a deliberate decision? hp -- _ | Peter J. Holzer | Story must make more sense than reality. |_|_) | | | | | hjp at hjp.at | -- Charles Stross, "Creative writing __/ | http://www.hjp.at/ | challenge!" -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 833 bytes Desc: not available URL: From PythonList at DancesWithMice.info Sun Aug 6 20:18:23 2023 From: PythonList at DancesWithMice.info (dn) Date: Mon, 7 Aug 2023 12:18:23 +1200 Subject: Where is the error? In-Reply-To: <20230806204151.rvaspz6iu4w3w5db@hjp.at> References: <20230806204151.rvaspz6iu4w3w5db@hjp.at> Message-ID: <11f7fbdc-dbd2-1249-40cd-e07777bf16fe@DancesWithMice.info> On 07/08/2023 08.41, Peter J. Holzer via Python-list wrote: > Mostly, error messages got a lot better in Python 3.10, but this one had > me scratching my head for a few minutes. ... > > The error message is now a lot better, of course, but the fact that it > points at the expression *before* the error completely threw me. The > underlined expression is clearly not missing a comma, nor is there an > error before that. My real program was a bit longer of course, so I > checked the lines before that to see if I forgot to close any > parentheses. Took me some time to notice the missing comma *after* the > underlined expression. > > Is this "clairvoyant" behaviour a side-effect of the new parser or was > that a deliberate decision? Found myself chuckling at this - not to be unkind, but because can easily imagine such confusion on my own part. The issue of unhelpful error messages or information aimed at a similar but different context, has been the story of our lives. Advice to trainees has always been to cast-about looking for the error - rather than taking the line-number as a precise location. Have made a note to avoid advising folk to work 'backwards'! Meantime (back at the ranch?), haven't experienced this. Using an IDE means all such stuff is reported, as one types, through highlights and squiggly lines (which should(?) be considered and cleared - before pressing the GO-button). In this case, the PyCharm* editor adds red-squiggles where the commas should have been. Hovering the cursor over a squiggle, the IDE reports "',' expected"! Its PythonConsole behaves similarly (without offering a 'hover'). Plus, even after the closing brace, it continues to assume a multi-line compound-statement (and thus won't execute, per expected REPL behavior). Way-back (grey-beard time!) when we submitted card-decks of code to be compiled over-night, one idea to avoid expensive, trivial errors/eras; was that spelling-checkers should be built-in to compilers, eg to auto-magically correct typos, eg AFF 1 TO TOTAL instead of: ADD 1 TO TOTAL These days, we can look at code from two or more years ago, 'produced' by ChatGPT (et al), aka "The Stochastic Parrot". There is some thought that artificial 'intelligence' will one-day be able to do the coding for us/predict what is required/act as a crystal ball... Speaking of which, and just because I could, here's what Chat-GPT had to say when I asked "what's wrong with ...": ?The issue in the given Python code is that you're missing commas between the key-value pairs in the dictionary. Commas are required to separate different key-value pairs within a dictionary. Here's the corrected version of the code: ... ? Question: If a Chat-AI is built into the IDE (I stripped such out from mine), does it take-over error reporting and diagnosis (and offer the option of replacing with its 'corrected version'?) - rather than requiring an extra copy-paste step, per above? (and need for my assumption of where the error is located) Hope you've exerted copyright over the "clairvoyant" description! * JetBrains kindly sponsor our PUG with a monthly door-prize. -- -- Regards, =dn From cs at cskk.id.au Mon Aug 7 00:04:59 2023 From: cs at cskk.id.au (Cameron Simpson) Date: Mon, 7 Aug 2023 14:04:59 +1000 Subject: Where is the error? In-Reply-To: <20230806204151.rvaspz6iu4w3w5db@hjp.at> References: <20230806204151.rvaspz6iu4w3w5db@hjp.at> Message-ID: On 06Aug2023 22:41, Peter J. Holzer wrote: >Mostly, error messages got a lot better in Python 3.10, but this one had >me scratching my head for a few minutes. > >Consider this useless and faulty script: >------------------------------------------------------------------------ >r = { > "x": (1 + 2 + 3) > "y": (4 + 5 + 6) > "z": (7 + 8 + 9) >} >------------------------------------------------------------------------ [...] >Python 3.10 and 3.11 report: > >------------------------------------------------------------------------ > File "/home/hjp/tmp/foo", line 2 > "x": (1 + 2 + 3) > ^^^^^^^^^^ >SyntaxError: invalid syntax. Perhaps you forgot a comma? >------------------------------------------------------------------------ > >The error message is now a lot better, of course, but the fact that it >points at the expression *before* the error completely threw me. The >underlined expression is clearly not missing a comma, nor is there an >error before that. Well, it's hard to underline a token which isn't present. But maybe the message could be more evocative: SyntaxError: invalid syntax. Perhaps you forgot a comma after the underlined code? >Is this "clairvoyant" behaviour a side-effect of the new parser or was >that a deliberate decision? I have the vague impression the new parser enabled the improved reporting. Used to use a Pascal compiler once which was uncannily good at suggesting where you'd missing a semicolon. Cheers, Cameron Simpson From barry at barrys-emacs.org Mon Aug 7 03:02:40 2023 From: barry at barrys-emacs.org (Barry) Date: Mon, 7 Aug 2023 08:02:40 +0100 Subject: Where is the error? In-Reply-To: References: Message-ID: <6F59360C-082F-4F94-8266-EF66EC9C5F36@barrys-emacs.org> > On 7 Aug 2023, at 05:28, Cameron Simpson via Python-list wrote: > > Used to use a Pascal compiler once which was uncannily good at suggesting where you'd missing a semicolon. Was that on DEC VMS? It was a goal at DEC for its compilers to do this well. They could output the errors in a machine readable format to allow editors to auto fix. I am learning rust and it is very good at suggesting fixes. There is a command to apply fixes automatically, cargo fix. Barry From cs at cskk.id.au Mon Aug 7 05:08:00 2023 From: cs at cskk.id.au (Cameron Simpson) Date: Mon, 7 Aug 2023 19:08:00 +1000 Subject: Where is the error? In-Reply-To: <6F59360C-082F-4F94-8266-EF66EC9C5F36@barrys-emacs.org> References: <6F59360C-082F-4F94-8266-EF66EC9C5F36@barrys-emacs.org> Message-ID: On 07Aug2023 08:02, Barry wrote: >> On 7 Aug 2023, at 05:28, Cameron Simpson via Python-list wrote: >> Used to use a Pascal compiler once which was uncannily good at >> suggesting where you'd missing a semicolon. > >Was that on DEC VMS? It was a goal at DEC for its compilers to do this well. No, a PDP-11 using V7 UNIX. >They could output the errors in a machine readable format to allow editors to auto fix. >I am learning rust and it is very good at suggesting fixes. >There is a command to apply fixes automatically, cargo fix. Neat. Cheers, Cameron Simpson From agbenikemichael at gmail.com Sun Aug 6 16:59:09 2023 From: agbenikemichael at gmail.com (Michael Agbenike) Date: Sun, 6 Aug 2023 15:59:09 -0500 Subject: Where is the error? In-Reply-To: <20230806204151.rvaspz6iu4w3w5db@hjp.at> References: <20230806204151.rvaspz6iu4w3w5db@hjp.at> Message-ID: When i try to open a python script it either says theres no ctk module or no pip On Sun, Aug 6, 2023, 3:51 PM Peter J. Holzer via Python-list < python-list at python.org> wrote: > Mostly, error messages got a lot better in Python 3.10, but this one had > me scratching my head for a few minutes. > > Consider this useless and faulty script: > > ------------------------------------------------------------------------ > r = { > "x": (1 + 2 + 3) > "y": (4 + 5 + 6) > "z": (7 + 8 + 9) > } > ------------------------------------------------------------------------ > > Python 3.9 (and earlier) reports: > > ------------------------------------------------------------------------ > File "/home/hjp/tmp/foo", line 3 > "y": (4 + 5 + 6) > ^ > SyntaxError: invalid syntax > ------------------------------------------------------------------------ > > This isn't great, but experience with lots of programming languages > tells me that an error is noticed where or after it actually occurs, so > it's easy to see that there is a comma missing just before the "y". > > Python 3.10 and 3.11 report: > > ------------------------------------------------------------------------ > File "/home/hjp/tmp/foo", line 2 > "x": (1 + 2 + 3) > ^^^^^^^^^^ > SyntaxError: invalid syntax. Perhaps you forgot a comma? > ------------------------------------------------------------------------ > > The error message is now a lot better, of course, but the fact that it > points at the expression *before* the error completely threw me. The > underlined expression is clearly not missing a comma, nor is there an > error before that. My real program was a bit longer of course, so I > checked the lines before that to see if I forgot to close any > parentheses. Took me some time to notice the missing comma *after* the > underlined expression. > > Is this "clairvoyant" behaviour a side-effect of the new parser or was > that a deliberate decision? > > hp > > -- > _ | Peter J. Holzer | Story must make more sense than reality. > |_|_) | | > | | | hjp at hjp.at | -- Charles Stross, "Creative writing > __/ | http://www.hjp.at/ | challenge!" > -- > https://mail.python.org/mailman/listinfo/python-list > From phd at phdru.name Tue Aug 8 14:11:22 2023 From: phd at phdru.name (Oleg Broytman) Date: Tue, 8 Aug 2023 21:11:22 +0300 Subject: Cheetah 3.3.2 Message-ID: Hello! I'm pleased to announce version 3.3.2, the 2nd bug-fix of branch 3.3 of CheetahTemplate3. What's new in CheetahTemplate3 ============================== The contributor for this release is nate.k. Thanks! Bug fixes: - Fixed printing to stdout in ``CheetahWrapper``. CI: - CI(GHActions): Install all Python and PyPy versions from ``conda-forge``. What is CheetahTemplate3 ======================== Cheetah3 is a free and open source (MIT) Python template engine. It's a fork of the original CheetahTemplate library. Python 2.7 or 3.4+ is required. Where is CheetahTemplate3 ========================= Site: https://cheetahtemplate.org/ Download: https://pypi.org/project/CT3/3.3.2 News and changes: https://cheetahtemplate.org/news.html StackOverflow: https://stackoverflow.com/questions/tagged/cheetah Mailing lists: https://sourceforge.net/p/cheetahtemplate/mailman/ Development: https://github.com/CheetahTemplate3 Developer Guide: https://cheetahtemplate.org/dev_guide/ Example ======= Install:: $ pip install CT3 # (or even "ct3") Below is a simple example of some Cheetah code, as you can see it's practically Python. You can import, inherit and define methods just like in a regular Python module, since that's what your Cheetah templates are compiled to :) :: #from Cheetah.Template import Template #extends Template #set $people = [{'name' : 'Tom', 'mood' : 'Happy'}, {'name' : 'Dick', 'mood' : 'Sad'}, {'name' : 'Harry', 'mood' : 'Hairy'}] How are you feeling?
    #for $person in $people
  • $person['name'] is $person['mood']
  • #end for
Oleg. -- Oleg Broytman https://phdru.name/ phd at phdru.name Programmers don't die, they just GOSUB without RETURN. From PythonList at DancesWithMice.info Tue Aug 8 19:26:52 2023 From: PythonList at DancesWithMice.info (dn) Date: Wed, 9 Aug 2023 11:26:52 +1200 Subject: Mtg ANN: Using computer vision AI to help protect the worlds rarest dolphin Message-ID: <38405e40-ec6d-b932-ee24-b7366a13d710@DancesWithMice.info> Wed 16 Aug 2023, 1800~20:30 NZST (0600~0830 UTC, late-Tue in US) Details and RSVP at https://www.meetup.com/nzpug-auckland/events/295091858/ Teaching a computer to see. How computer vision is helping to protect the world?s rarest dolphin and how you can train your own model. Tane van der Boon will talk about the MAUI63 project, and then lead us through how to train and utilise a custom computer vision object detector. Essentially allowing our software to be able to see. MAUI63 was given its name because when the venture began, there were only 63 M?ui dolphins left in existence. Using drone technology and AI to collect and process visual data, the founders took action to collect data to help save the world?s rarest dolphin from extinction and influence future marine conservation efforts. The MAUI63 team uses a customised drone to find and track the movement of dolphins, and enables individual dolphins to be identified through their fin markings. The information collected can then be used to inform better data driven decisions on how best to protect them. Later, Tane will lead us through a smaller task to build our own image recognizer. (more details in due course...) The Auckland Branch of the New Zealand Python Users' Group meet twice monthly. You're very welcome to attend online or in-person (as available). Meeting location-details or URL will be sent to those who RSVP. We are a healthy mix of Python users. Students, academics, hobbyists, industry professionals, and many completely new to Python. The "room" opens at 1800 (local time) with an opportunity to network with colleagues. Everything should be wrapped up by 2030. We are always keen to hear suggestions for meeting-topics, and to meet with folk who'd like to present or lead - eg a brief lightning talk, a practical coaching-session, a full lecture... Help is available if you've never done such a thing before! We follow the NZPUG Code of Conduct (https://python.nz/code-of-conduct) to create an inclusive and friendly environment. We express thanks to, and encourage you to investigate, our sponsors: Catalyst Cloud, New Zealand Open Source Society, JetBrains, and IceHouse Ventures. -- Regards =dn -- Regards, =dn From wilberhdez at gmail.com Tue Aug 8 22:28:43 2023 From: wilberhdez at gmail.com (Wilber H) Date: Tue, 8 Aug 2023 22:28:43 -0400 Subject: Planning a Python / PyData conference Message-ID: Hi, I would like to plan a Python / PyData conference in the country of the Dominican Republic, and would like your feedback on how to best plan for the conference. Regards, Wilber Hernandez 1-201-220-7082 From PythonList at DancesWithMice.info Wed Aug 9 01:06:47 2023 From: PythonList at DancesWithMice.info (dn) Date: Wed, 9 Aug 2023 17:06:47 +1200 Subject: Planning a Python / PyData conference In-Reply-To: References: Message-ID: <833b6b19-74aa-5f1d-3c0a-344bee87c386@DancesWithMice.info> Hi Wilber, On 09/08/2023 14.28, Wilber H via Python-list wrote: > Hi, > > I would like to plan a Python / PyData conference in the country of the > Dominican Republic, and would like your feedback on how to best plan > for the conference. Recommend making your request of the folks who organise EuroPython and/or PyConUS - and then same for smaller gatherings. (would suggest to ours, but those folk are already over-loaded to be ready in a few weeks' time) -- Regards, =dn From miked at dewhirst.com.au Wed Aug 9 01:58:32 2023 From: miked at dewhirst.com.au (Mike Dewhirst) Date: Wed, 9 Aug 2023 15:58:32 +1000 Subject: zoneinfo and tzdata Message-ID: <216fb9f2-413c-df1b-4d07-771fb4ccafea@dewhirst.com.au> The zoneinfo module does not work on Windows unless you have installed tzdata. On Ubuntu that data seems to exist already. Not sure how or why but it obviously isn't there in a Windows virtualenv unless deliberately installed. I just spent a bit of time trying to switch from pytz to zoneinfo in Django without luck. I then asked and greatly embarrassed ChatGPT which kept apologizing when I fed back all the zoneinfo errors its advice caused. It wasn't until I read the docs that I saw zoneinfo would get timezone data from tzdata if the real info wasn't where it first looked. As soon as I installed tzdata, ChatGPT's advice started to work. When I reported this, it was very grateful and assured me my generosity in bothering to correct it would be very beneficial for other users having similar problems. Might I suggest that if zoneinfo comes up empty-handed it should raise an error saying no timezone information was found? Currently, it just nominates the timezone key you attempt to use. Behind the scenes it surely knows there are no such keys. In that case it might suggest installing tzdata. Cheers Mike From phd at phdru.name Wed Aug 9 08:19:08 2023 From: phd at phdru.name (Oleg Broytman) Date: Wed, 9 Aug 2023 15:19:08 +0300 Subject: SQLObject 3.10.2 Message-ID: Hello! I'm pleased to announce version 3.10.2, a minor feature release and the second bugfix release of branch 3.10 of SQLObject. What's new in SQLObject ======================= The contributor for this release is Igor Yudytskiy. Thanks! Minor features -------------- * Class ``Alias`` grows a method ``.select()`` to match ``SQLObject.select()``. Bug fixes --------- * Fixed a bug in ``SQLRelatedJoin`` in the case where the table joins with itself; in the resulting SQL two instances of the table must use different aliases. Thanks to Igor Yudytskiy for providing an elaborated bug report. For a more complete list, please see the news: http://sqlobject.org/News.html What is SQLObject ================= SQLObject is a free and open-source (LGPL) Python object-relational mapper. Your database tables are described as classes, and rows are instances of those classes. SQLObject is meant to be easy to use and quick to get started with. SQLObject supports a number of backends: MySQL/MariaDB (with a number of DB API drivers: ``MySQLdb``, ``mysqlclient``, ``mysql-connector``, ``PyMySQL``, ``mariadb``), PostgreSQL (``psycopg2``, ``PyGreSQL``, partially ``pg8000`` and ``py-postgresql``), SQLite (builtin ``sqlite``, ``pysqlite``, partially ``supersqlite``); connections to other backends - Firebird, Sybase, MSSQL and MaxDB (also known as SAPDB) - are less debugged). Python 2.7 or 3.4+ is required. Where is SQLObject ================== Site: http://sqlobject.org Download: https://pypi.org/project/SQLObject/3.10.2a0.dev20221222/ News and changes: http://sqlobject.org/News.html StackOverflow: https://stackoverflow.com/questions/tagged/sqlobject Mailing lists: https://sourceforge.net/p/sqlobject/mailman/ Development: http://sqlobject.org/devel/ Developer Guide: http://sqlobject.org/DeveloperGuide.html Example ======= Install:: $ pip install sqlobject Create a simple class that wraps a table:: >>> from sqlobject import * >>> >>> sqlhub.processConnection = connectionForURI('sqlite:/:memory:') >>> >>> class Person(SQLObject): ... fname = StringCol() ... mi = StringCol(length=1, default=None) ... lname = StringCol() ... >>> Person.createTable() Use the object:: >>> p = Person(fname="John", lname="Doe") >>> p >>> p.fname 'John' >>> p.mi = 'Q' >>> p2 = Person.get(1) >>> p2 >>> p is p2 True Queries:: >>> p3 = Person.selectBy(lname="Doe")[0] >>> p3 >>> pc = Person.select(Person.q.lname=="Doe").count() >>> pc 1 Oleg. -- Oleg Broytman https://phdru.name/ phd at phdru.name Programmers don't die, they just GOSUB without RETURN. From oliver+python at schinagl.nl Wed Aug 9 06:30:51 2023 From: oliver+python at schinagl.nl (Oliver Schinagl) Date: Wed, 9 Aug 2023 12:30:51 +0200 Subject: Imports and dot-notation Message-ID: <5f4f8962-08e6-ed0a-8c44-e83a2b10e0ba@schinagl.nl> Dear list, First a disclaimer, I am a python novice ;) so apologies beforehand for any incorrect terms and use thereof :) I have a question about the preferred/pythonic way dealing with imports. But let me start by giving a little bit of an example (which lead me to this question). Looking at a python projects code and repository layout, we see the following directory structure. /project/core /project/components/module1 ... /project/components/moduleN /projects/util (this is far from complete, but enough to help paint a picture. Some modules import other modules, and I see (at the very least) two (kind of three?) different ways of doing so. `from project.components.module1 import function1, function2 as func, CONST1, CONST2 as CONST` or maybe even (which has as an advantage that it becomes clear which namespace something belongs to `from project.components.module1 import function1, function2 as module1_function2, CONST1, CONST2 as MODULE1_CONST2` but then it really just becomes personal preference, as the number of characters saved on typing is almost negative (due to having a more complex import). but also the dot notation being used `from project.components import module1` where obviously the functions are invoked as `module1.function1` etc I hope the above is clear enough from an example. Simply put, which of the two would be considered cleaner and more pythonic? Now for a bit more thought, looking at PEP8, we notes about imports, but sadly PEP8 does not state which method is better/preferred. While obviously in the end, it's always the maintainers choice in what they prefer, so are tabs vs spaces and PEP8 is opinionated about that too (in a good way, even though I'm not a fan :p). Likewise, if we look at PEP20, there's quite a few 'guidelines' that suggest the dot-notation. To name a few (opinionated) examples (but note I am just using PEP20 as a helper to give some arguments, I know some people feel strongly against pep20 :p): * Beautiful is better than ugly. ? - Personally, I think the dot notation is more beautiful, but I understand that some people find the short notation more beautiful and less of an eye sore ;) * Explicit is better than implicit. ? - To me, this is a strong point. Being more explicit is always better, using the dot notation (if though it's not doing the WHOLE path) is a nice balance in being explicit enough. Code readability comes from being more explicit (without being to terse of course). * Simple is better than complex. * Flat is better than nested. ? -? I think having more flat and simple imports, and (while more characters to potentially type in the invocation) more readable invocations would be better? * Readability counts. ? - The dot notation seems to help in readability. For those unfamiliar (or less familiar) with a code base, it becomes incredibly clear where a something comes from (WITHOUT having to rely on IDE's; sure you can hover over something and see that the IDE has hopefully worked out where something came from, but this doesn't work when just reading a page of code, you aren't going to hover over everything and remember all that context). * In the face of ambiguity, refuse the temptation to guess. ? - I'd argue this is almost self-explanatory, not using dot-notation makes it more ambiguous where something is coming from. * There should be one-- and preferably only one --obvious way to do it. ? - This is where my confusion/question obviously comes from, as there's multiple ways of doing it, so maybe PEP8 (or a new one) should more strongly favor one? * Namespaces are one honking great idea -- let's do more of those! ? - Basically, this question/proposal would 'force/nudge' you into writing more with namespaces by using the namespace as prefix. So what IS the preferred/more pythonic/recommended way to deal with imports? Why was this not mentioned in PEP8? Is it worth while to introduce a new PEP or amend PEP8? For what it's worth, hallucinating chatgpt/google bard both say the same about this topic, that within the python community, it is generally preferred and a good idea to use dot-notation. But how correct are they lol. Thank you for reading, Olliver From estates at hestates.org Wed Aug 9 14:14:23 2023 From: estates at hestates.org (Fulian Wang) Date: Wed, 9 Aug 2023 18:14:23 +0000 Subject: Planning a Python / PyData conference In-Reply-To: <833b6b19-74aa-5f1d-3c0a-344bee87c386@DancesWithMice.info> References: <833b6b19-74aa-5f1d-3c0a-344bee87c386@DancesWithMice.info> Message-ID: I recommend Sichuan ,Taiwan , or Thailand Get Outlook for iOS ________________________________ From: Python-list on behalf of dn via Python-list Sent: Wednesday, August 9, 2023 00:10 To: python-list at python.org Subject: Re: Planning a Python / PyData conference Hi Wilber, On 09/08/2023 14.28, Wilber H via Python-list wrote: > Hi, > > I would like to plan a Python / PyData conference in the country of the > Dominican Republic, and would like your feedback on how to best plan > for the conference. Recommend making your request of the folks who organise EuroPython and/or PyConUS - and then same for smaller gatherings. (would suggest to ours, but those folk are already over-loaded to be ready in a few weeks' time) -- Regards, =dn -- https://mail.python.org/mailman/listinfo/python-list From PythonList at DancesWithMice.info Wed Aug 9 19:28:36 2023 From: PythonList at DancesWithMice.info (dn) Date: Thu, 10 Aug 2023 11:28:36 +1200 Subject: Imports and dot-notation In-Reply-To: <5f4f8962-08e6-ed0a-8c44-e83a2b10e0ba@schinagl.nl> References: <5f4f8962-08e6-ed0a-8c44-e83a2b10e0ba@schinagl.nl> Message-ID: <749cae90-dc17-7f4a-2c03-b87394134d28@DancesWithMice.info> On 09/08/2023 22.30, Oliver Schinagl via Python-list wrote: ...> Looking at a python projects code and repository layout, we see the > following directory structure. > > /project/core > /project/components/module1 > ... > /project/components/moduleN > /projects/util ...> Some modules import other modules, and I see (at the very least) two > (kind of three?) different ways of doing so. > > `from project.components.module1 import function1, function2 as func, > CONST1, CONST2 as CONST` > > or maybe even (which has as an advantage that it becomes clear which > namespace something belongs to > > `from project.components.module1 import function1, function2 as > module1_function2, CONST1, CONST2 as MODULE1_CONST2` > > but then it really just becomes personal preference, as the number of > characters saved on typing is almost negative (due to having a more > complex import). > > but also the dot notation being used > > `from project.components import module1` > > where obviously the functions are invoked as `module1.function1` etc Firstly, the path followed will depend upon the starting position! Keep reading and you should come across a reference to 'hobgoblin of little minds'. What should we be concentrating on/about? If 'naming' is a great (?the greatest) challenge of programming, surely remembering the names of classes, methods, functions, modules, etc; follows... (and by implication, as you've illustrated, perhaps where they come-from), ie code is read more often than it is written, so think about comprehension rather than typing! If one (one's team!) frequently uses a module, then a jargon may develop. For example: import numpy as np ... a = np.arange(6) In which case, those au-fait with the jargon know that the "np." prefix tells them where "arange()" can be found - conversely, that if the IDE doesn't alert, that np/numpy must be (first) import-ed. However, there is a cognitive-load to 'translate' "np" into "numpy". Not much, but then over-load is not a single thought but the combination of 'everything'. The second option (OP) is very (laboriously) clear in mapping the source of each function or constant. By way of comparison then, the code may now appear cluttered, because there's so much text to read. There would be less if an abbreviation were used. The dev.tool in-use may also influence this decision. If hovering-over an identifier reveals source-information, what value the extra code? Intelligent completion also reduces relevance of 'number of characters saved on typing'. Accordingly, give frequently-used functions/modules the abbreviation treatment -but only if YOU feel it right. Otherwise, use a longer-form to improve readability/comprehension. THE answer will thus vary by library/package/module, by application, and by coder (jargon works best if 'all' use it/understand same). Side note: Using "...import identifier, ..." does not save storage-space over "import module" (the whole module is imported regardless, IIRC), however it does form an "interface" and thus recommend leaning into the "Interface Segregation Principle", or as our InfoSec brethren would say 'the principle of least privilege'. Accordingly, prefer "from ... import ... as ...". -- Regards, =dn From cs at cskk.id.au Wed Aug 9 19:22:41 2023 From: cs at cskk.id.au (Cameron Simpson) Date: Thu, 10 Aug 2023 09:22:41 +1000 Subject: Imports and dot-notation In-Reply-To: <5f4f8962-08e6-ed0a-8c44-e83a2b10e0ba@schinagl.nl> References: <5f4f8962-08e6-ed0a-8c44-e83a2b10e0ba@schinagl.nl> Message-ID: On 09Aug2023 12:30, Oliver Schinagl wrote: >Looking at a python projects code and repository layout, we see the >following directory structure. > > >/project/core >/project/components/module1 >... >/project/components/moduleN >/projects/util > >(this is far from complete, but enough to help paint a picture. > >Some modules import other modules, and I see (at the very least) two >(kind of three?) different ways of doing so. > >`from project.components.module1 import function1, function2 as func, >CONST1, CONST2 as CONST` > >or maybe even (which has as an advantage that it becomes clear which >namespace something belongs to > >`from project.components.module1 import function1, function2 as >module1_function2, CONST1, CONST2 as MODULE1_CONST2` > >but then it really just becomes personal preference, as the number of >characters saved on typing is almost negative (due to having a more >complex import). > > >but also the dot notation being used > >`from project.components import module1` > >where obviously the functions are invoked as `module1.function1` etc > >I hope the above is clear enough from an example. > > >Simply put, which of the two would be considered cleaner and more pythonic? This is almost entirely a programmer preference thing. The Zen, as usual, offers guideance but not dictates. As you say, the module1.func form is very clear and has its beauty. Personally I lean towards the single name flavour, sometimes with a rename. FOr example, with os.path I often go: from os.path import join as joinpath and likewise for several other names from there, because the bare names are very generic (eg "join"). I see to be alone here. Many other people use: import os.path and use the full os.path.join in their code, which I find jarring and visually noisy. >Now for a bit more thought, looking at PEP8, we notes about imports, >but sadly PEP8 does not state which method is better/preferred. While >obviously in the end, it's always the maintainers choice in what they >prefer, so are tabs vs spaces and PEP8 is opinionated about that too >(in a good way, even though I'm not a fan :p). PEP8 is for the stdlib source code; that said it is also the basis for most Python coding styles in the wild. For me, the Zen's "readability counts" is the most important guideline; and to this end, your "module1.function" is an entirely reasonable response, particularly if you've got a lot of imports. But it does make for more verbose code, and that works against readability to a degree. This is why it's all subjective. Particular workplaces may mandate particular styles, but in your personal code? Do what seem best, and experience will cause that to evolve over time. Also, the style can depend on the code you're working on. For a small module with few imports the: from module1 import funcname can be a win because the code is short, and this short form of funcname is both clear and readable. But in a very long piece of code with many imports you might go for module1.funcname for clarity, particularly if funcname is generic or overlaps with another similar imported name. Cheers, Cameron Simpson From mats at wichmann.us Thu Aug 10 10:45:31 2023 From: mats at wichmann.us (Mats Wichmann) Date: Thu, 10 Aug 2023 08:45:31 -0600 Subject: Imports and dot-notation In-Reply-To: <749cae90-dc17-7f4a-2c03-b87394134d28@DancesWithMice.info> References: <5f4f8962-08e6-ed0a-8c44-e83a2b10e0ba@schinagl.nl> <749cae90-dc17-7f4a-2c03-b87394134d28@DancesWithMice.info> Message-ID: On 8/9/23 17:28, dn via Python-list wrote: > Side note: Using "...import identifier, ..." does not save storage-space > over "import module" (the whole module is imported regardless, IIRC), > however it does form an "interface" and thus recommend leaning into the > "Interface Segregation Principle", or as our InfoSec brethren would say > 'the principle of least privilege'. Accordingly, prefer "from ... import > ... as ...". > Attribute lookup has *some* cost. That is, finding "c" in the local namespace is going to be a little quicker than "b.c", where Python finds "b" in the local namespace and then finds its "c" attribute; that's then a little quicker than "a.b.c", etc. See all relevant commentary about premature optimisation, spending time optimising the wrong things, etc. but there *are* cases where it matters (c.f. a tight loop that will be run many many times) From bernd.lentes at helmholtz-muenchen.de Thu Aug 10 15:28:20 2023 From: bernd.lentes at helmholtz-muenchen.de (Bernd Lentes) Date: Thu, 10 Aug 2023 19:28:20 +0000 Subject: problems installing Python 3.11 Message-ID: Hi ML, i hope this is the right place for my question. If not please tell me where I can ask. I tried to install python 3.11.4 on a SLES 15 SP5. ./configure ran fine, just one package missing. Installed the package, configure ran fine with complaints. make was ok, make test not. This is what I got to the end: =================================================================================================================================== =============================================================== ERROR: test_build_cpp11 (test.test_cppext.TestCPPExt.test_build_cpp11) ---------------------------------------------------------------------- Traceback (most recent call last): File "/root/Python-3.11.4/Lib/test/test_cppext.py", line 21, in test_build_cpp11 self.check_build(False, '_testcpp11ext') File "/root/Python-3.11.4/Lib/test/test_cppext.py", line 39, in check_build self._check_build(std_cpp03, extension_name) File "/root/Python-3.11.4/Lib/test/test_cppext.py", line 80, in _check_build run_cmd('Build', cmd) File "/root/Python-3.11.4/Lib/test/test_cppext.py", line 64, in run_cmd subprocess.run(cmd, check=True) File "/root/Python-3.11.4/Lib/subprocess.py", line 571, in run raise CalledProcessError(retcode, process.args, subprocess.CalledProcessError: Command '['env/bin/python', '-X', 'dev', '/root/Python-3.11.4/Lib/test/setup_testcppext.py', 'build_ext', '--verbose']' returned non-zero exit status 1. ---------------------------------------------------------------------- Ran 2 tests in 9.939s FAILED (errors=2) test test_cppext failed 1 test failed again: test_cppext == Tests result: FAILURE then FAILURE == 403 tests OK. 1 test failed: test_cppext 30 tests skipped: test_bz2 test_curses test_dbm_gnu test_dbm_ndbm test_devpoll test_gdb test_idle test_ioctl test_kqueue test_launcher test_lzma test_msilib test_nis test_ossaudiodev test_readline test_smtpnet test_sqlite3 test_ssl test_startfile test_tcl test_tix test_tk test_ttk_guionly test_ttk_textonly test_turtle test_winconsoleio test_winreg test_winsound test_zipfile64 test_zoneinfo 2 re-run tests: test___all__ test_cppext Total duration: 28 min 23 sec Tests result: FAILURE then FAILURE make: *** [Makefile:1798: test] Error 2 ========================================================================================================= I'm not very familiar with compiling software, normally I use the packages from my distro. Can you help me ? Or maybe there is no big problem, afterall 403 tests were fine and just two not. I need Python 3.11 for borgbackup. Thanks. Bernd Bernd Lentes -- Bernd Lentes System Administrator MCD Helmholtzzentrum M?nchen +49 89 3187 1241 bernd.lentes at helmholtz-munich.de https://www.helmholtz-munich.de/en/mcd Helmholtz Zentrum M?nchen ? Deutsches Forschungszentrum f?r Gesundheit und Umwelt (GmbH) Ingolst?dter Landstra?e 1, D-85764 Neuherberg, https://www.helmholtz-munich.de Gesch?ftsf?hrung: Prof. Dr. med. Dr. h.c. Matthias Tsch?p, Daniela Sommer (komm.) | Aufsichtsratsvorsitzende: MinDir?in Prof. Dr. Veronika von Messling Registergericht: Amtsgericht M?nchen HRB 6466 | USt-IdNr. DE 129521671 From estates at hestates.org Thu Aug 10 20:35:11 2023 From: estates at hestates.org (Fulian Wang) Date: Fri, 11 Aug 2023 00:35:11 +0000 Subject: Planning a Python / PyData conference In-Reply-To: References: <833b6b19-74aa-5f1d-3c0a-344bee87c386@DancesWithMice.info> Message-ID: I have a brilliant business idea and want to build a team. We collect used cars transfer them to brand new cars inside and outside. Change the gas engine to electric engine with solar panel. Anyone wants to join please contact me. I have the idea, best fiber, website ,Pcb design and manufacture source. Anyone is interested please contact Ms. Wang (832)208-3196 estates at hestates.org Get Outlook for iOS ________________________________ From: Fulian Wang Sent: Wednesday, August 9, 2023 1:14:23 PM To: dn ; python-list at python.org Subject: Re: Planning a Python / PyData conference I recommend Sichuan ,Taiwan , or Thailand Get Outlook for iOS ________________________________ From: Python-list on behalf of dn via Python-list Sent: Wednesday, August 9, 2023 00:10 To: python-list at python.org Subject: Re: Planning a Python / PyData conference Hi Wilber, On 09/08/2023 14.28, Wilber H via Python-list wrote: > Hi, > > I would like to plan a Python / PyData conference in the country of the > Dominican Republic, and would like your feedback on how to best plan > for the conference. Recommend making your request of the folks who organise EuroPython and/or PyConUS - and then same for smaller gatherings. (would suggest to ours, but those folk are already over-loaded to be ready in a few weeks' time) -- Regards, =dn -- https://mail.python.org/mailman/listinfo/python-list From bernd.lentes at helmholtz-muenchen.de Fri Aug 11 06:00:46 2023 From: bernd.lentes at helmholtz-muenchen.de (Bernd Lentes) Date: Fri, 11 Aug 2023 10:00:46 +0000 Subject: problems installing Python 3.11 In-Reply-To: <56bb122b-86f1-96e5-aa12-fff105a2e1a3@udel.edu> References: <56bb122b-86f1-96e5-aa12-fff105a2e1a3@udel.edu> Message-ID: >-----Original Message----- >From: Terry Reedy >Sent: Thursday, August 10, 2023 9:55 PM >To: Bernd Lentes >Subject: Re: problems installing Python 3.11 > >On 8/10/2023 3:28 PM, Bernd Lentes via Python-list wrote: > >Private response because cannot post at present. > >It appears that what failed is building a C++ extension. (You can dig into the test >code to check. It is skipped on my Windows.) If you do not need to do that, you >should not have a problem. > Hi Terry, I found out that cc1plus was missing. I installed g++, rerun make and this error disappeared. But another has arised: ==================================================================================== --- STDERR --- Traceback (most recent call last): File "", line 1, in File "/tmp/tmphpwu2qwj/cpython/Lib/sysconfig.py", line 715, in get_config_var return get_config_vars().get(name) ^^^^^^^^^^^^^^^^^ File "/tmp/tmphpwu2qwj/cpython/Lib/sysconfig.py", line 670, in get_config_vars _init_posix(_CONFIG_VARS) File "/tmp/tmphpwu2qwj/cpython/Lib/sysconfig.py", line 531, in _init_posix _temp = __import__(name, globals(), locals(), ['build_time_vars'], 0) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ModuleNotFoundError: No module named '_sysconfigdata__linux_x86_64-linux-gnu' ---- END ---- building python parallel='-j21' in /tmp/tmphpwu2qwj/python-build... installing python into /tmp/tmphpwu2qwj/python-installation... freezing /tmp/tmphpwu2qwj/app.py... ok ---------------------------------------------------------------------- Ran 1 test in 95.606s OK == Tests result: FAILURE then SUCCESS == 404 tests OK. 30 tests skipped: test_bz2 test_curses test_dbm_gnu test_dbm_ndbm test_devpoll test_gdb test_idle test_ioctl test_kqueue test_launcher test_lzma test_msilib test_nis test_ossaudiodev test_readline test_smtpnet test_sqlite3 test_ssl test_startfile test_tcl test_tix test_tk test_ttk_guionly test_ttk_textonly test_turtle test_winconsoleio test_winreg test_winsound test_zipfile64 test_zoneinfo 1 re-run test: test_tools Total duration: 29 min 56 sec Tests result: FAILURE then SUCCESS ================================================================================ Or does " FAILURE then SUCCESS" mean that everything is ok now ? Bernd Helmholtz Zentrum M?nchen ? Deutsches Forschungszentrum f?r Gesundheit und Umwelt (GmbH) Ingolst?dter Landstra?e 1, D-85764 Neuherberg, https://www.helmholtz-munich.de Gesch?ftsf?hrung: Prof. Dr. med. Dr. h.c. Matthias Tsch?p, Daniela Sommer (komm.) | Aufsichtsratsvorsitzende: MinDir?in Prof. Dr. Veronika von Messling Registergericht: Amtsgericht M?nchen HRB 6466 | USt-IdNr. DE 129521671 From bernd.lentes at helmholtz-muenchen.de Fri Aug 11 09:16:30 2023 From: bernd.lentes at helmholtz-muenchen.de (Bernd Lentes) Date: Fri, 11 Aug 2023 13:16:30 +0000 Subject: problems installing Python 3.11 In-Reply-To: References: <56bb122b-86f1-96e5-aa12-fff105a2e1a3@udel.edu> Message-ID: >-----Original Message----- >From: Python-list muenchen.de at python.org> On Behalf Of Bernd Lentes via Python-list >Sent: Friday, August 11, 2023 12:01 PM >To: Terry Reedy >Cc: Python ML (python-list at python.org) >Subject: RE: problems installing Python 3.11 Hi, I read the readme.rst and found something helpful. I reran explicitly the test which failed: ============================================================= localhost:~/Python-3.11.4 # make test TESTOPTS="-v test_tools" CC='gcc -pthread' LDSHARED='gcc -pthread -shared ' OPT='-DNDEBUG -g -fwrapv -O3 -Wall' ./python -E ./setup.py build running build running build_ext The necessary bits to build these optional modules were not found: _bz2 _curses _curses_panel _dbm _gdbm _hashlib _lzma _ssl _tkinter _uuid nis readline To find the necessary bits, look in setup.py in detect_modules() for the module's name. The following modules found by detect_modules() in setup.py have not been built, they are *disabled* by configure: _sqlite3 Could not build the ssl module! Python requires a OpenSSL 1.1.1 or newer running build_scripts copying and adjusting /root/Python-3.11.4/Tools/scripts/pydoc3 -> build/scripts-3.11 copying and adjusting /root/Python-3.11.4/Tools/scripts/idle3 -> build/scripts-3.11 copying and adjusting /root/Python-3.11.4/Tools/scripts/2to3 -> build/scripts-3.11 changing mode of build/scripts-3.11/pydoc3 from 644 to 755 changing mode of build/scripts-3.11/idle3 from 644 to 755 changing mode of build/scripts-3.11/2to3 from 644 to 755 renaming build/scripts-3.11/pydoc3 to build/scripts-3.11/pydoc3.11 renaming build/scripts-3.11/idle3 to build/scripts-3.11/idle3.11 renaming build/scripts-3.11/2to3 to build/scripts-3.11/2to3-3.11 ./python -E ./Tools/scripts/run_tests.py -v test_tools /root/Python-3.11.4/python -u -W default -bb -E -E -m test -r -w -j 0 -u all,-largefile,-audio,-gui -v test_tools == CPython 3.11.4 (main, Aug 11 2023, 00:05:59) [GCC 7.5.0] == Linux-5.14.21-150500.55.12-default-x86_64-with-glibc2.31 little-endian == cwd: /root/Python-3.11.4/build/test_python_8347? == CPU count: 32 == encodings: locale=UTF-8, FS=utf-8 Using random seed 9455548 0:00:00 load avg: 0.07 Run tests in parallel using 34 child processes 0:00:30 load avg: 2.51 running: test_tools (30.0 sec) 0:01:00 load avg: 2.44 running: test_tools (1 min) 0:01:30 load avg: 2.16 running: test_tools (1 min 30 sec) 0:01:40 load avg: 2.21 [1/1] test_tools passed (1 min 40 sec) test_alter_comments (test.test_tools.test_fixcid.Test.test_alter_comments) ... ok test_directory (test.test_tools.test_fixcid.Test.test_directory) ... ok test_parse_strings (test.test_tools.test_fixcid.Test.test_parse_strings) ... ok test_freeze_simple_script (test.test_tools.test_freeze.TestFreeze.test_freeze_simple_script) ... creating the script to be frozen at /tmp/tmp73do0elf/app.py copying the source tree into /tmp/tmp73do0elf/cpython... configuring python in /tmp/tmp73do0elf/python-build... CalledProcessError: Command '['/tmp/tmp73do0elf/cpython/python', '-c', 'import sysconfig; print(sysconfig.get_config_var("CONFIG_ARGS"))']' returned non-zero exit status 1. --- STDOUT --- --- STDERR --- Traceback (most recent call last): File "", line 1, in File "/tmp/tmp73do0elf/cpython/Lib/sysconfig.py", line 715, in get_config_var return get_config_vars().get(name) ^^^^^^^^^^^^^^^^^ File "/tmp/tmp73do0elf/cpython/Lib/sysconfig.py", line 670, in get_config_vars _init_posix(_CONFIG_VARS) File "/tmp/tmp73do0elf/cpython/Lib/sysconfig.py", line 531, in _init_posix _temp = __import__(name, globals(), locals(), ['build_time_vars'], 0) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ModuleNotFoundError: No module named '_sysconfigdata__linux_x86_64-linux-gnu' ---- END ---- building python parallel='-j21' in /tmp/tmp73do0elf/python-build... installing python into /tmp/tmp73do0elf/python-installation... freezing /tmp/tmp73do0elf/app.py... ok test_gprof (test.test_tools.test_gprof2html.Gprof2htmlTests.test_gprof) ... ok test_POT_Creation_Date (test.test_tools.test_i18n.Test_pygettext.test_POT_Creation_Date) Match the date format from xgettext for POT-Creation-Date ... ok test_calls_in_fstring_with_keyword_args (test.test_tools.test_i18n.Test_pygettext.test_calls_in_fstring_with_keyword_args) ... ok test_calls_in_fstring_with_multiple_args (test.test_tools.test_i18n.Test_pygettext.test_calls_in_fstring_with_multiple_args) ... ok test_calls_in_fstring_with_partially_wrong_expression (test.test_tools.test_i18n.Test_pygettext.test_calls_in_fstring_with_partially_wrong_expression) ... ok test_calls_in_fstrings (test.test_tools.test_i18n.Test_pygettext.test_calls_in_fstrings) ... ok test_calls_in_fstrings_attribute (test.test_tools.test_i18n.Test_pygettext.test_calls_in_fstrings_attribute) ... ok test_calls_in_fstrings_nested (test.test_tools.test_i18n.Test_pygettext.test_calls_in_fstrings_nested) ... ok test_calls_in_fstrings_raw (test.test_tools.test_i18n.Test_pygettext.test_calls_in_fstrings_raw) ... ok test_calls_in_fstrings_with_call_on_call (test.test_tools.test_i18n.Test_pygettext.test_calls_in_fstrings_with_call_on_call) ... ok test_calls_in_fstrings_with_format (test.test_tools.test_i18n.Test_pygettext.test_calls_in_fstrings_with_format) ... ok test_calls_in_fstrings_with_wrong_input_1 (test.test_tools.test_i18n.Test_pygettext.test_calls_in_fstrings_with_wrong_input_1) ... ok test_calls_in_fstrings_with_wrong_input_2 (test.test_tools.test_i18n.Test_pygettext.test_calls_in_fstrings_with_wrong_input_2) ... ok test_classdocstring (test.test_tools.test_i18n.Test_pygettext.test_classdocstring) ... ok test_classdocstring_bytes (test.test_tools.test_i18n.Test_pygettext.test_classdocstring_bytes) ... ok test_classdocstring_early_colon (test.test_tools.test_i18n.Test_pygettext.test_classdocstring_early_colon) Test docstring extraction for a class with colons occurring within ... ok test_classdocstring_fstring (test.test_tools.test_i18n.Test_pygettext.test_classdocstring_fstring) ... ok test_files_list (test.test_tools.test_i18n.Test_pygettext.test_files_list) Make sure the directories are inspected for source files ... ok test_funcdocstring (test.test_tools.test_i18n.Test_pygettext.test_funcdocstring) ... ok test_funcdocstring_annotated_args (test.test_tools.test_i18n.Test_pygettext.test_funcdocstring_annotated_args) Test docstrings for functions with annotated args ... ok test_funcdocstring_annotated_return (test.test_tools.test_i18n.Test_pygettext.test_funcdocstring_annotated_return) Test docstrings for functions with annotated return type ... ok test_funcdocstring_bytes (test.test_tools.test_i18n.Test_pygettext.test_funcdocstring_bytes) ... ok test_funcdocstring_defvalue_args (test.test_tools.test_i18n.Test_pygettext.test_funcdocstring_defvalue_args) Test docstring for functions with default arg values ... ok test_funcdocstring_fstring (test.test_tools.test_i18n.Test_pygettext.test_funcdocstring_fstring) ... ok test_funcdocstring_multiple_funcs (test.test_tools.test_i18n.Test_pygettext.test_funcdocstring_multiple_funcs) Test docstring extraction for multiple functions combining ... ok test_header (test.test_tools.test_i18n.Test_pygettext.test_header) Make sure the required fields are in the header, according to: ... ok test_moduledocstring (test.test_tools.test_i18n.Test_pygettext.test_moduledocstring) ... ok test_moduledocstring_bytes (test.test_tools.test_i18n.Test_pygettext.test_moduledocstring_bytes) ... ok test_moduledocstring_fstring (test.test_tools.test_i18n.Test_pygettext.test_moduledocstring_fstring) ... ok test_msgid (test.test_tools.test_i18n.Test_pygettext.test_msgid) ... ok test_msgid_bytes (test.test_tools.test_i18n.Test_pygettext.test_msgid_bytes) ... ok test_msgid_fstring (test.test_tools.test_i18n.Test_pygettext.test_msgid_fstring) ... ok test_lll_multiple_dirs (test.test_tools.test_lll.lllTests.test_lll_multiple_dirs) ... ok test_checksum_fodder (test.test_tools.test_md5sum.MD5SumTests.test_checksum_fodder) ... ok test_dash_l (test.test_tools.test_md5sum.MD5SumTests.test_dash_l) ... ok test_dash_s (test.test_tools.test_md5sum.MD5SumTests.test_dash_s) ... ok test_dash_t (test.test_tools.test_md5sum.MD5SumTests.test_dash_t) ... ok test_multiple_files (test.test_tools.test_md5sum.MD5SumTests.test_multiple_files) ... ok test_noargs (test.test_tools.test_md5sum.MD5SumTests.test_noargs) ... ok test_usage (test.test_tools.test_md5sum.MD5SumTests.test_usage) ... ok test_pathfix (test.test_tools.test_pathfix.TestPathfixFunctional.test_pathfix) ... ok test_pathfix_adding_errors (test.test_tools.test_pathfix.TestPathfixFunctional.test_pathfix_adding_errors) ... ok test_pathfix_adding_flag (test.test_tools.test_pathfix.TestPathfixFunctional.test_pathfix_adding_flag) ... ok test_pathfix_keeping_flags (test.test_tools.test_pathfix.TestPathfixFunctional.test_pathfix_keeping_flags) ... ok test_recursive (test.test_tools.test_pathfix.TestPathfixFunctional.test_recursive) ... ok test_inverse_attribute_error (test.test_tools.test_pdeps.PdepsTests.test_inverse_attribute_error) ... ok test_process_errors (test.test_tools.test_pdeps.PdepsTests.test_process_errors) ... ok test_empty_line (test.test_tools.test_pindent.PindentTests.test_empty_line) ... ok test_escaped_newline (test.test_tools.test_pindent.PindentTests.test_escaped_newline) ... ok test_multilevel (test.test_tools.test_pindent.PindentTests.test_multilevel) ... ok test_oneline (test.test_tools.test_pindent.PindentTests.test_oneline) ... ok test_preserve_indents (test.test_tools.test_pindent.PindentTests.test_preserve_indents) ... ok test_selftest (test.test_tools.test_pindent.PindentTests.test_selftest) ... ok test_statements (test.test_tools.test_pindent.PindentTests.test_statements) ... ok test_help (test.test_tools.test_reindent.ReindentTests.test_help) ... ok test_noargs (test.test_tools.test_reindent.ReindentTests.test_noargs) ... ok test_reindent_file_with_bad_encoding (test.test_tools.test_reindent.ReindentTests.test_reindent_file_with_bad_encoding) ... ok test_analyze_dxp_import (test.test_tools.test_sundry.TestSundryScripts.test_analyze_dxp_import) ... ok test_sundry (test.test_tools.test_sundry.TestSundryScripts.test_sundry) ... ok test_sundry_windows (test.test_tools.test_sundry.TestSundryScripts.test_sundry_windows) ... skipped 'Windows-only test' ---------------------------------------------------------------------- Ran 64 tests in 100.758s OK (skipped=1) == Tests result: SUCCESS == 1 test OK. Total duration: 1 min 40 sec Tests result: SUCCESS =================================================== Now I'm unsure. SUCCESS despite a traceback ? Bernd Helmholtz Zentrum M?nchen ? Deutsches Forschungszentrum f?r Gesundheit und Umwelt (GmbH) Ingolst?dter Landstra?e 1, D-85764 Neuherberg, https://www.helmholtz-munich.de Gesch?ftsf?hrung: Prof. Dr. med. Dr. h.c. Matthias Tsch?p, Daniela Sommer (komm.) | Aufsichtsratsvorsitzende: MinDir?in Prof. Dr. Veronika von Messling Registergericht: Amtsgericht M?nchen HRB 6466 | USt-IdNr. DE 129521671 From c.buhtz at posteo.jp Thu Aug 17 03:10:32 2023 From: c.buhtz at posteo.jp (c.buhtz at posteo.jp) Date: Thu, 17 Aug 2023 07:10:32 +0000 Subject: GNU gettext: Print string translated and untranslated at the same time Message-ID: <2ecc54498066930d20ada6343bf4374d@posteo.de> X-Post: https://stackoverflow.com/q/76913082/4865723 I want to display one string in its original source (untranslated) version and in its translated version site by site without duplicating the string in the python source code? It wouldn't be a big deal if it is only one word. print('The translated string "{}" is originally "{}".'.format(_('Hello'), 'Hello')) But in my situation it is a multi line string containing multiple paragraphs. It is a full text. I don't want to duplicate that string. # Imagine 'Hello' as a 50x70 characters multi line string. original = 'Hello' translated = _('Hello') print('The translated string "{}" is originally "{}".'.format(translated, original)) I do use the "class based API" of GNU gettext. My current approach, which is not working, is to somehow (how!?) disable (or mask) the translation function "_()" temporarily. But as described in the stackoverflow question (see first line of this mail) this do not work. def foobar(translate): if not translate: # I try to mask the global _() builtins-function def _(txt): return txt return _('Hello') if __name__ == '__main__': # To ilustrate that _() is part of "builtins" namespace print(_('No problem.')) print('The translated string "{}" is originally "{}".' .format(foobar(True), foobar(False))) This is the output: Traceback (most recent call last): File "/home/user/ownCloud/_transfer/./z.py", line 27, in .format(foobar(True), foobar(False))) File "/home/user/ownCloud/_transfer/./z.py", line 19, in foobar return _('Hello') UnboundLocalError: local variable '_' referenced before assignment The full MWE can be found at stackoverflow (https://stackoverflow.com/q/76913082/4865723). The question is if this can be solved somehow or if there is an alternative approach. The "_()" function is installed in the builtins namespace because of gettext class based API. This is nice. Maybe I can somehow manipulate that builtins namespace? I tried to import builtins and played around with it but couldn't find a way to do it. Thanks Christian Buhtz PS: This is IMHO not relevant for my question but if someone is interested the connection to productive code can be found in this issue: https://github.com/bit-team/backintime/issues/1473 There I describe what I want to achive and also provide a GUI mockup. From mirkok.lists at googlemail.com Thu Aug 17 12:19:35 2023 From: mirkok.lists at googlemail.com (Mirko) Date: Thu, 17 Aug 2023 18:19:35 +0200 Subject: GNU gettext: Print string translated and untranslated at the same time In-Reply-To: <2ecc54498066930d20ada6343bf4374d@posteo.de> References: <2ecc54498066930d20ada6343bf4374d@posteo.de> Message-ID: <57971807-ed3a-9e79-28d5-f37a45409dd0@googlemail.com> Am 17.08.23 um 09:10 schrieb c.buhtz--- via Python-list: > ??? UnboundLocalError: local variable '_' referenced before assignment This is a common gotcha: https://docs.python.org/3/faq/programming.html#why-am-i-getting-an-unboundlocalerror-when-the-variable-has-a-value You could solve it by defining _() locally like so: def foobar(translate): _ = gettext.gettext if not translate: # I try to mask the global _() builtins-function def _(txt): return txt return _('minutes') > The question is if this can be solved somehow or if there is an alternative approach. However, you might not need this, because the following seems to work for me: def orig_and_trans(msg): return (_(msg), msg) print('The translated string "{}" is originally "{}".'.format(*orig_and_trans("hello"))) From dieter at handshake.de Thu Aug 17 12:16:03 2023 From: dieter at handshake.de (Dieter Maurer) Date: Thu, 17 Aug 2023 18:16:03 +0200 Subject: GNU gettext: Print string translated and untranslated at the same time In-Reply-To: <2ecc54498066930d20ada6343bf4374d@posteo.de> References: <2ecc54498066930d20ada6343bf4374d@posteo.de> Message-ID: <25822.18371.305435.696844@ixdm.fritz.box> c.buhtz at posteo.jp wrote at 2023-8-17 07:10 +0000: >I want to display one string in its original source (untranslated) >version and in its translated version site by site without duplicating >the string in the python source code? Is it an option for you to replace the `gettext` binding by `zope.i18nmessageid`? Its `Message` instances provide access to all interesting attributes (id, default, mapping, domain). Together with other packages (--> `zope.i18n` and `i18ndude`) it is compatible with `GNU gettext` translation catalogs. If this is not an option, use Python's inspection functionality to learn which attributes are made available by the binding's message class. From Richard at damon-family.org Thu Aug 17 12:41:21 2023 From: Richard at damon-family.org (Richard Damon) Date: Thu, 17 Aug 2023 12:41:21 -0400 Subject: GNU gettext: Print string translated and untranslated at the same time In-Reply-To: <2ecc54498066930d20ada6343bf4374d@posteo.de> References: <2ecc54498066930d20ada6343bf4374d@posteo.de> Message-ID: <886A66C8-6C39-4D91-B3BC-117857280B40@damon-family.org> > On Aug 17, 2023, at 10:02 AM, c.buhtz--- via Python-list wrote: > > ?X-Post: https://stackoverflow.com/q/76913082/4865723 > > I want to display one string in its original source (untranslated) version and in its translated version site by site without duplicating the string in the python source code? > It wouldn't be a big deal if it is only one word. > > print('The translated string "{}" is originally "{}".'.format(_('Hello'), 'Hello')) > > But in my situation it is a multi line string containing multiple paragraphs. It is a full text. I don't want to duplicate that string. > > # Imagine 'Hello' as a 50x70 characters multi line string. > original = 'Hello' > translated = _('Hello') > print('The translated string "{}" is originally "{}".'.format(translated, original)) > > I do use the "class based API" of GNU gettext. My current approach, which is not working, is to somehow (how!?) disable (or mask) the translation function "_()" temporarily. > But as described in the stackoverflow question (see first line of this mail) this do not work. > > def foobar(translate): > if not translate: > # I try to mask the global _() builtins-function > def _(txt): > return txt > > return _('Hello') > > if __name__ == '__main__': > > # To ilustrate that _() is part of "builtins" namespace > print(_('No problem.')) > > print('The translated string "{}" is originally "{}".' > .format(foobar(True), foobar(False))) > > This is the output: > > Traceback (most recent call last): > File "/home/user/ownCloud/_transfer/./z.py", line 27, in > .format(foobar(True), foobar(False))) > File "/home/user/ownCloud/_transfer/./z.py", line 19, in foobar > return _('Hello') > UnboundLocalError: local variable '_' referenced before assignment > > The full MWE can be found at stackoverflow (https://stackoverflow.com/q/76913082/4865723). > > The question is if this can be solved somehow or if there is an alternative approach. > The "_()" function is installed in the builtins namespace because of gettext class based API. This is nice. > Maybe I can somehow manipulate that builtins namespace? I tried to import builtins and played around with it but couldn't find a way to do it. > > Thanks > Christian Buhtz > > PS: This is IMHO not relevant for my question but if someone is interested the connection to productive code can be found in this issue: https://github.com/bit-team/backintime/issues/1473 There I describe what I want to achive and also provide a GUI mockup. > -- > https://mail.python.org/mailman/listinfo/python-list One thing to remember is that the _() function, which calls gettext doesn?t need a literal string, so you can set a variable to ?raw? string, and then translate it to another variable, so you can have both. From dieter at handshake.de Thu Aug 17 13:19:38 2023 From: dieter at handshake.de (Dieter Maurer) Date: Thu, 17 Aug 2023 19:19:38 +0200 Subject: GNU gettext: Print string translated and untranslated at the same time In-Reply-To: <2ecc54498066930d20ada6343bf4374d@posteo.de> References: <2ecc54498066930d20ada6343bf4374d@posteo.de> Message-ID: <25822.22186.232678.81747@ixdm.fritz.box> c.buhtz at posteo.jp wrote at 2023-8-17 07:10 +0000: >I want to display one string in its original source (untranslated) >version and in its translated version site by site without duplicating >the string in the python source code? You could try to translate into an unknown language: this should give you the default translation. From c.buhtz at posteo.jp Thu Aug 17 15:17:49 2023 From: c.buhtz at posteo.jp (c.buhtz at posteo.jp) Date: Thu, 17 Aug 2023 19:17:49 +0000 Subject: GNU gettext: Print string translated and untranslated at the same time In-Reply-To: <57971807-ed3a-9e79-28d5-f37a45409dd0@googlemail.com> References: <2ecc54498066930d20ada6343bf4374d@posteo.de> <57971807-ed3a-9e79-28d5-f37a45409dd0@googlemail.com> Message-ID: <41921d940be15b658cf4e5f1d96f4131@posteo.de> Hello Mirko, thanks for reply. Am 17.08.2023 18:19 schrieb Mirko via Python-list: > You could solve it by defining _() locally like so: > > def foobar(translate): > _ = gettext.gettext I see no way to do that. It is not the "class based API" of gettext installing _() into the builtins namespace. My users are able to configure the language of their UI explicit. It is a full application. > def orig_and_trans(msg): > return (_(msg), msg) This will be ignored by GNU gettext utils (xgettext in my case) will ignore this line because they do not know what "msg" is. The string "hello" won't appear in the pot-file. From mirkok.lists at googlemail.com Thu Aug 17 17:30:09 2023 From: mirkok.lists at googlemail.com (Mirko) Date: Thu, 17 Aug 2023 23:30:09 +0200 Subject: GNU gettext: Print string translated and untranslated at the same time In-Reply-To: <41921d940be15b658cf4e5f1d96f4131@posteo.de> References: <2ecc54498066930d20ada6343bf4374d@posteo.de> <57971807-ed3a-9e79-28d5-f37a45409dd0@googlemail.com> <41921d940be15b658cf4e5f1d96f4131@posteo.de> Message-ID: <54d76987-81ae-2677-e25d-c850ca8cbe9d@googlemail.com> Am 17.08.23 um 21:17 schrieb c.buhtz--- via Python-list: > Hello Mirko, > > thanks for reply. > > Am 17.08.2023 18:19 schrieb Mirko via Python-list: >> You could solve it by defining _() locally like so: >> >> def foobar(translate): >> ??? _ = gettext.gettext > > I see no way to do that. It is not the "class based API" of gettext > installing _() into the builtins namespace. Does this work: def foobar(translate): _ = __builtins__._ > My users are able to configure the language of their UI explicit. It > is a full application. > >> def orig_and_trans(msg): >> ??? return (_(msg), msg) > > This will be ignored by GNU gettext utils (xgettext in my case) will > ignore this line because they do not know what "msg" is. The string > "hello" won't appear in the pot-file. xgettext has an option "-k" which allows you to specify an additional "keyword" (like a function name, I guess) for detecting translatable strings. With the orig_and_trans() function, the following command produces a messages.po with "hello" in it. xgettext -korig_and_trans source.py From greg.ewing at canterbury.ac.nz Fri Aug 18 02:14:44 2023 From: greg.ewing at canterbury.ac.nz (Greg Ewing) Date: Fri, 18 Aug 2023 18:14:44 +1200 Subject: GNU gettext: Print string translated and untranslated at the same time In-Reply-To: References: <2ecc54498066930d20ada6343bf4374d@posteo.de> Message-ID: On 17/08/23 7:10 pm, c.buhtz at posteo.jp wrote: > def foobar(translate): > ??? if not translate: > ??????? # I try to mask the global _() builtins-function > ??????? def _(txt): > ??????????? return txt > > ??? return _('Hello') This causes _ to become a local that is left undefined on one branch of the if. You need to ensure it's always defined. Here's one way that should work: gttran = _ def foobar(translate): def _(txt): if translate: return gttran(txt) else: return txt return _('Hello') -- Greg From barry at barrys-emacs.org Fri Aug 18 02:59:06 2023 From: barry at barrys-emacs.org (Barry) Date: Fri, 18 Aug 2023 07:59:06 +0100 Subject: GNU gettext: Print string translated and untranslated at the same time In-Reply-To: <2ecc54498066930d20ada6343bf4374d@posteo.de> References: <2ecc54498066930d20ada6343bf4374d@posteo.de> Message-ID: > On 17 Aug 2023, at 15:01, c.buhtz--- via Python-list wrote: > > I want to display one string in its original source (untranslated) version and in its translated version site by site without duplicating the string in the python source code? > It wouldn't be a big deal if it is only one word. The key to solving this to separate the parsing of the string into the .po file and its translation. def i18n(s): return s msg = i18n(?my message?) print(_(msg)) print(msg) Now you tell the xgettex, pygettext etc, to parse to use ?i18n? to find strings to translate. This is covered in the docs at https://docs.python.org/3/library/gettext.html#localizing-your-module Barry From priisdk at gmail.com Sat Aug 19 03:43:44 2023 From: priisdk at gmail.com (Poul Riis) Date: Sat, 19 Aug 2023 00:43:44 -0700 (PDT) Subject: Near and far clip plane in glowscript Message-ID: <2241f99a-0599-46ce-8db1-f041273a8755n@googlegroups.com> Yes, I know that this is not the right forum to present my problem but I have tried the glowscript forum without succes. A different programming language, PyWeb3D, has this simple command to control the distances from the camera to the near and far planes: camera=PerspectiveCamera( 45, width / height, 1, 1000 ) where 1 is the distance to the near plane and 1000 is the distance to the far plane. - see https://threejs.org/docs/index.html?q=perspec#api/en/cameras/PerspectiveCamera I am convinced that there must be a similar way to control these parameters from glowscript because it is obvious that they are set to some default values because I see objects disappear in some cases. But I have no idea how!?!? I suspect it has to to with WebGL and how to reach WebGL commands from glowscript. What I hope is that someone at this forum can give a little hint as to get closer to a solution. It would make me very, very happy! Poul Riis Denmark From info at egenix.com Mon Aug 21 09:41:45 2023 From: info at egenix.com (eGenix Team) Date: Mon, 21 Aug 2023 15:41:45 +0200 Subject: ANN: eGenix Antispam Bot for Telegram 0.5.0 Message-ID: *ANNOUNCING* eGenix Antispam Bot for Telegram Version 0.5.0 A simple, yet effective bot implementation to address Telegram signup spam. This announcement is also available on our web-site for online reading: https://www.egenix.com/company/news/eGenix-Antispam-Bot-for-Telegram-0.5.0-GA.html ------------------------------------------------------------------------ *INTRODUCTION* eGenix has long been running a local Python user group meeting in D?sseldorf called /Python Meeting D?sseldorf / and we are using a Telegram group for most of our communication. In the early days, the group worked well and we only had few spammers joining it, which we could well handle manually. More recently, this has changed dramatically. We are seeing between 2-5 spam signups per day, often at night. Furthermore, the signups accounts are not always easy to spot as spammers, since they often come with profile images, descriptions, etc. With the bot, we now have a more flexible way of dealing with the problem. Please see our project page for details and download links: https://www.egenix.com/library/telegram-antispam-bot/ ------------------------------------------------------------------------ *FEATURES* * Low impact mode of operation: the bot tries to keep noise in the group to a minimum * ?Several challenge mechanisms to choose from, more can be added as needed * ?Flexible and easy to use configuration * ?Only needs a few MB of RAM, so can easily be put into a container or run on a Raspberry Pi * ?Can handle quite a bit of load due to the async implementation * ?Works with Python 3.9+ * ?MIT open source licensed ------------------------------------------------------------------------ *NEWS* The 0.5.0 release fixes a few bugs and adds more features: * Added support for muting the bot messages and enabled this per default; thanks to Alexander Ananchenko * Added support for also removing the approval message after a timeout (not enabled per default); thanks to Alexander Ananchenko * Bot conversations are now logged before removing them; this makes it easier to debug challenges (some may be too easy) It has been battle-tested in production for more than two months already and is proving to be a really useful tool to help with Telegram group administration. Enjoy, -- Marc-Andre Lemburg eGenix.com Professional Python Services directly from the Experts (#1, Aug 21 2023) >>> Python Projects, Coaching and Support ... https://www.egenix.com/ >>> Python Product Development ... https://consulting.egenix.com/ ________________________________________________________________________ ::: We implement business ideas - efficiently in both time and costs ::: eGenix.com Software, Skills and Services GmbH Pastor-Loeh-Str.48 D-40764 Langenfeld, Germany. CEO Dipl.-Math. Marc-Andre Lemburg Registered at Amtsgericht Duesseldorf: HRB 46611 https://www.egenix.com/company/contact/ https://www.malemburg.com/ From rob.cliffe at btinternet.com Fri Aug 18 05:14:18 2023 From: rob.cliffe at btinternet.com (Rob Cliffe) Date: Fri, 18 Aug 2023 10:14:18 +0100 Subject: divmod with negative Decimal values Message-ID: I am using Python 3.11.4. Can anyone explain why Decimal values behave differently from ints when negative values are used in divmod as follows: >>> divmod(-1, 60) (-1, 59)????????????????????????????????????????????????????? # as expected >>> divmod(Decimal("-1"), 60) (Decimal('-0'), Decimal('-1')) Best wishes Rob Cliffe From arequipeno at gmail.com Tue Aug 22 10:45:05 2023 From: arequipeno at gmail.com (Ian Pilcher) Date: Tue, 22 Aug 2023 09:45:05 -0500 Subject: Getty fully qualified class name from class object Message-ID: <3397987e-ad50-ed09-640f-e55965456ea2@gmail.com> How can I programmatically get the fully qualified name of a class from its class object? (I'm referring to the name that is shown when str() or repr() is called on the class object.) Neither the __name__ or __qualname__ class attributes include the module. For example: >>> import logging >>> str(logging.Handler) "" >>> logging.Handler.__name__ 'Handler' >>> logging.Handler.__qualname__ 'Handler' How can I programmatically get 'logging.Handler' from the class object? -- ======================================================================== Google Where SkyNet meets Idiocracy ======================================================================== From greg.ewing at canterbury.ac.nz Tue Aug 22 12:13:08 2023 From: greg.ewing at canterbury.ac.nz (Greg Ewing) Date: Wed, 23 Aug 2023 04:13:08 +1200 Subject: Getty fully qualified class name from class object In-Reply-To: References: <3397987e-ad50-ed09-640f-e55965456ea2@gmail.com> Message-ID: On 23/08/23 2:45 am, Ian Pilcher wrote: > How can I programmatically get 'logging.Handler' from the class object? Classes have a __module__ attribute: >>> logging.Handler.__module__ 'logging' -- Greg From list1 at tompassin.net Tue Aug 22 12:49:01 2023 From: list1 at tompassin.net (Thomas Passin) Date: Tue, 22 Aug 2023 12:49:01 -0400 Subject: divmod with negative Decimal values In-Reply-To: References: Message-ID: <54b65c84-8ced-4c29-d1e1-d19321886c8b@tompassin.net> On 8/18/2023 5:14 AM, Rob Cliffe via Python-list wrote: > divmod(Decimal("-1"), 60) It's not divmod per se, but the modulus operation: from decimal import Decimal D1 = Decimal(-1) D1 % 60 # Decimal(-1) fmod() performs the same way: from math import fmod fmod(-1, 60) # -1.0 From the Python docs on math.fmod: "math.fmod(x, y) Return fmod(x, y), as defined by the platform C library. Note that the Python expression x % y may not return the same result. The intent of the C standard is that fmod(x, y) be exactly (mathematically; to infinite precision) equal to x - n*y for some integer n such that the result has the same sign as x and magnitude less than abs(y). Python?s x % y returns a result with the sign of y instead, and may not be exactly computable for float arguments. For example, fmod(-1e-100, 1e100) is -1e-100, but the result of Python?s -1e-100 % 1e100 is 1e100-1e-100, which cannot be represented exactly as a float, and rounds to the surprising 1e100. For this reason, function fmod() is generally preferred when working with floats, while Python?s x % y is preferred when working with integers." I'm not sure this is helpful in a practical way here ... From jsf80238 at gmail.com Wed Aug 23 11:41:07 2023 From: jsf80238 at gmail.com (Jason Friedman) Date: Wed, 23 Aug 2023 09:41:07 -0600 Subject: Context manager for database connection Message-ID: I want to be able to write code like this: with Database() as mydb: conn = mydb.get_connection() cursor = conn.get_cursor() cursor.execute("update table1 set x = 1 where y = 2") cursor.close() cursor = conn.get_cursor() cursor.execute("update table2 set a = 1 where b = 2") cursor.close() I'd like for both statements to succeed and commit, or if either fails to stop and for all to rollback. Is what I have below correct? import jaydebeapi as jdbc class Database: database_connection = None def __init__(self, auto_commit: bool = False): self.database_connection = jdbc.connect(...) self.database_connection.jconn.setAutoCommit(auto_commit) def __enter__(self) -> jdbc.Connection: return self def __exit__(self, exception_type: Optional[Type[BaseException]], exception_value: Optional[BaseException], traceback: Optional[types.TracebackType]) -> bool: if exception_type: self.database_connection.rollback() else: self.database_connection.commit() self.database_connection.close() def get_connection(self) -> jdbc.Connection: return self.database_connection From PythonList at DancesWithMice.info Wed Aug 23 14:11:02 2023 From: PythonList at DancesWithMice.info (dn) Date: Thu, 24 Aug 2023 06:11:02 +1200 Subject: Context manager for database connection In-Reply-To: References: Message-ID: On 24/08/2023 03.41, Jason Friedman via Python-list wrote: > I want to be able to write code like this: > > with Database() as mydb: > conn = mydb.get_connection() > cursor = conn.get_cursor() > cursor.execute("update table1 set x = 1 where y = 2") > cursor.close() > cursor = conn.get_cursor() > cursor.execute("update table2 set a = 1 where b = 2") > cursor.close() > > I'd like for both statements to succeed and commit, or if either fails to > stop and for all to rollback. > > Is what I have below correct? > > > import jaydebeapi as jdbc > class Database: > database_connection = None > > def __init__(self, auto_commit: bool = False): > self.database_connection = jdbc.connect(...) > self.database_connection.jconn.setAutoCommit(auto_commit) > > def __enter__(self) -> jdbc.Connection: > return self > > def __exit__(self, exception_type: Optional[Type[BaseException]], > exception_value: Optional[BaseException], > traceback: Optional[types.TracebackType]) -> bool: > if exception_type: > self.database_connection.rollback() > else: > self.database_connection.commit() > self.database_connection.close() > > def get_connection(self) -> jdbc.Connection: > return self.database_connection Looking good! Assuming this is the only DB-interaction, a context-manager seems appropriate. If the real use-case calls for more interactions, the cost of establishing and breaking DB-connections becomes a consideration. Alternately, the 'length'?'life' of the context-manager *might* complicate things. Intriguing that given such a start, the code doesn't feature a context-manager for a query. That two cursors are established is also a 'cost'. Could both queries utilise the same cursor? (in which case, could consider adding to __init__() or __enter__(), and close in __exit__() ) Because the context-manager has been implemented as a class, there is no reason why one can't add more methods to that class (it doesn't need to be limited to the functional __enter__() and __exit__() methods! Indeed there is already get_connection(). Why not also a query( self, sql-code ) method? These might reduce the mainline-code to something like: if __name__ == "__main__": with Database() as mydb: mydb.query( "update table1 set x = 1 where y = 2" ) mydb.query( "update table2 set a = 1 where b = 2" ) -- Regards, =dn From arequipeno at gmail.com Wed Aug 23 15:05:44 2023 From: arequipeno at gmail.com (Ian Pilcher) Date: Wed, 23 Aug 2023 14:05:44 -0500 Subject: Getty fully qualified class name from class object In-Reply-To: References: <3397987e-ad50-ed09-640f-e55965456ea2@gmail.com> Message-ID: <9f0424cd-ac13-2edc-dd48-67c0bf297342@gmail.com> On 8/22/23 11:13, Greg Ewing via Python-list wrote: > Classes have a __module__ attribute: > > >>> logging.Handler.__module__ > 'logging' Not sure why I didn't think to look for such a thing. Looks like it's as simple as f'{cls.__module__}.{cls.__qualname__}'. Thanks! -- ======================================================================== Google Where SkyNet meets Idiocracy ======================================================================== From PythonList at DancesWithMice.info Wed Aug 23 19:28:48 2023 From: PythonList at DancesWithMice.info (dn) Date: Thu, 24 Aug 2023 11:28:48 +1200 Subject: Context manager for database connection In-Reply-To: References: Message-ID: <72fec275-53fe-4a72-941a-a153442c7279@DancesWithMice.info> On 24/08/2023 06.11, dn via Python-list wrote: > On 24/08/2023 03.41, Jason Friedman via Python-list wrote: >> with Database() as mydb: >> conn = mydb.get_connection() >> cursor = conn.get_cursor() >> cursor.execute("update table1 set x = 1 where y = 2") >> cursor.close() >> cursor = conn.get_cursor() >> cursor.execute("update table2 set a = 1 where b = 2") >> cursor.close() >> >> >> import jaydebeapi as jdbc >> class Database: >> ???? database_connection = None >> >> ???? def __init__(self, auto_commit: bool = False): >> ???????? self.database_connection = jdbc.connect(...) >> ???????? self.database_connection.jconn.setAutoCommit(auto_commit) >> >> ???? def __enter__(self) -> jdbc.Connection: >> ???????? return self >> >> ???? def __exit__(self, exception_type: Optional[Type[BaseException]], >> ????????????????? exception_value: Optional[BaseException], >> ????????????????? traceback: Optional[types.TracebackType]) -> bool: >> ???????? if exception_type: >> ???????????? self.database_connection.rollback() >> ???????? else: >> ???????????? self.database_connection.commit() >> ???????? self.database_connection.close() >> >> ???? def get_connection(self) -> jdbc.Connection: >> ???????? return self.database_connection Using a context-manager is a good idea: it ensures clean-up with/without an exception occurring. Accordingly, I (and may I presume, most) like the idea when working with life-cycle type resources, eg I/O. Absolutely nothing wrong with the idea! However, the scope of a c-m is the with-block. If there are a number of 'nested operations' to be performed (which could conceivably involve other c-ms, loops, or similar code-structures) the code could become harder to read and the length of the scope unwieldy. An ease of management tactic is being able to see the start and end of a construct on the same page/screen. Such would 'limit' the length of a c-m's scope. Perhaps drawing an inappropriate parallel, but like a try-except block, there seems virtue in keeping a c-m's scope short, eg releasing resources such as a file opened for output, and some basic DBMS-es which don't offer multi-access. Accordingly, why I stopped using a c-m for database work. NB YMMV! There were two other reasons: 1 multiple databases 2 principles (and my shining virtue (?) ) 1 came across a (statistics) situation where the client was using two DBMS-es. They'd used one for some time, but then preferred another. For their own reasons, they didn't migrate old data to the new DBMS. Thus, when performing certain analyses, the data-collection part of the script might have to utilise different DB 'sources'. In at least one case, comparing data through time, the routine needed to access both DBMS-es. (oh what a tangled web we weave...) 2 another situation where the script may or may not actually have needed to access the DB. Odd? In which case, the 'expense' of the 'entry' and 'exit' phases would never be rewarded. Thus, 'inspired' to realise that had (long) been contravening SOLID's DSP advice?rule (Dependency Inversion Principle). Accordingly, these days adopt something like the following (explaining it 'backwards' to aid comprehension in case you (gentle reader) have not come-across such thinking before - remember that word, "inversion"!) - in the mainline, prior to processing, instantiate a database object database = Database( credentials ) - assume the mainline calls a function which is the substance of the script: def just_do_it( database_instance, other_args, ): while "there's work to be done": database.query( query, data, etc, ) # could be SELECT or UPDATE in and amongst the 'work' - a basic outline of query() might be: def query( self, sql, data, etc, ): cursor = self.get_cursor() cursor.execute( sql, data, ) # according to DB/connector, etc # return query results - a query can't happen without a "cursor", so either use an existing cursor, or create a fresh one: def get_cursor( self ): if not self._cursor: connection = self.get_connection() self._cursor = connection.cursor() return self._cursor NB assuming the DBMS has restrictions on cursors, I may have multiple connections with one cursor each, but in some situations it may be applicable to run multiple cursors through a single connection. - a cursor can't exist without a "connection", so either ... : def get_connection( self ): if not self._connection: self._connection = # connect to the DB return self._connection - to instantiate a DB-object in the first place, the class definition: class Database: def __init__(self): self._connection = None self._cursor = None - and the one part of the exposition that's not 'backwards': def close(self): if self._connection: self._connection.close() It might be a plan to have several query() methods, according to application. If each is a dedicated query, such avoids the need to pass SQL around. Alternately, and because having "SELECT ..." sprinkled throughout one's code is a 'code smell' ("magic constants"), it's a good idea to have all such collected into a separate module. This would also facilitate the corporate situation where a DBA will provide services to the applications team. (don't EVER let a DBA into your Python code - you have been warned!) Just as with all toy-examples, much detail has been omitted. Specifically the OP's concern for error-checking. The above enables more thorough checking and more precise error-reporting; because the steps are discrete (very SRP = Single Responsibility Principle). That said, from an application point-of-view, all the DB stuff has been centralised and it either works or the whole thing should probably be drawn to a grinding-halt. The one glaring disadvantage is in the situation where a lot of (expensive) processing is carried-out, and only at the end is the DB accessed (presumably to persist the results). It could be frustrating to do 'all the work' and only thereafter find out that the DBMS is asleep-at-the-wheel, eg that Docker container has been started. Doh! The OP had a linked-query 'commit or rollback' situation. The structure of a separate method for that query-pair (perhaps calling individual methods for each query) with attendant controls (as described previously) will work nicely. Should you be foolish-enough to be required to (and capable of) cope with more than one DBMS, you can likely see that turning the Database class into an ABC, will enable consistency between multiple concrete and specific database class implementations. Thereafter a 'factory' to choose which DB-class to use, and all will be roses... (yeah right!) -- Regards, =dn From guenther.sohler at gmail.com Thu Aug 24 07:23:26 2023 From: guenther.sohler at gmail.com (Guenther Sohler) Date: Thu, 24 Aug 2023 13:23:26 +0200 Subject: Collecting unassigned Expressions Message-ID: Hi I am wondering If an embedded Python Interpreter can detect unassigned Expressions. Cases where functions Return values but they are Not assignwd. E.g. Calc_square(4) Or 3*4-myval() Thank you for your hints From lukasz at langa.pl Thu Aug 24 17:06:08 2023 From: lukasz at langa.pl (=?utf-8?Q?=C5=81ukasz_Langa?=) Date: Thu, 24 Aug 2023 23:06:08 +0200 Subject: [RELEASE] Python 3.11.5, 3.10.13, 3.9.18, and 3.8.18 is now available Message-ID: <52D8805C-BD62-4301-9AC9-A6D1F1916729@langa.pl> There?s security content in the releases, let?s dive right in. gh-108310 : Fixed an issue where instances of ssl.SSLSocket were vulnerable to a bypass of the TLS handshake and included protections (like certificate verification) and treating sent unencrypted data as if it were post-handshake TLS encrypted data. Security issue reported as CVE-2023-40217?1 by Aapo Oksman. Patch by Gregory P. Smith. Upgrading is highly recommended to all users of affected versions. Python 3.11.5 Get it here: https://www.python.org/downloads/release/python-3115/ This release was held up somewhat by the resolution of this CVE, which is why it includes a whopping 328 new commits since 3.11.4 (compared to 238 commits between 3.10.4 and 3.10.5). Among those, there is a fix for CVE-2023-41105 which affected Python 3.11.0 - 3.11.4. See gh-106242 for details. There are also some fixes for crashes, check out the change log to see all information. Most importantly, the release notes on the downloads page include a description of the Larmor precession. I understood some of the words there! Python 3.10.13 Get it here: https://www.python.org/downloads/release/python-31013/ 16 commits. Python 3.9.18 Get it here: https://www.python.org/downloads/release/python-3918/ 11 commits. Python 3.8.18 Get it here: https://www.python.org/downloads/release/python-3818/ 9 commits. Stay safe and upgrade! Thanks to all of the many volunteers who help make Python Development and these releases possible! Please consider supporting our efforts by volunteering yourself or through organization contributions to the Python Software Foundation. -- ?ukasz Langa @ambv on behalf of your friendly release team, Ned Deily @nad Steve Dower @steve.dower Pablo Galindo Salgado @pablogsal ?ukasz Langa @ambv Thomas Wouters @thomas -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 833 bytes Desc: Message signed with OpenPGP URL: From jsf80238 at gmail.com Mon Aug 28 14:46:20 2023 From: jsf80238 at gmail.com (Jason Friedman) Date: Mon, 28 Aug 2023 12:46:20 -0600 Subject: Generating documentation with Sphinx Message-ID: I have two questions, please (this is after reading https://docs.readthedocs.io/en/stable/guides/cross-referencing-with-sphinx.html#automatically-label-sections ). This is my project structure: my_project api stuff1.py stuff2.py lib stuff3.py stuff4.py main_application.py In my_project/main_application.py I have two functions: def construct_response(exit_code: int, message: str) -> Response: """ Construct a Flask-suitable response :param exit_code: 0 or something else :param message: something useful :return: a Flask-suitable response """ @app.route(f"/{version}/", methods=[GET, POST]) def serve(page) -> Response: """ Do some stuff and return 200 or 500 :param page: this is a REST endpoint we are advertising to callers :return: a Flask Response generated by construct_response """ Question 1: how do I embed in the serve function docstring a link to the construct_response function? Question 2: how do I embed in, for example, lib/stuff3.py, a link to the construct_response function? I tried: :ref:`my_project/api/stuff1:construct_response` but that gives an undefined label warning. From PythonList at DancesWithMice.info Mon Aug 28 15:06:11 2023 From: PythonList at DancesWithMice.info (dn) Date: Tue, 29 Aug 2023 07:06:11 +1200 Subject: Co-op Group: Django web framework Message-ID: Are you interested in learning Django? Would like to improve your Django knowledge and skills? Have you been picking-up Django piecemeal, and need to consolidate and clarify? Do you know some Django and would like to acquire mentoring and coaching skills? If so, please join us to form a Learning Django Co-op. RSVP at https://www.meetup.com/nzpug-auckland/events/295727130/ -- Regards =dn From jsf80238 at gmail.com Mon Aug 28 15:39:40 2023 From: jsf80238 at gmail.com (Jason Friedman) Date: Mon, 28 Aug 2023 13:39:40 -0600 Subject: Generating documentation with Sphinx In-Reply-To: References: Message-ID: > > def construct_response(exit_code: int, message: str) -> Response: > """ > Construct a Flask-suitable response > > :param exit_code: 0 or something else > :param message: something useful > :return: a Flask-suitable response > """ > > > @app.route(f"/{version}/", methods=[GET, POST]) > def serve(page) -> Response: > """ > Do some stuff and return 200 or 500 > > :param page: this is a REST endpoint we are advertising to callers > :return: a Flask Response generated by construct_response > """ > > > Question 1: how do I embed in the serve function docstring a link to the > construct_response function? > > > Question 2: how do I embed in, for example, lib/stuff3.py, a link to the > construct_response function? > > > I tried: > :ref:`my_project/api/stuff1:construct_response` > > but that gives an undefined label warning. > I can answer my own Question 1: :func:`construct_response` From jsf80238 at gmail.com Mon Aug 28 17:12:34 2023 From: jsf80238 at gmail.com (Jason Friedman) Date: Mon, 28 Aug 2023 15:12:34 -0600 Subject: Generating documentation with Sphinx In-Reply-To: References: Message-ID: And I can answer my own Question 2: :func:`my_project.main_application.construct_response` On Mon, Aug 28, 2023 at 1:39?PM Jason Friedman wrote: > def construct_response(exit_code: int, message: str) -> Response: >> """ >> Construct a Flask-suitable response >> >> :param exit_code: 0 or something else >> :param message: something useful >> :return: a Flask-suitable response >> """ >> >> >> @app.route(f"/{version}/", methods=[GET, POST]) >> def serve(page) -> Response: >> """ >> Do some stuff and return 200 or 500 >> >> :param page: this is a REST endpoint we are advertising to callers >> :return: a Flask Response generated by construct_response >> """ >> >> >> Question 1: how do I embed in the serve function docstring a link to the >> construct_response function? >> >> >> Question 2: how do I embed in, for example, lib/stuff3.py, a link to the >> construct_response function? >> >> >> I tried: >> :ref:`my_project/api/stuff1:construct_response` >> >> but that gives an undefined label warning. >> > > I can answer my own Question 1: > :func:`construct_response` > From jsf80238 at gmail.com Mon Aug 28 17:13:06 2023 From: jsf80238 at gmail.com (Jason Friedman) Date: Mon, 28 Aug 2023 15:13:06 -0600 Subject: Generating documentation with Sphinx In-Reply-To: References: Message-ID: def construct_response(exit_code: int, message: str) -> Response: >> """ >> Construct a Flask-suitable response >> >> :param exit_code: 0 or something else >> :param message: something useful >> :return: a Flask-suitable response >> """ >> >> >> @app.route(f"/{version}/", methods=[GET, POST]) >> def serve(page) -> Response: >> """ >> Do some stuff and return 200 or 500 >> >> :param page: this is a REST endpoint we are advertising to callers >> :return: a Flask Response generated by construct_response >> """ >> >> >> Question 1: how do I embed in the serve function docstring a link to the >> construct_response function? >> >> >> Question 2: how do I embed in, for example, lib/stuff3.py, a link to the >> construct_response function? >> >> >> I tried: >> :ref:`my_project/api/stuff1:construct_response` >> >> but that gives an undefined label warning. >> > > I can answer my own Question 1: > :func:`construct_response` > And I can answer my own Question 2: :func:`my_project.main_application.construct_response` From c.buhtz at posteo.jp Wed Aug 30 07:32:02 2023 From: c.buhtz at posteo.jp (c.buhtz at posteo.jp) Date: Wed, 30 Aug 2023 11:32:02 +0000 Subject: Using "textwrap" package for unwrappable languages (Japanese) Message-ID: <17c67561e4735322f28c42161e1774e2@posteo.de> Hi, I do use "textwrap" package to wrap longer texts passages. Works well with English. But the source string used is translated via gettext before it is wrapped. Using languages like Japanese or Chinese would IMHO result in unwrapped text. Japanese rules do allow to break a line nearly where ever you want. How can I handle it with "textwrap"? At runtime I don't know which language is really used. So I'm not able to decide using "textwrap" or just inserting "\n" every 65 characters. Another approach would be to let the translators handle the line breaks. But I would like to avoid it because some of them don't know what "\n" means and they don't know the length rule (in my case 65 characters). Any ideas about it? Kind Christian From hjp-python at hjp.at Wed Aug 30 08:07:06 2023 From: hjp-python at hjp.at (Peter J. Holzer) Date: Wed, 30 Aug 2023 14:07:06 +0200 Subject: Using "textwrap" package for unwrappable languages (Japanese) In-Reply-To: <17c67561e4735322f28c42161e1774e2@posteo.de> References: <17c67561e4735322f28c42161e1774e2@posteo.de> Message-ID: <20230830120706.edyu4zyznbwas2eu@hjp.at> On 2023-08-30 11:32:02 +0000, c.buhtz--- via Python-list wrote: > I do use "textwrap" package to wrap longer texts passages. Works well with > English. > But the source string used is translated via gettext before it is wrapped. > > Using languages like Japanese or Chinese would IMHO result in unwrapped > text. Japanese rules do allow to break a line nearly where ever you want. > > How can I handle it with "textwrap"? > > At runtime I don't know which language is really used. So I'm not able to > decide using "textwrap" or just inserting "\n" every 65 characters. I don't have a solution but want to add another caveat: Japanese characters are usually double-width. So (unless your line length is 130 characters for English) you would want to add that line break every 32 characters. (unicodedata.east_asian_width() seems to be the canonical name to find the width of a character, but it returns a code (like 'W' or 'Na') not a number.) hp -- _ | Peter J. Holzer | Story must make more sense than reality. |_|_) | | | | | hjp at hjp.at | -- Charles Stross, "Creative writing __/ | http://www.hjp.at/ | challenge!" -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 833 bytes Desc: not available URL: From c.buhtz at posteo.jp Wed Aug 30 09:18:25 2023 From: c.buhtz at posteo.jp (c.buhtz at posteo.jp) Date: Wed, 30 Aug 2023 13:18:25 +0000 Subject: Using "textwrap" package for unwrappable languages (Japanese) In-Reply-To: <20230830120706.edyu4zyznbwas2eu@hjp.at> References: <17c67561e4735322f28c42161e1774e2@posteo.de> <20230830120706.edyu4zyznbwas2eu@hjp.at> Message-ID: <7a06c95720e6b369ccf7b3f90513da92@posteo.de> Dear Peter, thanks for your reply. That is a very interesting topic. I was a bit wrong. I realized that textwrap.wrap() do insert linebreaks when "words" are to long. So even a string without any blank space well get wrapped. Am 30.08.2023 14:07 schrieb Peter J. Holzer via Python-list: > another caveat: Japanese > characters are usually double-width. So (unless your line length is 130 > characters for English) you would want to add that line break every 32 > characters. I don't get your calculation here. Original line length is 130 but for "double-with" characters you would break at 32 instead of 65 ? > ( Then I will do something like this unicodedata.east_asian_width(mystring[0]) W is "wide". But there is also "F" (full-width). What is the difference between "wide" and "full-width"? My application do support (currently 46) languages including Simplified and Traditional Chinese, Vietnamese, Korean, Japanese, Cyrylic. From hjp-python at hjp.at Wed Aug 30 13:52:50 2023 From: hjp-python at hjp.at (Peter J. Holzer) Date: Wed, 30 Aug 2023 19:52:50 +0200 Subject: Using "textwrap" package for unwrappable languages (Japanese) In-Reply-To: <7a06c95720e6b369ccf7b3f90513da92@posteo.de> References: <17c67561e4735322f28c42161e1774e2@posteo.de> <20230830120706.edyu4zyznbwas2eu@hjp.at> <7a06c95720e6b369ccf7b3f90513da92@posteo.de> Message-ID: <20230830175250.u5ifiabh7whqnyct@hjp.at> On 2023-08-30 13:18:25 +0000, c.buhtz--- via Python-list wrote: > Am 30.08.2023 14:07 schrieb Peter J. Holzer via Python-list: > > another caveat: Japanese characters are usually double-width. So > > (unless your line length is 130 characters for English) you would > > want to add that line break every 32 characters. > > I don't get your calculation here. Original line length is 130 but for > "double-with" characters you would break at 32 instead of 65 ? No, I wrote "*unless* your original line length was 130 characters". I assumed that you want your line to be 65 latin characters wide since this is what fits nicely on an A4 (or letter) page with a bit of a margin on both sides. Or on an 80 character terminal screen or window. And it's also generally considered to be a good line length for readability. But Asian "full width" or "wide" characters are twice as wide, so you can fit only half as many in a single line. Hence 65 // 2 = 32. But that was only my assumption. I considered it possible that you started with 130 characters per line (many terminals back in the day had a 132 character mode, and that's also approximately the line length in landscape mode or when using a compressed typeface - so 132 is also a common length limit, although rarely for text (too wide to read comfortably) and more for code, tables, etc.), divided that by two and arrived at 65 Japanese characters per line that way. So I mentioned that to indicate that I had considered the possibility but concluded that it probably wasn't what you meant. (And as usual when I write a short sentence to clarify something I wind up writing 4 paragraphs clarifying the clarification :-/) > Then I will do something like this > > unicodedata.east_asian_width(mystring[0]) > > W is "wide". But there is also "F" (full-width). > What is the difference between "wide" and "full-width"? I'm not an expert on Japanese typography by any means. But they have some full width variants of latin characters and halfwidth variants of katakana characters. I assume that the categories 'F' and 'H' are for those, while "normal" Japanese characters are "W": >>> unicodedata.east_asian_width("\N{DIGIT ONE}") 'Na' >>> unicodedata.east_asian_width("\N{FULLWIDTH DIGIT ONE}") 'F' >>> unicodedata.east_asian_width("\N{KATAKANA LETTER ME}") 'W' >>> unicodedata.east_asian_width("\N{HALFWIDTH KATAKANA LETTER ME}") 'H' hp -- _ | Peter J. Holzer | Story must make more sense than reality. |_|_) | | | | | hjp at hjp.at | -- Charles Stross, "Creative writing __/ | http://www.hjp.at/ | challenge!" -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 833 bytes Desc: not available URL: From rob.cliffe at btinternet.com Sun Aug 27 17:19:02 2023 From: rob.cliffe at btinternet.com (Rob Cliffe) Date: Sun, 27 Aug 2023 22:19:02 +0100 Subject: f-string error message Message-ID: <6e981ac8-9648-8fd7-4b00-35c6cf45dd7e@btinternet.com> I am currently using Python 3.11.4. First I want to say: f-strings are great!? I use them all the time, mostly but by no means exclusively for debug messages.? And in 3.12 they will get even better. And the improved error messages in Python (since 3.9) are great too!? Keep up the good work. However the following error message confused me for a while when it happened in real code: >>> import decimal >>> x=42 >>> f"{x:3d}" ' 42' >>> x=decimal.Decimal('42') >>> f"{x:3d}" Traceback (most recent call last): ? File "", line 1, in ValueError: invalid format string I understand that this is an error: I'm telling the f-string to expect an integer when in fact I'm giving it a Decimal. And indeed f"{x:3}" gives ' 42' whether x is an int or a Decimal. However, to my mind it is not the format string that is invalid, but the value supplied to it. Would it be possible to have a different error message, something like ValueError: int expected in format string but decimal.Decimal found Or am I missing something? Best wishes Rob Cliffe From random832 at fastmail.com Thu Aug 31 00:15:12 2023 From: random832 at fastmail.com (Random832) Date: Thu, 31 Aug 2023 00:15:12 -0400 Subject: f-string error message In-Reply-To: <6e981ac8-9648-8fd7-4b00-35c6cf45dd7e@btinternet.com> References: <6e981ac8-9648-8fd7-4b00-35c6cf45dd7e@btinternet.com> Message-ID: <9f25c385-b2b2-4be1-a785-39dd04bc4c55@app.fastmail.com> On Sun, Aug 27, 2023, at 17:19, Rob Cliffe via Python-list wrote: > I understand that this is an error: I'm telling the f-string to expect > an integer when in fact I'm giving it a Decimal. > And indeed f"{x:3}" gives ' 42' whether x is an int or a Decimal. > However, to my mind it is not the format string that is invalid, but the > value supplied to it. > Would it be possible to have a different error message, something like > > ValueError: int expected in format string but decimal.Decimal found > > Or am I missing something? It's up to the type what format strings are valid for it, so you can't really go "int expected". However, a more detailed error string like "invalid format string '3d' for object Decimal('42')" might be useful. right now we have some inconsistencies: - float object [same for str, int, etc] ValueError: Unknown format code 'd' for object of type 'float' [if it thinks it's identified a single-letter 'code' in the usual microlanguage] ValueError: Invalid format specifier '???' for object of type '[type]' - arbitrary object that doesn't override __format__, ipaddress TypeError: unsupported format string passed to [type].__format__ - datetime, decimal ValueError: Invalid format string neither shows the value of the offending object, only its type. incidentally, ipaddress and object don't support the usual field width, padding, etc specifiers [int supports code 'f' just fine, by the way, but has the same message as float if you give it 's'] Going beyond that, it *might* be viable to have some sort of "guess what numeric type the format string was intended for", shared across at least all numeric types of objects. Alternatively, we could require all numeric types to support all numeric formats, even ones that don't make a lot of sense. From cl at isbd.net Thu Aug 31 16:32:04 2023 From: cl at isbd.net (Chris Green) Date: Thu, 31 Aug 2023 21:32:04 +0100 Subject: What sort of exception when a class can't find something? Message-ID: <4v97sj-csgm.ln1@esprimo.zbmc.eu> What sort of exception should a class raise in __init__() when it can't find an appropriate set of data for the parameter passed in to the class instantiation? E.g. I have a database with some names and address in and have a class Person that gets all the details for a person given their name. .... .... person.Person('Fred') ... ... If Fred doesn't exist in the database what sort of exception should there be? Is it maybe a ValueError? -- Chris Green ? From hjp-python at hjp.at Thu Aug 31 16:53:28 2023 From: hjp-python at hjp.at (Peter J. Holzer) Date: Thu, 31 Aug 2023 22:53:28 +0200 Subject: What sort of exception when a class can't find something? In-Reply-To: <4v97sj-csgm.ln1@esprimo.zbmc.eu> References: <4v97sj-csgm.ln1@esprimo.zbmc.eu> Message-ID: <20230831205328.txykpigo37aselzc@hjp.at> On 2023-08-31 21:32:04 +0100, Chris Green via Python-list wrote: > What sort of exception should a class raise in __init__() when it > can't find an appropriate set of data for the parameter passed in to > the class instantiation? > > E.g. I have a database with some names and address in and have a > class Person that gets all the details for a person given their > name. > > .... > .... > person.Person('Fred') > ... > ... > > > If Fred doesn't exist in the database what sort of exception should > there be? Is it maybe a ValueError? It you are going for a builtin exception, I think KeyError is the most appropriate: It should be a LookupError, since the lookup failed and a database is more like a mapping than a sequence. But it would probably be best to define your own exception for that. hp -- _ | Peter J. Holzer | Story must make more sense than reality. |_|_) | | | | | hjp at hjp.at | -- Charles Stross, "Creative writing __/ | http://www.hjp.at/ | challenge!" -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 833 bytes Desc: not available URL: From rosuav at gmail.com Thu Aug 31 17:01:39 2023 From: rosuav at gmail.com (Chris Angelico) Date: Fri, 1 Sep 2023 07:01:39 +1000 Subject: What sort of exception when a class can't find something? In-Reply-To: <4v97sj-csgm.ln1@esprimo.zbmc.eu> References: <4v97sj-csgm.ln1@esprimo.zbmc.eu> Message-ID: On Fri, 1 Sept 2023 at 06:39, Chris Green via Python-list wrote: > > What sort of exception should a class raise in __init__() when it > can't find an appropriate set of data for the parameter passed in to > the class instantiation? > > E.g. I have a database with some names and address in and have a > class Person that gets all the details for a person given their > name. > > .... > .... > person.Person('Fred') > ... > ... > > > If Fred doesn't exist in the database what sort of exception should > there be? Is it maybe a ValueError? > There's no clear answer to this, because you aren't really constructing a Person here. So there are a few options that seem pretty reasonable: 1) As you say, raise ValueError. The problem is the value passed in (it's the right type, but the value wasn't found), so, ValueError. 2) KeyError. This emphasizes the fact that you're effectively looking up in a mapping. Quite odd for a constructor though. 3) A custom RecordNotFound exception. You're doing something unusual, so make it your own exception. TBH I would suggest making a slightly different API: person.Person.from_name('Fred') ie a classmethod alternate constructor. These can most definitely raise ValueError when the value given isn't appropriate: >>> datetime.datetime.fromordinal(-1) Traceback (most recent call last): File "", line 1, in ValueError: ordinal must be >= 1 and it makes good sense for a method like this to be doing lookups, rather than construction per se. (At a technical level, it's presumably constructing new objects.) To help with making that decision, what happens if you construct two Person objects for the same actual person? Would you return the same object (ie maintain a cache and deduplicate)? Or does each one take a snapshot of the data at the instant of construction, and thus you can observe changes through time by constructing more? Both are reasonable and make sense, but they lend themselves to slightly different approaches. ChrisA From cl at isbd.net Thu Aug 31 17:08:58 2023 From: cl at isbd.net (Chris Green) Date: Thu, 31 Aug 2023 22:08:58 +0100 Subject: What sort of exception when a class can't find something? References: <4v97sj-csgm.ln1@esprimo.zbmc.eu> Message-ID: Several helpful replies, thank you all. -- Chris Green ? From cl at isbd.net Thu Aug 31 17:15:36 2023 From: cl at isbd.net (Chris Green) Date: Thu, 31 Aug 2023 22:15:36 +0100 Subject: Why do I always get an exception raised in this __init__()? Message-ID: I'm obviously doing something very silly here but at the moment I can't see what. Here's the code:- #!/usr/bin/python3 # # # GPIO # import gpiod # # # Simple wrapper class for gpiod to make set and clearing outputs easier # class Gpiopin: def __init__(self, pin): # # # scan through the GPIO chips to find the line/pin we want # for c in ['gpiochip0', 'gpiochip1', 'gpiochip2', 'gpiochip3']: chip = gpiod.Chip(c) for l in range(32): line = chip.get_line(l) if pin in line.name(): print("Found: ", line.name()) return else: raise ValueError("Can't find pin '" + pin + "'") def print_name(self): print (self.line.name()) def set(self): self.line.set_value(1) def clear(self): self.line.set_value(0) This is by no means the final code, the print() in the __init__() is just a diagnostic for example. However I really can't understand why I see the following when I try it:- >>> import ngp >>> ngp.Gpiopin("P9_23") Found: P9_23 Traceback (most recent call last): File "", line 1, in File "/home/chris/.cfg/hosts/bbb/bin/ngp.py", line 24, in __init__ return ValueError: Can't find pin 'P9_23' >>> Does a return in __init__() not do what I think it does? How else could/should I do this? -- Chris Green ? From cl at isbd.net Thu Aug 31 17:25:02 2023 From: cl at isbd.net (Chris Green) Date: Thu, 31 Aug 2023 22:25:02 +0100 Subject: Why do I always get an exception raised in this __init__()? References: Message-ID: Chris Green wrote: [snip code and question] Sorry folks, it was a caching problem, I wasn't running the code I thought I was running! When I made sure I had cleared everything out and tried again it all worked as I expected. -- Chris Green ? From larry.martell at gmail.com Thu Aug 31 18:34:55 2023 From: larry.martell at gmail.com (Larry Martell) Date: Thu, 31 Aug 2023 15:34:55 -0700 Subject: Why do I always get an exception raised in this __init__()? In-Reply-To: References: Message-ID: On Thu, Aug 31, 2023 at 3:19?PM Chris Green via Python-list wrote: > > I'm obviously doing something very silly here but at the moment I > can't see what. > > Here's the code:- > > #!/usr/bin/python3 > # > # > # GPIO > # > import gpiod > # > # > # Simple wrapper class for gpiod to make set and clearing outputs > easier > # > class Gpiopin: > > def __init__(self, pin): > # > # > # scan through the GPIO chips to find the line/pin we want > # > for c in ['gpiochip0', 'gpiochip1', 'gpiochip2', 'gpiochip3']: > > chip = gpiod.Chip(c) > for l in range(32): > line = chip.get_line(l) > if pin in line.name(): > print("Found: ", line.name()) > return > else: > raise ValueError("Can't find pin '" + pin + "'") > > def print_name(self): > print (self.line.name()) > > def set(self): > self.line.set_value(1) > > def clear(self): > self.line.set_value(0) > > > This is by no means the final code, the print() in the __init__() is > just a diagnostic for example. However I really can't understand why I > see the following when I try it:- > > >>> import ngp > >>> ngp.Gpiopin("P9_23") > Found: P9_23 > Traceback (most recent call last): > File "", line 1, in > File "/home/chris/.cfg/hosts/bbb/bin/ngp.py", line 24, in __init__ > return > ValueError: Can't find pin 'P9_23' > >>> > > Does a return in __init__() not do what I think it does? > > How else could/should I do this? Change the return to a break