4th September 2022
Coding⚑
Languages⚑
PDM⚑
-
To help package maintainers, you can allow pre-releases to be validate candidates, that way you'll get the issues sooner. It will mean more time to maintain the broken CIs if you update your packages daily (as you should!), but it's the least you can do to help your downstream library maintainers
By default,
pdm
's dependency resolver will ignore prereleases unless there are no stable versions for the given version range of a dependency. This behavior can be changed by setting allow_prereleases to true in[tool.pdm]
table:[tool.pdm] allow_prereleases = true
-
New: Solve circular dependencies.
Sometimes
pdm
is not able to locate the best package combination, or it does too many loops, so to help it you can update your version constrains so that it has the minimum number of candidates.To solve circular dependencies we first need to locate what are the conflicting packages,
pdm
doesn't make it easy to detect them. Locate all the outdated packages by doingpdm show
on each package until this issue is solved and runpdm update {package} --unconstrained
for each of them. If you're already on the latest version, update yourpyproject.toml
to match the latest state.Once you have everything to the latest compatible version, you can try to upgrade the rest of the packages one by one to the latest with
--unconstrained
.In the process of doing these steps you'll see some conflicts in the dependencies that can be manually solved by preventing those versions to be installed or maybe changing the
python-requires
.
Python Snippets⚑
-
New: Fix R1728: Consider using a generator.
Removing
[]
inside calls that can use containers or generators should be considered for performance reasons since a generator will have an upfront cost to pay. The performance will be better if you are working with long lists or sets.Problematic code:
list([0 for y in list(range(10))]) # [consider-using-generator] tuple([0 for y in list(range(10))]) # [consider-using-generator] sum([y**2 for y in list(range(10))]) # [consider-using-generator] max([y**2 for y in list(range(10))]) # [consider-using-generator] min([y**2 for y in list(range(10))]) # [consider-using-generator]
Correct code:
list(0 for y in list(range(10))) tuple(0 for y in list(range(10))) sum(y**2 for y in list(range(10))) max(y**2 for y in list(range(10))) min(y**2 for y in list(range(10)))
-
New: Fix W1510: Using subprocess.run without explicitly set check is not recommended.
The
run
call in the example will succeed whether the command is successful or not. This is a problem because we silently ignore errors.import subprocess def example(): proc = subprocess.run("ls") return proc.stdout
When we pass
check=True
, the behavior changes towards raising an exception when the return code of the command is non-zero. -
byte_var.decode('utf-8')
-
New: Use pipes with subprocess.
To use pipes with subprocess you need to use the flag
check=True
which is a bad idea. Instead you should use two processes and link them together in python:ps = subprocess.Popen(('ps', '-A'), stdout=subprocess.PIPE) +output = subprocess.check_output(('grep', 'process_name'), stdin=ps.stdout) ps.wait()
-
New: Pass input to the stdin of a subprocess.
import subprocess p = subprocess.run(['myapp'], input='data_to_write', text=True)
-
New: Copy and paste from clipboard.
You can use many libraries to do it, but if you don't want to add any other dependencies you can use
subprocess run
.To copy from the
selection
clipboard, assuming you've gotxclip
installed, you could do:subprocess.run( ['xclip', '-selection', 'clipboard', '-i'], input='text to be copied', text=True, check=True, )
To paste it:
subprocess.check_output( ['xclip', '-o', '-selection', 'clipboard'] ).decode('utf-8')
Good luck testing that in the CI xD
Generic Coding Practices⚑
Use warnings to evolve your code⚑
-
New: Use environmental variables to evolve your packages.
A cleaner way to handle the package evolve is with environmental variables, that way you don't need to change the signature of the function twice. I've learned this from boto where they informed their users this way:
- If you wish to test the new feature we have created a new environment variable
BOTO_DISABLE_COMMONNAME
. Setting this totrue
will suppress the warning and use the new functionality. - If you are concerned about this change causing disruptions, you can pin your version of
botocore
to<1.28.0
until you are ready to migrate. -
If you are only concerned about silencing the warning in your logs, use
warnings.filterwarnings
when instantiating a new service client.import warnings warnings.filterwarnings('ignore', category=FutureWarning, module='botocore.client')
- If you wish to test the new feature we have created a new environment variable
Abstract Syntax Trees⚑
-
New: Introduce abstract syntax trees.
Abstract syntax trees (AST) is a tree representation of the abstract syntactic structure of text (often source code) written in a formal language. Each node of the tree denotes a construct occurring in the text.
The syntax is "abstract" in the sense that it does not represent every detail appearing in the real syntax, but rather just the structural or content-related details. For instance, grouping parentheses are implicit in the tree structure, so these do not have to be represented as separate nodes. Likewise, a syntactic construct like an if-condition-then statement may be denoted by means of a single node with three branches.
This distinguishes abstract syntax trees from concrete syntax trees, traditionally designated parse trees. Parse trees are typically built by a parser during the source code translation and compiling process. Once built, additional information is added to the AST by means of subsequent processing, e.g., contextual analysis.
Abstract syntax trees are also used in program analysis and program transformation systems.
pyparsing
looks to be a good candidate to construct an AST