Planet Python

Subscribe to Planet Python feed
Planet Python - http://planetpython.org/
Updated: 20 hours 36 min ago

Matt Layman: More Go Standard Library - Building SaaS #198

Thu, 2024-08-15 20:00
In this episode, we continued the break from JourneyInbox to look through more of the Go standard library. In this session, we explored JSON serialization, Go template support, and embedding of static files for easy access.
Categories: FLOSS Project Planets

Matt Layman: PDF Text Extraction With Python

Wed, 2024-08-14 20:00
Is your data locked up in portable document format (PDFs)? In this talk we’re going to explore methods to extract text and other data from PDFs using readily-available, open-source Python tools (such as pypdf), as well as techniques such as OCR (optical character recognition) and table extraction. We will also discuss the philosophy of text extraction as a whole.
Categories: FLOSS Project Planets

Real Python: The Walrus Operator: Python's Assignment Expressions

Wed, 2024-08-14 10:00

Each new version of Python adds new features to the language. Back when Python 3.8 was released, the biggest change was the addition of assignment expressions. Specifically, the := operator gave you a new syntax for assigning variables in the middle of expressions. This operator is colloquially known as the walrus operator.

This tutorial is an in-depth introduction to the walrus operator. You’ll learn some of the motivations for the syntax update and explore examples where assignment expressions can be useful.

In this tutorial, you’ll learn how to:

  • Identify the walrus operator and understand its meaning
  • Understand use cases for the walrus operator
  • Avoid repetitive code by using the walrus operator
  • Convert between code using the walrus operator and code using other assignment methods
  • Use appropriate style in your assignment expressions

Note that all walrus operator examples in this tutorial require Python 3.8 or later to work.

Get Your Code: Click here to download the free sample code that shows you how to use Python’s walrus operator.

Take the Quiz: Test your knowledge with our interactive “The Walrus Operator: Python's Assignment Expressions” quiz. You’ll receive a score upon completion to help you track your learning progress:

Interactive Quiz

The Walrus Operator: Python's Assignment Expressions

In this quiz, you'll test your understanding of the Python Walrus Operator. This operator was introduced in Python 3.8, and understanding it can help you write more concise and efficient code.

Walrus Operator Fundamentals

First, look at some different terms that programmers use to refer to this new syntax. You’ve already seen a few in this tutorial.

The := operator is officially known as the assignment expression operator. During early discussions, it was dubbed the walrus operator because the := syntax resembles the eyes and tusks of a walrus lying on its side. You may also see the := operator referred to as the colon equals operator. Yet another term used for assignment expressions is named expressions.

Hello, Walrus!

To get a first impression of what assignment expressions are all about, start your REPL and play around with the following code:

Python 1>>> walrus = False 2>>> walrus 3False 4 5>>> (walrus := True) 6True 7>>> walrus 8True Copied!

Line 1 shows a traditional assignment statement where the value False is assigned to walrus. Next, on line 5, you use an assignment expression to assign the value True to walrus. After both lines 1 and 5, you can refer to the assigned values by using the variable name walrus.

You might be wondering why you’re using parentheses on line 5, and you’ll learn why the parentheses are needed later on in this tutorial.

Note: A statement in Python is a unit of code. An expression is a special statement that can be evaluated to some value.

For example, 1 + 2 is an expression that evaluates to the value 3, while number = 1 + 2 is an assignment statement that doesn’t evaluate to a value. Although running the statement number = 1 + 2 doesn’t evaluate to 3, it does assign the value 3 to number.

In Python, you often see simple statements like return statements and import statements, as well as compound statements like if statements and function definitions. These are all statements, not expressions.

There’s a subtle—but important—difference between the two types of assignments with the walrus variable. An assignment expression returns the value, while a traditional assignment doesn’t. You can see this in action when the REPL doesn’t print any value after walrus = False on line 1 but prints out True after the assignment expression on line 5.

You can see another important aspect about walrus operators in this example. Though it might look new, the := operator does not do anything that isn’t possible without it. It only makes certain constructs more convenient and can sometimes communicate the intent of your code more clearly.

Now you have a basic idea of what the := operator is and what it can do. It’s an operator used in assignment expressions, which can return the value being assigned, unlike traditional assignment statements. To get deeper and really learn about the walrus operator, continue reading to see where you should and shouldn’t use it.

Implementation

Like most new features in Python, assignment expressions were introduced through a Python Enhancement Proposal (PEP). PEP 572 describes the motivation for introducing the walrus operator, the details of the syntax, and examples where the := operator can be used to improve your code.

This PEP was originally written by Chris Angelico in February 2018. Following some heated discussion, PEP 572 was accepted by Guido van Rossum in July 2018.

Since then, Guido announced that he was stepping down from his role as benevolent dictator for life (BDFL). Since early 2019, the Python language has been governed by an elected steering council instead.

The walrus operator was implemented by Emily Morehouse, and made available in the first alpha release of Python 3.8.

Motivation Read the full article at https://realpython.com/python-walrus-operator/ »

[ Improve Your Python With 🐍 Python Tricks 💌 – Get a short & sweet Python Trick delivered to your inbox every couple of days. >> Click here to learn more and see examples ]

Categories: FLOSS Project Planets

Real Python: Quiz: The Walrus Operator: Python's Assignment Expressions

Wed, 2024-08-14 08:00

In this quiz, you’ll test your understanding of the Python Walrus Operator. This operator, used for assignment expressions, was introduced in Python 3.8 and can be used to assign values to variables as part of an expression.

[ Improve Your Python With 🐍 Python Tricks 💌 – Get a short & sweet Python Trick delivered to your inbox every couple of days. >> Click here to learn more and see examples ]

Categories: FLOSS Project Planets

Python Anywhere: Postal code validation for card payments

Wed, 2024-08-14 07:00
TL;DR

We recently started validating that the postal codes used for paid PythonAnywhere accounts match the ones that people’s banks have on file for the card used. This has led to some confusion, in particular because banks handle postal code validation in a complicated way – charges that fail because of this kind of error can show up in your bank app as a payment that then disappears later, or even as a charge followed by a refund. This blog post is to summarise why that is, so hopefully it will make things a bit less confusing!

The long version…

Card fraud is, sadly, a fact of life on the Internet. If you have a website that accepts payments, eventually someone will try to use a stolen card on it. If your site is online for some time, hackers might even start using you to test lists of stolen cards – that is, they don’t want to use your product in particular, they’re just trying each of the cards to find the ones that are valid, so that they can use them elsewhere.

We recently saw an uptick in the number of these “card probers” (as we call them internally) on PythonAnywhere. We have processes in place to identify them, so that we can refund all payments they get through, and report them as fraudulent to Stripe – our card processor – so that the cards in question are harder for them to use on other sites. But this takes time – time which we would much rather spend on building new features for PythonAnywhere.

Looking into the recent charges, we discovered that many of them were using the wrong postal code when testing the cards. The probers had the numbers, the expiry dates, the CVVs, but not the billing addresses. So we re-introduced something that had been disabled on our Stripe account for some time: postal code validation for payments. You may be wondering why it wasn’t enabled already, or why it might even be something that anyone would disable; this blog post is an introduction to why postal codes and card payments can be more complicated than you might think.

Categories: FLOSS Project Planets

Paolo Melchiorre: Python Software Foundation fellow member

Wed, 2024-08-14 05:43

The Python Software Foundation made me a PSF fellow member, along with Adam Johnson.

Categories: FLOSS Project Planets

PyCharm

Tue, 2024-08-13 17:41

The new and improved AI Assistant for the 2024.2 versions of JetBrains IDEs is now out, featuring smarter and faster AI code completion for Java, Kotlin, and Python; an enhanced UX when working with code in the editor; AI functionality for Git conflict resolution, in-terminal code generation, new customizable prompts, improved test generation, and more.

Don’t have AI Assistant yet? 

To experience the latest enhancements, simply open a project in your preferred JetBrains IDE version 2024.2, click the AI icon on the right toolbar to initiate the installation, and follow the instructions to enable it. 

You can also experience free local AI completion functionality with full line code completion (FLCC) in your IDE of choice, including CLion and Rider starting from 2024.2. Learn more about FLCC in this blog post. 

Faster and smarter cloud code completion

One of the main focuses of this release was to enhance the user experience of AI code completion in JetBrains IDEs. Here are some of the major advances we’ve made in this direction:

JetBrains code completion models for Python, Java, and Kotlin

We’ve significantly improved the quality and reduced the latency of our code completion for Java, Kotlin, and Python. These enhancements are powered by JetBrains’ internally trained large language models. Enhanced locations for cloud completion invocation extend the variety of usage scenarios, while improved suffix matching ensures that the predicted code snippet correctly completes the existing code.

Syntax highlighting for suggested code

Inline code completion suggestions now come with syntax highlighting, improving the readability of the suggested code.

Incremental acceptance of code suggestions

To simplify the process of reviewing suggestions, multiline code suggestions are now displayed only after accepting a single-line suggestion, allowing you to review and accept code gradually. Additionally, if you don’t want to accept an entire suggested line, you can accept it word by word using the same shortcut that you’d typically use to move the caret to the following word (Ctrl+→ for Windows and ⌥→ for macOS).

Seamless interaction of all available code completion types

We have made UX improvements to better integrate AI code completion features into IDE workflows. This includes a reworked UX for multiline completion and the ability to display suggestions alongside basic IDE completions.

Enhanced in-editor code generation

With the latest update, JetBrains IDEs now feature an improved AI code generation experience. Previously, generated code would open in a new tab. Now, it’s displayed directly in the current editor tab, allowing for an immediate review of the generated content. Check it out using the shortcut ⌘\ on macOS or Ctrl+\ on Windows and Linux.

AI chat becomes smarter GPT-4o support

With the new release, AI Assistant now supports the latest GPT-4o model, bringing a boost to the AI Assistant’s chat-related functionalities, such as finding and explaining errors, explaining code, and refactoring.

Chat references and commands

We have introduced chat references and commands to enhance your AI Assistant’s chat experience, giving you more control over your context. Now, you can reference any symbols, allowing you to quickly indicate the context of your query and get more precise responses. Additionally, you can easily mention specific files or uncommitted local changes. Supported commands include /explain and /refactor, allowing you to quickly get explanations or refactor selected code without typing out questions in the chat.

New feature: merge VCS conflicts with AI

When multiple contributors are making changes to the same part of the codebase, and you try to pull your changes, conflicts may arise. To avoid any issues down the line, JetBrains IDEs now provide a tool for reviewing and resolving any such conflicts. Starting from version 2024.2, the Git conflict resolution modal dialog features AI capabilities to assist with merging conflicts. After AI has done its job, you can review the merged result and either accept everything or revert the changes individually. 

New feature: AI-powered command generation in the new Terminal

Generate commands with AI directly in your IDE via the new Terminal tool window. This integration ensures you can efficiently complete command-line tasks without distraction, improving your overall workflow.

Enhanced unit test generation with AI Assistant

Starting from version 2024.2, the Generate Unit Tests action can be invoked not only on methods but also on classes. If a class has multiple methods, the AI will automatically choose the most suitable one for testing. The latest update also includes more customization options for unit test generation. 

Customizable unit test guidelines

Users can set their own unit test guidelines by customizing the test generation prompt in the AI Assistant’s Prompt Library. This allows you to add specific testing rules for Java, Kotlin, JavaScript, Go, Python, PHP, and Ruby.

Adding test cases to existing tests

AI Assistant now supports adding new test cases to existing test files for Java and Kotlin, allowing you to generate new tests using AI.

Сustom prompts for documentation generation 

The latest update to JetBrains IDEs introduces customizable documentation generation prompts. This feature allows the model to generate documentation for a selected code element and inserts it directly into the code. Users can now define the desired content of the generated documentation for different languages and specify various formatting options, such as Javadoc for Java, ensuring the documentation adheres to preferred styles and standards.

Natural Language setting

You can now specify the language in which you want to interact with the AI chat via Settings. After enabling the Natural Language setting, the context of the current chat will be updated, and any new answers generated by the AI will be provided in the user’s chosen language.

Using AI for working with databases

The new release brings AI to a variety of database-specific features within JetBrains IDEs. You can try these out in DataGrip or in a JetBrains IDE of your choice using the bundled Database Tools and SQL plugin.

Get AI assistance when modifying tables

AI Assistant can now help you change the database-specific parameters of a table. Ask AI Assistant to modify a table according to your requirements right in the Modify dialog. Once AI Assistant generates the requested SQL code, you’ll be able to review it in the preview pane of the dialog and then apply the changes.

Explain and fix SQL problems


DataGrip’s code inspections detect various issues with your SQL queries before execution, which are then categorized according to predefined severity levels.

The latest update integrates AI to enhance the comprehension and resolution of SQL problems. For issues with a severity level higher than Weak warning, the AI Assistant offers explanations and fixes. For better context and more accurate suggestions, you can also attach your database schema.

AI Enterprise: unlocking organizational productivity

Are you looking to maximize productivity at an organizational scale? AI Enterprise runs on premises as part of JetBrains IDE Services, ensuring complete control over data and AI operations within your organization’s infrastructure. It also provides AI usage statistics and reports, offering insights into how AI tools are utilized across your development teams. Learn more about AI Enterprise.

Enhance your writing with Grazie, now included in the AI Pro subscription plan

We’re excited to share that Grazie, our AI writing companion for people in tech, is now included in the AI Pro subscription plan. Use Grazie to transform your thoughts into clear, well-articulated writing, with features like instant proofreading, inline text completion, summarization, translation, rephrasing, and more!

Grazie is now available as a plugin for your JetBrains IDEs and as an extension for browsers. While there is a free version, AI Pro subscribers enjoy full volume access to the entire suite of Grazie’s AI features, which is 500 times greater than the basic volume and replenishes weekly.

Explore AI Assistant and share your feedback

You can learn more about AI Assistant’s key features here. However, the best way to explore its capabilities is by trying it out yourself.

As always, we look forward to hearing your feedback. You can also tell us about your experience via the Share your feedback link in the AI Assistant tool window or by submitting feature requests or bug reports in YouTrack.

Happy developing!

Categories: FLOSS Project Planets

PyCoder’s Weekly: Issue #642 (Aug. 13, 2024)

Tue, 2024-08-13 15:30

#642 – AUGUST 13, 2024
View in Browser »

Testing Coverage and Using nox

This is part 9 in an in-depth series on testing. This part talks about using coverage tools to check how much of your code gets executed during tests, and how to use the nox tool to test against a matrix of Python and dependency versions.
BITE CODE!

Asynchronous Iterators and Iterables in Python

In this tutorial, you’ll learn how to create and use asynchronous iterators and iterables in Python. You’ll explore their syntax and structure and discover how they can be leveraged to handle asynchronous operations more efficiently.
REAL PYTHON

500 Devs, Deploying 200x a Day, While Maintaining 4 Million Lines of Code 😮‍💨

Sounds tricky right? Well that’s exactly what Kraken Technologies is doing. Learn how they manage 100s of deployments a day and how they handle errors when they crop up. Sneak peak: they use Sentry to reduce noise, prioritize issues, and maintain code quality–without relying on a dedicated QA team →
SENTRY sponsor

Log Context Propagation in Python ASGI Apps

This explains how to automatically attach contextual information to all the log messages coming out of a Python ASGI application.
REDOWAN DELOWAR • Shared by Redowan Delowar

PEP 750: Tag Strings for Domain-Specific Languages (Added)

PEP

Python 3.12.5 Released

CPYTHON DEV BLOG

Django Security Releases: 5.0.8 and 4.2.15

DJANGO SOFTWARE FOUNDATION

Django 5.1 Released

DJANGO SOFTWARE FOUNDATION

Quiz: Python Basics: Lists and Tuples

REAL PYTHON

Quiz: How to Write Beautiful Python Code With PEP 8

REAL PYTHON

Articles & Tutorials Fixing CTRL+left and CTRL+right in the REPL on macOS

The upcoming release of Python 3.13 has some great new features in the REPL making it easier to move around and edit your code. One feature is the ability to move word by word using CTRL+left and right arrow keys. Unfortunately, macOS traps these keys. This quick TIL post shows you how to fix that.
RODRIGO GIRÃO SERRÃO

Strings and Character Data in Python

In this tutorial, you’ll learn how to use Python’s rich set of operators and functions for working with strings. You’ll cover the basics of creating strings using literals and the str() function, applying string methods, using operators and built-in functions with strings, and more!
REAL PYTHON

Learning Through Building the Black Python Devs Community

What hurdles must be cleared when starting an international organization? How do you empower others in a community by sharing responsibilities? This week on the show, we speak with Jay Miller about Black Python Devs.
REAL PYTHON podcast

Taking Notes on a New Codebase

Nat is a consultant which means they spend a lot of time reading other people’s code. When trying to understand large systems taking notes along the way can help. This post talks about the techniques Nat uses.
NAT BENNETT

Create Amazing Progress Bars in Python With alive-progress

Have you ever needed a progress bar in your Python command-line application? One great way of creating a progress bar is to use the alive-progress package. This article shows you how.
MIKE DRISCOLL

PyCon US 2024 Recap and Recording Release

PyCon US 2024 had a record breaking attendance with over 2,700 in-person tickets sold. This article is a recap from the conference runners and links to all the available recordings.
PYCON

Knuckledragger, a Semi-Automated Python Proof Assistant

This post describes Knuckledragger, a Z3 based semi-automated proof assistant. The post covers the basic design, applications, and a variety of theory types it can work with.
PHILIP ZUCKER

Python Extensions Should Be Lazy

Evan has been using the ast.parse function a lot and has found it to be slow even though it is built as a C extension. This article digs into what is going on.
EVAN DOYLE

SonarQube: Open Source Security Automation

SonarQube is a freely available static code analysis tool. This article shows you what it can do and how to get it going on your system.
PRINCE ONYEANUNA

The Trouble With __all__

This post talks about the __all__ attribute and how it declares the public interface to a module, but does not enforce access.
CAELEAN BARNES

Parsing nginx Server Logs With Regular Expressions

This practical article on regular expressions shows you how to build regexes to parse the logs from the nginx web server.
JUHA-MATTI SANTALA

Python’s Operator Precedence

Stephen uses a story-telling style to explain how operator precedence works in Python.
STEPHEN GRUPPETTA • Shared by Stephen Gruppetta

Projects & Code RustPython: A Python Interpreter Written in Rust

GITHUB.COM/RUSTPYTHON

fasthtml: The Fastest Way to Create an HTML App

GITHUB.COM/ANSWERDOTAI

wat: Deep Inspection of Python Objects

GITHUB.COM/IGREK51

zulip-terminal: Official Zulip Chat Terminal Client

GITHUB.COM/ZULIP

emptylog: Expand the Logger Protocol and Test Logs

GITHUB.COM/POMPONCHIK • Shared by Evgeniy Blinov (pomponchik)

Events Weekly Real Python Office Hours Q&A (Virtual)

August 14, 2024
REALPYTHON.COM

PyData Bristol Meetup

August 15, 2024
MEETUP.COM

PyLadies Dublin

August 15, 2024
PYLADIES.COM

SheDevelopers: Python Mastery Workshop 1st Edition

August 16 to August 17, 2024
SHEDEVSPYTHONWORKSHOP.CO.ZW

PyCon Somalia 2024

August 21 to August 23, 2024
PYCON.ORG.SO

Kiwi PyCon XIII

August 23 to August 26, 2024
KIWIPYCON.NZ

Happy Pythoning!
This was PyCoder’s Weekly Issue #642.
View in Browser »

[ Subscribe to 🐍 PyCoder’s Weekly 💌 – Get the best Python news, articles, and tutorials delivered to your inbox once a week >> Click here to learn more ]

Categories: FLOSS Project Planets

Python Software Foundation: Announcing Python Software Foundation Fellow Members for Q1 2024! 🎉

Tue, 2024-08-13 10:20

The PSF is pleased to announce its first batch of PSF Fellows for 2024! Let us welcome the new PSF Fellows for Q1! The following people continue to do amazing things for the Python community:

Adam Johnson

Website, Mastodon, Github

Paolo Melchiorre 

Website, Mastodon, GitHub, Stack Overflow, YouTube, LinkedIn, X

Thank you for your continued contributions. We have added you to our Fellow roster.

The above members help support the Python ecosystem by being phenomenal leaders, sustaining the growth of the Python scientific community, maintaining virtual Python communities, maintaining Python libraries, creating educational material, organizing Python events and conferences, starting Python communities in local regions, and overall being great mentors in our community. Each of them continues to help make Python more accessible around the world. To learn more about the new Fellow members, check out their links above.

Let's continue recognizing Pythonistas all over the world for their impact on our community. The criteria for Fellow members is available online: https://www.python.org/psf/fellows/. If you would like to nominate someone to be a PSF Fellow, please send a description of their Python accomplishments and their email address to psf-fellow at python.org. Quarter 2 nominations are currently in review. We are accepting nominations for Quarter 3 through August 20, 2024.

Are you a PSF Fellow and want to help the Work Group review nominations? Contact us at psf-fellow at python.org.

Categories: FLOSS Project Planets

Real Python: Sorting Dictionaries in Python: Keys, Values, and More

Tue, 2024-08-13 10:00

You’ve got a dictionary, but you’d like to sort the key-value pairs. Perhaps you’ve tried passing a dictionary to the sorted() function but didn’t receive the results you expected. In this video course, you’ll go over everything you need to know to sort dictionaries in Python.

In this video course, you’ll:

  • Review how to use the sorted() function
  • Learn how to get dictionary views to iterate over
  • Understand how dictionaries are cast to lists during sorting
  • Learn how to specify a sort key to sort a dictionary by value, key, or nested attribute
  • Review dictionary comprehensions and the dict() constructor to rebuild your dictionaries
  • Consider alternative data structures for your key-value data

[ Improve Your Python With 🐍 Python Tricks 💌 – Get a short & sweet Python Trick delivered to your inbox every couple of days. >> Click here to learn more and see examples ]

Categories: FLOSS Project Planets

Stefanie Molin: How Pre-Commit Works

Tue, 2024-08-13 09:51
So, you've just set up pre-commit hooks on your repository using `pre-commit`, but do you know what actually happened when you ran `pre-commit install` or why you had to run it in the first place? How does `pre-commit` actually work with Git? In this article, I will take you behind the scenes of how your `pre-commit` setup works.
Categories: FLOSS Project Planets

Python Bytes: #396 uv-ing your way to Python

Tue, 2024-08-13 04:00
<strong>Topics covered in this episode:</strong><br> <ul> <li><a href="https://github.com/astral-sh/uv/blob/0.2.35/docs/concepts/python-versions.md?featured_on=pythonbytes"><strong>uv venv</strong></a><a href="https://github.com/astral-sh/uv/blob/0.2.35/docs/concepts/python-versions.md?featured_on=pythonbytes"> </a><a href="https://github.com/astral-sh/uv/blob/0.2.35/docs/concepts/python-versions.md?featured_on=pythonbytes"><strong>--python</strong></a><a href="https://github.com/astral-sh/uv/blob/0.2.35/docs/concepts/python-versions.md?featured_on=pythonbytes"> <strong>&amp; uv python</strong></a></li> <li><strong><a href="https://docs.python.org/release/3.12.5/whatsnew/changelog.html#python-3-12-5">Python 3.12.5 released</a></strong></li> <li><strong><a href="https://blog.rxbc.se/posts/compile-and-use-dependencies-for-multiple-python-versions-in-tox/?featured_on=pythonbytes">Compile and use dependencies for multiple Python versions in Tox</a></strong></li> <li><strong><a href="https://hallofshame.design/collection/?featured_on=pythonbytes">Catalog of Dark Patterns</a></strong></li> <li><strong>Extras</strong></li> <li><strong>Joke</strong></li> </ul><a href='https://www.youtube.com/watch?v=0Sa0z2XXwwk' style='font-weight: bold;'data-umami-event="Livestream-Past" data-umami-event-episode="396">Watch on YouTube</a><br> <p><strong>About the show</strong></p> <p>Sponsored by ScoutAPM: <a href="https://pythonbytes.fm/scout"><strong>pythonbytes.fm/scout</strong></a></p> <p><strong>Connect with the hosts</strong></p> <ul> <li>Michael: <a href="https://fosstodon.org/@mkennedy"><strong>@mkennedy@fosstodon.org</strong></a></li> <li>Brian: <a href="https://fosstodon.org/@brianokken"><strong>@brianokken@fosstodon.org</strong></a></li> <li>Show: <a href="https://fosstodon.org/@pythonbytes"><strong>@pythonbytes@fosstodon.org</strong></a></li> </ul> <p>Join us on YouTube at <a href="https://pythonbytes.fm/stream/live"><strong>pythonbytes.fm/live</strong></a> to be part of the audience. Usually Tuesdays at 10am PT. Older video versions available there too.</p> <p>Finally, if you want an artisanal, hand-crafted digest of every week of the show notes in email form? Add your name and email to <a href="https://pythonbytes.fm/friends-of-the-show">our friends of the show list</a>, we'll never share it. </p> <p><strong>Brian #1:</strong> <a href="https://github.com/astral-sh/uv/blob/0.2.35/docs/concepts/python-versions.md?featured_on=pythonbytes"><strong>uv venv</strong></a><a href="https://github.com/astral-sh/uv/blob/0.2.35/docs/concepts/python-versions.md?featured_on=pythonbytes"> </a><a href="https://github.com/astral-sh/uv/blob/0.2.35/docs/concepts/python-versions.md?featured_on=pythonbytes"><strong>--python</strong></a><a href="https://github.com/astral-sh/uv/blob/0.2.35/docs/concepts/python-versions.md?featured_on=pythonbytes"> <strong>&amp; uv python</strong></a></p> <ul> <li>I was reading this article <a href="https://dev.to/astrojuanlu/python-packaging-is-great-now-uv-is-all-you-need-4i2d?featured_on=pythonbytes">Python Packaging is Great Now:</a><a href="https://dev.to/astrojuanlu/python-packaging-is-great-now-uv-is-all-you-need-4i2d?utm_source=pocket_shared&featured_on=pythonbytes"> </a><a href="https://dev.to/astrojuanlu/python-packaging-is-great-now-uv-is-all-you-need-4i2d?utm_source=pocket_shared&featured_on=pythonbytes"><code>uv</code></a><a href="https://dev.to/astrojuanlu/python-packaging-is-great-now-uv-is-all-you-need-4i2d?utm_source=pocket_shared&featured_on=pythonbytes"> is all you need</a></li> <li>It’s a little too “look, a silver bullet” for me, but it did point out some cool uv stuff I didn’t know about. <ul> <li>uv venv venv --python 3.12 creates a virtual environment with Python 3.12, <ul> <li>even if you didn’t have 3.12 installed on your system already.</li> <li>If it doesn’t work, try adding --python-preference managed</li> </ul></li> <li>uv python list shows all the python versions on your computer</li> <li>There’s quite a few “experimental features” <ul> <li><strong>run</strong> Run a command or script (experimental)</li> <li><strong>init</strong> Create a new project (experimental)</li> <li><strong>add</strong> Add dependencies to the project (experimental)</li> <li><strong>remove</strong> Remove dependencies from the project (experimental)</li> <li><strong>sync</strong> Update the project's environment (experimental)</li> <li><strong>lock</strong> Update the project's lockfile (experimental)</li> <li><strong>tree</strong> Display the project's dependency tree (experimental)</li> <li><strong>tool</strong> Run and manage tools provided by Python packages (experimental)</li> <li><strong>python</strong> Manage Python versions and installations (experimental)</li> </ul></li> </ul></li> <li>uv add --dev pytest will add pytest to your dev dependencies.</li> <li>uv tree rocks</li> <li>uv might not have “solved packaging” (or maybe it might have) <ul> <li>but it sure is fun to watch the experimentation of different workflows.</li> </ul></li> </ul> <p><strong>Michael #2:</strong> <a href="https://docs.python.org/release/3.12.5/whatsnew/changelog.html#python-3-12-5">Python 3.12.5 released</a></p> <ul> <li>Lots of changes, see the <a href="https://docs.python.org/release/3.12.5/whatsnew/changelog.html#python-3-12-5">release notes</a></li> </ul> <p><strong>Brian #3:</strong> <a href="https://blog.rxbc.se/posts/compile-and-use-dependencies-for-multiple-python-versions-in-tox/?featured_on=pythonbytes">Compile and use dependencies for multiple Python versions in Tox</a></p> <ul> <li>Viktor Rimark</li> <li>Cool idea to use the {envname}, which specifies the tox environment, in the name of a requirements-dev.txt file name.</li> <li>Then add a requirements tox target to generate pip-compile-ed files.</li> <li>Now I gotta try doing all of this with uv lock</li> <li>Then we need everyone to mod their tools to comply with <a href="https://peps.python.org/pep-0751/?featured_on=pythonbytes">PEP 571</a>, when/if it’s adopted (covered it last week)</li> </ul> <p><strong>Michael #4:</strong> <a href="https://hallofshame.design/collection/?featured_on=pythonbytes">Catalog of Dark Patterns</a></p> <ul> <li>Including <ul> <li>Bait and Switch</li> <li>Confirm Shaming</li> <li>Disguised Ads</li> <li>Roach Motel</li> <li>Fake Scarcity</li> <li>…</li> </ul></li> </ul> <p><strong>Extras</strong> </p> <p>Brian:</p> <ul> <li>Recording of <a href="https://courses.pythontest.com/hello-pytest?featured_on=pythonbytes">Hello, pytest!</a> is done. Editing now. On track for the 19th (or before).</li> </ul> <p>Michael:</p> <ul> <li><a href="https://www.djangoproject.com/weblog/2024/aug/07/django-51-released/?featured_on=pythonbytes">Django 5.1</a> released</li> <li><a href="https://blog.python.org/2024/08/python-3130-release-candidate-1-released.html?featured_on=pythonbytes">Python 3.13.0 release candidate 1</a> released</li> </ul> <p><strong>Joke:</strong> </p> <ul> <li><a href="https://clownstrike.lol/?featured_on=pythonbytes">clownstrike</a> <ul> <li><a href="https://arstechnica.com/tech-policy/2024/08/parody-site-clownstrike-refused-to-bow-to-crowdstrikes-bogus-dmca-takedown?featured_on=pythonbytes">ARS Technica article on DMCA for ClownStrike</a></li> </ul></li> </ul>
Categories: FLOSS Project Planets

PyCharm: PyCharm 2024.2 Is Here: Improvements for Jupyter Notebooks, Databricks Integration, New AI Assistant Features, and More!

Mon, 2024-08-12 10:06

Offering a wide range of new and improved functionality, including Hugging Face integration, new AI Assistant features, a new default UI, and an overall better user experience, PyCharm 2024.2 is a must for anyone looking to increase their productivity. 

Learn about all the updates on our What’s New page, download the latest version from our website, or update your current version through our free Toolbox App.

Download PyCharm 2024.2 PyCharm 2024.2 key features Databricks integration PRO

PyCharm now provides direct integration with Databricks via a plugin. You can connect to a Databricks cluster, execute scripts and notebooks as workflows, execute files directly in a Spark shell on a cluster, and monitor the progress – all from the comfort of your IDE.

This integration allows you to harness the power of your IDE when working with Databricks, making the process faster and easier. 

Hugging Face integration PRO

PyCharm 2024.2 can now suggest the most relevant Hugging Face models based on your use case. When you select a model, the IDE will suggest inserting a code snippet that allows you to use it directly in the open file, and PyCharm will download and install any missing dependencies automatically.

You can also identify unused models installed on your machine and delete them to free up disk space directly from the IDE. 

Additionally, you can inspect your Hugging Face Datasets library data as an interactive dataframe, utilizing features like the chart view, pagination, and the ability to sort and export tables.

Read more Jupyter notebooks PRO

Instantly preview the value of a chosen variable simply by hovering over the variable’s line. You no longer need to use the debugger or print statements!

Furthermore, you can now expand and collapse cells, as well as run them straight from the gutter. Additionally, cells now display their statuses and assigned tags.

All these improvements are designed to make working with Jupyter notebooks in PyCharm seamless, fast, and efficient. 

AI cells in Jupyter notebooks

With our new AI cell option, you can add prompts directly inside your notebooks and work with AI Assistant right from there. A light bulb icon next to the AI cell provides suggestions about the next steps in your data analysis workflow.

One-click dataframe visualization

Visualize your dataframes with the help of AI Assistant, which now provides suggestions about the graphs and plots most suitable to your context.

AI Assistant

JetBrains AI Assistant 2024.2 enhances cloud-based code completion with faster, more accurate suggestions and a better UX, including syntax highlighting and the option to accept suggestions incrementally. The AI chat now uses the latest GPT-4o model and supports chat references and semantic search. 

New features include AI integration in the Terminal tool window for command generation, AI-assisted VCS conflict resolution, and customizable prompts for documentation and unit test creation.

Learn about these and other AI Assistant enhancements in this dedicated blog post.

Database tools PRO New AI Assistant features 

With the text-to-SQL feature, you can generate SQL code directly in the editor by clicking Generate Code with AI and entering your prompt. You can accept, regenerate, or refine the code, and take it to the AI chat if you have further questions.

Additionally, AI Assistant can help with modifying tables, allowing you to request changes like switching all VARCHAR data types to CHAR.

It can also help you understand and fix SQL problems, suggesting explanations and fixes. 

Read more User experience Preview option in Search Everywhere

The Search Everywhere dialog now includes an option to preview the codebase elements you’re searching for, offering additional context and making it easier to navigate through your project.

Improved full line code completion PRO

In 2024.2, full line code completion suggestions now include code highlighting, and new shortcuts allow you to accept individual words or entire lines from longer suggestions. We’ve also refined how accepted changes are integrated into your code, eliminating any formatting issues.

Run/Debug String variable visualizers for JSON, XML, and other formats

Debugging and browsing long string variables with complex data formats is now much easier. The updated debugger offers properly formatted visualizations for string variables with strings encoded in JSON, XML, HTML, JWT, and URL.

Frameworks and technologies PRO GraalJS as the execution engine for the HTTP Client 

We’ve upgraded the JavaScript execution engine used in the HTTP Client to GraalJS. This allows you to use all GraalJS features, including full support for the ECMAScript 2023 specification, when testing endpoints with PyCharm’s HTTP Client and using JavaScript in .http files to handle the results.

HTTP Client improvements

In the HTTP Client, we’ve added XPath functionality for querying and manipulating XML and HTML documents, support for iterating through collections using JSONPath to automate requests, and the ability to create and add custom API methods effortlessly. 

Enhanced Terraform support 

We’ve enhanced PyCharm’s Terraform support with full line code completion, improved context-aware code completion, refined syntax highlighting, and better error detection with quick-fix suggestions. Additionally, a quick documentation feature now provides instant tooltips, offering immediate information to streamline your Terraform workflow.

Frontend PRO Improved support for major web frameworks

PyCharm can now resolve paths for frameworks that use file-system-based routing. It can also resolve link paths based on your project’s file system, providing autocompletion and navigation for Next.js, Nuxt, SvelteKit, and Astro. There is also support for new Svelte 5 snippets and render tags. 

Additionally, we’ve implemented language server protocol (LSP) support for Astro and upgraded the Vue LSP to Vue Language Service v2, improving code completion and the overall developer experience.

Ability to run and debug TypeScript files directly

You can now run and debug TypeScript files from different entry points, including the file context menu, the Run widget, and the Current File configuration. 

Remote development PRO Reverse port forwarding

With reverse port forwarding, you can now connect a remote IDE to ports available on the client machine. This is particularly useful for mobile development and connecting to local databases.

Download PyCharm 2024.2

These are all the key features of this release, but there’s much more to explore! Visit our What’s New page or release notes for the full breakdown and additional details about the features mentioned here. 

If you encounter any problems, please report them in our issue tracker so we can address them promptly. 

Connect with us on X (formerly Twitter) to share your thoughts on PyCharm 2024.2. We’re looking forward to hearing them!

Categories: FLOSS Project Planets

Real Python: Python News Roundup: August 2024

Mon, 2024-08-12 10:00

In July, there was some exciting news for the Python community as the Python core development team released versions 3.13.0b4 and 3.13.0rc1 of the language. The 3.13.0b4 release marked the end of the beta phase and paved the way for the release candidate phase.

Note that 3.13.0rc1 is a pre-release, so you shouldn’t use it for production environments. However, it provides a great way to try some new and exciting language features.

There’s also great some news from the Python Software Foundation, PyOhio 2024, and the Python ecosystem.

Let’s dive into the most exciting Python news from last month!

Python 3.13.0b4 and 3.13.0rc1

Python 3.13 has reached its fourth beta release, marking the end of the beta phase. Beta releases serve to test new features and bug fixes. However, it’s important to note that this is a preview release and it isn’t recommended for use in production environments.

If you’re a library maintainer, you’re encouraged to test your code with this new version so you can prepare it to support the latest features of the language.

Note: To learn more about pre-releases, check out the How Can You Install a Pre-Release Version of Python? tutorial.

One of the most significant new features of Python 3.13 is the improved interactive interpreter or REPL, which now provides several cool features, including:

  • Colorized prompts
  • Multiline editing with history preservation
  • Interactive help browsing with F1 and a separate command history
  • History browsing with F2
  • Paste mode for larger blocks of code with F3
  • REPL-specific commands like help, exit, and quit without the call parentheses

This is exciting news! The standard REPL up until Python 3.13 was lacking, and sometimes it was necessary to install a third-party tool like bpython or IPython to compensate.

Again, with this release, the beta phase has officially ended, and the first release candidate—3.13.0rc1—is considered the penultimate release preview. In this release candidate phase, only bug fixes are allowed.

The second candidate, which is the last planned release preview, should be out on September 3, 2024, and the official release of 3.13 should be ready on October 1, 2024. Only more excitement lies ahead!

The Python Software Foundation (PSF) Shares Great News Read the full article at https://realpython.com/python-news-august-2024/ »

[ Improve Your Python With 🐍 Python Tricks 💌 – Get a short & sweet Python Trick delivered to your inbox every couple of days. >> Click here to learn more and see examples ]

Categories: FLOSS Project Planets

Mike Driscoll: Creating Progress Bars in Your Terminal with Python and Textual

Mon, 2024-08-12 08:21

The Textual package is a great way to create GUI-like applications with Python in your terminal. These are known as text-based user interfaces or TUIs. Textual has many different widgets built-in to the framework.

One of those widgets is the ProgressBar. If you need to show the progress of a download or long-running process, then you will probably want to use a progress bar or some kind of spinner widget to show the user that your application is working.

This tutorial will show you how to create a simple progress bar with Textual!

Installation

If you do not have Textual installed yet, you can get it by using Python’s handy pip tool. Open up your terminal and run the following command there:

python -m pip install textual

Textual will get installed, along with all its dependencies. You may want to create a virtual environment first and install Textual there.

Creating a ProgressBar in Textual

Creating a progress bar with Textual is pretty straightforward. The following code is based on an example from the Textual documentation. The main difference is that this version uses a button to start the timer, simulating a download or some other long-running process rather than catching a key event.

You can copy this code into your favorite Python editor and give it a quick study:

# progressbar_demo.py from textual.app import App, ComposeResult from textual.containers import Center, Middle from textual.timer import Timer from textual.widgets import Button, ProgressBar class Progress(App[None]): timer = Timer def compose(self) -> ComposeResult: with Center(): with Middle(): yield ProgressBar() yield Button("Start") def on_mount(self) -> None: """ Set up the timer to simulate progress """ self.timer = self.set_interval(1 / 10, self.advance_progressbar, pause=True) def advance_progressbar(self) -> None: """ Called to advance the progress bar """ self.query_one(ProgressBar).advance(1) def on_button_pressed(self) -> None: """ Event handler that is called when button is pressed """ self.query_one(ProgressBar).update(total=100) self.timer.resume() if __name__ == "__main__": app = Progress() app.run()

The compose() method is kind of fun as it uses both the Center() and the Middle() containers to position the widgets in the middle of the terminal. You then set up the timer object in on_mount() and you start the timer in on_button_pressed()which is the Button widget’s event handler.

When you run this code, you will initially see what’s known as an indeterminate progress bar. What that means is that Textual doesn’t have any information about how long the progress is, so the progress bar just shows a kind of “bouncing” or “cycling” progress:

When you press the “Start” button, you will see the progress bar go from 0-100%, and the text fields to the right will update as well:

If you want to make your progress bar stand out, add a gradient. A gradient will make the colors of the progress bar change over time and make the widget look neat!

Wrapping Up

Adding a progress bar or simply showing some kind of informational widget that lets the user know your application is working is always a good idea. You don’t want the user to think the application has crashed or frozen. The user might be forced to close the application and lose their information after all!

Fortunately, Textual makes adding a progress bar easy. Not only is it easy, but the progress bar is easy to update so you can accurately give the user a sense of when the work will be done. Give it a try and see what you think!

Related Reading

Want to learn more about Textual? Check out the following articles:

The post Creating Progress Bars in Your Terminal with Python and Textual appeared first on Mouse Vs Python.

Categories: FLOSS Project Planets

Zato Blog: How to correctly integrate APIs in Python

Mon, 2024-08-12 04:00
How to correctly integrate APIs in Python 2024-08-12, by Dariusz Suchojad

Understanding how to effectively integrate various systems and APIs is crucial. Yet, without a dedicated integration platform, the result will be brittle point-to-point, spaghetti integrations, that never lead to good outcomes.

Read this article about Zato, an open-source integration platform in Python, for an overview of what to avoid and how to do it correctly instead.

More blog posts
Categories: FLOSS Project Planets

Carl Trachte: Embedding an SVG in a graphviz Generated SVG and More DAG Hamilton

Fri, 2024-08-09 21:39

Last time I used a previous post's DAG Hamilton graphviz output to generate a series of functionally highlighted DAG Hamilton workflow graphs. The  SVG (scalable vector graphics) versions of these graphs will serve as the input for this post.

I was dissatisfied with the quality of the PNG output, or at least how it rendered, fuzzy and illegible. My thought was that an SVG presentation would provide a more crisp, scalable (hence the name SVG) view of each graph.

Where I ran into problems was the embedded logos. Applications like PowerPoint allowed the inclusion of the logos as SGV "images" within the SVG "image" in PowerPoint, but did not render them; blank spaces remained.

So I set out to embed the SVG of the logos inline as elements within the final SVG file; it turned into quite the journey . . .

So SVG is really just XML, right? No, it is XML; it's just not just XML. There are XML tags and what is inside those tags can contain multiple SVG characteristics, all in their own syntax, most listed as quoted text.

At this point finding a library that allows for programmatic manipulation of SGV by tag or reviewing some open source browser source code may have helped. I did not do either of those things (a brief internet search yielded Python libraries, but they seemed focused more on conversion to and from SVG and other image formats) and set out on my own.

Like most people, I have played with Inkscape and converted images to SVG format. I even blogged about having done this with POVRay rendered pysanky eggs back in the day. Using something with software written by people way smarter than you and actually understanding it are two entirely different animals.

To make matters worse . . . I cannot actually display the SVG images or inline them here on Blogger. Smaller SVG snippets seem to work, but an entire graph with SVG logos is either too much or I am doing something wrong. Another (blurry) PNG example of the output will have to do.

Important concepts with links:

1) viewBox, scale, dimensions - Soueiden (classic, kind of the standard as far as I can tell):

https://www.sarasoueidan.com/blog/mimic-relative-positioning-in-svg/

2) the four quadrants of svg space (but you only see the lower right):

http://dh.obdurodon.org/coordinate-tutorial.xhtml

3) use x, y positioning to place embedded SVG rather than viewBox coordinates:

I have lost the link, but whoever suggested this, thank you.

4) (no link) Allow graphviz to do as much work as possible before editing any svg. For instance, when bolding edges of the graph in SVG, the edges will invariably overlap the nodes. This looks ugly. graphviz handles all that and it is far far simpler than trying to do it on your own.

5) bezier curves - nothing in this post about them, but they were part of my real introduction to SVG, and the most fun part. Recommend.

https://javascript.info/bezier-curve#de-casteljau-s-algorithm

Methodology for putting SVG logos inside the SVG document (not necessarily in order):

1) scale the embedded SVGs with the "width" and "height" attributes (SVG). I made mine proportional relative to the original SVGs' dimensions.

2) Calculate where the SVGs are supposed to go within the graphviz generated SVG coordinate space.

graphviz pushes everything into the upper right SVG space quadrant with an SVG "translate" command with 4 units padding. This needs to be taken into account when positioning the SVG elements relative to graphviz' coordinate space. The elements will be using the lower right SVG space quadrant coordinate space.

3) Leverage the positioning and size of the original PNG logos to place your SVG ones, then pop the old logo image elements and "erase" the boxes around them (yes, quite hacky, but effective).

This is a Python blog. Nutshell: I used xml.etree.ElementTree and rudimentary text processing of the SVG specific parts to get this done.

The whole thing got quite unwieldy and I turned once again to DAG Hamilton to help me organize and visualize things. (Blurry) screenshot below:





Wow, it looks like you just collected every piece of information you could about all the dimensions and smashed it all together in the final SVG document at the end.

Yes.

Hey, why is that one node just hanging out at a dead end not doing anything?

I was not getting the whole coordinate thing and needed it for reference.

The code:

# run.py - the DAG Hamilton control file.

"""Hamilton wrapper."""
# https://hamilton.dagworks.io/en/latest/concepts/driver/#recap
import sys
import pprint
from hamilton import driver
import editsvgs as esvg
OUTPUTFILES = {'data_source_highlighted':'data_source_highlighted_final',               'web_scraping_functions_highlighted':'web_scraping_functions_highlighted_final',               'output_functions_highlighted':'output_functions_highlighted_final'}
dr = driver.Builder().with_modules(esvg).build()
dr.display_all_functions('esvg.svg', deduplicate_inputs=True, keep_dot=True, orient='BR')
for keyx in OUTPUTFILES:    results = dr.execute(['hamilton_logo_root',                          'company_logo_root',                          'graph_root',                          'doc_attrib',                          'hamilton_logo_tree_indices',                          'company_logo_tree_indices',                          'hamilton_logo_png_attrib',                          'company_logo_png_attrib',                          'parsed_hamiltonlogo_png_attrib',                          'parsed_companylogo_png_attrib',                          'biggerdimension',                          'dimensionratio',                          'parsed_graph_dimensions',                          'hamilton_logo_position',                          'hamilton_svg_dimensions',                          'hamilton_logo_dimensions_orig',                          'biggerdimension_company',                          'dimensionratio_company',                          'company_logo_position',                          'company_svg_dimensions',                          'company_logo_dimensions_orig',                          'final_svg_file'],                          inputs={'hamiltonlogofile':'hamiltonlogolarge.svg',                                  'companylogofile':'fauxcompanylogo.svg',                                  'testfile':keyx + '.svg',                                  'outputfile':OUTPUTFILES[keyx] + '.svg',                                  'hamiltonlogopng':'hamiltonlogolarge.png',                                  'companylogopng':'fauxcompanylogo.png'})        print('\ndoc_attrib =\n')    pprint.pprint(results['doc_attrib'])    print('\nhamilton_logo_tree_indices =\n')    pprint.pprint(results['hamilton_logo_tree_indices'])    print('\ncompany_logo_tree_indices =\n')    pprint.pprint(results['company_logo_tree_indices'])    print('\nhamilton_logo_png_attrib =\n')    pprint.pprint(results['hamilton_logo_png_attrib'])    print('\nparsed_hamiltonlogo_png_attrib =\n')    pprint.pprint(results['parsed_hamiltonlogo_png_attrib'])    print('\ncompany_logo_png_attrib =\n')    pprint.pprint(results['company_logo_png_attrib'])    print('\nparsed_companylogo_png_attrib =\n')    pprint.pprint(results['parsed_companylogo_png_attrib'])    print('\nbiggerdimension =\n')    pprint.pprint(results['biggerdimension'])    print('\ndimensionratio =\n')    pprint.pprint(results['dimensionratio'])    print('\nparsed_graph_dimensions =\n')    pprint.pprint(results['parsed_graph_dimensions'])    print('\nhamilton_logo_position =\n')    pprint.pprint(results['hamilton_logo_position'])    print('\nhamilton_svg_dimensions =\n')    pprint.pprint(results['hamilton_svg_dimensions'])    print('\nhamilton_logo_dimensions_orig =\n')    pprint.pprint(results['hamilton_logo_dimensions_orig'])    print('\ndimensionratio_company =\n')    pprint.pprint(results['dimensionratio_company'])    print('\ncompany_logo_position =\n')    pprint.pprint(results['company_logo_position'])    print('\ncompany_svg_dimensions =\n')    pprint.pprint(results['company_svg_dimensions'])    print('\ncompany_logo_dimensions_orig =\n')    pprint.pprint(results['company_logo_dimensions_orig'])    print('\nfinal_svg_file =\n')    pprint.pprint(results['final_svg_file'])
# editsvgs.py - DAG Hamilton noun-named functions.

# python 3.12
"""Attempt to position svg logos and editflowchart with svg."""
import os
import pprint
import xml.etree.ElementTree as ET
import itertools
import sys
import copy
import reusedfunctions as rf
# Pop this to get rid of png image.# '{http://www.w3.org/1999/xlink}href': 'hamiltonlogolarge.png'}PNG_ATTRIB_KEY = '{http://www.w3.org/1999/xlink}href'# '{http://www.w3.org/1999/xlink}href': 'fauxcompanylogo.png'}
def hamilton_logo_root(hamiltonlogofile:str) -> ET.Element:    """    Get root of ElementTree object for Hamilton    logo svg file.
    hamiltonlogofile is the svg file with the Hamilton logo.    """    print('Getting Hamilton logo svg file root Element . . .')    return rf.getroot(hamiltonlogofile)
def company_logo_root(companylogofile:str) -> ET.Element:    """    Get root of ElementTree object for company    logo svg file.
    companylogofile is the svg file with the company logo.    """    print('Getting company logo svg file root Element . . .')    return rf.getroot(companylogofile)
def graph_root(testfile:str) -> ET.Element:    """    Gets root Element of graphviz graph svg.
    testfile is the graphviz svg file.    """    print('Getting root Element of main graph svg file . . .')    return rf.getroot(testfile)
def doc_attrib(graph_root:ET.Element) -> dict:    """    Gets graphviz svg document's dimensions and viewBox    in a dictionary.
    graph_root is the graphviz svg file root Element. 
    Returns dictionary of xml/svg data for doc.    """    print('Getting dimensions and viewBox for main graph svg file . . .')    return graph_root.attrib
def hamilton_logo_tree_indices(graph_root:ET.Element, hamiltonlogopng:str) -> tuple:    """    Get tree indices (3 deep) for original png    Hamilton logo on graph.
    graph_root is the root Element of graphviz graph svg.
    hamiltonlogopng is the name of the png file referenced    in the image link in the svg file (string).
    Returns 3 tuple of integers.    """    print('Getting ElementTree indices for tree for Hamilton png logo Element . . .')    return rf.gettreeindices(graph_root, hamiltonlogopng)
def company_logo_tree_indices(graph_root:ET.Element, companylogopng:str) -> tuple:    """    Get tree indices (3 deep) for original png    company logo on graph.
    graph_root is the root Element of graphviz graph svg.
    companylogopng is the name of the png file referenced    in the image link in the svg file (string).
    Returns 3 tuple of integers.    """    print('Getting ElementTree indices for tree for company png logo Element . . .')    return rf.gettreeindices(graph_root, companylogopng)
def hamilton_logo_png_attrib(graph_root:ET.Element, hamilton_logo_tree_indices:tuple) -> dict:    """    Get attrib dictionary for original Hamilton png file Element in graph svg.
    graph_root is the root Element of graphviz graph svg.
    hamilton_logo_tree_indices are the lookup indices for the Hamilton    logo png Element within the xml tree.    """    print('Getting attrib dictionary for original Hamilton png file Element in graph svg . . .')    return rf.getpngattrib(graph_root, hamilton_logo_tree_indices)
def company_logo_png_attrib(graph_root:ET.Element, company_logo_tree_indices:tuple) -> dict:    """    Get attrib dictionary for original company png file Element in graph svg.
    graph_root is the root Element of graphviz graph svg.
    company_logo_tree_indices are the lookup indices for the company    logo png Element within the xml tree.    """    print('Getting attrib dictionary for original company png file Element in graph svg . . .')    return rf.getpngattrib(graph_root, company_logo_tree_indices)
def parsed_hamiltonlogo_png_attrib(hamilton_logo_png_attrib:dict) -> dict:    """    Work dictionary that has information on former    location of png Hamilton logo image in the     graphviz svg.
    Basically getting svg text values into float format.
    Returns new dictionary.    """    print('Getting svg text values into float format for Hamilton png Element . . .')    return rf.parsepngattrib(hamilton_logo_png_attrib)
def parsed_companylogo_png_attrib(company_logo_png_attrib:dict) -> dict:    """    Work dictionary that has information on former    location of png company logo image in the     graphviz svg.
    Basically getting svg text values into float format.
    Returns new dictionary.    """    print('Getting svg text values into float format for company logo png Element . . .')    return rf.parsepngattrib(company_logo_png_attrib)
def biggerdimension(hamilton_logo_root:ET.Element) -> str:    """    hamilton_logo_root is the ElementTree Element    for the big svg Hamilton logo.
    Returns 'Y' if the y dimension is the     bigger one, and 'X' if the x one is.
    Returns None if there is a key error.    """    print('Determining bigger dimension for svg Hamilton logo . . .')    return rf.getbiggerdimension(hamilton_logo_root)
def dimensionratio(biggerdimension:str, hamilton_logo_root:ET.Element) -> float:    """    biggerdimension is a string, 'X' or 'Y'.
    hamilton_logo_root is the ElementTree Element    for the big svg Hamilton logo.
    Returns ratio of bigger dimension    to smaller one (float).    """    print('Calculating dimensions ratio for Hamilton logo svg . . .')    return rf.getdimensionratio(biggerdimension, hamilton_logo_root)
def parsed_graph_dimensions(graph_root:ET.Element) -> tuple:    """    Get translate coordinates from graphviz    svg root Element.
    Returns two tuple of x, y translation.    """    graph0dimensions = graph_root[0].attrib    coordstr = graph0dimensions['transform']    coordstr = coordstr[coordstr.index('translate'):]    coordstr = coordstr[coordstr.index('(') + 1:-1]    vals = [float(x) for x in coordstr.split(' ')]    return tuple(vals)
def hamilton_logo_position(parsed_graph_dimensions:tuple,                           parsed_hamiltonlogo_png_attrib:dict) -> tuple:    """    parsed_graph_dimensions is an x, y two tuple.
    parsed_hamiltonlogo_png_attrib is a dictionary.
    Returns x, y position of Hamilton logo svg graphic as a    two tuple.    """    print('Getting position of Hamilton logo . . .')    return rf.getposition(parsed_graph_dimensions, parsed_hamiltonlogo_png_attrib)
def company_logo_position(parsed_graph_dimensions:tuple,                          parsed_companylogo_png_attrib:dict) -> tuple:    """    parsed_graph_dimensions is an x, y two tuple.
    parsed_hamiltonlogo_png_attrib is a dictionary.
    Returns x, y position of company logo svg graphic as a    two tuple.    """    print('Getting position of company logo . . .')    # Add 4.    x = parsed_companylogo_png_attrib['X'] + parsed_graph_dimensions[0]    # Add negative number with big absolute value.    # Upper right quadrant translation thing.    y = parsed_companylogo_png_attrib['Y'] + parsed_graph_dimensions[1]     return x, y
def hamilton_svg_dimensions(parsed_hamiltonlogo_png_attrib:dict,                            biggerdimension:str,                            dimensionratio:float) -> tuple:    """    Get width and height of svg Hamilton logo within    final document.
    parsed_hamiltonlogo_png_attrib is the dictionary of    numeric values associated with the original image    position of the Hamilton png logo within the    svg document.
    biggerdimension is the 'X' or 'Y' value that    indicates which dimension is the larger of    the two.
    dimensionratio is the ratio of the larger    dimension to the smaller one.
    Returns x, y two tuple of floats.    """    print('Getting size of Hamilton logo in final doc . . .')    return rf.getdimensions(parsed_hamiltonlogo_png_attrib, biggerdimension, dimensionratio)
def hamilton_logo_dimensions_orig(hamilton_logo_root:ET.Element) -> tuple:    """    hamilton_logo_root is the ElementTree Element    for the big svg Hamilton logo.
    Returns two tuple of width, height.    """    print('Retrieving dimensions of Hamilton logo svg . . .')    return rf.getdimensionsorig(hamilton_logo_root)
def final_svg_file(testfile:str,                   outputfile:str,                   hamilton_logo_root:ET.Element,                   hamilton_logo_tree_indices:tuple,                   hamilton_logo_position:tuple,                   hamilton_svg_dimensions:tuple,                   hamilton_logo_dimensions_orig:tuple,                   company_logo_tree_indices:tuple,                   parsed_companylogo_png_attrib:dict,                   company_logo_position:tuple,                   company_logo_root:ET.Element,                   company_svg_dimensions:tuple,                   company_logo_dimensions_orig:tuple,                   ) -> str:    """    Replaces image logos with scaleable    svg ones.
    testfile is the name of the original svg file.
    outputfile is the name of the intended final    svg file.
    hamilton_logo_root is the elementree root object    for the Hamilton logo svg file.
    hamilton_logo_tree_indices are nested indices     indicating the location of the original Hamilton    logo png elementree Element within the input    svg document.
    hamilton_logo_position - x, y tuple - where to    put the svg Hamilton logo within the final    svg document.
    hamilton_svg_dimensions - x, y tuple - width and    height of Hamilton svg logo within the final    svg document.
    hamilton_logo_dimensions_orig - two tuple of width, height    of original svg file Hamilton logo.
    company_logo_tree_indices are nested indices     indicating the location of the original company    logo png elementree Element within the input    svg document.
    company_logo_position - x, y tuple - where to    put the svg company logo within the final    svg document.
    company_logo_root is the elementree root object    for the company logo svg file.     company_svg_dimensions - x, y tuple - width and    height of company svg logo within the final    svg document.
    company_logo_dimensions_orig - two tuple of width, height    of original svg file company logo.
    Returns string filename.    """    print('Making changes to svg . . .')    hlti = hamilton_logo_tree_indices     retval = outputfile    tree = ET.parse(testfile)    root = tree.getroot()    # pop Hamilton png    print('Popping original Hamilton png logo . . .')    root[hlti[0]][hlti[1]][hlti[2]].attrib.pop(PNG_ATTRIB_KEY)    print('Appending Hamilton svg to root Element . . .')    root.append(hamilton_logo_root)    print('Adjusting viewBox for Hamilton svg . . .')    root[-1].attrib['viewBox'] = '0.00 0.00 {0:.3f} {1:.3f}'.format(*hamilton_logo_dimensions_orig)    print('Adjusting height and width for Hamilton svg . . .')    root[-1].attrib['height'] = str(hamilton_svg_dimensions[1])    root[-1].attrib['width'] = str(hamilton_svg_dimensions[0])    print('Positioning Hamilton logo svg within final svg . . .')    root[-1].attrib['x'] = str(hamilton_logo_position[0])    root[-1].attrib['y'] = str(hamilton_logo_position[1])    print('Erasing Hamilton logo bounding box . . .')    # After popping png, polygon resides one index unit back.    root[hlti[0]][hlti[1]][hlti[2] - 1].attrib['stroke'] = 'none'    clti = company_logo_tree_indices    # pop company png    print('Popping original company png logo . . .')    root[clti[0]][clti[1]][clti[2]].attrib.pop(PNG_ATTRIB_KEY)    print('Adding company logo svg Element to main svg file . . .')    root.append(company_logo_root)    print('Adjusting viewBox for company svg . . .')    root[-1].attrib['viewBox'] = '0.00 0.00 {0:.3f} {1:.3f}'.format(*company_logo_dimensions_orig)    print('Adjusting height and width for company svg . . .')    root[-1].attrib['height'] = str(company_svg_dimensions[1])    root[-1].attrib['width'] = str(company_svg_dimensions[0])    print('Moving company logo svg to the correct position in the display . . .')    # Had to adjust 15 units to get it out of the way of the legend.    root[-1].attrib['x'] = str(company_logo_position[0] - 15)    root[-1].attrib['y'] = str(company_logo_position[1])    print('Erasing company logo bounding box . . .')    # After popping png, polygon resides one index unit back.    root[clti[0]][clti[1]][clti[2] - 1].attrib['stroke'] = 'none'    print('Writing new svg . . .')    tree.write(retval)    return retval
def biggerdimension_company(company_logo_root:ET.Element) -> str:    """    company_logo_root is the ElementTree Element    for the big svg company logo.
    Returns 'Y' if the y dimension is the     bigger one, and 'X' if the x one is.    """    print('Determining bigger dimension for svg company logo . . .')    return rf.getbiggerdimension(company_logo_root)
def dimensionratio_company(biggerdimension_company:str,                           company_logo_root:ET.Element) -> float:    """    biggerdimension is a string, 'X' or 'Y'.
    company_logo_root is the ElementTree Element    for the big svg company logo.
    Returns ratio of bigger dimension    to smaller one (float).    """    print('Calculating dimensions ratio for company logo svg . . .')    return rf.getdimensionratio(biggerdimension_company,                                company_logo_root)
def company_logo_position(parsed_graph_dimensions:tuple,                          parsed_companylogo_png_attrib:dict) -> tuple:    """    parsed_graph_dimensions is an x, y two tuple.
    parsed_companylogo_png_attrib is a dictionary.
    Returns x, y position of company logo svg graphic as a    two tuple.    """    print('Getting position of company logo . . .')    return rf.getposition(parsed_graph_dimensions,                          parsed_companylogo_png_attrib)
def company_svg_dimensions(parsed_companylogo_png_attrib:dict,                           biggerdimension_company:str,                           dimensionratio_company:float) -> tuple:    """    Get width and height of svg company logo within    final document.
    parsed_companylogo_png_attrib is the dictionary of    numeric values associated with the original image    position of the company png logo within the    svg document.
    biggerdimension is the 'X' or 'Y' value that    indicates which dimension is the larger of    the two.
    dimensionratio_company is the ratio of the larger    dimension to the smaller one.
    Returns x, y two tuple of floats.    """    pprint.pprint(parsed_companylogo_png_attrib)    print('Getting size of company logo in final doc . . .')    return rf.getdimensions(parsed_companylogo_png_attrib,                             biggerdimension_company,                            dimensionratio_company)
def company_logo_dimensions_orig(company_logo_root:ET.Element) -> tuple:    """    company_logo_root is the ElementTree Element    for the big svg company logo.
    Returns two tuple of width, height.    """    print('Retrieving dimensions of company logo svg . . .')    return rf.getdimensionsorig(company_logo_root)

# reusedfunctions.py - utility/helper/main functionality
#                      at a granular level.

# python 3.12
"""Auxiliary module to Hamilton svg script."""
import itertools
import xml.etree.ElementTree as ET
# Pop this to get rid of png image.# '{http://www.w3.org/1999/xlink}href': 'hamiltonlogolarge.png'}PNG_ATTRIB_KEY = '{http://www.w3.org/1999/xlink}href'
def gettreeindices(graph_root, png):    """    Get tree indices (3 deep) for png on graph.
    graph_root is the root Element of graphviz graph svg.
    png is the name of the png file referenced    in the image link in the svg file (string).
    Returns 3 tuple of integers.    """    countergeneratorx = itertools.count()    counterx = next(countergeneratorx)    for nodex in graph_root:        countergeneratory = itertools.count()        countery = next(countergeneratory)        for nodey in nodex:            countergeneratorz = itertools.count()            counterz = next(countergeneratorz)            for nodez in nodey:                if PNG_ATTRIB_KEY in nodez.attrib:                    if nodez.attrib[PNG_ATTRIB_KEY] == png:                        return counterx, countery, counterz                counterz = next(countergeneratorz)            countery = next(countergeneratory)        counterx = next(countergeneratorx)
def getroot(filename):    """    Get root of ElementTree object for svg file.
    filename is the svg file string.    """    return ET.parse(filename).getroot()
def getpngattrib(graph_root, indices):    """    Get attrib dictionary for png file Element in graph svg.
    graph_root is the root Element of graphviz graph svg.
    indices are the lookup indices for the     png Element within the xml tree.    """    return graph_root[indices[0]][indices[1]][indices[2]].attrib
def parsepngattrib(attrib):    """    Work dictionary that has information on    location of png image in the     graphviz svg.
    Basically getting svg text values into float format.
    Returns new dictionary.    """    retval = {}    retval['X'] = float(attrib['x'])    retval['Y'] = float(attrib['y'])    retval['height'] = float(attrib['height'][:attrib['height'].index('px')])    retval['width'] = float(attrib['width'][:attrib['width'].index('px')])    return retval
def getbiggerdimension(root):    """    root is the ElementTree Element    for the svg file element to be    embedded into the main svg file.
    Returns 'Y' if the y dimension is the     bigger one, and 'X' if the x one is.
    Returns None if there is a key error.    """    dimensions = root.attrib    try:        if float(dimensions['height']) > float(dimensions['width']):            return 'Y'        else:            # X bigger or equal            return 'X'    except ValueError:        pass    return None
def getdimensionratio(biggerdimension, root):    """    biggerdimension is a string, 'X' or 'Y'.
    root is the etree Element for the    svg Element that is to be embedded    into the final svg file
    Returns ratio of bigger dimension    to smaller one (float).    """    dimensions = root.attrib    if biggerdimension == 'Y':        return float(dimensions['height']) / float(dimensions['width'])    else:        return float(dimensions['width']) / float(dimensions['height'])
def getposition(dimensions, attrib):    """    dimensions is an x, y two tuple.
    attrib is a dictionary.
    Returns x, y position of svg graphic as a    two tuple.    """    # Add 4.    x = attrib['X'] + dimensions[0]    # Add negative number with big absolute value.    # Upper right quadrant translation thing.    y = attrib['Y'] + dimensions[1]     return x, y
def getdimensions(attrib, biggerdimension, dimensionratio):    """    Get width and height of svg within    final document.
    attrib is the dictionary of numeric values    associated with the original image    position of the png within the    svg document.
    biggerdimension is the 'X' or 'Y' value that    indicates which dimension is the larger of    the two.
    dimensionratio is the ratio of the larger    dimension to the smaller one.
    Returns x, y two tuple of floats.    """    if biggerdimension == 'Y':        return (attrib['width'],  dimensionratio * attrib['width'])    else:        return (dimensionratio * attrib['height'], attrib['height'])
def getdimensionsorig(root):    """    root is the ElementTree Element    for the svg Element to be embedded     in the main svg file.
    Returns two tuple of width, height.    """    return float(root.attrib['width']), float(root.attrib['height'])

# OUTPUT (stdout)

Getting Hamilton logo svg file root Element . . .Getting company logo svg file root Element . . .Getting root Element of main graph svg file . . .Getting dimensions and viewBox for main graph svg file . . .Getting ElementTree indices for tree for Hamilton png logo Element . . .Getting ElementTree indices for tree for png Element . . .Getting ElementTree indices for tree for company png logo Element . . .Getting ElementTree indices for tree for png Element . . .Getting attrib dictionary for original Hamilton png file Element in graph svg . . .Getting attrib dictionary for original company png file Element in graph svg . . .Getting svg text values into float format for Hamilton png Element . . .Getting svg text values into float format for company logo png Element . . .Determining bigger dimension for svg Hamilton logo . . .Calculating dimensions ratio for Hamilton logo svg . . .Getting position of Hamilton logo . . .Getting size of Hamilton logo in final doc . . .Retrieving dimensions of Hamilton logo svg . . .Determining bigger dimension for svg company logo . . .Calculating dimensions ratio for company logo svg . . .Getting position of company logo . . .Getting size of company logo in final doc . . .Retrieving dimensions of company logo svg . . .Making changes to svg . . .Popping original Hamilton png logo . . .Appending Hamilton svg to root Element . . .Adjusting viewBox for Hamilton svg . . .Adjusting height and width for Hamilton svg . . .Positioning Hamilton logo svg within final svg . . .Erasing Hamilton logo bounding box . . .Popping original company png logo . . .Adding company logo svg Element to main svg file . . .Adjusting viewBox for company svg . . .Adjusting height and width for company svg . . .Moving company logo svg to the correct position in the display . . .Erasing company logo bounding box . . .Writing new svg . . .
doc_attrib =
{'height': '825pt', 'viewBox': '0.00 0.00 936.00 824.60', 'width': '936pt'}
hamilton_logo_tree_indices =
(0, 4, 2)
company_logo_tree_indices =
(0, 5, 2)
hamilton_logo_png_attrib =
{'height': '43.2px', 'preserveAspectRatio': 'xMinYMin meet', 'width': '43.2px', 'x': '218.3', 'y': '-673.9', '{http://www.w3.org/1999/xlink}href': 'hamiltonlogolarge.png'}
parsed_hamiltonlogo_png_attrib =
{'X': 218.3, 'Y': -673.9, 'height': 43.2, 'width': 43.2}
company_logo_png_attrib =
{'height': '43.2px', 'preserveAspectRatio': 'xMinYMin meet', 'width': '367.2px', 'x': '279.3', 'y': '-673.9', '{http://www.w3.org/1999/xlink}href': 'fauxcompanylogo.png'}
parsed_companylogo_png_attrib =
{'X': 279.3, 'Y': -673.9, 'height': 43.2, 'width': 367.2}
biggerdimension =
'X'
dimensionratio =
1.0421153385977506
parsed_graph_dimensions =
(4.0, 820.6)
hamilton_logo_position =
(222.3, 146.70000000000005)
hamilton_svg_dimensions =
(45.01938262742283, 43.2)
hamilton_logo_dimensions_orig =
(8710.0, 8358.0)
dimensionratio_company =
9.047619047619047
company_logo_position =
(283.3, 146.70000000000005)
company_svg_dimensions =
(390.8571428571429, 43.2)
company_logo_dimensions_orig =
(712.5, 78.75)
final_svg_file =
'data_source_highlighted_final.svg'

# . . . etc. 2 more times.

Note on DAG Hamilton: my use case for this tool is very rudimentary and somewhat pedestrian. That said, it is becoming essential to my workflows.

The DAG Hamilton project is still at its relatively early stages with some very exciting active development ongoing. It seems like every week some amazing new decorator feature gets released.

I am not much of one for decorators use - grateful for their existence and use in the 3rd party modules I use. Truthfully, 3/4 of the work I do could probably be accomplished with a relatively recent version of Python and dictionaries.

Where DAG Hamilton helps me out a lot is in corralling and organizing code. I tend to get a bit undisciplined and have trouble "seeing" the execution path. DAG Hamilton helps there.

Thanks for stopping by.










Categories: FLOSS Project Planets

Ruslan Spivak: 7 Things That Helped Me Grow as a Software Engineer

Fri, 2024-08-09 12:26

Hi everyone,

Growth as a software engineer is an ongoing journey. Looking back, a few key principles helped me progress during the early days of my career. These lessons shaped my path, and many of them continue to guide me today, even though I’m no longer an individual contributor:

  1. Drive

    Ambition isn’t a skill — it’s a will. You either have it or you don’t. To grow, you need that inner drive pushing you forward. Sometimes it’s a conscious choice, and other times, you just can’t help it — something inside you refuses to stand still, driving you to keep learning and moving forward. I remember diving into Python and CI/CD back in the day, teaching it even when I was still learning myself.

  2. Delivering results

    You might have gaps in your technical or soft skills, but if you consistently deliver, that goes a long way.  I always gave extra effort (probably leaning a bit on the workaholic side), especially on projects that excited me. Delivering results also helps you build your reputation and credibility — a win-win.

  3. Choosing the right projects

    Whenever possible, work on projects that have the highest impact for the company and that interest you personally. There are two benefits: high impact projects give you the visibility and future opportunities you need, and personal interest helps you push forward when the going gets tough, and the going will get tough at some point — pretty much guaranteed.

  4. Craft

    Delivering high impact with speed and quality requires deep expertise in your field. Which, in turn, requires understanding what’s going on under the hood. Expanding the breadth of your knowledge while diving deep into specific technologies (the so-called T-shaped expertise) served me well.

  5. Teaching

    Teaching is a great way to solidify your knowledge and identify gaps in your understanding. Teaching also boosts your visibility and can establish you as a go-to person. Sharing what you know helps others and also helps you deepen your understanding. Personally, I view well-done code reviews as a form of teaching too.

  6. Tolerance for conflict

    Criticism comes with the territory. Sometimes it’s called feedback, and other times it’s just plain criticism. I took many classes at the University of Hard Knocks on this one: I missed deadlines, over-engineered technical solutions, cut corners, and delivered feedback in a less-than-perfect way at that stage of my career. My advice: start building a thick skin sooner, but be smart about it. Know when to stand your ground and when to let things slide. Above all, don’t be a jerk.

  7. Learning how business works

    This one’s underrated, and it took me a long, long time to learn. I wish I’d figured it out sooner, but better late than never.  While you can succeed at a certain level without focusing on this, understanding how the business works helps you identify high-impact projects and stand out as a valued partner — not just another tech person from a cost center.

As the saying goes, “The only way to do great work is to love what you do.” I’d add — love the challenges, love the process, and love the growth that comes with them.

Stay curious,

Ruslan

Categories: FLOSS Project Planets

Real Python: The Real Python Podcast – Episode #216: Learning Through Building the Black Python Devs Community

Fri, 2024-08-09 08:00

What hurdles must be cleared when starting an international organization? How do you empower others in a community by sharing responsibilities? This week on the show, we speak with Jay Miller about Black Python Devs.

[ Improve Your Python With 🐍 Python Tricks 💌 – Get a short & sweet Python Trick delivered to your inbox every couple of days. >> Click here to learn more and see examples ]

Categories: FLOSS Project Planets

PyPy: Conda-forge proposes sunsetting support for PyPy

Fri, 2024-08-09 02:27

Conda-forge has kindly been providing support for PyPy since 2019. The conda-forge team has been very patient and generous with resources, but it seems the uptake of PyPy has not justified the effort. Major packages still are not available on PyPy, others find it hard to update versions. We don't get much feedback at all about people using PyPy, and even less about PyPy on conda-forge. The conda-forge team has proposed sunsetting PyPy going forward, which means current packages would remain but no new packages would be built. If you have an opinion, you can comment on that PR, or on this blog post.

Since conda-forge supports PyPy3.9 but not PyPy3.10, we have continued releasing PyPy3.9 even though we typically support only one version of PyPy3. With the sunsetting proposal, we will not release any more updates to PyPy3.9. I opened a poll about the intention to drop PyPy3.9. If you have an opinion, please chime in.

Categories: FLOSS Project Planets

Pages