Re: TKinter in Python - advanced notions
On 6/21/23 09:47, Dan Kolis wrote: I've write a huge biotech program ( an IDE for synthetic biology ), and am slowly outgrowing TKINTER. Has anybody out there merged a little bit of TCL direct calls from Python 3.X to get more freedom then TKINTER for just some Windows ? I wish it looked better, but its 'ok'. I believe X11 IO is considerably superior for serious work the HTML. I mean 'serious' work. with lots of multi media windows. I am not talking about fb "Oh ! There is a window it opened inthe corner !"... trivial functionality. I don't know if it would help, but you can extend/add tcl/tk packages I don't remember the full instructions right off, but quickly reverse engineering my old stuff I think you just need to drop them in /usr/share/tcltk/ or equivalent. (I needed to do that to replace the terrible looking default file dialog for unix/linux with fsdialog.) then running something like the following from your Tk object self.eval('package require fsdialog') (reverse engineering the python tkinter source you can likely find other ways of doing more tcl direct stuff) I have not researched if there are some better, more featured (non-buggy) Text widgets implemented in tcl that can be dropped in, (I know several of the tcl drop in widgets I tried were lacking in refinement). From what I can tell, once upon a time there were better, more interesting projects and tutorials on extending tkinter, such as WCK (tkinter3000), but the only remnants of those remain publicly available are outdated unmaintained archives. You might also consider looking at the Grail browser source for research purposes, as it does some interesting things with some of the widgets, (parsing html and such), even though it is 20 years old now (and written in python 1). The update attempts from 10+ years ago have disappeared. (it's license is considered questionable from what I understand, so not sure if that is an aspect of it, the other being one of it's main features, python applets, is unsafe and was not easily fixable) You might already be beyond some of these things though. I know what you mean as far is feeling like the little bit extra you need pushes beyond what tkinter can do / makes you feel like you have outgrown the module. (I had to take a break from one of my projects and send it to development hell until my UI knowledge/skills improve after I found myself considering using xml schema appinfo annotations to store json formatted widget specific information, lol.) I have felt that sense of lack with most of the UI modules I have tried though. I don't know of a clear better python-only solution though that fits my personal needs. So I have to lean toward improving my tcl / C in hopes that it might help steer me toward that extra (which seems to be in the spirit of what tcl/tk's intent is to begin with). That will be a while for me though if I get there. -- https://mail.python.org/mailman/listinfo/python-list
Re: What to use instead of nntplib?
I used to run my own mail server. Now I don't. Practicality beats purity. To be quite frank, the moralistic approach of complaining about the way other people are too happy to give control to big companies is NEVER going to achieve anything. You're welcome to be a little island, that one Gaulish village that still holds out against the invaders, but all you'll actually be doing is sidelining yourself. I'm not saying that this is a GOOD situation, but facts are facts, and I use Chrome and GitHub and a wide variety of other tools that aren't free. ChrisA Don't get me wrong, I know I have lost the battle in this age, lol. The opening statement probably came off way less pragmatic than I intended before writing it. The attempt to steer the ol' "bitching just to bitch" toward more if a statement as to the fundamentals of why there is a bitch and frustration with how things are didn't quite make it there. But regardless my positions are correct, lol, you know the situation is "NOT" GOOD, and you justify your compromises, as we tend to do to whatever extent we decide that we can live with, and time tells how those things play out. For there to have been an elicited reaction to my statements sort of goes against the statement "NEVER going to achieve anything". I am fine in my cave, a lot of things seen as "facts are facts" tend to change over time, and I don't see anyone else going anywhere that I need to go. -- https://mail.python.org/mailman/listinfo/python-list
Re: What to use instead of nntplib?
On 5/22/23 12:10, Grant Edwards wrote: On 2023-05-21, Retrograde wrote: Who ever came up with "Removing dead batteries" as a slogan, when some of those batteries still work perfectly well, needs to rethink it. Go ahead and remove code that no longer works, OK. But removing unpopular modules? That undercuts the entire philosophy of the platform, in my opinion. And one of the metrics of "popularity" seems to be "activity" (e.g. changes committed). For things that have been around for 20+ years and have all the features they need and all of the bugs fixed (and are now very stable) that lack of "activity" is interpreted as "unpopular" regardless of how many people are using the module. -- Grant To add an additional bitching, I don't really ever see anyone discussing the dynamics and downsides of github (and things like it). Or how things like mozilla killing off usenet and mailing lists changes the entire dynamic of who manages and gets a say in how technology gets to move forward. As someone who sees software independence and using free software as moral imperatives, signing up for github and agreeing to yet another terms of service is a no go for me, so moving to these platforms locks me out from contributing. (and a lot of python packages have code that also works with proprietary operating systems, so non-gnu/gnu hosting isn't a solution either) And as someone who uses usenet to post to this list (I object to the google captcha on the mailing list sign up, and captchas in general), I imagine eventually a discussion will take place in a place like github that will do away with this avenue as well. As far as modern commit dynamics, Even if I did partake in the modern github style of code distribution, how many packages have issues where the "maintainers" inherited the package and really haven't dug deep enough in to the code to see how it really works. They have issues that sit around for YEARS, and when someone says "this sucks, this is broken and could be better", and the githubian response is typically a dismissive "Nothing is stopping you from making a PR". Then when you get down to dedicating a month to polishing a PR to extend or redesign something with the features you need, it just sits there, for YEARS, because again, the authority that went in to the package in the first place is often gone, and there is no one with that knowledge to give the PR the review it deserves. You end up with your fork, but it is lost, indistinguished from all the other forks of nothing. There are now probably dozens of nntplib preservation implementations floating around, but how do you even consider which one to use? Without some energy behind it, to be certain in what you are doing, each person will practically have to download Python3.11 and extract it themselves, and then either add it in to the latest version themselves, or comparitively study it vs a collection of new implementations to see which one feels most like a correct updated standard. You also have to consider, is this a one off update? At 3.13 will I have to do it all over again? (at that point, doing it yourself really does become the only solution). At the end of the day, what is there boils down to the influence of who is offering the resources.. And I would say most of that today comes from the microsofts and googles of the world that have no interest in preserving the independent ethos of the early web.. I personally am partial to autonomous website distribution, and mailmanv2 dev collaborations, so you can independently share modified versions of packages or tutorials you've written for your own purposes, and if they help others, great.. But I personally haven't found a place that accepts small cash payments and feels neutral enough to fit my needs and limited resources. -- https://mail.python.org/mailman/listinfo/python-list
Re: Tkinter docs?
On 5/23/23 21:18, Rob Cliffe wrote: Comments, anyone? Better yet (holds breath ...) can anyone point me towards some decent tkinter documentation? The variables are slightly more integrated when using tcl/tk directly, python has to have the object so you can track/use them easier. And the variables are more of what is intended to track a widgets purpose, vs state stuff that is more the state of the displaying of the widget. occasionally giving tcl/tk a try directly helps, and using the official tcl/tk docs in addition to a couple other decent docs below. https://anzeljg.github.io/rin2/book2/2405/docs/tkinter/index.html https://tkdocs.com/tutorial/styles.html https://www.tcl.tk/man/tcl8.6/ https://www.tcl.tk/man/tcl8.6/TkCmd/contents.html https://www.tcl.tk/man/tcl8.6/TkLib/contents.html (this used to be some documentation that I only discovered existed recently, but most of it doesn't load and I don't know that anyone backed it up for rehosting..) https://web.archive.org/web/20200227170827/http://effbot.org/tkinterbook tk is decent for what it can do, (and it could do potentially more if you had a lifetime to dedicate to it, lol) and it's reasonably stable and not being perpetually hacked about and broken like gtk. A couple additional pointers in case these haven't been figured out yet: Running it interactively and using tab complete helps. If you are running an app you can comment out the mytk.mainloop() statement then run python -i yourtk.py to give you access to all widgets live. For navigating them, just come up with a widget naming convention that works for you in a similar vein to how tk does (like .frame.frame.label to start), i.e. main = tk.Tk() main.frame = tk.Frame() That way if you have anchored your widgets to something at the root level you can navigate down to whatever you are looking for easily. (you can also use winfo_children() iteratively to travel the way tcl structures them, but that is tedious). -- https://mail.python.org/mailman/listinfo/python-list
Re: [pygettext] --package-name and --package-version unknown
On 5/5/23 04:39, c.bu...@posteo.jp wrote: That being said, the git repo linked earlier has accepted commits to that file earlier this year. So read in to that what you will *shrugs* -- https://mail.python.org/mailman/listinfo/python-list
Re: [pygettext] --package-name and --package-version unknown
On 5/5/23 04:39, c.bu...@posteo.jp wrote: Thanks for the answer. Am 05.05.2023 03:24 schrieb aapost: pygettext is deprecated since xgettext supports python now, so using xgettext is recommended. If this is the official case then it should be mentioned in the python docs. The 3.11 docs still tell about pygettext and xgettext and don't recommend one of it. Yep, no disagreement. A lot of things 'should' be though, and technically it is (which docs being the key, lol): $man pygettext PYGETTEXT(1) General Commands Manual PYGETTEXT(1) NAME pygettext - Python equivalent of xgettext(1) SYNOPSIS pygettext [OPTIONS] INPUTFILE ... DESCRIPTION pygettext is deprecated. The current version of xgettext supports many languages, including Python. pygettext uses Python's standard tokenize module to scan Python source code, generating .pot files identical to what GNU xgettext generates for C and C++ code. From there, the standard GNU tools can be used. pygettext searches only for _() by default, even though GNU xgettext recognizes the following keywords: gettext, dgettext, dcgettext, and gettext_noop. See the -k/--keyword flag below for how to augment this. (I have never used either, I just spent a few minutes trying to be helpful =P) -- https://mail.python.org/mailman/listinfo/python-list
Re: [pygettext] --package-name and --package-version unknown
On 5/4/23 17:38, c.bu...@posteo.jp wrote: am I right to assume that "pygettext" is part of the official Python3 "package"? So it is OK to aks here? How can I set the "Project-Id-Version"? With "xgettext" I would use the arguments "--package-name" and "--package-version" for this but they are unknown for "pygettext". pygettext is deprecated since xgettext supports python now, so using xgettext is recommended. That being said, pygettext does not support the options, but it could be modified pretty easily. Untested but if you wanted to add that functionality in just create a modified pygettext.py with something like: link PACKAGE and VERSION to variables: pot_header = _('''\ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR ORGANIZATION # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: %(packagename)s %(packageversion)s\\n" "POT-Creation-Date: %(time)s\\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n" "Last-Translator: FULL NAME \\n" "Language-Team: LANGUAGE \\n" "MIME-Version: 1.0\\n" "Content-Type: text/plain; charset=%(charset)s\\n" "Content-Transfer-Encoding: %(encoding)s\\n" "Generated-By: pygettext.py %(version)s\\n" ''') add attributes to Options class: class Options: # constants GNU = 1 SOLARIS = 2 # defaults extractall = 0 # FIXME: currently this option has no effect at all. escape = 0 keywords = [] outpath = '' outfile = 'messages.pot' writelocations = 1 locationstyle = GNU verbose = 0 width = 78 excludefilename = '' docstrings = 0 nodocstrings = {} packagename = "PACKAGE" packageversion = "VERSION" modify option parsing for loop to look for new options: for opt, arg in opts: elif opt in ('--package-name',): options.packagename = arg elif opt in ('--package-version',): options.packageversion = arg grab those options when generating file output: def write(self, fp): options = self.__options packagename = options.packagename packageversion = options.packageversion timestamp = time.strftime('%Y-%m-%d %H:%M%z') encoding = fp.encoding if fp.encoding else 'UTF-8' print(pot_header % {'packagename': packagename, 'packageversion': packageversion, 'time': timestamp, 'version': __version__, 'charset': encoding, 'encoding': '8bit'}, file=fp) (did not test, so might be a bug or two) -- https://mail.python.org/mailman/listinfo/python-list
Note when migrating '#' formats for PyArgs_ParseTuple
Just in case anyone else runs in to it. If you have code such as: char* a; char* b; char* d; int size; if (!PyArg_ParseTuple(args, "sss#:f", &a, &b, &d, &size)) return NULL; and it tells you to: #define PY_SSIZE_T_CLEAN #include "Python.h" Be sure to change int size; to: Py_ssize_t size; If you forget, your code will compile fine and still work perfectly fine on all py2 and py3 i386 variants, but will break 64bit variants in very non-obvious ways. In the above example the mismatched pointer type of size messes up the seemingly unrelated pointer a padr a 0x7f1f padr b 0x7f1fa656b960 padr d 0x7f1fa65579a0 So while accessing the s# argument works fine, you get a segfault when you access a I spent quite a while chasing my tail researching variadics, picking apart the code trying to understand how and where 'a' gets stomped on before I realized the size type mismatch. -- On that note, I will say that the removal of distutils/setup.py-ability from 3.12 without a similarly simple out of the box replacement is unfortunate. (if setup.py usage had design flaws that lead to deprecation fine, but python should have some form of stand alone equivalency included out of the box by default) For researching issues like the above, and for people who want to use python for off-internet projects, it is nice to be able to spin up a virtual machine from any said era, and do a ./configure make ./python setup.py install --user As things diverge in the future, things start to break, and you don't always have all the pieces to put it back together, and pip kind of sucks and is not simple when it doesn't work. It's pushy, it wants to force everyone to connect to the hive, it demands ssl, etc, when I just want it to shut up and make ./python -m pip install . do what ./python setup.py install --user does I will figure out what works best situationally moving forward as far as work arounds (probably modifying pip), but just saying, the modern way of jenkinizing everything sucks, and takes the fun out of tinkering in a cave. -- https://mail.python.org/mailman/listinfo/python-list
Re: Question regarding unexpected behavior in using __enter__ method
On 4/20/23 18:44, Lorenzo Catoni wrote: Here, the TypeError occurred because "self" was passed as an input Instantiate X and observe it there x2 = X() >>> X.__enter__ >>> X.__exit__ at 0x...> >>> x2.__enter__ >>> x2.__exit__ of <__main__.X object at 0x...>> To receive self the method must be bound. __enter__ = int doesn't bind the int type/class on instantiation, so it never gets self. Your custom function binds and receives self. I am not sure if there is documentation to explain better specifically what makes makes type different and not bindable. -- https://mail.python.org/mailman/listinfo/python-list
Re: Pycharm IDE
On 4/18/23 19:18, Kevin M. Wilson wrote: Why complain about a 'comma', or a ')'??? print (f'"I am thinking of a number between 1 to {LIMIT}\n") my version says it expects ' first (to close the fstring) then on a new line below it, it mentions the comma and ) I believe that is just showing you after ' it expects you to end the print with ) as you have or , to add additional arguments to print -- https://mail.python.org/mailman/listinfo/python-list
Re: Cannot install pkg_resources using pip
On 4/17/23 08:45, Rich Shepard wrote: On Sun, 16 Apr 2023, Thomas Passin wrote: Slackware isn't as straight forward in it's management as other distros (not standardized anyway). If this is someone elses install I would be cautious in using any advice I am providing, as it would be better for someone with familiarity with how they want the device set up to address the issues (such as if they prefer using some sort of package scheme or if doing everything from source is ok). That being said, if you start from python source (as in overwriting what is currently there and doing a fresh reinstall), you can download Python3.9, then run ./configure make make install after doing that, verify (python may still link to something old, that may be ok in this case, but good to note) python --version python3 --version python3.9 --version pkg_resources is inside of setuptools so you would run python3.9 -m pip install setuptools (might already be there with the reinstall) after that run python3.9 then run import pkg_resources import setuptools to see if you get errors or successful imports if they import successfully, attempt to reinstall meson and ninja against your fresh python install python3.9 -m pip install meson python3.9 -m pip install ninja verify versions with meson -v ninja --version Then follow the instructions of the meson package from there (you mentioned some sort of pulseaudio-equalizer, depending on your desktop environment, you may run in to additional issues depending on how your slackware is setup). -- https://mail.python.org/mailman/listinfo/python-list
Re: tksheet - Copy and Paste with headers
On 4/14/23 14:33, angela vales wrote: I have recently created a tkinter app and need the ability to copy and paste data from tksheet table into an Excel file. I do have a button for export, but it will be beneficial to also allow the user to simply copy,paste. I have enabled the appropriate bindings but cannot find a solution to also copy the header information during the copy and paste. the csv export code runs through a different path than the ctrl_c code, one operating on the sheet level, one on the main table level (I didn't dig in to the depths but my assumptions would be that main table doesn't mathematically consider the headers in the same way). def yield_sheet_rows in _tksheet.py vs def ctrl_c in _tksheet_main_table.py Comparing how the each path functions, without a larger redesign of tksheet, you could create a custom button press combo binding to something other than ctrl-c utilizing the yield_sheet_rows (or - disallow all other ctrl-c functionality in favor of ONLY a csv style everything dump when using ctrl-c): Import these: import csv as csv_module import io This would be your custom binding functionality: rows = self.sheet.yield_sheet_rows(get_header = True, get_index = False) s = io.StringIO() writer = csv_module.writer(s, dialect = csv_module.excel_tab, lineterminator = "\n") for row in rows: writer.writerow(row) self.clipboard_clear() self.clipboard_append(s.getvalue()) It would need something deeper if you wanted to integrate it to ctrl-c and keep the existing ctrl-c functionality -- https://mail.python.org/mailman/listinfo/python-list
Re: Embedded python is not 100% stable
On 4/13/23 03:40, Guenther Sohler wrote: Attachments are stripped, so they weren't included. Glancing at the branch and the 2 lines you mentioned. You have a comment with a link for python 2.3 documentation. Yet you have python 3.10 code included elsewhere (and openscad itself requires the modern spec C++17, so I assume your aim is at current versions) https://docs.python.org/3.10/extending/newtypes.html is the equivalent doc for that. I am not experienced in defining PyType objects in C, but notice syntactical discrepancies, missing "static" on dealloc, use of typecasted malloc rather than PyType_GenericAlloc() https://docs.python.org/3.10/c-api/typeobj.html#c.PyTypeObject.tp_alloc Without digging in deeper and learning more I can't say for certain whether or not those are issues, but intuitively I assume they would be and that the implementation needs to more closely mirror the syntactical flow implementations of modern working examples.. -- https://mail.python.org/mailman/listinfo/python-list
Re: Weak Type Ability for Python
On 4/12/23 04:03, Ali Mohseni Roodbari wrote: > On 4/13/23 07:50, Stefan Ram wrote: >If tomorrow Python would allow "string+int" and "int+string" >in the sense of "string+str(int)" and "str(int)+string", >what harm would be there? > >But for now, I think a typical approach would be to just use "str", >i.e., "string+str(int)" and "str(int)+string". I agree with Py Zen rule 2 in this case: Explicit is better than implicit. I hate when things try to guess what I am doing... It is why I can't use lxml. -- https://mail.python.org/mailman/listinfo/python-list
Re: How does a method of a subclass become a method of the base class?
On 3/26/23 13:43, Jen Kris wrote: My question is: what makes "choose_method" a method of the base class, called as self.choose_method instead of UrnaryConstraint.choose_method? Is it super(UrnaryConstraint, self).__init__(strength) or just the fact that Constraint is its base class? When referring to "self" you are referring to an "instance" of the class or classes, think in terms of objects (the instance, usually self) vs a blueprint (the class, usually cls). saying self.choose_method(mark) checks the "instance" of self to see if it has something called choose_method at run time (instances being created at run time). If you have an instance of just Constraint, and never had a choose_method defined for it, you will get an error because it can't find it (which in this case is presumed as designed). If the "instance" is of a subclass of Constraint that does have a choose_method, that also inherits the stuff from Constraint, it will successfully call it against the "instance" that has been constructed with attributes of both classes. if the instance of a subclass has a definition for something that is in the base class, for instance IF UrnaryConstraint had it's own def satisfy() method, the instance would call the subclass version. In the case given, it does not, so it looks to the parent to see if it has inherited satisfy() from higher up. Hopefully that helps a little bit.. just have to get a feel for OO instantiated object vs class.. -- https://mail.python.org/mailman/listinfo/python-list
Re: Tkinter and cv2: "not responding" popup when imshow launched from tk app
On 3/15/23 07:37, John O'Hagan wrote: On Tue, 2023-03-14 at 16:22 -0400, aapost wrote: On 3/14/23 06:54, John O'Hagan wrote: [...] Read an alternative description of the waitKey behavior >For example, waitKey(0) will display the window infinitely until any keypress (it is suitable for image display). waitKey(25) will display a frame and wait approximately 25 ms for a key press (suitable for displaying a video frame-by-frame). To remove the window, use cv::destroyWindow. I went back to double check and I stand corrected on the "any keypress" part. Any keypress on the 'keyboard' does break the wait (as I incorrectly concluded and assumed only ESC did). It is still slightly ambiguous in explaining that when using 25ms, keypress or not, the wait breaks at 25ms (or before that if you press a keyboard key). For my setup the window is stale at that point, no controls, just a stale frame behind the tkinter window that needs to be destroyed or reused. Whether that is the exact behavior on all set-ups isn't clear, the note further uses the ambiguous phrasing "might". >Note: This function should be followed by a call to cv::waitKey or cv::pollKey to perform GUI housekeeping tasks that are necessary to actually show the given image and make the window respond to mouse and keyboard events. Otherwise, it won’t display the image and the window might lock up. It seems with the several variations, behavior varies between them, like one comment saying startWindowThread when using c++ and gtk allows you to not use waitKey (not the case here.. it seems -- changing my language to not misspeak, lol). I haven't come across any examples beyond imshow running stand-alone as in my solution suggestion 2. But waitKey does return a keyvalue for the keypess to allow extending the functionality, so you can grab it, do something, and go right back to waiting, I haven't seen any use of this though. You can also leave out reference to tkinter all together when using startWindowThread: import sys import cv2 cv2.startWindowThread() cv2.namedWindow("W", cv2.WND_PROP_FULLSCREEN) cv2.setWindowProperty("W", cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN) cv2.imshow("W", cv2.imread(sys.argv[1])) while(1): a = cv2.waitKey(0) if a == 27:#ESC break #elif a == something else, do something cv2.destroyAllWindows() exit() But it still blocks if integrated in to the main tkinter thread, and appears to use tkinter under the hood. And as tkinter is considered thread-unsafe, the startWindowThread would only be ok when spawned as a separate process like the subprocess example. Anyway, apologies for the mistake on the any key part. -- https://mail.python.org/mailman/listinfo/python-list
Re: Tkinter and cv2: "not responding" popup when imshow launched from tk app
On 3/15/23 07:37, John O'Hagan wrote: On Tue, 2023-03-14 at 16:22 -0400, aapost wrote: On 3/14/23 06:54, John O'Hagan wrote: Doing a quick read, tkinter is not threadsafe, so diving in to a threading solution is probably not the best approach. But just to throw out another possible solution to see if you can find a "good enough" work around that fits your desired behavior. You could spawn the imshow as it's own program: file2: sp.py import sys import cv2 import tkinter as tk def show(img, root): cv2.namedWindow(str(root), cv2.WND_PROP_FULLSCREEN) cv2.setWindowProperty(str(root), cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN) cv2.imshow(str(root), cv2.imread(img)) cv2.waitKey(0) cv2.destroyAllWindows() exit() root=tk.Tk() show(sys.argv[1], root) tk.mainloop() file1:main.py import cv2 import tkinter as tk import subprocess images=['c.jpg', 'b.jpg', 'c.jpg'] control = { "counter" : 0, "pid": None } def show(control): if control["pid"]: control["pid"].kill() control["pid"] = subprocess.Popen(["python", "sp.py", images[control["counter"] % len(images)]]) control["counter"] += 1 root=tk.Tk() root.wm_attributes("-topmost", 1) tk.Button(root, text=' Show ', command=lambda: show(control)).pack() tk.mainloop() refactor/design as needed, you track the pid, kill the existing on each subsequent show press. caveats would be that since it is an entirely separate program, if you close the main window, the other window will still linger until it is also closed. You could try to catch the close to run a .kill() on the subprocess if you want right before the exit, etc. But this gives control back to the main GUI since they are now independent of each other and not within the same thread. If they need to talk to each other in some way more than that, I am sure deeper design solutions could be thought up. -- https://mail.python.org/mailman/listinfo/python-list
Re: Tkinter and cv2: "not responding" popup when imshow launched from tk app
On 3/15/23 07:37, John O'Hagan wrote: On Tue, 2023-03-14 at 16:22 -0400, aapost wrote: On 3/14/23 06:54, John O'Hagan wrote: It works up to a point - I can cycle through the images by clicking the button - but if I mouse-click on the displayed image (e.g. to use the zooming and panning features of cv2), nothing happens, and a few seconds later the image greys out and a popup appears saying "'Unknown' is not responding" and giving the option of waiting or forcing close (but sometimes these options are greyed out too). Clicking "wait", if available, closes the popup but it comes back a few seconds later. If I then click on the tkinter window titlebar, the popup changes to "'Tk' is not responding". Clicking on the button still works and after a few clicks the popup closes. [...] I think this particular popup is a Gnome thing, but AIUI most DEs have something similar to detect stuck apps. But the app is not stuck. I suspect this is some kind of interaction between the call to cv2.waitKey (which is necessary but I've never understood why!) and the tkinter event loop, but it's beyond my knowledge. Any suggestions about causes or workarounds? Thanks -- John I don't get any of the zoom/panning behavior with waitKey(1). But a couple notes from the web: https://docs.opencv.org/2.4/modules/highgui/doc/user_interface.html Note This function should be followed by waitKey function which displays the image for specified milliseconds. Otherwise, it won’t display the image. For example, waitKey(0) will display the window infinitely until any keypress (it is suitable for image display). waitKey(25) will display a frame for 25 ms, after which display will be automatically closed. (If you put it in a loop to read videos, it will display the video frame-by-frame) https://pythonexamples.org/python-opencv-imshow/ cv2.waitKey(0) is important for holding the execution of the python program at this statement, so that the image window stays visible. If you do not provide this statement, cv2.imshow() executes in fraction of a second and the program closes all the windows it opened, which makes it almost impossible to see the image on the window. if I change waitKey to 0, I get the ability to zoom/pan, but it places the tk window in a blocked state because it is waiting on cv2 to return. If I hit the ESC key, it releases the wait and gives control back to the tk window, allowing me to press show again to continue to the next image. I can try to change waitKey to a high ms like 1000 and have zoom/pan for that amount of time before it gives control back to tk (not a sensical approach). The fact that you can still see the image after tk takes back control is I believe just a matter of design, some examples show cv2.destroyAllWindows() after waitKey(0) to clean that up, but of course if you are reusing the same window, that destroys the target. You can resolve that if you move cv2.namedWindow('W', cv2.WND_PROP_FULLSCREEN) cv2.setWindowProperty('W', cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN) to inside the show, and destroy it after the wait, and make waitKey 0, this allows creation/cleanup of that window per image Hitting ESC when done zooming/panning on each image to get back to tk. Thanks for your reply. I'm afraid in the real app it won't be practical to have no gui control while viewing images. But your suggestions have made me realise that my issue has nothing to do with tkinter, it seems to be the way imshow is supposed to work. This code gives the same behaviour described above: cv2.imshow('W', array) cv2.waitKey(100) time.sleep(20) I've seen the docs you mention that say the window will close if no keypress happens within the waitKey time, but that doesn't seem to be what happens as you say. After waitKey returns, the image remains and everything works, but for some reason the desktop complains about an unresponsive app. You can use cv2 to display video with: while 1: frame = camera.read() #pseudocode cv2.imshow('W', frame) cv2.waitKey(1) (In fact this used to work without waitKey if you called cv2.startWindowThread() after creating the window, but that stopped working at some point.) The fact that this works, presumably because the image is being replaced often enough, suggested the following workaround to my problem, using a call to after() to re-display the current image before the desktop starts complaining: images=[cv2.imread(i) for i in ('a.jpg', 'b.jpg', 'c.jpg')] cv2.namedWindow('W', cv2.WND_PROP_FULLSCREEN) cv2.setWindowProperty('W', cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN) counter=[0] image = [None] def show(): im = images[counter[0] % 3] cv2.imshow('W', im) cv2.waitKey(1) image[:] = [im] counter[0] += 1 root=Tk() root.wm_attributes(&q
Re: =- and -= snag
On 3/14/23 18:50, Rob Cliffe wrote: On 14/03/2023 21:28, avi.e.gr...@gmail.com wrote: Type hints are actually situationally quite useful (though yes, kind of hard to understand when you first come across their use, largely because of things like Union). And I wouldn't recommend their use in all situations because maintaining them is frustrating. xmlschema uses them extensively though and I appreciate them. The module does what I need where all the other offerings failed, and parsing the source because of the subject matter would have been harder to quickly grok without them. Alternatively, I spent quite a while on the subject of pep 232 (before finding the pep) trying to understand it because intuitively I felt like there was something I must be missing. Turns out there isn't. And what my thoughts were assuming was the intent, are discussed under "Future Directions", but when seeing it laid out like that, subjectively the dissenting conclusion of "It opens the way to mind abuse." is more correct. "What if I launch a virtual machine inside a virtual machine inside a virtual machine inside a virtual machine, what happens?"... If I want to have a grouping of minor functionality or attributes on a callable, I can get that with creating a class that defines __call__. I would say 232 is fine for what it is (I don't have to use it, and in many cases it probably is), but the only wide use I know of that I have come across is in the standard library ElementTree: # For tests and troubleshooting register_namespace._namespace_map = _namespace_map Which I hate that variable and it's design with a passion. lol. And exactly, the more a language starts policing my ability to be flexible in my trying to find a creative solution to a problem, the less I want to use it. Sometimes to have something useably beautiful to interact with requires something painfully complex under the surface. Hiding and avoiding all complexity away so you never have to see it or make mistakes prevents you from growing. Anyway, the 20th rule to The Zen of Python is: Don't believe your own bullshit *shrug* -- https://mail.python.org/mailman/listinfo/python-list
Re: Tkinter and cv2: "not responding" popup when imshow launched from tk app
On 3/14/23 06:54, John O'Hagan wrote: Hi list I'm trying to use cv2 to display images created as numpy arrays, from within a tkinter app (which does other things with the arrays before they are displayed as images). The arrays are colour-coded visualisations of genomes and can be over a billion elements in size, and I've found the PIL methods to display images in tkinter are too slow and memory-heavy. Here is minimal code that demonstrates the problem in the subject line: import cv2 from tkinter import * images=['a.jpg', 'b.jpg', 'c.jpg'] #change to image paths cv2.namedWindow('W', cv2.WND_PROP_FULLSCREEN) cv2.setWindowProperty('W', cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN) counter=[0] def show(): cv2.imshow('W', cv2.imread(images[counter[0] % len(images)])) cv2.waitKey(1) counter[0] += 1 root=Tk() root.wm_attributes("-topmost", 1) Button(root, text=' Show ', command=show).pack() mainloop() It works up to a point - I can cycle through the images by clicking the button - but if I mouse-click on the displayed image (e.g. to use the zooming and panning features of cv2), nothing happens, and a few seconds later the image greys out and a popup appears saying "'Unknown' is not responding" and giving the option of waiting or forcing close (but sometimes these options are greyed out too). Clicking "wait", if available, closes the popup but it comes back a few seconds later. If I then click on the tkinter window titlebar, the popup changes to "'Tk' is not responding". Clicking on the button still works and after a few clicks the popup closes. This happens under both x11 and wayland, but under wayland, I also get this error: "QSocketNotifier: Can only be used with threads started with QThread qt.qpa.wayland: Wayland does not support QWindow::requestActivate()" and only every second button press displays a new image ,with only every second image displayed. I think this particular popup is a Gnome thing, but AIUI most DEs have something similar to detect stuck apps. But the app is not stuck. I suspect this is some kind of interaction between the call to cv2.waitKey (which is necessary but I've never understood why!) and the tkinter event loop, but it's beyond my knowledge. Any suggestions about causes or workarounds? Thanks -- John I don't get any of the zoom/panning behavior with waitKey(1). But a couple notes from the web: https://docs.opencv.org/2.4/modules/highgui/doc/user_interface.html Note This function should be followed by waitKey function which displays the image for specified milliseconds. Otherwise, it won’t display the image. For example, waitKey(0) will display the window infinitely until any keypress (it is suitable for image display). waitKey(25) will display a frame for 25 ms, after which display will be automatically closed. (If you put it in a loop to read videos, it will display the video frame-by-frame) https://pythonexamples.org/python-opencv-imshow/ cv2.waitKey(0) is important for holding the execution of the python program at this statement, so that the image window stays visible. If you do not provide this statement, cv2.imshow() executes in fraction of a second and the program closes all the windows it opened, which makes it almost impossible to see the image on the window. if I change waitKey to 0, I get the ability to zoom/pan, but it places the tk window in a blocked state because it is waiting on cv2 to return. If I hit the ESC key, it releases the wait and gives control back to the tk window, allowing me to press show again to continue to the next image. I can try to change waitKey to a high ms like 1000 and have zoom/pan for that amount of time before it gives control back to tk (not a sensical approach). The fact that you can still see the image after tk takes back control is I believe just a matter of design, some examples show cv2.destroyAllWindows() after waitKey(0) to clean that up, but of course if you are reusing the same window, that destroys the target. You can resolve that if you move cv2.namedWindow('W', cv2.WND_PROP_FULLSCREEN) cv2.setWindowProperty('W', cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN) to inside the show, and destroy it after the wait, and make waitKey 0, this allows creation/cleanup of that window per image Hitting ESC when done zooming/panning on each image to get back to tk. -- https://mail.python.org/mailman/listinfo/python-list
Re: =- and -= snag
On 3/13/23 17:26, Morten W. Petersen wrote: It went into negative numbers, when that shouldn't have been possible. Turns out I had a very small typo, I had =- instead of -=. Isn't it unpythonic to be able to make a mistake like that? That is why I tell Alice it is always best to stay positive and use x-=-1 to avoid situations like that. *shrugs* -- https://mail.python.org/mailman/listinfo/python-list
Re: Problem with wxPython form
On 3/10/23 15:15, Chris wrote: Hi everyone. I'm new to Python and wxPython. I've got a form I use to calculate the Sq In of a leather project. I'm using python 3.9.13 and wxPython 4.20 I'm having the following issues: 1) When I come into the form, no grid cell has the focus set - I start typing and nothing happens. I have to click the cell. If I hit Tab or Enter, the OnKeyDown fires, but does not move to the appropriate cell - it does nothing but run the update and move off of the current cell. The action I'm trying to make is this ENTER KEY: Always go down 1 row and to col 0 TAB, if Col 0 Move to Col 1 on same row, if Col 1 go to Row +1, Col 0 I also need to have what3ever cell it is supposed to land on to get the focus so I can just type. Currently I have to click in each cell I want/need to add. There could be up to 20 pieces of leather with differing sizes, so in order to accurately calculate the Sq In, I need to get all the measurements in. The form, one of several tabs, comes up and does everything else I've coded for great. Just no navigation. Can anyone assist? Here is the module with the form Your source was badly mangled by whatever you submitted it in, so it was very difficult to parse. Additionally, it is usually best to strip your code down to a minimal example of the issue, and remove any references to modules that are likely not publicly available (i.e. alwlogic) (putting basic dummy data in place if need be). That being said: 2 things will likely address your issue, remove self.grid.SetCellHighlightPenWidth(0) since this is making the highlight box of the selected cell invisible, this is preventing you from seeing that your tabs and enters are working as you are expecting. Next, the wx.EVT_KEY_DOWN binding is grabbing all key presses, and your function is only addressing 2 keys, you need to add an else: to the end with an event.Skip() to allow the default behaviors of the grid cells to pass through for other keys (i.e. typing). That should get you the behavior you need. -- https://mail.python.org/mailman/listinfo/python-list
Re: Lambda returning tuple question, multi-expression
On 3/10/23 22:16, Thomas Passin wrote: On 3/10/2023 7:07 PM, aapost wrote: which does start to break down readability due to line length, as there isn't really an indention rule set for something uncommonly used. but some renaming makes the pattern clearer pids.update({"messages" :subprocess.Popen(["cmd1"])}) if not pids["messages"] else None, pids.update({"syslog" :subprocess.Popen(["cmd2"])}) if not pids["syslog"] else None, pids.update({"kern" :subprocess.Popen(["cmd3"])}) if not pids["kern"] else None, pids.update({"user" :subprocess.Popen(["cmd4"])}) if not pids["user"] else None, I'd make the pattern in this example even more understandable and less error-prone: def update_pids(target): cmd = ["tail", "-n", "1", "-f", f"/var/log/{target}"] pids.update({target: subprocess.Popen(cmd)}) if not \ pids[target] else None lambda x: ( # The Tk callback includes an event arg, doesn't it? update_pids('messages'), update_pids('syslog'), # etc ) So yeah, that's along the same lines. cmd could be in a function, or just outside the lambdas. Could also do from subprocess import Popen to shorten that, etc. The .trace( on the tkinter Vars use events, so you have to do something like lambda _a, _b, _c: stuff But not in the above case. My focus these last couple week hasn't used any of those so the specifics aren't as fresh (still heading back in that direction), when required python will definitely let you know, lol. The additional note in the above is, when taking the def route above, the thing you would have to consider is what scope is the dictionary pids? Do you need to submit it to the lambda and subsequently the function such as lambda pids=pids: ( update_pids("messages", pids), update_pids("syslog", pids), So that update_pids can access it? Or in your design do you have a separate management of it that def update_pids already has access to? (either is valid depending on design intent). In the direction I am going, in trying to build some compound widgets, and I need to grab stuff from one widget and send it to another within the same widget group, so in cases where it goes to an external function, it has to be sent as an arg through the lambda whatever=whatever: ( function(whatever), ) -- https://mail.python.org/mailman/listinfo/python-list
Re: Lambda returning tuple question, multi-expression
On 3/9/23 15:25, Thomas Passin wrote: >>> # this is a code snippet from a Tkinter gui app >>> # in this case lambda is quite convenient >>> self.btn_cancel = Button(self.progress_container, text='Cancel', >>> command=lambda: subprocess.call('taskkill /f /im uberzip.exe', >>> shell=True)) def kill_uberzip(): """Kill an external running program named uberzip.exe.""" subprocess.call('taskkill /f /im uberzip.exe', shell=True)) self.btn_cancel = Button(self.progress_container, text='Cancel', command = kill_uberzip()) This way, it's easy to understand what btn_cancel() will do each time you scan that line of code. Using the lambda makes you reparse the line and spend mental effort each time you scan it. And this way, you know directly that the button is going to cause a side effect outside your program, which you have to infer (an indirect mental operation) when you scan the lambda. For this particular example, it might turn out that there could be more than one instance of uberzip.exe running at the same time. Which one should be killed, and how do you kill the right one? With the function, you can get those details under control, but I hate to think what might happen to the lambda expression. Yes, of course, there can be times when the lambda expression is somewhat easy to understand and the side effects are harmless. In that case, it may be easy enough to grasp quickly that the anonymous function would not benefit from having a name. So OK, it's not a hard-and-fast rule. The not knowing which uberzip to kill is a design choice, the bad design of the the example is not really the fault of the lambda. And in general with naming anything, much has to do with context. Buttons perform actions, it should be implicitly understood at the button level and in context of where it is placed what it is a button is for. A button without a command has no use, so it is understood it needs to do something, with good design it would be better to know what the buttons purpose is, rather than having to then parse an additional function to figure it out. Case in point, to solve the subprocess problem, (ignoring the "whys" and the lack of usefulness of this example, just grok the pattern, maybe you are designing a game of whack-a-mole and are watching 4 things and need to do something when you see a change from 1 of them) import tkinter as tk import subprocess main = tk.Tk() main.pids = { "messages": None, "syslog": None, "kern": None, "user": None, } tk.Button( master=main, text="Start tailing logs", command=lambda: ( main.pids.update({"messages" :subprocess.Popen(["tail", "-n", "1", "-f", "/var/log/messages"])}), main.pids.update({"syslog" :subprocess.Popen(["tail", "-n", "1", "-f", "/var/log/syslog"])}), main.pids.update({"kern" :subprocess.Popen(["tail", "-n", "1", "-f", "/var/log/kern.log"])}), main.pids.update({"user" :subprocess.Popen(["tail", "-n", "1", "-f", "/var/log/user.log"])}), ), ).pack() tk.Button( master=main, text="Kill messages tail", command=lambda: ( main.pids["messages"].kill() if main.pids["messages"] else None, ), ).pack() tk.Button( master=main, text="Kill syslog tail", command=lambda: ( main.pids["syslog"].kill() if main.pids["syslog"] else None, ), ).pack() tk.Button( master=main, text="Kill kern tail", command=lambda: ( main.pids["kern"].kill() if main.pids["kern"] else None, ), ).pack() tk.Button( master=main, text="Kill user tail", command=lambda: ( main.pids["user"].kill() if main.pids["user"] else None, ), ).pack() tk.Button( master=main, text="Kill all tails", command=lambda: ( main.pids["messages"].kill() if main.pids["messages"] else None, main.pids["syslog"].kill() if main.pids["syslog"] else None, main.pids["kern"].kill() if main.pids["kern"] else None, main.pids["user"].kill() if main.pids["user"] else None, ), ).pack() main.mainloop() -- https://mail.python.org/mailman/listinfo/python-list
Re: Lambda returning tuple question, multi-expression
On 3/10/23 18:46, aapost wrote: main.pids.update({"messages" :subprocess.Popen(["tail", "-n", "1", "-f", "/var/log/messages"])}), main.pids.update({"syslog" :subprocess.Popen(["tail", "-n", "1", "-f", "/var/log/syslog"])}), main.pids.update({"kern" :subprocess.Popen(["tail", "-n", "1", "-f", "/var/log/kern.log"])}), main.pids.update({"user" :subprocess.Popen(["tail", "-n", "1", "-f", "/var/log/user.log"])}), ), To pre-emptively address the bug there it would need to be: main.pids.update({"messages" :subprocess.Popen(["tail", "-n", "1", "-f", "/var/log/messages"])}) if not main.pids["messages"] else None, main.pids.update({"syslog" :subprocess.Popen(["tail", "-n", "1", "-f", "/var/log/syslog"])}) if not main.pids["syslog"] else None, main.pids.update({"kern" :subprocess.Popen(["tail", "-n", "1", "-f", "/var/log/kern.log"])}) if not main.pids["kern"] else None, main.pids.update({"user" :subprocess.Popen(["tail", "-n", "1", "-f", "/var/log/user.log"])}) if not main.pids["user"] else None, which does start to break down readability due to line length, as there isn't really an indention rule set for something uncommonly used. but some renaming makes the pattern clearer pids.update({"messages" :subprocess.Popen(["cmd1"])}) if not pids["messages"] else None, pids.update({"syslog" :subprocess.Popen(["cmd2"])}) if not pids["syslog"] else None, pids.update({"kern" :subprocess.Popen(["cmd3"])}) if not pids["kern"] else None, pids.update({"user" :subprocess.Popen(["cmd4"])}) if not pids["user"] else None, and adding a comment to say something like # starting a series of processes via lambda tuple sequence if process not running #pattern: p.update({"name":sp.Popen(cmd)}) if not p["name"] else None, -- https://mail.python.org/mailman/listinfo/python-list
Re: Lambda returning tuple question, multi-expression
On 3/9/23 16:37, Cameron Simpson wrote: On 09Mar2023 09:06, Alan Gauld wrote: Just a note that some code formatters use a trailing comma on the last element to make the commas fold points. Both yapf (my preference) and black let you write a line like (and, indeed, flatten if short enough): ( a, b, c ) but if you write: ( a, b, c, ) they'll fold the lines like: ( a, b, c, ) Cameron Simpson Thanks for the info, good to know, I actually do like the idea of trailing commas for tuples (helps prevent things like the difference between ("abc") and ("abc",) and makes swapping things around nicer. I've just been using a lot of json lately and it has been subconsciously training me different, lol. -- https://mail.python.org/mailman/listinfo/python-list
Re: Lambda returning tuple question, multi-expression
On 3/9/23 04:06, Alan Gauld wrote: Thank you for the feedback, I appreciate the comments. To add a little extra, there is actually a reason I lean toward overuse of .config() for a lot of things even though they could be sent to the constructor (other than that w["attribute"]= doesn't work in a lambda). It comes from a use case I needed to solve in the shortcoming of tk with frames not being scrollable, requiring a canvas. When dynamically generating a series of widgets (i.e. loading a custom json/xml layout config file), getting the scrollable area right is a bit of a chore with a catch-22 situation. With an inner frame in a canvas, pack_propogate(tk.True) is the default on the frame, so that the children dictate the size, but in doing so it prevents the frame from expanding to the full width of the area it's given within the UI layout. If you turn pack_propogate to tk.False, it breaks the ability for the canvas to return bbox(tk.ALL) (which is kind of rough anyway as the tcl docs state "The return value may overestimate the actual bounding box by a few pixels."). So you end up with 1,1 and no way of knowing what size scrollable area to set. Trying to obtain this value from a source outside of the canvas requires knowing what you are placing the canvas in each time, and was creating a similar catch-22 as the outer widget doesn't know what it wants it's size to be without knowing what the inner widget wants.. Switching to False, grabbing bbox, then back to True of course causes an unsightly flicker and disrupts the smoothness of the user experience. So my solution is to create a widget instantiator which does a few things, mainly adding something I call a "ghost". it's something like this: instantiator(qlass, master, config_args=None, pack_args=None, init_args=None, ghost=False): if not init_args: init_args = {} object = qlass(master=master, **init_args) if hasattr(master, "ghost"): object.ghost = qlass(master=master.ghost, **init_args) elif ghost: object.ghost = qlass(master=tk.Frame(), **init_args) When i pass it a canvas and say ghost=True, the canvas gets a .ghost duplicate, which is attached to an arbitrary frame that I never pack and stays invisible. Subsequent widgets created to the canvas then see that their parent, starting with the canvas, have a ghost, and in return get a ghost of themselves attached to their parents ghost. This allows you to get an accurate bbox size from the unseen ghost canvas that mirrors the visible version. Keeping the init_args down to only what is necessary helps in consistency, and the subsequent config_args and pack_args I have in their respective dicts. This also allows me to create a quality of life pack function I call ppack() def ppack(self): self.pack(**self.pack_args) if hasattr(self, "ghost"): self.ghost.pack(**self.ghost.pack_args) return self That allows each primary widget to manage and track their own set of configurations. Of course I could strip a lot of that crap out if I find a better and smooth way of obtaining those bbox numbers, but I didn't see any quick solutions in glancing through the tcl/tk source so I went with what works for now. -- https://mail.python.org/mailman/listinfo/python-list
Re: Lambda returning tuple question, multi-expression
On 3/9/23 00:13, Thomas Passin wrote: lol.. 'us'.. So.. to give an example from your own code: but_play = Tk.Button(_frame, text='Play', width = BUTTONWIDTH + 1, pady = PADY, command=lambda x=plotmgr:play_macro(x), bg = BUTTON_BG, font = NEWFONT) Can be written as: b = Tk.Button(master=_frame) b.config(text='Play', width = BUTTONWIDTH + 1, pady = PADY, command=lambda x=plotmgr:play_macro(x), bg = BUTTON_BG, font = NEWFONT) .config() is just a way of adding/modifying most of the same initialization arguments after the instantiation of the object. tkinter objects are flexible by design, You can also do b["text"] = "adsfa" b["command"] = lambda: (a,b,c,d) I could also rewrite the original example with the exact same result: b = tk.Button( master=main, text="Enable", command=lambda: ( e1.config(state="normal"), e2.config(state="normal"), e3.config(state="normal") ) ) b.pack() b is not changing states at any point. Nothing "happens" to state when .config() is called. b does nothing without a command= configured. .config() is binding the button press event via command= to a call so than an action can occur on button press. There is no 'instead' of b.config() (unless of course using one of the equivalent examples above to do the exact same thing) The disconnect is not in the not understanding of my code, it's in the not understanding of .config(). (which is no big deal, I forgot what a file buffer was just this week, lol) So, as far as the examples, they are simplified abstract psuedo-like-code illustrations to accompany the ask of and open ended question regarding a programming practice. (I did forgot to include main.mainloop() at the end of each one, as I was using python -i when I quickly wrote them) example 1 described: A button press does sequence of actions against widgets, i.e. I have 3 disabled widgets, I press a button, now in sequence all 3 are enabled so I can type in them. Without a lambda tuple sequence this requires a def and an another lambda. example 2 described: dict with an attribute assigned to a label (you can't assign directly to external variables within a lambda, but you can call something with a method like .update(), which why would that be considered any different than any other state changing call?) Then lambda assigned to a label and called to start it up, recursively performs an update to said widget every 1 second. There are several ways to do this without a lambda tuple sequence, none as concise. The 'what I am trying to do' is ask a question regarding opinions and practices on issuing a sequence of actions within a lambda via a tuple (since the common practice approaches against it - mainly with tkinter - feel more convoluted), and in doing so leaving it open ended to get a feel on what opinions are, and to see if any opinions influence mine. -- https://mail.python.org/mailman/listinfo/python-list
Re: Lambda returning tuple question, multi-expression
On 3/8/23 16:56, aapost wrote: Thomas > Cameron def set_entries_enabled_state(enabled = True): state = 'normal' if enabled else 'disabled' for e in (e1, e2, e3): e.config(state=state) def config_b_and_entries(enabled = True): state = 'normal' if enabled else 'disabled' b.config(state = state) set_entries_enabled_state(enabled) I admit adding commenting might be useful to clearly express intent for patterns I don't commonly see. But when you are managing a bunch of widgets and experimenting with the design, the variable name word salad approach 'in the name of readability' starts to melt your brain a bit and it all starts too look like a wall of..: the_thing.the_things_thing.do_this_thing_to_that_other_thing_but_only_if_this_one_time() So the button b in the example only needs a reference to a callable configured, set with the command= parameter in .config() The code: def func(): pass b.config(command=func) Is equivalent. So that if the button is clicked, code at func (or the lambda) gets called. In both cases (as per my intent), care about the return values of the expressions does not matter and I am fairly certain regardless of what the callable returns, it does not get evaluated/assigned/considered anywhere. (at least that is how I have been considering it, a void foo(void) if you will..). Now as far as the tuple, yes, left to right evaluation is what I expect, (hope anyway, lol), meaning (3, False, 1, x := 5+9, print("hello{}".format(x))) would return a tuple of (3, False, 1, 14, None) which gets assigned to nothing and the string "hello14" printed to console. Now.. When you want to assign a callable that requires args, the main examples people give are a combo of them both, def func(x,y,z): pass x = y = x = "something" b.config(command=lambda x,y,z: func(x,y,z)) So as far as the examples given above (which I can't really parse), if you meant for passing in a bool value, to do so would require something like: b.config(command=lambda enabled: config_b_and_entries(enabled)) Which that type of thing to me gets even harder to grok after a while, and I guess for me I find having to go to a different scope or a separate file to parse a bunch of definitions like these: def set_entries_enabled_state(enabled = True): def config_b_and_entries(enabled = True): ends up taking me out of an object oriented focus / headspace of the layout at hand. And it is sort of like.. Ok I can either b.config(command=lambda: ( a.expr, b.expr.update({something: "morecomplicated"}), c.expr ) ) OR.. b.config(command=lambda a=a, b=b, c=c, s=something: foo(a, b, c, s)) somewhere else: def foo(a, b, c, something): a.expr b.expr.update({something: "morecomplicated"}) c.expr When you are trying to add a bit of dynamic feel to the tediousness of the widget management, keeping things kind of contained to their object just feels more natural to me (at the moment anyway).. (all the packing, unpacking, making collections of widgets within frames appear or go away based on states, colour changes based on input, dynamic widget generation and where their relative attachment should go, etc) I read a lot of sentiment against complicated lambdas suggesting one should go for more functions, but I guess I feel pushing a more complicated lambda to contain behavior more closely to an instance feels more intuitive at the moment (and the sentiment against it doesn't really resonate with me), so long as it isn't introducing some inherent behavioral flaw or bug I am blind to.. Of course I might change my mind at some point during a refactor and think "what the hell is that, why didn't I just..".. Which will probably come in a few weeks. lol One additional note on the Thread comment, I haven't really needed to dig in to that too deeply, but Threading is amazing for tkinter UI troubleshooting, if you add something like: t = threading.Thread(target=maintk.mainloop) and run it with python -i so long has you have attached every widget to some relative position on to the root (maintk in this case), you can interact with any object/widget directly live to see what is going on or what a change does. -- https://mail.python.org/mailman/listinfo/python-list
Lambda returning tuple question, multi-expression
When making a UI there are a lot of binding/trace operations that need to occur that lead to a lot of annoying 1 use function definitions. I don't really see lambda use like below. Giving 2 working lambda examples using a returned tuple to accomplish multiple expressions - what sort of gotchas, if any, might make the following bad practice if I am missing something? Example 1: import tkinter as tk main = tk.Tk() e1 = tk.Entry(master=main) e1["state"] = "disabled" e1.pack() e2 = tk.Entry(master=main) e2["state"] = "disabled" e2.pack() e3 = tk.Entry(master=main) e3["state"] = "disabled" e3.pack() b = tk.Button(master=main, text="Enable") b.config( command=lambda: ( e1.config(state="normal"), e2.config(state="normal"), e3.config(state="normal") ) ) b.pack() Example 2: import tkinter as tk main = tk.Tk() l = tk.Label(master=main) l.a = {"seconds":0} l._updater = lambda: ( l.a.update({"seconds": 1 + l.a["seconds"]}), l.config(text=l.a["seconds"]), l.after(ms=1000, func=l._updater) ) l._updater() l.pack() -- https://mail.python.org/mailman/listinfo/python-list
Re: Bug 3.11.x behavioral, open file buffers not flushed til file closed.
On 3/5/23 19:02, Cameron Simpson wrote: On 05Mar2023 10:38, aapost wrote: Additionally (not sure if this still applies): flush() does not necessarily write the file’s data to disk. Use flush() followed by os.fsync() to ensure this behavior. Yes. You almost _never_ need or want this behaviour. A database tends to fsync at the end of a transaction and at other critical points. However, once you've `flush()`ed the file the data are then in the hands of the OS, to get to disc in a timely but efficient fashion. Calling fsync(), like calling flush(), affects writing _efficiency_ by depriving the OS (or for flush(), the Python I/O buffering system) the opportunity to bundle further data efficiency. It will degrade the overall performance. Also, fsync() need not expedite the data getting to disc. It is equally valid that it just blocks your programme _until_ the data have gone to disc. I practice it probably does expedite things slightly, but the real world effect is that your pogramme will gratuitously block anyway, when it could just get on with its work, secure in the knowledge that the OS has its back. flush() is for causality - ensuring the data are on their way so that some external party _will_ see them rather than waiting forever for data with are lurking in the buffer. If that external party, for you, is an end user tailing a log file, then you might want to flush(0 at the end of every line. Note that there is a presupplied line-buffering mode you can choose which will cause a file to flush like that for you automatically. So when you flush is a policy decision which you can make either during the programme flow or to a less flexible degree when you open the file. As an example of choosing-to-flush, here's a little bit of code in a module I use for writing packet data to a stream (eg a TCP connection): https://github.com/cameron-simpson/css/blob/00ab1a8a64453dc8a39578b901cfa8d1c75c3de2/lib/python/cs/packetstream.py#L624 Starting at line 640: `if Q.empty():` it optionally pauses briefly to see if more packets are coming on the source queue. If another arrives, the flush() is _skipped_, and the decision to flush made again after the next packet is transcribed. In this way a busy source of packets can write maximally efficient data (full buffers) as long as there's new data coming from the queue, but if the queue is empty and stays empty for more that `grace` seconds we flush anyway so that the receiver _will_ still see the latest packet. Cheers, Cameron Simpson Thanks for the details. And yes, that above quote was from a non-official doc without a version reference that several forum posts were referencing, with no further reasoning as to why they make the suggestion or to what importance it was (for the uninformed trying to parse it, the suggestion could be because of anything, like python lacking something that maybe was fixed, or who knows.) Thanks. -- https://mail.python.org/mailman/listinfo/python-list
Re: Bug 3.11.x behavioral, open file buffers not flushed til file closed.
On 3/5/23 09:35, aapost wrote: I have run in to this a few times and finally reproduced it. Whether it is as expected I am not sure since it is slightly on the user, but I can think of scenarios where this would be undesirable behavior.. This occurs on 3.11.1 and 3.11.2 using debian 12 testing, in case the reasoning lingers somewhere else. If a file is still open, even if all the operations on the file have ceased for a time, the tail of the written operation data does not get flushed to the file until close is issued and the file closes cleanly. 2 methods to recreate - 1st run from interpreter directly: f = open("abc", "w") for i in range(5): f.write(str(i) + "\n") you can cat the file and see it stops at 49626 until you issue an f.close() a script to recreate: f = open("abc", "w") for i in range(5): f.write(str(i) + "\n") while(1): pass cat out the file and same thing, stops at 49626. a ctrl-c exit closes the files cleanly, but if the file exits uncleanly, i.e. a kill command or something else catastrophic. the remaining buffer is lost. Of course one SHOULD manage the closing of their files and this is partially on the user, but if by design something is hanging on to a file while it is waiting for something, then a crash occurs, they lose a portion of what was assumed already complete... >Cameron >Eryk Yeah, I later noticed open() has the buffering option in the docs, and the warning on a subsequent page: Warning Calling f.write() without using the with keyword or calling f.close() might result in the arguments of f.write() not being completely written to the disk, even if the program exits successfully. I will have to set the buffer arg to 1. I just hadn't thought about buffering in quite a while since python just handles most of the things lower level languages don't. I guess my (of course incorrect) assumptions would have leaned toward some sort of auto handling of the flush, or a non-buffer default (not saying it should). And I understand why it is the way it is from a developer standpoint, it's sort of a mental thing in the moment, I was in a sysadmin way of thinking, switching around from doing things in bash with multiple terminals, forgetting the fundamentals of what the python interpreter is vs a sequence of terminal commands. That being said, while "with" is great for many use cases, I think its overuse causes concepts like flush and the underlying "whys" to atrophy (especially since it is obviously a concept that is still important). It also doesn't work well when doing quick and dirty work in the interpreter to build a file on the fly with a sequence of commands you haven't completely thought through yet, in addition to the not wanting to close yet, the subsequent indention requirement is annoying. f = open("fn", "w", 1) will be the go to for that type of work since now I know. Again, just nitpicking, lol. -- https://mail.python.org/mailman/listinfo/python-list
Re: Cutting slices
On 3/5/23 17:43, Stefan Ram wrote: The following behaviour of Python strikes me as being a bit "irregular". A user tries to chop of sections from a string, but does not use "split" because the separator might become more complicated so that a regular expression will be required to find it. But for now, let's use a simple "find": |>>> s = 'alpha.beta.gamma' |>>> s[ 0: s.find( '.', 0 )] |'alpha' |>>> s[ 6: s.find( '.', 6 )] |'beta' |>>> s[ 11: s.find( '.', 11 )] |'gamm' |>>> . The user always inserted the position of the previous find plus one to start the next "find", so he uses "0", "6", and "11". But the "a" is missing from the final "gamma"! And it seems that there is no numerical value at all that one can use for "n" in "string[ 0: n ]" to get the whole string, isn't it? I would agree with 1st part of the comment. Just noting that string[11:], string[11:None], as well as string[11:16] work ... as well as string[11:324242]... lol.. -- https://mail.python.org/mailman/listinfo/python-list
Re: Bug 3.11.x behavioral, open file buffers not flushed til file closed.
On 3/5/23 09:35, aapost wrote: Guess it could just be an annoying gotcha thing on me. calling at least f.flush() in any cases where an explicit close is delayed would be the solution. Additionally (not sure if this still applies): flush() does not necessarily write the file’s data to disk. Use flush() followed by os.fsync() to ensure this behavior. -- https://mail.python.org/mailman/listinfo/python-list
Bug 3.11.x behavioral, open file buffers not flushed til file closed.
I have run in to this a few times and finally reproduced it. Whether it is as expected I am not sure since it is slightly on the user, but I can think of scenarios where this would be undesirable behavior.. This occurs on 3.11.1 and 3.11.2 using debian 12 testing, in case the reasoning lingers somewhere else. If a file is still open, even if all the operations on the file have ceased for a time, the tail of the written operation data does not get flushed to the file until close is issued and the file closes cleanly. 2 methods to recreate - 1st run from interpreter directly: f = open("abc", "w") for i in range(5): f.write(str(i) + "\n") you can cat the file and see it stops at 49626 until you issue an f.close() a script to recreate: f = open("abc", "w") for i in range(5): f.write(str(i) + "\n") while(1): pass cat out the file and same thing, stops at 49626. a ctrl-c exit closes the files cleanly, but if the file exits uncleanly, i.e. a kill command or something else catastrophic. the remaining buffer is lost. Of course one SHOULD manage the closing of their files and this is partially on the user, but if by design something is hanging on to a file while it is waiting for something, then a crash occurs, they lose a portion of what was assumed already complete... -- https://mail.python.org/mailman/listinfo/python-list
Re: Python - working with xml/lxml/objectify/schemas, datatypes, and assignments
On 1/11/23 13:21, Dieter Maurer wrote: aapost wrote at 2023-1-10 22:15 -0500: On 1/4/23 12:13, aapost wrote: On 1/4/23 09:42, Dieter Maurer wrote: ... You might have a look at `PyXB`, too. It tries hard to enforce schema restrictions in Python code. ... Unfortunately picking it apart for a while and diving deeper in to a rabbit hole, PyXB looks to be a no-go. PyXB while interesting, and I respect it's complexity and depth, is lacking in design consistency in how it operates if you are trying to modify and work with the resulting structure intuitively. ... problem with simple types ... I use `PyXB` in `dm.saml2` and `dm.zope.saml2`, i.e. with the SAML2 schema definitions (which include those of XML signature and XML encryption). I had no problems with simple types. I just assign them to attributes of the Python objects representing the XML elements. `PyXB` does the right thing when it serializes those objects into XML. It does do a lot of good things, and I am sad to see all the good work in it not get used, but for me it really boils down to what it can sum up itself in a couple comments from the author in it's first file (which I appreciate them and their honesty, because those are comments I could see myself writing in a similar situation)... ## class cscRoot (object): """This little bundle of joy exists because in Python 2.6 it became an error to invoke C{object.__init__} with parameters (unless you also override C{__new__}, in which case it's only a warning. Whatever.). Since I'm bloody not going to check in every class whether C{super(Myclass,self)} refers to C{object} (even if I could figure out how to do that, 'cuz the obvious solutions don't work), we'll just make this thing the root of all U{cooperative super calling<http://www.geocities.com/foetsch/python/new_style_classes.htm#super>} hierarchies. ## ## def __init__ (self, *args, **kw): # Oh gross. If this class descends from list (and probably dict), we # get here when object is *not* our direct superclass. In that case, # we have to pass the arguments on up, or the strings don't get # created right. Below is the only way I've figured out to detect the # situation. # # Note that we might also get here if you mix-in a class that used # object as a parent instead of cscRoot. Don't do that. Printing the # mro() is a decent way of identifying the problem. ## using that suggestion you can see that on simple types >>> pyxbxmlroot.SomeString._mro() [, 'pyxb.binding.basis.simpleTypeDefinition'>, 'pyxb.binding.basis._TypeBinding_mixin'>, 'pyxb.utils.utility.Locatable_mixin'>, 'pyxb.utils.utility._DeconflictSymbols_mixin'>, 'pyxb.binding.basis._DynamicCreate_mixin'>, , , ] it has a python type that it sends all the way up right next to object, when that doesn't actually occur until after simpleType in class string (basis.simpleTypeDefinition, str): This makes the object dependent on it's parent, since it itself IS the value, I can't assign to or do anything to it by itself, or it and all the other stuff goes away. As designed it is very hard to change anything in it without breaking something. After working with xmlschema, it pretty much confirmed my assumptions that it doesn't need to be that way. I was able to follow what was going on and tweak xmlschema fairly easily. That and the fact that PyXB was abandoned 5-6 years ago make it a strong no-go to use in a project. It would need to be adopted with fresh development, stripped of the python2 stuff, and the object structure redesigned in a more uniform way with functionality properly containerized instead of all stuffed together... -- https://mail.python.org/mailman/listinfo/python-list
Re: Python - working with xml/lxml/objectify/schemas, datatypes, and assignments
On 1/3/23 22:57, aapost wrote: I am trying to wrap my head around how one goes about working with and editing xml elements ... Back to contemplating and tinkering.. For anyone in a similar situation, xmlschema is actually quite nice. It didn't have the features I was looking for out of the box, but it does have a to_objects function and I have learned quite a bit while picking it apart. I am able to patch it to be good enough for my requirements. Below is the patch for anyone interested: # # Contribution for the xmlschema & elementpath python modules which are # Copyright (c), 2016-2020, SISSA (International School for Advanced Studies). # All rights reserved. # # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # Patching and expansion of the xmlschema.dataobjects.DataElement object features # to get the best demonstration, change schema variable to your .xsd, and xmlobj to your .xml files # then run this as $ python -i filename.py from typing import Any, Optional, Union, Tuple #from types import MethodType class ValueLockedError(Exception): def __init__(self, obj, variable_name): self.message = "Can't set ." + variable_name + \ "\nThe object:\n" + str(obj) + \ "\nis Locked (._locked is set to True)" super().__init__(self.message) # importing in order necessary for intended monkey patch import elementpath.etree as ep_etree # Monkey patching additional static functions to the import of elementpath.etree # for namespace management of xml.etree.ElementTree code paths (which use # the global variable register_namespace._namespace_map for namespace registering) def etree_remove_registered_namespace(elem: ep_etree.ElementProtocol, uri: str = '') -> None: etree_module: Any if not ep_etree.is_etree_element(elem): raise TypeError(f"{elem!r} is not an Element") elif isinstance(elem, ep_etree.PyElementTree.Element): etree_module = ep_etree.PyElementTree elif not hasattr(elem, 'nsmap'): etree_module = ep_etree.ElementTree else: import lxml.etree as etree_module # type: ignore[no-redef] if not hasattr(elem, 'nsmap'): if uri in etree_module.register_namespace._namespace_map: del etree_module.register_namespace._namespace_map[uri] else: # TODO research this for better understanding # _namespace_map is uri->prefix # DataElement.nsmap prefix->uri # lxml etree .nsmap ?->? # not using lxml anyway so not really an issue as # this condition shouldn't be met for key, value in elem.nsmap.items(): # research - can there be multiple instances of uri to prefix?.. # or are they intended to be 1:1?.. if value == uri: if key in elem.nsmap: del elem.nsmap[key] #patching setattr(ep_etree, "etree_remove_registered_namespace", staticmethod(etree_remove_registered_namespace)) # for namespace management of xml.etree.ElementTree code paths (which use # the global variable register_namespace._namespace_map for namespace registering) def etree_get_registered_namespaces(elem: ep_etree.ElementProtocol) -> dict: etree_module: Any if not ep_etree.is_etree_element(elem): raise TypeError(f"{elem!r} is not an Element") elif isinstance(elem, ep_etree.PyElementTree.Element): etree_module = ep_etree.PyElementTree elif not hasattr(elem, 'nsmap'): etree_module = ep_etree.ElementTree else: import lxml.etree as etree_module # type: ignore[no-redef] if not hasattr(elem, 'nsmap'): return etree_module.register_namespace._namespace_map else: return elem.nsmap # shouldn't be met #patching setattr(ep_etree, "etree_get_registered_namespaces", staticmethod(etree_get_registered_namespaces)) # for namespace management of xml.etree.ElementTree code paths (which use # the global variable register_namespace._namespace_map for namespace registering) def etree_register_namespace(elem: ep_etree.ElementProtocol, prefix: str = None, uri: str = None) -> None: etree_module: Any if not ep_etree.is_etree_element(elem): raise TypeError(f"{elem!r} is not an Element") elif isinstance(elem, ep_etree.PyElementTree.Element): etree_module = ep_etree.PyElementTree elif not hasattr(elem, 'nsmap'): etree_module = ep_etree.ElementTree else: import lxml.etree as etree_module # type: ignore[no-redef] if prefix != None and uri != None: if not hasattr(elem, 'nsmap'): etree_module.register_namespace(prefix, uri) else: # TODO research this for better understanding # _namespac
Re: Python - working with xml/lxml/objectify/schemas, datatypes, and assignments
On 1/4/23 12:13, aapost wrote: On 1/4/23 09:42, Dieter Maurer wrote: aapost wrote at 2023-1-3 22:57 -0500: ... Consider the following: from lxml import objectify, etree schema = etree.XMLSchema(file="path_to_my_xsd_schema_file") parser = objectify.makeparser(schema=schema, encoding="UTF-8") xml_obj = objectify.parse("path_to_my_xml_file", parser=parser) xml_root = xml_obj.getroot() let's say I have a Version element, that is defined simply as a string in a 3rd party provided xsd schema Does your schema include the third party schema? You might have a look at `PyXB`, too. It tries hard to enforce schema restrictions in Python code. Yes, to clarify, they provide the schema, which is what we use, downloaded locally. Basically just trying to remain compliant with their structures that they already define without reinventing the wheel for numerous calls and custom types, and in a way that feels more live rather than just checking validity at the end of the edits as if I were modifying the XML manually. Thank you for the suggestion, PyXB works much more like how I envisioned working with xml in my head: >>> xml_root.Version = 1231.32000 pyxb.exceptions_.SimpleTypeValueError: Type {http://www.w3.org/2001/XMLSchema}string cannot be created from: 1231.32 >>> xml_root.Version = "1231.32000" I will have to do some more testing to see how smooth the transition back to a formatted document goes, since it creates a variable for all possible fields defined in the type, even if they are optional and not there in the situational template. Thanks Unfortunately picking it apart for a while and diving deeper in to a rabbit hole, PyXB looks to be a no-go. PyXB while interesting, and I respect it's complexity and depth, is lacking in design consistency in how it operates if you are trying to modify and work with the resulting structure intuitively. It was developed on Python2 14 years ago, made compatible with python3 late, seems like it was trying to maintain vast version compatibility rather than getting a needed overhaul, before being abandoned in 2017 after the author moved on to more interesting work... I don't blame him, lol.. The community forks are just minor bug fixes currently. There are no setValue()/_setValue() functions for SimpleTypes (the bulk of your objects) so you can't change their values directly. Assigning to them appears to work if they are nested inside a parent that has __setattr__ overloaded (as a default resulting structure does when you first load a document), but it is a rats nest as far as what happens from there. Sometimes it calls .Factory(), sometimes it goes through a series of __init__s, but nothing is really clear on what is or is not a kosher approach to managing value changes, and my attempts have failed so far to see if I could figure out how to encompass those paths in to a single _setValue() call. Then there are ComplexTypes, with a value called _IsSimpleContent, which indicates whether it is a wrapper for a custom SimpleType, or something that does not contain SimpleType data. These DO have _setValue() functions IF it contains SimpleType data, where the SimpleType is stored in a __content member variable. Assignment on these also appears to work but the results aren't good, you need to use _setValue(), or you lose things like attributes. It would have been nicer if the structure of the ComplexType was called something else and wrapped all objects with a common set of functions. The validate functions do not work how one would assume, like they do for other libraries, where they go back and verify the data. I believe they only function on the way in, because if the data becomes invalid through some manual messing with it after the fact, they indicate that the data is still valid even when it's not. It seems like what I am probably looking for may reside in java with JAXB, but nothing really beyond that. generateDS, doesn't really offer anything I need from what I could tell in messing with it, and by the looks of it, I might have to bite the bullet and use the xmlschema library, work with dicts, handle many more corner cases on my side, and just let the result be a lot clunkier than I was hoping. Unless I find 8 years to redesign the wheel myself, not sure I am granted that ability though. Oh well. lol -- https://mail.python.org/mailman/listinfo/python-list
Re: Python - working with xml/lxml/objectify/schemas, datatypes, and assignments
On 1/4/23 09:42, Dieter Maurer wrote: aapost wrote at 2023-1-3 22:57 -0500: ... Consider the following: from lxml import objectify, etree schema = etree.XMLSchema(file="path_to_my_xsd_schema_file") parser = objectify.makeparser(schema=schema, encoding="UTF-8") xml_obj = objectify.parse("path_to_my_xml_file", parser=parser) xml_root = xml_obj.getroot() let's say I have a Version element, that is defined simply as a string in a 3rd party provided xsd schema Does your schema include the third party schema? You might have a look at `PyXB`, too. It tries hard to enforce schema restrictions in Python code. Yes, to clarify, they provide the schema, which is what we use, downloaded locally. Basically just trying to remain compliant with their structures that they already define without reinventing the wheel for numerous calls and custom types, and in a way that feels more live rather than just checking validity at the end of the edits as if I were modifying the XML manually. Thank you for the suggestion, PyXB works much more like how I envisioned working with xml in my head: >>> xml_root.Version = 1231.32000 pyxb.exceptions_.SimpleTypeValueError: Type {http://www.w3.org/2001/XMLSchema}string cannot be created from: 1231.32 >>> xml_root.Version = "1231.32000" I will have to do some more testing to see how smooth the transition back to a formatted document goes, since it creates a variable for all possible fields defined in the type, even if they are optional and not there in the situational template. Thanks -- https://mail.python.org/mailman/listinfo/python-list
Python - working with xml/lxml/objectify/schemas, datatypes, and assignments
I am trying to wrap my head around how one goes about working with and editing xml elements since it feels more complicated than it seems it should be.. Just to get some feedback on how others might approach it and see if I am missing anything obvious that I haven't discovered yet, since maybe I am wandering off in a wrong way of thinking.. I am looking to interact with elements directly, loaded from a template, editing them, then ultimately submitting them to an API as a modified xml document. Consider the following: from lxml import objectify, etree schema = etree.XMLSchema(file="path_to_my_xsd_schema_file") parser = objectify.makeparser(schema=schema, encoding="UTF-8") xml_obj = objectify.parse("path_to_my_xml_file", parser=parser) xml_root = xml_obj.getroot() let's say I have a Version element, that is defined simply as a string in a 3rd party provided xsd schema and is set to a number 2342 in my document The xml file loads with the above code successfully against the schema But lxml objectify decides the element type is Int, and the pytype is int.. Version Version.pyval Let's say I want this loaded into a UI with a variety of dynamically loaded entry widgets so I can edit a large number of values like this and of many other different types. I can assign in one of two ways (both resulting the same) xml_root.Version = xml_root['Version'] = (if there is some other more kosher way of assignment, let me know) I can assign "2342" and the element suddenly becomes a 'lxml.objectify.StringElement'> I can assign 1.4 and the element suddenly becomes a 'lxml.objectify.FloatElement'> The schema does not check during this assignment, it could be invalid, like assigning "abc" to a xs:dateTime and it does so any way. The original value is lost. The only way I see to verify against the schema again is to do so explicitly against the whole root. schema.validate(xml_root) This returns False because of the added xmlns:py, py:pytype stuff, I can strip those with: objectify.deannotate(xml_root[etree.QName(xml_root.Version.tag).localname], cleanup_namespaces=True) and get back to schema.validate(xml_root) validating True. BUT, it validates True whether the element is a String, Int, Float, etc (so long as it 'could' potentially be a string or something..).. So let's say a Version is 322.1121000, should be a string, validates against the schema as string, but is now 322.1121 (much more relevant for something like a product identification number) If it is a case where the validate remains False, I then have to manually look at the error log via schema.error_log for something like this: api_files/Basic:0:0:ERROR:SCHEMASV:SCHEMAV_CVC_DATATYPE_VALID_1_2_1: Element '{nsstuff}StartTime': 'asdfasdfa' is not a valid value of the atomic type 'xs:dateTime'. Then I have to consider how I should reject the users input.. From a UI design standpoint it just seems like a lot of added steps, and redundant work on top of a object layer that doesn't really do anything other than give me a thumbs up on the way in and a thumbs up on a way out. Rather than interacting with an object that can say your change is schema approved or not from the get-go, I instead seem to have to parse 10+ lines of xsd and design UI interaction much more situationally and granularly to assert types and corner cases and preserve original values in duplicate structures, etc.. My original assumptions when hearing about xml features doesn't seem to exist from what I have found so far. Where schema should be the law, if my schema says something should be loaded as a string, it should be a string (or something close enough, definitely not an int or float), then attempting to assign something to it that doesn't match schema should be denied or throw an error. I am sure under the hood it would probably have performance draw backs or something.. Oh well.. Back to contemplating and tinkering.. -- https://mail.python.org/mailman/listinfo/python-list