Planet Python
Python Bytes: #399 C will watch you in silence
Armin Ronacher: Progress
As I'm getting older a lot of my social circles are becoming ever more conservative. The focus shifts from building with ambition to fiercly protecting what one has achieved. Shifting the mind on protectionism makes one consider all that can cause damage. It puts the focus on the negative, it makes those negative thoughts feel much more significant than they are and one dwells on the past, instead of envisioning of what opportunity might lie ahead.
Yet, when we look back at history, it becomes clear that progress and fresh ideas tend to prevail over time. Not every new idea will succeed, but the overall trend is undeniable.
I believe that every day presents us with a choice: to step forward with courage and optimism or to cling to the status quo, even as it becomes increasingly untenable. Embracing new ideas carries inherent risks, but so does the refusal to explore them.
Right now we find ourselves slowly sliding down from our local maximum and some people try to pull you back up to where we were standing. On the other hand if you dare to run you will find a bigger and more impressive hill to scale. One that offers a better vantage point and when water rises undoubtedly the better place to be.
In today's political environment, the rhetoric is dominated by a yearning for the past. Some politicians will promote a return to fossil fuels and conservative social norms. They play into your fears of others and promote individualism at cost of the collective. The will uphold every bad news as a reason to fortify borders and strengthen nation-states.
But as time marches on, future generations will likely look back at these regressive inclinations and wonder how we could have been so short-sighted.
Hynek Schlawack: How to Ditch Codecov for Python Projects
Codecov’s unreliability breaking CI on my open source projects has been a constant source of frustration for me for years. I have found a way to enforce coverage over a whole GitHub Actions build matrix that doesn’t rely on third-party services.
Real Python: Generate Images With DALL·E and the OpenAI API
Describe any image, then let a computer create it for you. What sounded futuristic only a few years ago has become reality with advances in neural networks and latent diffusion models (LDM). DALL·E by OpenAI has made a splash through the amazing generative art and realistic images that people create with it.
OpenAI allows access to DALL·E through their API, which means that you can incorporate its functionality into your Python applications.
In this tutorial, you’ll:
- Get started using the OpenAI Python library
- Explore API calls related to image generation
- Create images from text prompts
- Create variations of your generated image
- Convert Base64 JSON responses to PNG image files
You’ll need some experience with Python, JSON, and file operations to breeze through this tutorial. You can also study up on these topics while you go along, as you’ll find relevant links throughout the text.
Get Your Code: Click here to download the free sample code that you’ll use to generate stunning images with DALL·E and the OpenAI API.
Take the Quiz: Test your knowledge with our interactive “Generate Images With DALL·E and the OpenAI API” quiz. You’ll receive a score upon completion to help you track your learning progress:
Interactive Quiz
Generate Images With DALL·E and the OpenAI APIIn this quiz, you'll test your understanding of generating images with DALL·E by OpenAI using Python. You'll revisit concepts such as using the OpenAI Python library, making API calls for image generation, creating images from text prompts, and converting Base64 strings to PNG image files.
Complete the Setup RequirementsIf you’ve seen what DALL·E can do and you’re eager to make its functionality part of your Python applications, then you’re in the right spot! In this first section, you’ll quickly walk through what you need to do to get started using DALL·E’s image creation capabilities in your own code.
Install the OpenAI Python LibraryConfirm that you’re running Python version 3.7.1 or higher, create and activate a virtual environment, and install the OpenAI Python library:
Windows PowerShell PS> python --version Python 3.12.5 PS> python -m venv venv PS> .\venv\Scripts\activate (venv) PS> python -m pip install openai Copied! Shell $ python --version Python 3.12.5 $ python -m venv venv $ source venv/bin/activate (venv) $ python -m pip install openai Copied!The openai package gives you access to the full OpenAI API. In this tutorial, you’ll focus on image generation, which lets you interact with DALL·E models to create and edit images from text prompts.
Get Your OpenAI API KeyYou need an API key to make successful API calls. Sign up with OpenAI and create a new project API key by clicking on the Dashboard menu and then API keys on the bottom left of the navigation menu:
On this page, you can create and manage your API keys, which allow you to access the service that OpenAI offers through their API. You can create and delete secret keys.
Click on Create new secret key to create a new API key, and copy the value shown in the pop-up window.
Note: OpenAI assigns your API usage through unique key values, so make sure to keep your API key private. The company calculates the pricing of requests to generate images on a per-image basis that depends on the model you use and the resolution of the output image.
Keep in mind that OpenAI’s API services and pricing policies may change. Be sure to check their website for up-to-date information about pricing and offers.
Always keep this key secret! Copy the value of this key so you can later use it in your project. You’ll only see the key value once.
Save Your API Key as an Environment VariableA quick way to save your API key and make it available to your Python scripts is to save it as an environment variable. Select your operating system to learn how:
Windows PowerShell (venv) PS> $ENV:OPENAI_API_KEY = "<your-key-value-here>" Copied! Shell (venv) $ export OPENAI_API_KEY="<your-key-value-here>" Copied! Read the full article at https://realpython.com/generate-images-with-dalle-openai-api/ »[ 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 ]
Real Python: Quiz: How to Use Conditional Expressions With NumPy where()
In this quiz, you’ll test your understanding of How to Use Conditional Expressions With NumPy where().
By working through the questions, you’ll consolidate the knowledge you gained from the tutorial and take yourself beyond what you learned.
To answer some of the questions, you’ll need to do some research outside of the tutorial itself. Embrace this challenge because exploration can take you on a valuable learning journey.
[ 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 ]
Real Python: Quiz: Generate Images With DALL·E and the OpenAI API
In this quiz, you’ll test your understanding of generating images with DALL·E by OpenAI API using Python.
By working through this quiz, you’ll revisit how to use the OpenAI Python library, make API calls related to image generation, create images from text prompts, create variations of an image, and convert Base64 strings to PNG image files.
[ 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 ]
Zato Blog: Airport integrations in Python
Did you know you can use Python as an integration platform for your airport systems? It's Open Source too.
From AODB, transportation, business operations and partner networks, to IoT, cloud and hybrid deployments, you can now use Python to build flexible, scalable and future-proof architectures that integrate your airport systems and support your master plan.
➤ Read here about what is possible and learn more why Python and Open Source are the right choice.
More blog posts➤Quansight Labs Blog: Towards Inclusive Documentation: the PyData Sphinx Theme, Before and After Accessibility Fixes
Tryton News: Newsletter August 2024
In the last month we focused on fixing bugs, improving the behaviour of things, speeding-up performance issues - building on the changes from our last release. We also added some new features which we would like to introduce to you in this newsletter.
For an in depth overview of the Tryton issues please take a look at our issue tracker or see the issues and merge requests filtered by label.
Changes for the User Sales, Purchases and ProjectsNow Tryton warns the user when submitting another complaint for the same origin.
Accounting, Invoicing and PaymentsNow Tryton allows to copy account moves from closed periods. When copy a move from a closed period we now set the period of the duplicate to the current period and the date to the actual date, while informing the user about the changes.
Stock, Production and ShipmentsOur sendcloud integration now adds package weight and warehouse as shipping method criteria.
User InterfaceNow we add a searcher for summary fields, which searches the whole description.
We’ve now merged the HTML edit and translate buttons into a single button that asks for the language before opening, with the current language pre-selected.
System Data and ConfigurationNow you can configure the license key for TinyMCE.
Now Tryton supports the UTR (United Kingdom Unique Taxpayer Reference) identifier.
New Documentation We've created or updated the following documentations:- Server Modules (ir, res, report): look-up changes…
- account_es_sii: look-up changes…
- account_invoice_correction: look-up changes…
- account_invoice_history: look-up changes…
- account_invoice_line_standalone: look-up changes…
- account_invoice_secondary_unit: look-up changes…
- account_payment_braintree: look-up changes…
- account_payment_sepa_cfonb: look-up changes…
- account_statement_coda: look-up changes…
We released bug fixes for the currently maintained long term support series
7.0 and 6.0, and for the penultimate series 7.2.
1 post - 1 participant
Carl Trachte: Scalable Vector Graphics Followup
A quick follow up to the last post:
1) I spelled scalable wrong in the title; hopefully it's fixed.
2) The svg partial logo that rendered in Blogger did not render on the Planet Python feed.
3) The logo svg is too big for Blogger. I need to find a way to make a smaller (file size) one.
One more try with svg in Blogger. The png DAG Hamilton logo first:
And one more attempt:
Carl Trachte: Scaleable Vector Graphics (svg) - Decomposing and Scaling Elements for Blogger
Last post I lamented the failure of any the svg graphs I had for DAG Hamilton workflows to render in Blogger. I set out to rectify this and have had some initial success.
My first attempt to get svg to show up in Blogger has the DAG Hamilton logo as its subject. My approach was to bring the svg elements down to the most basic primitives I could manage, then scale and translate their individual coordinates to bring them into the view.Fortunately, I was able to find an example from someone who had successfully rendered svg in Blogger. The subject blog post is eleven years old. It appears svg never totally caught on for some platforms. Nonetheless, I used this as a template, and, after some initial success, managed to render the Hamilton logo.
The post will step through the individual path components of the Hamilton logo (7) and show the code used to transform the coordinates to make the svg elements render at an appropriate location and size. The individual path elements that make up the logo are a large number of 3 coordinate bezier curves. The manner in which the curves listed is very format specific to the platform that created them. Unfortunately, I cannot recall which online png to svg converter I used to create the svg. Portable Inkscape kept crashing on the large png file, so I brute forced the issue by using an online converter.
The first element of the logo is basically a purple background for the whole logo. A gap or divit can be seen just left of center on the upper part. I'll cover the manual "fixing" of this further on.
Second path (orange)
Third path (deep purple)
Fourth path (yellow top point)
Fifth path (light orangey left leg were the star to face out from the screen)
Sixth path (medium purple little triangle in the center)
Seventh path (light orangey little triangle to the right of center)
Fixing that niggling divit on the top half of the logo (the thin subvertical line).
Final product. This is the one svg inline drawing I was able to show (content size limitations of Blogger?)
The full logo refuses to render (although I swear it did before). Well, at least there is an svg element showing up on the page (a purple star). <sigh> Another png . . .
The code. I'm not strong on HTML, but it was necessary to edit this post inline. As part of that exercise, I included the post outline generation as part of the script.
# python 3.12
# blog_post_make_outline.py
"""
Attempt to scale, translate, and inline svg
elements for display in Blogger.
"""
import re
import pprint
import sys
import copy
import xml.etree.ElementTree as ET
# REGEX patterns.
PATHPAT = r'[<]path[ ]d[=]["]'
MPAT = r'M([-]*[0-9]+[.]*[0-9]*)[ ]([-]*[0-9]+[.]*[0-9]*)[ ]'
# first bezier curve coord
BEZPAT = (r'C([-]*[0-9]+[.]*[0-9]*)[ ]([-]*[0-9]+[.]*[0-9]*)[ ]'
# second bezier curve coord
r'([-]*[0-9]+[.]*[0-9]*)[ ]([-]*[0-9]+[.]*[0-9]*)[ ]'
# third bezier curve coord
r'([-]*[0-9]+[.]*[0-9]*)[ ]([-]*[0-9]+[.]*[0-9]*)[ ]')
ZPAT = r'Z[ ]'
FILLPAT = (r'["] fill[=]["]([#][A-F0-9][A-F0-9][A-F0-9]'
r'[A-F0-9][A-F0-9][A-F0-9])["][ ]')
# transform="translate(4756.96875,109.12890625)"
# transform="translate(5619,4112)"/>
TRANSFORMPAT = (r'transform[=]["]translate[(]'
r'([-]*[0-9]+[.]*[0-9]*)[,]([-]*[0-9]+[.]*[0-9]*)[)]["]')
# Output formats/constants.
BEZFMT = ('C{0:.7f} {1:.7f} '
'{2:.7f} {3:.7f} '
'{4:.7f} {5:.7f} ')
PATHFMT_OPEN = '<path d="'
PATHFMT_1 = 'M{mstartx:.5f} {mstarty:.5f} {path:s} Z '
PATHFMT_2 = '" fill="{fill:s}" transform="translate({translatex:.7f},{translatey:.7f})"'
PATHFMT_CLOSE = ' />'
SVG_TAG_OPEN = ('<svg xmlns="http://www.w3.org/2000/svg" '
'xmlns:xlink="http://www.w3.org/1999/xlink" '
"width='500px' height='500px'>")
SVG_TAG_CLOSE = '</svg>'
def parse_path(pathstring):
"""
Capture path elements in a dictionary.
pathstring is the svg string for the path (one line).
For a path comprised entirely of bezier curves
in the format (all one line):
<ns0:path d="M0 0 C2.54601018 1.57157072 5.09846344 3.13131386 7.65625 4.68359375 C39.179 . . . 0 0 Z M-690.96875 4007.87109375 C-707.702 . . . Z " fill="#C3368C" transform="translate(4756.96875,109.12890625)" />
Returns dictionary.
"""
retval = {}
patpath = re.compile(PATHPAT)
match = patpath.match(pathstring)
startindex = match.span()[1]
mpat = re.compile(MPAT)
# MPAT
match = mpat.match(pathstring[startindex:])
mpatgroups = match.groups()
retval['mpatgroups'] = []
retval['mpatgroups'].append(mpatgroups)
startindex += match.span()[1]
bezpat = re.compile(BEZPAT)
zpat = re.compile(ZPAT)
retval['paths'] = []
while match:
pathpoints = []
# BEZPAT
match = bezpat.match(pathstring[startindex:])
while match:
# Sentinel.
if not match:
continue
pathpoints.append(match.groups())
startindex += match.span()[1]
match = bezpat.match(pathstring[startindex:])
retval['paths'].append(pathpoints)
# ZPAT
match = zpat.match(pathstring[startindex:])
startindex += match.span()[1]
# Then look for MPAT
# MPAT
match = mpat.match(pathstring[startindex:])
# If MPAT not there, work on color and transform.
if not match:
continue
startindex += match.span()[1]
retval['mpatgroups'].append(mpatgroups)
fillpat = re.compile(FILLPAT)
match = fillpat.match(pathstring[startindex:])
startindex += match.span()[1]
print('adding fill . . .')
fill = match.groups()[0]
retval['fill'] = fill
transformpat = re.compile(TRANSFORMPAT)
match = transformpat.match(pathstring[startindex:])
transform = match.groups()
print('adding transform . . .')
retval['transform'] = transform
return retval
def parse_all_paths(svgfilepath):
"""
Finds and parses all svg paths
within an svg file (very format
specific - bezier curves only).
Returns list of dictionaries, one
for each path line of the svg file.
"""
# Do all paths in Hamilton logo.
# Make list of dictionaries.
patpath = re.compile(PATHPAT)
with open(svgfilepath, 'r') as f:
paths = []
# Line one.
next(f)
# Line two.
next(f)
for linex in f:
print(PATHPAT)
print(linex[:30])
match = patpath.match(linex)
if not match:
break
paths.append(parse_path(linex))
return paths
def work_paths(paths, fcn):
"""
Apply an operation to all coordinates in
the bezier curve paths represented in
paths.
Also covers translate and fill.
paths is a list of dictionaries. Each
dictionary represents one line of an
svg file with a path made up of
bezier curves.
"""
# Return value.
newpaths = []
# M - start of path segment.
for pthx in paths:
newmpatgroups = []
for coordsx in pthx['mpatgroups']:
newmpatgroups.append([fcn(x) for x in coordsx])
newpaths.append({'mpatgroups':newmpatgroups})
# to Z - end of path segment.
# List of path dictionaries (paths).
for pthx, newpath in zip(paths, newpaths):
newpath['paths'] = []
# Each M to Z path segment.
for path in pthx['paths']:
curvegroup = []
for curve in path:
newcurve = [fcn(x) for x in curve]
curvegroup.append(newcurve)
newpath['paths'].append(curvegroup)
# transform and fill.
for pthx, newpath in zip(paths, newpaths):
newpath['transform'] = [fcn(x) for x in pthx['transform']]
newpath['fill'] = pthx['fill']
return newpaths
def translate_paths(paths, translation):
"""
From a two tuple of x, y translation,
adjust dictionary values for x, y
translation in each path in path
list accordingly.
Returns new dictionary
"""
# TRANSLATE
# ['mpatgroups', 'paths', 'fill', 'translate']
translated_paths = copy.deepcopy(paths)
for pathx in translated_paths:
pathx['transform'][0] += translation[0]
pathx['transform'][1] += translation[1]
return translated_paths
def get_path_strings(paths):
"""
From a list of path dictionaries,
builds one line strings for insertion
into svg file.
Returns list
"""
pathdict_2 = {'fill':None,
'translatex':None,
'translatey':None}
path_segment_dict = {'mstartx':None,
'mstarty':None,
'path':None}
pathstrings = []
for pathx in paths:
# Copy and initialize fill/translate dictionary.
fill_translate = copy.deepcopy(pathdict_2)
fill_translate['fill'] = pathx['fill']
fill_translate['translatex'] = pathx['transform'][0]
fill_translate['translatey'] = pathx['transform'][1]
# Zip together M and path segments.
path_segs = zip(pathx['mpatgroups'], pathx['paths'])
# For each path segment.
path_strings = []
for M, path_seg in path_segs:
seg_dict = copy.deepcopy(path_segment_dict)
seg_dict['mstartx'] = M[0]
seg_dict['mstarty'] = M[1]
# Build path segment string.
path_seg_strings = [BEZFMT.format(*coords) for coords in path_seg]
path = ''.join(path_seg_strings)
seg_dict['path'] = path
# Make final segment string with M (PATHFMT_1)
path_with_M = PATHFMT_1.format(**seg_dict)
path_strings.append(path_with_M)
path_all_together = ''.join(path_strings)
# Tack on fill/translate at end and beginning with d path flag.
# Add to pathstrings.
pathstrings.append(PATHFMT_OPEN +
path_all_together +
PATHFMT_2.format(**fill_translate) +
PATHFMT_CLOSE)
return pathstrings
paths = parse_all_paths('hamilton_logo_large.svg')
print('len(paths) = {0:d}'.format(len(paths)))
pprint.pprint([x for x in paths[0]])
paths = work_paths(paths, float)
scale = 0.035
scaleit = lambda x: scale * x
paths = work_paths(paths, scaleit)
# pprint.pprint(paths[0]['paths'][0])
paths = translate_paths(paths, (125, 0))
pathstrings = get_path_strings(paths)
# with open('test_paths.txt', 'w') as f:
# for pathx in pathstrings:
# print(pathx, file=f)
# print('\n\n', file=f)
GAP_FIX = "<polygon points='265 90.25, 245 143.75, 268 144.1, 295 90.25' style='fill: black;' />"
GAP_FIX_PROPER_COLOR = "<polygon points='265 90.25, 245 143.75, 268 144.1, 295 90.25' style='fill: #C3368C;' />"
TEXT = '<p>{0:s}</p>'
CODE = """
<p> </p><pre style="background: rgb(238, 238, 238); border-bottom-color: initial; border-bottom-style: initial; border-image: initial; border-left-color: initial; border-left-style: initial; border-radius: 10px; border-right-color: initial; border-right-style: initial; border-top-color: rgb(221, 221, 221); border-top-style: solid; border-width: 5px 0px 0px; color: #444444; font-family: "Courier New", Courier, monospace; font-stretch: inherit; font-variant-east-asian: inherit; font-variant-numeric: inherit; line-height: inherit; margin-bottom: 1.5em; margin-top: 0px; overflow-wrap: normal; overflow: auto; padding: 12px; vertical-align: baseline;"><span style="font-size: 13px;">{0:s}</span></pre>
"""
textlist = ['blah blah blah',
'blah blah blah again',
'blah blah blah a third time',
'blah blah blah a fourth time',
'blah blah blah a fifth time',
'blah blah blah a sixth time',
'blah blah blah a seventh time',
'fix divit',
'final product']
fixed_divit = copy.deepcopy(pathstrings)
fixed_divit.insert(1, GAP_FIX_PROPER_COLOR)
svglist = [pathstrings[0:1],
pathstrings[0:2],
pathstrings[0:3],
pathstrings[0:4],
pathstrings[0:5],
pathstrings[0:6],
pathstrings[0:],
pathstrings[0:] + [GAP_FIX],
fixed_divit]
with open('blogpost.html', 'w') as f:
for blah, svgels in zip(textlist, svglist):
print(TEXT.format(blah), file=f)
print(SVG_TAG_OPEN, file=f)
for svgelement in svgels:
print(svgelement, file=f)
print(SVG_TAG_CLOSE, file=f)
print(TEXT.format('More blah about code'), file=f)
print(CODE.format('>>> import this'), file=f)
print('Done')
Notes:
1) I had had good intentions of including a code box (the CODE string constant in the Python code) and I hit a bit of a wall. Not only is my code a mixed bag (this blog was always intended as a learning experience and a place for trying things out), it doesn't look good. We deal.
Which brings me to the point: you hear titles like front end developer, designer, website marketer etc. and think, "Well, it's kind of like art, kind of like coding . . . sort of creative." I now know, it's coding and it's thinking and it's grinding. All respect.
2) Steven Lott recently published a book that I bought (pdf). I have found it helpful. It's very pragmatic. I'm only about 15% of the way into it, but his treatment of regular expressions as just another tool not be scared of made me less tentative in my REGEX use (even if my REGEXes are far from elegant). Group capture with parens was really helpful for this exercise.
3) Our chief geology database administrator commented that the colors of the DAG Hamilton logo are those of the Spanish shawl nudibranch. There is a resemblance.
Photo courtesy of iNaturalist.
Thanks for stopping by.