FLOSS Project Planets

Talk Python to Me: #311 Get inside the .git folder

Planet Python - Thu, 2021-04-08 04:00
These days Git is synonymous with source control itself. Rare are the current debates of whether to use git vs SVN vs some fossil like SourceSafe vs you name it. But do you know how Git works? What about it's internals? I'm sure you've seen a .git folder in your project's root. But to most folks, it's a black box. <br/> <br/> In this episode, you'll meet Rob Richardson. He's going pop the lid on that black box as we dive into git internals and the .git folder, among other things source control.<br/> <br/> <strong>Links from the show</strong><br/> <br/> <div><b>Rob's Site</b>: <a href="https://robrich.org/" target="_blank" rel="noopener">robrich.org</a><br/> <b>Rob on Twitter</b>: <a href="https://twitter.com/rob_rich" target="_blank" rel="noopener">@rob_rich</a><br/> <br/> <b>YouTube Live Stream Recording</b>: <a href="https://www.youtube.com/watch?v=gdY_RpY2oyU" target="_blank" rel="noopener">youtube.com</a><br/> <br/> <b>Talk at PWC</b>: <a href="https://pwc2021.loudswarm.com/session/definitive-deep-dive-git-folder" target="_blank" rel="noopener">loudswarm.com</a><br/> <b>Git Explorer App</b>: <a href="https://github.com/robrich/git-explorer" target="_blank" rel="noopener">github.com</a><br/> <b>Pre-commit framework</b>: <a href="https://pre-commit.com/" target="_blank" rel="noopener">pre-commit.com</a><br/> <b>.gitignore project</b>: <a href="https://github.com/github/gitignore" target="_blank" rel="noopener">github.com</a><br/> <b>git-hooks project</b>: <a href="https://www.npmjs.com/package/git-hooks" target="_blank" rel="noopener">npmjs.com</a><br/> <b>Git Source Control</b>: <a href="https://git-scm.com/" target="_blank" rel="noopener">git-scm.com</a><br/> <b>SVN</b>: <a href="https://subversion.apache.org/" target="_blank" rel="noopener">subversion.apache.org</a><br/> <br/> <b>Oh My Posh Shell</b>: <a href="https://ohmyposh.dev/" target="_blank" rel="noopener">ohmyposh.dev</a><br/> <b>Oh My ZSH Shell</b>: <a href="https://ohmyz.sh/" target="_blank" rel="noopener">ohmyz.sh</a><br/> <br/> <b>Oh !*#! Git Site</b>: <a href="https://ohshitgit.com/" target="_blank" rel="noopener">oh*!#!git.com</a><br/> <b>Work-safe version</b>: <a href="https://dangitgit.com/en" target="_blank" rel="noopener">dangitgit.com</a><br/></div><br/> <strong>Sponsors</strong><br/> <br/> <a href='https://talkpython.fm/training'>Talk Python Training</a>
Categories: FLOSS Project Planets

undpaul: Information for Drupal 9 upgrades from Drupal 8

Planet Drupal - Thu, 2021-04-08 03:30
Drupal is facing an end-of-life this year: Support for Drupal 8 will be discontinued as of 11/2/2021. Since Drupal 8 will no longer be supported after the EOL, we can only urge all Drupal 8 site owners to upgrade their system to Drupal 9 in time.
Categories: FLOSS Project Planets

PyPy: PyPy v7.3.4: release of python 2.7 and 3.7

Planet Python - Thu, 2021-04-08 01:53
PyPy v7.3.4: release of python 2.7 and 3.7

The PyPy team is proud to release the version 7.3.4 of PyPy, which includes two different interpreters:

  • PyPy2.7, which is an interpreter supporting the syntax and the features of Python 2.7 including the stdlib for CPython 2.7.18+ (the + is for backported security updates)

  • PyPy3.7, which is an interpreter supporting the syntax and the features of Python 3.7, including the stdlib for CPython 3.7.10. We no longer refer to this as beta-quality as the last incompatibilities with CPython (in the re module) have been fixed.

We are no longer releasing a Python3.6 version, as we focus on updating to Python 3.8. We have begun streaming the advances towards this goal on Saturday evenings European time on https://www.twitch.tv/pypyproject. If Python3.6 is important to you, please reach out as we could offer sponsored longer term support.

The two interpreters are based on much the same codebase, thus the multiple release. This is a micro release, all APIs are compatible with the other 7.3 releases. Highlights of the release include binary Windows 64 support, faster numerical instance fields, and a preliminary HPy backend.

A new contributor (Ondrej Baranovič - thanks!) took us up on the challenge to get windows 64-bit support. The work has been merged and for the first time we are releasing a 64-bit Windows binary package.

The release contains the biggest change to PyPy's implementation of the instances of user-defined classes in many years. The optimization was motivated by the report of performance problems running a numerical particle emulation. We implemented an optimization that stores int and float instance fields in an unboxed way, as long as these fields are type-stable (meaning that the same field always stores the same type, using the principle of type freezing). This gives significant performance improvements on numerical pure-Python code, and other code where instances store many integers or floating point numbers.

There were also a number of optimizations for methods around strings and bytes, following user reported performance problems. If you are unhappy with PyPy's performance on some code of yours, please report an issue!

A major new feature is prelminary support for the Universal mode of HPy: a new way of writing c-extension modules to totally encapsulate PyObject*. The goal, as laid out in the HPy documentation and recent HPy blog post, is to enable a migration path for c-extension authors who wish their code to be performant on alternative interpreters like GraalPython (written on top of the Java virtual machine), RustPython, and PyPy. Thanks to Oracle and IBM for sponsoring work on HPy.

Support for the vmprof statistical profiler has been extended to ARM64 via a built-in backend.

Several issues exposed in the 7.3.3 release were fixed. Many of them came from the great work ongoing to ship PyPy-compatible binary packages in conda-forge. A big shout out to them for taking this on.

Development of PyPy takes place on https://foss.heptapod.net/pypy/pypy. We have seen an increase in the number of drive-by contributors who are able to use gitlab + mercurial to create merge requests.

The CFFI backend has been updated to version 1.14.5 and the cppyy backend to 1.14.2. We recommend using CFFI rather than C-extensions to interact with C, and using cppyy for performant wrapping of C++ code for Python.

As always, we strongly recommend updating to the latest versions. Many fixes are the direct result of end-user bug reports, so please continue reporting issues as they crop up.

You can find links to download the v7.3.4 releases here:

https://pypy.org/download.html

We would like to thank our donors for the continued support of the PyPy project. If PyPy is not quite good enough for your needs, we are available for direct consulting work. If PyPy is helping you out, we would love to hear about it and encourage submissions to our renovated blog site via a pull request to https://github.com/pypy/pypy.org

We would also like to thank our contributors and encourage new people to join the project. PyPy has many layers and we need help with all of them: PyPy and RPython documentation improvements, tweaking popular modules to run on PyPy, or general help with making RPython's JIT even better. Since the previous release, we have accepted contributions from 10 new contributors, thanks for pitching in, and welcome to the project!

If you are a python library maintainer and use C-extensions, please consider making a cffi / cppyy version of your library that would be performant on PyPy. In any case both cibuildwheel and the multibuild system support building wheels for PyPy.

What is PyPy?

PyPy is a Python interpreter, a drop-in replacement for CPython 2.7, 3.7, and soon 3.8. It's fast (PyPy and CPython 3.7.4 performance comparison) due to its integrated tracing JIT compiler.

We also welcome developers of other dynamic languages to see what RPython can do for them.

This PyPy release supports:

  • x86 machines on most common operating systems (Linux 32/64 bits, Mac OS X 64 bits, Windows 32/64 bits, OpenBSD, FreeBSD)

  • big- and little-endian variants of PPC64 running Linux,

  • s390x running Linux

  • 64-bit ARM machines running Linux.

PyPy does support ARM 32 bit processors, but does not release binaries.

What else is new?

For more information about the 7.3.4 release, see the full changelog.

Please update, and continue to help us make PyPy better.

Cheers, The PyPy team

Categories: FLOSS Project Planets

Codementor: Online Job Support

Planet Python - Thu, 2021-04-08 01:20
Proxy job support provides the best job support for IT related works. We have a good ability and experts personality to complete our customer’s regular task. Our Online Job support team provide support on all the time zone. Our mission is to complete the job support queries from customers on punctually.
Categories: FLOSS Project Planets

hussainweb.me: The magic of Drupal events

Planet Drupal - Wed, 2021-04-07 23:59
I missed joining the DrupalNYC meetup today. Well, I almost missed it but I was able to catch the last 10 minutes or so. That got me thinking about events and that's the topic for today–Drupal events and their impact on my life. I travelled extensively for 4-5 years before the pandemic restrictions were put in place and since then, I have attended events around the world while sitting in my chair. These travels and events are responsible for my learnings and my professional (and personal) growth. And these are the perspectives that have given me the privilege that I enjoy.
Categories: FLOSS Project Planets

Kristen Pol: Celebrate 20 Years of Drupal with DrupalFest and DrupalCon!

Planet Drupal - Wed, 2021-04-07 20:21


Image credit: Aaron Deutsch

If you use Drupal at all, you've probably already heard that 2021 is Drupal's 20th anniversary! Pretty cool. :) Check out wikipedia to see Drupal's initial release by Dries Buytaert was January 15, 2001.

In honor of Drupal's 20th year, DrupalFest is this month which is built around the popular DrupalCon North America event. Due to the pandemic, DrupalCon NA is online again this year, but this allows for a more unique content and contribution event model. The events are spread out throughout the month of April to allow for more participation and better integration into everyone's schedule. Hope to "see you" next week at DrupalCon or at one of the Drupal summits!

read more

Categories: FLOSS Project Planets

Ryan Kavanagh: Writing BASIC-8 on the TSS/8

Planet Debian - Wed, 2021-04-07 20:08

I recently discovered SDF’s PiDP-8. You can access it over SSH and watch the blinkenlights over its twitch stream. It runs TSS/8, a time-sharing operating system written in 1967 by Adrian van de Goor while a grad student here at CMU. I’ve been having fun tinkering with it, and I just wrote my first BASIC program1 since high school. It plots the graph of some user-specified univariate function. I don’t claim that it’s elegant or well-engineered, but it works!

10 DEF FNC(X) = 19 * COS(X/2) 20 FOR Y = 20 TO -20 STEP -1 30 FOR X = -25 TO 24 40 LET V = FNC(X) 50 GOSUB 90 60 NEXT X 70 PRINT "" 80 NEXT Y 85 STOP 90 REM SUBROUTINE PRINTS AXES AND PLOT 100 IF X = 0 THEN 150 110 IF Y = 0 THEN 150 120 REM X != 0 AND Y != 0 SO IN QUADRANT 130 GOSUB 290 140 RETURN 150 GOSUB 170 160 RETURN 170 REM SUBROUTINE PRINTS AXES (X = 0 OR Y = 0) 180 IF X + Y = 0 THEN 230 190 IF X = 0 THEN 250 200 IF Y = 0 THEN 270 210 PRINT "AXES INVARIANT VIOLATED" 220 STOP 230 PRINT "+"; 240 GOTO 280 250 PRINT "I"; 260 GOTO 280 270 PRINT "-"; 280 RETURN 290 REM SUBROUTINE PRINTS FUNCTION GRAPH (X != 0 AND Y != 0) 300 IF 0 <= Y THEN 350 310 REM Y < 0 320 IF V <= Y THEN 410 330 REM Y < 0 AND Y < V SO OUTSIDE OF PLOT AREA 340 GOTO 390 350 REM 0 <= Y 360 IF Y <= V THEN 410 370 REM 0 <= Y AND V < Y SO OUTSIDE OF PLOT AREA 380 GOTO 390 390 PRINT " "; 400 RETURN 410 PRINT "*"; 420 RETURN 430 REM COPYRIGHT 2021 RYAN KAVANAGH RAK AT RAK.AC 440 END

It produces the following output:

I I * ** I ** * ** I ** ** ** *I* ** * ** ** *I* ** * ** *** *I* *** * ** **** *I* **** * ** **** *I* **** * ** **** *I* **** * ** **** **I** **** * *** **** **I** **** ** *** **** **I** **** ** *** **** **I** **** ** *** ***** **I** ***** ** *** ****** **I** ****** ** *** ****** **I** ****** ** *** ****** **I** ****** ** *** ****** **I** ****** ** *** ****** ***I*** ****** ** -------------------------+------------------------ ****** ****** I ****** ****** ****** ****** I ****** ****** ***** ****** I ****** ***** ***** ****** I ****** ***** ***** ***** I ***** ***** ***** ***** I ***** ***** ***** ***** I ***** ***** ***** **** I **** ***** ***** **** I **** ***** **** **** I **** **** **** **** I **** **** *** **** I **** *** *** *** I *** *** *** *** I *** *** *** *** I *** *** ** ** I ** ** ** ** I ** ** * * I * * I I

Next up, I am going to try my hand at writing some FORTRAN or some FOCAL69. If you like tinkering with old systems, then you should give the TSS/8 a try.

  1. It’s written in the BASIC-8 dialect. ↩︎

Categories: FLOSS Project Planets

Mike Driscoll: Python’s with Statement and Context Managers

Planet Python - Wed, 2021-04-07 14:52

Python came out with a special new keyword several years ago in Python 2.5 that is known as the with statement. This new keyword allows a developer to create context managers. But wait! What’s a context manager? They are handy constructs that allow you to set something up and tear something down automatically. For example, you might want to open a file, write a bunch of stuff to it and then close it. This is probably the classic example of a context manager. In fact, Python creates one automatically for you when you open a file using the with statement:

with open(path, 'w') as f_obj: f_obj.write(some_data)

Back in Python 2.4, you would have to do it the old fashioned way:

f_obj = open(path, 'w') f_obj.write(some_data) f_obj.close()

The way this works under the covers is by using some of Python’s magic methods: __enter__ and __exit__. Let’s try creating your own context manager to demonstrate how this all works!

Creating a Context Manager class

Rather than rewrite Python’s open method here, you’ll create a context manager that can create a SQLite database connection and close it when it’s done. Here’s a simple example:

import sqlite3 class DataConn: """""" def __init__(self, db_name): """Constructor""" self.db_name = db_name def __enter__(self): """ Open the database connection """ self.conn = sqlite3.connect(self.db_name) return self.conn def __exit__(self, exc_type, exc_val, exc_tb): """ Close the connection """ self.conn.close() if exc_val: raise if __name__ == '__main__': db = '/home/mdriscoll/test.db' with DataConn(db) as conn: cursor = conn.cursor()

In the code above, you created a class that takes a path to an SQLite database file. The __enter__ method executes automatically where it creates and returns the database connection object. Now that you have that, you can create a cursor and write to the database or query it. When you exit the with statement, it causes the __exit__ method to execute and that closes the connection.

Let’s try creating a context manager using another method.

Creating a Context Manager using contextlib

Python 2.5 not only added the with statement, but it also added the contextlib module. This allows you to create a context manager using contextlib’s contextmanager function as a decorator.

Let’s try creating a context manager that opens and closes a file after all:

from contextlib import contextmanager @contextmanager def file_open(path): try: f_obj = open(path, 'w') yield f_obj except OSError: print("We had an error!") finally: print('Closing file') f_obj.close() if __name__ == '__main__': with file_open('/home/mdriscoll/test.txt') as fobj: fobj.write('Testing context managers')

Here you import contextmanager from contextlib and decorate your file_open() function with it. This allows you to call file_open() using Python’s with statement. In your function, you open the file and then yield it out so the calling function can use it.

Once the with statement ends, control returns back to file_open() and it continues with the code following the yield statement. That causes the finally statement to execute, which closes the file. If you happen to have an OSError while working with the file, it gets caught, and the finally statement still closes the file handler.

contextlib.closing()

The contextlib module comes with some other handy utilities. The first one is the closing class which will close the thing upon the completion of the code block. The Python documentation gives an example that’s similar to the following one:

from contextlib import contextmanager @contextmanager def closing(db): try: yield db.conn() finally: db.close()

Basically what you’re doing is creating a closing function that’s wrapped in a contextmanager. This is the equivalent of what the closing class does. The difference is that instead of a decorator, you can use the closing class itself in your with statement.

Here’s what that will look like:

from contextlib import closing from urllib.request import urlopen with closing(urlopen('http://www.google.com')) as webpage: for line in webpage: # process the line pass

In this example, you open a URL but wrap it with your closing class. This will cause the handle to the web page to be closed once you fall out of the with statement’s code block.

contextlib.suppress(*exceptions)

Another handy little tool is the suppress class which was added in Python 3.4. The idea behind this context manager utility is that it can suppress any number of exceptions. A common example is when you want to ignore the FileNotFoundError exception. If you were to write the following context manager, it wouldn’t work:

>>> with open('fauxfile.txt') as fobj: for line in fobj: print(line) Traceback (most recent call last): Python Shell, prompt 4, line 1 builtins.FileNotFoundError: [Errno 2] No such file or directory: 'fauxfile.txt'

This context manager doesn’t handle this exception. If you want to ignore this error, then you can do the following:

from contextlib import suppress with suppress(FileNotFoundError): with open('fauxfile.txt') as fobj: for line in fobj: print(line)

Here you import suppress and pass it the exception that you want to ignore, which in this case is the FileNotFoundError exception. If you run this code, nothing happens as the file does not exist, but an error is also not raised. It should be noted that this context manager is reentrant. This will be explained later on in this article.

contextlib.redirect_stdout / redirect_stderr

The contextlib library has a couple of neat tools for redirecting stdout and stderr that were added in Python 3.4 and 3.5 respectively. Before these tools were added, if you wanted to redirect stdout, you would do something like this:

path = '/path/to/text.txt' with open(path, 'w') as fobj: sys.stdout = fobj help(sum)

With the contextlib module, you can now do the following:

from contextlib import redirect_stdout path = '/path/to/text.txt' with open(path, 'w') as fobj: with redirect_stdout(fobj): help(redirect_stdout)

In both of these examples, you are redirecting stdout to a file. When you call Python’s help(), instead of printing to stdout, it gets saved directly to the file. You could also redirect stdout to some kind of buffer or a text control type widget from a user interface toolkit like Tkinter or wxPython.

ExitStack

ExitStack is a context manager that will allow you to easily programmatically combine other context managers and cleanup functions. It sounds kind of confusing at first, so let’s take a look at an example from the Python documentation to help you understand this idea a bit better:

>>> from contextlib import ExitStack >>> with ExitStack() as stack: file_objects = [stack.enter_context(open(filename)) for filename in filenames] ]

This code basically creates a series of context managers inside the list comprehension. The ExitStack maintains a stack of registered callbacks that it will call in reverse order when the instance is closed, which happens when you exit the bottom of the with statement.

There are a bunch of neat examples in the Python documentation for contextlib where you can learn about topics like the following:

  • Catching exceptions from __enter__ methods
  • Supports a variable number of context managers
  • Replacing any use of try-finally
  • and much more!

You should check it out so you get a good feel for how powerful this class is.

Wrapping Up

Context managers are a lot of fun and come in handy all the time. I use them in my automated tests all the time for opening and closing dialogs, for example. Now you should be able to use some of Python’s built-in tools to create your own context managers. Be sure to take the time to read the Python documentation on contextlib as there are lots of additional information that is not covered in this chapter. Have fun and happy coding!

 

The post Python’s with Statement and Context Managers appeared first on Mouse Vs Python.

Categories: FLOSS Project Planets

Bounteous.com: How to Build a Great Drupal Team

Planet Drupal - Wed, 2021-04-07 13:35
Explore a breakdown of some of the challenges and solutions for you to consider in order to build a great Drupal team.
Categories: FLOSS Project Planets

Ben's SEO Blog: The Coffee Module

Planet Drupal - Wed, 2021-04-07 13:28
The Coffee Module Learn how to install configure, and use the Coffee Module. Coffee is the fastest way to get to any admin screen in Drupal. Tracy Cooper Wed, 04/07/2021 - 12:28
Categories: FLOSS Project Planets

FSF Blogs: March GNU Spotlight with Mike Gerwitz: 14 new GNU releases!

GNU Planet! - Wed, 2021-04-07 12:46
14 new GNU releases in the last month (as of March 25, 2021):
Categories: FLOSS Project Planets

March GNU Spotlight with Mike Gerwitz: 14 new GNU releases!

FSF Blogs - Wed, 2021-04-07 12:46
14 new GNU releases in the last month (as of March 25, 2021):
Categories: FLOSS Project Planets

Tag1 Consulting: Financially Supporting Your Open Source Development Work - with Dries Buytaert - Pt. 2

Planet Drupal - Wed, 2021-04-07 12:20

While there are many companies based in open source software that are successfully funding themselves based on consultancy and other services, that’s not necessarily true of individual contributors. As part of our series of talks with Open Source Leaders, Tag1 Consulting’s Managing Director Michael Meyers, VP of Software Engineering Fabian Franz, and Yjs founder Kevin Jahns talk with Dries Buytaert about open source projects and communities. This talk focuses on open source project sustainability and funding. Dries talks about some of the key points that made Drupal successful, and how the project and the Drupal Association have changed and pivoted based on challenges like the coronavirus pandemic. Dries also gives some pointers on how he started to sell his project to others, and how that started to change his role in the project over time, from the primary developer, to a project head focused on visibility. - Part 1 ### Additional resources - Elinor Ostrom: Governing the Commons: https://www.amazon.com/Governing-Commons-Evolution-Institutions-Collective/dp/0521405998 - Featured Essay: Elinor Ostrom’s work on Governing The Commons: An Appreciation --- _For a transcript of this video, see [Transcript: Open...

Read more lynette@tag1co… Wed, 04/07/2021 - 09:20
Categories: FLOSS Project Planets

Drupal Association blog: What's new on Drupal.org? - Q1 2021

Planet Drupal - Wed, 2021-04-07 12:09

Read our roadmap to understand how this work falls into priorities set by the Drupal Association with direction and collaboration from the Board and community. You can also review the Drupal project roadmap.

Drupal.org Updates Drupal's 20th Birthday Year

As we close out the first quarter of 2021, we continue the celebration of 20 years of Drupal with #DrupalFest and #DrupalCon!

#DrupalFest is a month-long celebration of all things Drupal, taking place online all around the world. DrupalFest lasts throughout the month of April. Most events are free, and we encourage everyone to attend, and even submit your own!

DrupalCon is right around the corner from April 12-16, happening online. This year's DrupalCon reflects a renewed focus on the strategic initiatives that drive innovation in Drupal. Each day has a half day of live programming for and then a half day of contribution, and all personas are welcome! Join us!

Increased focus on Strategic Initiatives

Speaking of strategic initiatives, the current primary initiatives being highlighted at DrupalCon and beyond are: 

  • Decoupled Menus - This initiative focuses on creating standardized tools and libraries for decoupled Drupal, starting with the menu system. This is the first step in making JavaScript front-ends a central part of the Drupal project. 
  • Easy out of the Box - This mega-initiative combines the efforts of Layout Builder, Media, and Claro to help empower content editors in Drupal to take advantage of the best that Drupal can offer.
  • Automatic Updates - This initiative is focused on the #1 most requested feature in Drupal: automatic updates. The initiative is building a robust and secure system for automatically updating Drupal, starting with security and patch releases.
  • Drupal 10 Readiness - The Drupal innovation train keeps rolling! The Drupal 10 Readiness initiative is rallying the community around what we need to reach our Drupal 10 release date, and helping site owners ensure they're ready for the upgrade when the time comes.

In addition to the content at DrupalCon, you can find ways to get involved in any of these initiatives by checking out the Drupal Strategic Initiative section on Drupal.org.

Decoupled Menu Initiative Support

General projects are a new content type on Drupal.org for code that does not fall into the neat categories of module, theme, or distribution. Instead, these can cover things like JavaScript Components, Drush Extensions, Install Profiles, Libraries, etc.

This is the first step in making Drupal a project greater than just PHP. This capability leans into Drupal's future in Decoupled applications, and in digital experiences beyond the web browser. 

Since the launch of general projects as a new content type on Drupal.org the Decoupled Menu Initiative has made great progress on creating standardized endpoints/libraries for decoupled Drupal solutions.

At DrupalCon North America the Decoupled Menus initiative leads invite you to a hackathon to begin to create applications for this work.

The rapid movement on this initiative shows how quickly the Drupal community can pivot into more robust and standardized Decoupled implementations, and furthers Drupal's lead in the marketplace.

Easy Out of the Box Support

For the Easy Out of the Box team, the Drupal Association has been focused on connecting the initiative leads to the Drupal Contribution Mentoring team, so that at DrupalCon there will be a variety of onramps to help new contributors support this work.

Easy Out of the Box is effectively three initiatives in one, focused on Layouts, Media, and the Claro administrative theme, so people with interest in any of those areas are more than welcome.

AutoUpdates Initiative Cross-Project Collaboration

The Drupal Association Engineering team continues its close collaboration with the AutoUpdates initiative team. Because AutoUpdates requires a server side component that will live on Drupal.org infrastructure, the engineering team needs to be closely involved.

This initiative has also had a heavy focus on cross-project collaboration - with three CMS partners in the PHP ecosystem collaborating together on the basic principles of supporting securely signed update packages.

      

We're also collaborating with other partners, such as the Cloud Native Computing Foundations 'TUF'(The Update Framework) team, and the team behind Composer. 

        

At DrupalCon North America the TUF team will be presenting about securing software package delivery - a topic that is sure to be interesting for all.

Drupal 10 Readiness Support

Drupal 10 is slated for release in June of 2022, which is only a little bit more than a year away. Fortunately, Drupal 10 follows the continuous innovation model of Drupal development that was so successful in the transition from Drupal 8 to Drupal 9. In essence, so long as site owners are up to date with the latest version of Drupal 9 they should be able to make the jump very easily. The only area of concern is deprecated code.

To that end, the Drupal Association engineering team collaborated with Gábor Hotjsy to set up automate code deprecation checking using the DrupalCI infrastructure. This allows the team to understand the most used instances of deprecated code, so that contributed module maintainers can be made aware of the need to update, and so that the Drupal Rector team(supported by Palantir.net) can begin creating automatic deprecation patches.

GitLab Merge Request Updates

Last year, Drupal.org migrated our community contribution tools to GitLab, by integrating the existing Drupal.org issue queues with GitLab's merge request functionality.

Thanks to these improvements, the complete contribution lifecycle can be completed entirely in the browser. As a contributor to Drupal you no longer need to use command line git, install a local development environment, or use a local IDE in order to make your contributions.

Since the initial launch, we've received feedback from many people in the community about improvements to usability with the Drupal.org issue queue integration. Looking at the child issues of this issue, we can see rapid usability improvements that have sped the pace of contribution.

More recently, we worked with our partners at Tugboat.qa to release live deployment previews of your code changes - first for Drupal Core, but now available for contributed projects on Drupal.org as well. This means that even reviewing visual changes or seeing your code deployed to a site can all be done without leaving your browser. This is a huge boon to all contributors, but especially to usability and accessibility experts who can much more easily view the impact of changes across issues.

Major improvements to Community events

In collaboration with the Events Organizers Working Group, the Drupal Association has updated the Drupal.org Community Events section. This new section represents a central repository for all of the events taking place across the Drupal Community, and will ultimately be the replacement for Groups.Drupal.org.

This section allows anyone in the community to submit their events, whether online or in-person, and provides a variety of views to help people find events they'd like to attend. Events can be filtered by type(con, camp, meetup, training, etc); proposed events can be submitted to help avoid scheduling conflicts; and calls for content/speakers can be promoted.

A feed of these events is made available for 3rd party tools built by the community, which is already being used to feed Drupical.com.

Local events are the heart of our community, so we hope that you'll help us by submitting your local events to this new tool!

Documentation updates

Led by community volunteer u/jhodgdon, Drupal.org's documentation tools have seen a variety of updates. In particular, the Drupal contributor guide is now much more complete, helping folks who are new to contribution in Drupal find a place to fit in and get started.

We've also deployed improvements that make it easier to understand whether the documentation you're reading is up-to-date, and how to report problems if you find them.

If you're looking for somewhere to contribute - helping to update documentation is a wonderful place to start!

Coming soon: Discover Drupal Portal

Coming up at DrupalCon is the announcement of a new program: Discover Drupal. This program is part of the Drupal Association's talent and education initiatives, and represents the Drupal Association's commitment to growing the Drupal talent pool and increasing diversity in our community.

With the official announcement just around the corner we won't spoil the details here, but very soon you'll be able to check out the new web portal for the Discover Drupal program and find out what it's all about.

Infrastructure Updates

Over the course of the last quarter the Drupal Association engineering team has provided a variety of feature updates for the Drupal project in terms of testing infrastructure: 

  • PHP8 Testing support - The Drupal Association provided PHP8 testing environments in DrupalCI, and so Drupal versions 9.1 and beyond are all fully PHP 8 compatible.Staying on the leading edge of compatibility gives Drupal the advantage of improved performance and security, and sets us up for success when it's time for Drupal 10.

  • Code Standards test for Drupal Core - Drupal Core tests now provide code standards testing results, saving a laborious manual step when reviewing core contributions.
  • GitLabCI/Pipelines - The Drupal Association has also enabled GitLabCI/Pipelines for these new general projects. This is a precursor to moving to GitLabCI for all Drupal CI uses. With direct maintainer control of the CI configuration for these projects, we can see automated workflows to support a wider variety of projects - allowing for more innovation. However, we need to be cognizant of cost controls as we open up this capability.

The year is off to a fast-paced, productive start and as always it is humbling and gratifying to see the great work that the community accomplishes with the tools the Drupal Association provides.

———

As always, we’d like to say thanks to all the volunteers who work with us, and to the Drupal Association Supporters, who make it possible for us to work on these projects. In particular, we want to thank: 

If you would like to support our work as an individual or an organization, consider becoming a member of the Drupal Association.
Follow us on Twitter for regular updates: @drupal_org, @drupal_infra

Categories: FLOSS Project Planets

PyCharm: PyCharm 2021.1 Is Out!

Planet Python - Wed, 2021-04-07 10:07

Try our new out-of-the-box collaborative development tool, auto-import for module member completion, and enhanced WSL support.

Download the new version

We’ve added quite a lot of new functionality in this release. Let’s focus on the “editor picks” first, from the PyCharm team:

In addition to those highlights, we’ve improved code insight, frontend development tools, and working with databases. For more details, please visit the release web page or browse the release notes to see all the new features we’ve added to PyCharm with this release.

Read on for more insight into the highlighted features, or upgrade to PyCharm 2021.1 and start using them right now!

Upgrade to PyCharm 2021.1

Faster indexing

Our new prebuilt indexes for the most popular Python interpreters have made standard library indexing much faster. The new approach to prebuilt indexes also helped us make the PyCharm installation file smaller.

WSL 2 support

You can now work in PyCharm with your project stored on the WSL filesystem without copying the project to your Windows file system.

Also, PyCharm now detects the WSL interpreter. If no WSL interpreter is configured for your project, PyCharm will look for system interpreters and set them as the default interpreter automatically.

What’s more, you can open any directory in \\wsl$ with PyCharm. If PyCharm detects any Python file in the directory, it will suggest creating a WSL-based interpreter. See the dedicated PyCharm Help page.

Once the project is open, PyCharm Terminal will already be configured to run on the WSL. As for version control, you can use Git that is installed on your WSL instance.

PyCharm now allows you to use custom Linux distributions run on the WSL. PyCharm auto-detects these distributions and adds it to the Linux Distribution list. You don’t need to add extra pre-configuring – starting with 2021.1, PyCharm will do everything for you.

Although debugging is fully supported for WSL 2, users still need to do a few things manually to configure the debugger to work with WSL 2. Thanks to the feedback from the PyCharm community (PY-44230), we’ve created a set of simple instructions on how to enable debugging for WSL configurations.

Auto import on module member completion

PyCharm now automatically adds an import statement when you refer to any module or package name in Python code and you invoke code completion with the list of available module members.

Auto-import on code completion is also applied to some popular package name aliases, such as np for NumPy or pd for pandas. You can learn more about autocompletion here.

Tool window for Python packages

You can install a new Python package or browse through all the packages available for download using the new Tool window, without having to leave the editor. This window is enabled by default, and you can find it at the bottom of the IDE together with the Terminal and Python Console. You can open it using the main menu at any time: View | Tool Windows | Python Packages.

The Python Packages tool window shows the installed packages and the packages that are available in the PyPI repository. Use the Search field to filter the list of the available packages. You can find a detailed description of how to use the Tool window to search packages in the Installing and Upgrading packages in PyCharm section of the documentation.

Code With Me for collaborative development

Code With Me connects remote teams in a feature-rich collaborative environment and helps you boost productivity, no matter where your team members are based. The essential IDE features, such as smart code insight, navigation, remote unit testing, and debugging, are available for participants during collaborative sessions. Teams can simultaneously edit code, track changes with diff previews, and follow each other in the shared project.

The embedded audio and video calls, along with chat messaging, will help software developers discuss the code, share their knowledge, and cooperate even more efficiently.

DOWNLOAD PYCHARM 2021.1

Those are the major features of this release. To learn about other important features included in PyCharm 2021.1, please head on to the What’s New page. And if you’d like to check out all the enhancements and changes in v2021.1, look through the release notes.

Do not hesitate to submit a bug request using our bug tracker.

Happy developing!

Categories: FLOSS Project Planets

Acro Media: Decoupling AcroMedia.com with Drupal 9 & React | Acro Media

Planet Drupal - Wed, 2021-04-07 10:00

How we jumped head-first into decoupling Drupal with a React-based design system built for performance and brand consistency.

Our latest corporate initiative is decoupling our website, upgrading to Drupal 9 and achieving the holy grail of web development — a CMS-driven back end, with a modern, decoupled javascript front end using a component-based design system.

Here is a breakdown of the project so far:

It’s funny how things go. As a company, we’re constantly working in Drupal: building, planning, and helping to maintain various modules and websites for both our clients and the Drupal community. While the large majority of our clients and work is in the latest version of Drupal, our site is still running Drupal 7. Shame on us, right! Like many businesses out there, it’s easy to push aside the upgrade when our internal systems and staff are comfortably using the existing platform and everything is working like a well-oiled machine. Well, we finally got the buy-in we needed from our internal stakeholders and we were off to the races. But, we didn’t want just another Drupal website. We wanted to explore the “bleeding edge” and see if we can achieve the holy grail of web development — a CMS-driven back end, with a modern, decoupled javascript front end using a component-based design system. Go big or go home!

Our approach to the back end

After a solid planning phase, we settled on an approach for the new site build and it was time to get going. We decided on Drupal (of course) for the back end since it’s our CMS of choice for many reasons and we could leverage all of the great work that has already been done with the JSON:API. However, not all of our needs were covered out-of-the-box.

Exploring API-first distributions

When we were first getting started, we spent some time looking at using ContentaCMS for our back end. It’s an API-first Drupal distribution that already contains most, if not all, of the modules we needed. Ultimately, we decided against it due to the number of extra modules that were unnecessary for our build. We also knew we wanted to use Paragraphs and Layout Builder, but found some display width issues that didn’t line up with our vision. We ditched ContentaCMS and went back to a fresh Drupal 9 install with just the modules we needed.

Decoupled menus

Another complication we came across focused around decoupled menus. Obviously, to build out a menu on the front end we needed to be able to get menu items. JSON:API Menu Items was installed and gave us a good starting point by exposing the menus in JSON:API. Next, we needed to get around the fact that JSON:API relies on UUID for content but menus use paths. Content also likes to have pretty URLs to use for navigation via path aliases. To display these path aliases from the front end and be able to retrieve the correct node, we need some way to resolve the path alias to its correct content. In comes the Decoupled Router module to solve the problem for us! This module provided the endpoints we needed.

Simplifying the JSON output

When you first install JSON:API, you get all of the data. While this is great, it negatively affects the developer experience by making it harder to find the data you need. JSON:API Extras was critical in improving this experience. With this module, we can easily remove unnecessary fields and customize our API path exactly how we want it. We also used the OpenAPI module to give developers a better high-level look at the available endpoints and their structure, opposed to looking at gross JSON output.

Our approach to the front end

With our back end sorted out, it’s time to get to the front end. When going decoupled, the front end suddenly becomes a whole lot more interesting than just a standard Drupal theme with Twig templates, SASS stylesheets and jQuery. We’re in a whole different realm now with new possibilities. We were 100% on board with having better integration between design and development, where the end result of the design was more than static assets and a 1-hour handoff. Here’s a breakdown of our front end approach.

A new strategy for consistency between design in development

In the past, creative exercises would provide static assets such as style guides to try and capture the design principles of a web property or brand. While this concept is rooted in good intentions, in practice, it never really worked well as a project evolved. It’s simply too difficult to keep design and development in sync in this way. For web development, it’s now understood that the code is a better source of truth, not a style guide, but we still need ways to involve our designers and have them contribute their knowledge of design and UX into the code that is being developed. After all, if you leave these decisions up to developers, you’re not going to end up in a good place (and most developers will readily agree with that sentiment). Luckily for us, applications like Figma, Sketch, and Adobe XD, are leading the way to bridge this gap. While this is still very new territory, there is a lot of exciting progress happening that is enabling the creation of robust design systems that act as a rulebook and single source of truth that is both easily updated, modular, and readily available for product application development.

After an internal study of available technologies for design, we settled on Figma for our design system creative work. Figma runs in either web or desktop applications and is a vector graphic editor and prototyping tool. The team developing it has done an incredible job pushing the envelope on how creative and development can work together. With Figma, we found it was possible to accomplish the following:

Extracting design tokens into our application

With our tokens living in Figma, we still needed a way to bring those static design token values into our development process. This is where Figmagic comes in. Figmagic is a nice tool for extracting design tokens and graphic assets out of Figma and into our application. Once set up, all we need to do in our local development environment is to run yarn figmagic. This connects to Figma and pulls down all of our defined tokens into an organized set of ready-to-use files. From there, we then simply import the file we need into our component and use the values as required. If a value needs to change, this is done in Figma. Re-running Figmagic brings in any updated value which updates any component using it. It works like... magic.

Building reusable front end components

Going decoupled meant breaking away from Drupal’s Twig templating and theming layer. For our front end application, we decided on React for our replacement. React continues to be very popular and well-liked, so we didn’t see any technical advantage to picking anything else. This change brought on some additional challenges in that, as a Drupal development company, our focus has not been React. We undertook some initial training exercises to get our development team on this project up-to-speed with the basics. Between this team, our CTO, our CXO, and a senior technical lead, we quickly trained up and settled on a suite of tools to achieve our desired outcomes of a component-driven React frontend.

Component UI frameworks to increase velocity

For us, the approach to developing the many React components that we needed was to first settle on an established framework. Like Bootstrap is to HTML/CSS development, several React-based frameworks are available to use as a foundation for development. It’s always debatable whether this is necessary or not, but we felt this was the best way for us to get started as it greatly increases the development velocity of our project while also providing good reference and documentation for the developers creating our components. We researched several and tried a few, but eventually found ourselves leaning towards Material UI. There were several reasons for this decision, but mainly we like the fact that it is an established, proven, framework that is flexible, well documented, and well supported. With Material UI (MUI), adjusting the base theme using our design tokens from Figma already gave us a good start. Its framework of pre-built components allowed us to make minimal changes to achieve our design goals while freeing up time to focus on our more unique components that were a bit more custom. This framework will continue to be of great benefit in the future as new requirements come up.

Previewing design system component without Drupal

Without a standard Drupal theme available, we needed somewhere to be able to preview our React components for both development and UX review. A decoupled front end, and the whole point of the design system, is that the front end should be as back end agnostic as possible. Each component should stand alone. The front end is the front end and the back end could be anything. Since we haven’t yet connected the front end components to Drupal’s JSON:API, we still needed an easy way to view our design system and the components within it. For this, we used Storybook. Storybook was made for developing and previewing UI components quickly. As a developer working locally, I install and spin up an instance of Storybook with a single command within our project repo. Storybook then looks at our project folder structure, finds any story files that we include as part of all of the components we develop, and generates a nice previewer where we can interactively test out our component props and create examples that developers in the future may need when implementing a component. Storybook is our design system library and previewer as well as our developer documentation. When we are done developing locally and push code to our repository, our deployment pipeline builds and deploys an updated Storybook preview online.

Bringing it all together

At this point, we have our back end and API established. We also have our front end component library created. Now we need to bring it all together and actually connect the two.

Matching the Drupal UI to our React components

React components are standalone UI elements and are made up of props that determine their functionality. So, for instance, a Button component could have many variants for how it looks. A button could include an icon before or after the text, or it could be used to open a link or a dialogue window, etc. A simple component like this might have a whole bunch of different props that can be used in different ways. To be able to control those props through the Drupal UI, we decided to use the Paragraphs module. A paragraph in Drupal is essentially a mini content type for a specific use. In Drupal, we created paragraphs that matched the functionality we needed from our React components so that the Drupal UI would be, in the end, setting the component props. This is a bit confusing to set up at first and something that will probably not be nailed down first try, but, in the process of setting up the Drupal UI in the context of the React components, you can really start to see how the connection between the two is made. At this point, it’s pretty easy to see if a component is missing any props or needs to be refactored in some way.

We also went with Paragraphs because we wanted to give our content creators a more flexible way of creating content. A standard Drupal content type is pretty rigid in structure, but with Paragraphs, we can give content creators a set of building blocks that can be grouped and combined in many different ways to create a wide variety of pages and layouts in a single content type. If you’re not familiar with this style of creating content in Drupal, I suggest you take a look at this post I wrote a while back. Look at that and imagine React components rendering on the page instead of Drupal templates. That’s essentially what we’re aiming to do here.

An argument against Paragraphs is that it could potentially make page building more time-consuming given that you don’t have that typical rigid structure of a content type. This is especially true if pages on a site being built typically all follow a similar format. In this case, we still like to use Paragraphs anyway but we will typically build out unpublished pages that act as templates. We then install the Replicate module which lets content creators clone the template and use it as a starting point. This makes creating pages easy and consistent while still allowing flexibility when needed. Win-win.

Taking the Next.js step

Since we settled on React, we started our front end project as a standard react build using the built-in create-react-app command. But, after some additional investigation, we decided that a better option for our use case would be to use the Next.js framework. Given that the corporate site is, at its core, is a marketing and blogging website, Next.js allows us to still build the frontend using React but gives us some extra capabilities this type of website needs.

One of these capabilities is incoming server-side rendering which we found increases the performance of our application. This also has SEO benefits due to pages being rendered serverside and sent to the client, as opposed to the standard client-side rendering most React applications use where the client machine handles processing and rendering.

Component factories are key to interpreting the API data

We were also attracted to the structure and organization of the project when using a framework like Next.js, as well as the dynamic routing capabilities. This significantly simplified the code required to implement our decoupled menu and page routing. Using the dynamic routes provided by Next.js, we could create “catch-all” routes to handle the ever-growing content in the CMS. By querying the Drupal API, we can get all the available path aliases for our content and feed it to Next.js so it can pre-build our pages. It can use the path aliases to resolve the content specific to the page through the Decouple Router module, which will then feed that data to a component factory to handle the decision as to what high-level React page component is necessary to build a page. For example, if the data is for a basic page content type, the page factory component returns our Page component, if it’s a blog post content type, it returns the Blog Page component, etc. Each of these components knows how to handle the specific data fed to it, but the factory component is what connects the data to the right page.

The way Paragraphs can be added to a page for composing a piece of content also created a challenge on its own in reading that data and returning the right component. We decided to create another factory component for this. Similar to the page factory component, this one takes in the paragraph data and determines which React components it needs to render the content.

What’s next in our decoupled adventure

Believe it or not, what we’re building is still a work in progress. While we have most of the tech requirements figured out, we’re still actively putting all of the final pieces in place and fine-tuning the backend UI and modules requirements. All in all, we’re feeling really good about this progress and can see the value of what we’re building both for ourselves and the clients we serve. In our opinion that is based on experience and research, decoupled is the future, and we’re excited to walk this path.

With that said, even once our own decoupled site has launched, we still have a lot of work left to do. For one, we still need to get a method in place for managing Drupal blocks and regions. More factory components will be critical here to interpret that data. Given that our clients are primarily ecommerce retailers in one form or another, we still have the whole ecommerce side of web development to sort out, including product catalogues, add-to-cart forms, carts, wish lists, checkout flows, etc. The list is long. However, what we have is a framework that can be repurposed and added on to. It finally helps tie together many disciplines of web development, both creative and technical, that are traditionally siloed. It’s also blazing fast and just plain cool. This is an investment not only in our own online business front but in something greater that we hope to share with others through work, community and general knowledge.

Thanks for taking the time to read this. If you want to chat about this initiative further, drop us a line.

Categories: FLOSS Project Planets

Real Python: The k-Nearest Neighbors (kNN) Algorithm in Python

Planet Python - Wed, 2021-04-07 10:00

In this tutorial, you’ll get a thorough introduction to the k-Nearest Neighbors (kNN) algorithm in Python. The kNN algorithm is one of the most famous machine learning algorithms and an absolute must-have in your machine learning toolbox. Python is the go-to programming language for machine learning, so what better way to discover kNN than with Python’s famous packages NumPy and scikit-learn!

Below, you’ll explore the kNN algorithm both in theory and in practice. While many tutorials skip the theoretical part and focus only on the use of libraries, you don’t want to be dependent on automated packages for your machine learning. It’s important to learn about the mechanics of machine learning algorithms to understand their potential and limitations.

At the same time, it’s essential to understand how to use an algorithm in practice. With that in mind, in the second part of this tutorial, you’ll focus on the use of kNN in the Python library scikit-learn, with advanced tips for pushing performance to the max.

In this tutorial, you’ll learn how to:

  • Explain the kNN algorithm both intuitively and mathematically
  • Implement kNN in Python from scratch using NumPy
  • Use kNN in Python with scikit-learn
  • Tune hyperparameters of kNN using GridSearchCV
  • Add bagging to kNN for better performance

Free Bonus: Click here to get access to a free NumPy Resources Guide that points you to the best tutorials, videos, and books for improving your NumPy skills.

Basics of Machine Learning

To get you on board, it’s worth taking a step back and doing a quick survey of machine learning in general. In this section, you’ll get an introduction to the fundamental idea behind machine learning, and you’ll see how the kNN algorithm relates to other machine learning tools.

The general idea of machine learning is to get a model to learn trends from historical data on any topic and be able to reproduce those trends on comparable data in the future. Here’s a diagram outlining the basic machine learning process:

This graph is a visual representation of a machine learning model that is fitted onto historical data. On the left are the original observations with three variables: height, width, and shape. The shapes are stars, crosses, and triangles.

The shapes are located in different areas of the graph. On the right, you see how those original observations have been translated to a decision rule. For a new observation, you need to know the width and the height to determine in which square it falls. The square in which it falls, in turn, defines which shape it is most likely to have.

Many different models could be used for this task. A model is a mathematical formula that can be used to describe data points. One example is the linear model, which uses a linear function defined by the formula y = ax + b.

If you estimate, or fit, a model, you find the optimal values for the fixed parameters using some algorithm. In the linear model, the parameters are a and b. Luckily, you won’t have to invent such estimation algorithms to get started. They’ve already been discovered by great mathematicians.

Once the model is estimated, it becomes a mathematical formula in which you can fill in values for your independent variables to make predictions for your target variable. From a high-level perspective, that’s all that happens!

Distinguishing Features of kNN

Now that you understand the basic idea behind machine learning, the next step is understanding why there are so many models available. The linear model that you just saw is called linear regression.

Linear regression works in some cases but doesn’t always make very precise predictions. That’s why mathematicians have come up with many alternative machine learning models that you can use. The k-Nearest Neighbors algorithm is one of them.

All these models have their peculiarities. If you work on machine learning, you should have a deep understanding of all of them so that you can use the right model in the right situation. To understand why and when to use kNN, you’ll next look at how kNN compares to other machine learning models.

kNN Is a Supervised Machine Learning Algorithm

The first determining property of machine learning algorithms is the split between supervised and unsupervised models. The difference between supervised and unsupervised models is the problem statement.

In supervised models, you have two types of variables at the same time:

  1. A target variable, which is also called the dependent variable or the y variable.
  2. Independent variables, which are also known as x variables or explanatory variables.

The target variable is the variable that you want to predict. It depends on the independent variables and it isn’t something that you know ahead of time. The independent variables are variables that you do know ahead of time. You can plug them into an equation to predict the target variable. In this way, it’s relatively similar to the y = ax + b case.

In the graph that you’ve seen before and the following graphs in this section, the target variable is the shape of the data point, and the independent variables are height and width. You can see the idea behind supervised learning in the following graph:

Read the full article at https://realpython.com/knn-python/ »

[ 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 for Beginners: Single Line and Multi Line Comments in Python

Planet Python - Wed, 2021-04-07 07:45

A comment is a piece of code that isn’t executed by the compiler or interpreter when the program is executed. Comments can only be read when we have access to the source code. Comments are used to explain the source code and to make the code more readable and understandable. In this article, we will see how to write single line and multi line comments using different methods in python.

What is a single line comment in python?

Single line comments are those comments which are written without giving a line break or newline in python. A python comment is written by initializing the text of comment with a # and terminates when the end of line is encountered. The following example shows a single line comment in a program where a function is defined to add a number and its square to a python dictionary as key value pair.

#This is a single line comment in python def add_square_to_dict(x,mydict): a=x*x mydict[str(x)]=a return mydict

We can also add a single line comment after another statement.

#This is a single line comment in python print("Pythonforbeginners.com") #This is also a python comment What is a multi line comment?

As the name specifies, a multi line comment expands up to multiple lines. But python does not have syntax for multi line comments. We can implement multi line comments in python using single line comments or triple quoted python strings.

How to implement multi line comments using # sign?

To implement multi line comments using # sign, we can simply depict each line of a multi line comment as a single line comment. Then we can start each line by using # symbol and we can implement multi line comments.

#This is a multiline comment in python #and expands to more than one line print("Pythonforbeginners.com")

When writing multi line comments using # symbol, we can also start multi line comments after any python statement.

#This is a multiline comment in python #and expands to more than one line print("Pythonforbeginners.com") #This is also a python comment #and it also expands to more than one line. How to implement multi line comments using triple quoted strings?

Multi line strings in python can be used as multi line comments if they are not assigned to variables. When the string isn’t assigned to any variable, they are parsed and evaluated by the interpreter but no byte code is generated because no address can be assigned to the strings. Effectively the unassigned multi line string works as a multi line comment.  

"""This is a multiline comment in python which expands to many lines"""

Here we have to keep in mind that the multi line comments are only string constants that have not been assigned to any variable. So they have to be properly intended unlike single line comments with # symbol so that syntax errors can be avoided.

Also, multi line comments which use triple quotes should always start with a newline which is not the case for a single line comment. 

#This is a multiline comment in python #and expands to more than one line """This is a multiline comment in python which expands to many lines""" print("Pythonforbeginners.com") """This is not a multiline comment in python and will cause syntax error""" Conclusion

In this article, we have seen how to write single line and multi line comments in python. We have also seen how to write multi line comments using strings. Stay tuned for more informative articles.

The post Single Line and Multi Line Comments in Python appeared first on PythonForBeginners.com.

Categories: FLOSS Project Planets

Learn PyQt: Create applications with QtQuick — Build modern applications with declarative QML

Planet Python - Wed, 2021-04-07 07:00

In previous tutorials we've used the Qt Widgets API for building our applications. This has been the standard method for building applications since Qt was first developed. However, Qt provides another API for building user interfaces: Qt Quick. This is a modern mobile-focused API for app development, with which you can create dynamic and highly customizable user interfaces.

QtQuick

Qt Quick uses a declarative scripting language -- the Qt Modeling Language (QML) -- to define user interfaces. With it you can build completely custom UIs, with dynamic graphical elements and fluid transitions and effects. UIs build with QML have more in common with mobile apps than traditional desktop applications, reflecting it's origin with Nokia, but Qt Quick can be used on all platforms supported by Qt.

QML syntax also supports embedded Javascript which can be used to handle application logic -- in simple applications the entire app can be implemented in the QML! But using PyQt/PySide you can also write your application code in Python and hook this up to your QML. This has the advantage of keeping your UI design (QML) and business logic (Python) implementation properly isolated, and gives you access to all the Python libraries to power the backend of your app.

Before starting this tutorial you will need to install PyQt or PySide, see the installation guides.

For building QML applications you can use PyQt5, PySide2, PyQt6 or PySide6. If using Qt 6 you will need v6.1 or later.

Getting started

In this tutorial we will be using PyQt/PySide with the Qt Quick/QML API. If you've used Qt Widgets before, many of the Qt Quick concepts will seem familiar. While QML does not make use of QtWidget classes, all the other parts of Qt (QtCore, QtGui, etc.) are still available.

Before we start writing out application, we can set up our project folder with the files we'll need in the right structure. You can also download a zip file containing these files.

  • Create a project folder for the app, in our example we will call it: clock
  • Inside your clock folder create an empty file named main.py
  • Create a file alongside main.py named main.qml, to hold our UI definition in QML
  • Create an empty folder alongside the main.py and main.qml called images
Creating a “Hello World” app

Open up the main.py in your editor and add the following skeleton code. This is the bare minimum code required to load a QML file and display it using the QML application engine.

main.py

python import sys from PyQt5.QtGui import QGuiApplication from PyQt5.QtQml import QQmlApplicationEngine app = QGuiApplication(sys.argv) engine = QQmlApplicationEngine() engine.quit.connect(app.quit) engine.load('./UI/main.qml') sys.exit(app.exec()) python import sys from PySide2.QtGui import QGuiApplication from PySide2.QtQml import QQmlApplicationEngine app = QGuiApplication(sys.argv) engine = QQmlApplicationEngine() engine.quit.connect(app.quit) engine.load('./UI/main.qml') sys.exit(app.exec_()) python import sys from PyQt6.QtGui import QGuiApplication from PyQt6.QtQml import QQmlApplicationEngine app = QGuiApplication(sys.argv) engine = QQmlApplicationEngine() engine.quit.connect(app.quit) engine.load('main.qml') sys.exit(app.exec()) python import sys from PySide6.QtGui import QGuiApplication from PySide6.QtQml import QQmlApplicationEngine app = QGuiApplication(sys.argv) engine = QQmlApplicationEngine() engine.quit.connect(app.quit) engine.load('main.qml') sys.exit(app.exec_())

The above code calls QGuiApplication and QQmlApplicationEngine Which will use QML instead of QtWidgets as the UI layer for the Qt Application. It then connects the UI layers quit function with the app’s main quit function. So both can close when the UI has been closed by the user. Next it loads the QML file as the QML code for the UI. The app.exec() starts the Qt event loop and launches the application, just as in Qt Widgets.

Here the call to app.exec() is wrapped inside sys.exit() to return the exit code to the calling process in case of errors, but this isn't strictly necessary.

Next, add the following code to the main.qml.

main.qml

qml import QtQuick 2.15 import QtQuick.Controls 2.15 ApplicationWindow { visible: true width: 600 height: 500 title: "HelloApp" Text { anchors.centerIn: parent text: "Hello World" font.pixelSize: 24 } }

The above code creates a Window with a width and height as specified, a title of HelloApp and a Text object that is centered in the parent (in this case the window). The text displayed is “Hello World”, with a pixel size of 24px.

The visible: true is very important, without that the UI will be created but will be invisible!

Once you've entered the above into the two files and save them, you can run it and see the result. You can run the code like any other Python script -- navigate into the folder containing the main.py script and run it using python (or python3 depending on your system).

shell $ cd helloApp $ python main.py

When the application launches you should see a window which looks like the following.

Success! We have a QML application, although it's very basic to start with. Next we'll modify the UI to make it a little more interesting and build towards a simple clock.

Updating the UI design

First lets add an image as a background.

Place this image in the folder we created earlier named images. This will be the background for our application window.

A simple background image with a gradient effect

If you like, you can substitute any other image you have. We'll be placing white text over it, so dark simple images will work better.

main.qml

qml import QtQuick 2.15 import QtQuick.Controls 2.15 ApplicationWindow { visible: true width: 400 height: 600 title: "Clock" Rectangle { anchors.fill: parent Image { anchors.fill: parent source: "./images/background.png" loading="lazy" width="564" height="1003" fillMode: Image.PreserveAspectCrop } Rectangle { anchors.fill: parent color: "transparent" Text { text: "16:38:33" font.pixelSize: 24 color: "white" } } } }

In this QML file we've defined our main application window using the ApplicationWindow object type. Within this we've defined an Image which holds our background image, filling the parent. The fillMode defines how the image will be sized. In this example we've set the image to fill the parent window using anchors.fill: parent while preserving aspect ratio and cropping. This ensures the image fills the window area, without being deformed. You can also set the image to follow the size of the parent using sourceSize, e.g.

qml Image { sourceSize.width: parent.width sourceSize.height: parent.height source: "./images/playas.jpg" fillMode: Image.PreserveAspectCrop }

This approach allows you some more control -- for example, you could scale an image to half the size of the parent window by dividing the sizes in two and use this to tile multiple images.

qml Image { sourceSize.width: parent.width/2 sourceSize.height: parent.height/2 source: "./images/background.png" loading="lazy" width="564" height="1003" fillMode: Image.PreserveAspectCrop }

Alongside the Image we've also defined a transparent Rectangle which also fills the window. Since the rectangle is defined alongside the Image you might think it would appear adjacent in the UI, however since there isn't a layout defined on the window the elements are stacked -- the Rectangle appears on top of the Image.

By default Rectangle objects have a white background.

Finally, inside the rectangle, we've defined a Text object with the text "16:38:33" to mock up a standard time display.

If you run the app now, the text will appear at the top-left corner of our application window.

shell $ python main.py

By default text appears in the top left

Let's move it somewhere else -- down to the bottom-left, with some margins to make it look nicer. In your QML code, update the Text object to include position anchors for the Text and change the size and color of the font.

main.qml

qml Text { anchors { bottom: parent.bottom bottomMargin: 12 left: parent.left leftMargin: 12 } text: "16:38:33" font.pixelSize: 48 color: "white" }

Run the application again as before.

shell $ python main.py

You will see the text has now moved to the bottom left.

Application window with text in the bottom left

So far, our time display is just a fixed text string -- it doesn't update, and unless you run it at the right time, it's going to be wrong. Not the most useful of clocks! Next we'll add some Python code to get the current system time and update our clock display automatically.

Getting the time from Python

The Python standard library provides functions for handling time and date, including a number of options for getting the current time. For example, the Python function time.gmtime() provides a struct containing the current GMT time, while time.localtime() will give the time in your current local timezone.

Once you have a time struct you can pass this to the time.strftime() function to get a properly formatted string. The strftime function accepts two arguments -- first a time format string, and second the time struct to use. The time format string uses tokens such as %H to place specific parts of the time date in a specific format.

For example, if you enter the following in a Python shell you'll get the current GMT (UTC) time output.

python from time import strftime, gmtime strftime("%H:%M:%S", gmtime())

The %H, %M and %S tokens tell strftime to insert the hours (24 hour, zero padded), minutes (zero padded) and seconds (zero padded) into the string.

You can read more about format codes for strftime in the Python documentation.

For local time, you can use the localtime method instead of gmtime.

python from time import strftime, localtime strftime("%H:%M:%S", localtime())

This adjusts to your computers local time settings and should output the same time displayed on your computer's clock.

If you're used to working with datetime objects, every datetime has a .strftime() method, which uses the same format strings and returns the same output. For example, the following will give the same output as the localtime example above.

python from time import strftime from datetime import datetime datetime.now().strftime("%H:%M:%S") Updating our app time display

To pass our formatted time string from Python to QML we can use QML properties. First, let's define a property on our QML ApplicationWindow called currTime. Update your QML code in main.qml as follows:

main.qml

qml ... ApplicationWindow { ... title: "Clock" property string currTime: "00:00:00" ...

The ... marks indicate where existing code should be left as it is.

Next, modify the text object to use the currTime property as its text value. When the currTime property is modified the text label will update automatically (along with any other places it is used).

main.qml

qml ... Text { ... text: currTime // used to be; text: "16:38:33" font.pixelSize: 48 color: "white" } ...

Finally, we need to send out curr_time variable from our Python code through to QML. Modified the Python code to add the time formatting code, using localtime() and then setting this property onto the QML object. The following code will set the QML property currTime to value of the Python variable curr_time.

main.py

python import sys from PyQt5.QtGui import QGuiApplication from PyQt5.QtQml import QQmlApplicationEngine from time import strftime, localtime app = QGuiApplication(sys.argv) engine = QQmlApplicationEngine() engine.quit.connect(app.quit) engine.load('main.qml') # Pass the current time to QML. curr_time = strftime("%H:%M:%S", localtime()) engine.rootObjects()[0].setProperty('currTime', curr_time) sys.exit(app.exec()) python import sys from PySide2.QtGui import QGuiApplication from PySide2.QtQml import QQmlApplicationEngine from time import strftime, localtime app = QGuiApplication(sys.argv) engine = QQmlApplicationEngine() engine.quit.connect(app.quit) engine.load('main.qml') # Pass the current time to QML. curr_time = strftime("%H:%M:%S", localtime()) engine.rootObjects()[0].setProperty('currTime', curr_time) sys.exit(app.exec_()) python import sys from PyQt5.QtGui import QGuiApplication from PyQt5.QtQml import QQmlApplicationEngine from time import strftime, localtime app = QGuiApplication(sys.argv) engine = QQmlApplicationEngine() engine.quit.connect(app.quit) engine.load('main.qml') # Pass the current time to QML. curr_time = strftime("%H:%M:%S", localtime()) engine.rootObjects()[0].setProperty('currTime', curr_time) sys.exit(app.exec()) python import sys from PySide6.QtGui import QGuiApplication from PySide6.QtQml import QQmlApplicationEngine from time import strftime, localtime app = QGuiApplication(sys.argv) engine = QQmlApplicationEngine() engine.quit.connect(app.quit) engine.load('main.qml') # Pass the current time to QML. curr_time = strftime("%H:%M:%S", localtime()) engine.rootObjects()[0].setProperty('currTime', curr_time) sys.exit(app.exec_())

The code engine.rootObjects()[0] gets all the root objects from the QML engine as a list. Our ApplicationWindow object is a root object because it appears at the top of the hierarchy. Next we use [0] to select the first item in that list -- in our case, there is only one item, our ApplicationWindow and that is what is returned. The .setProperty method is then called on that object.

If you run the application now, you should see the correct time displayed in the window. This means the time will be correct when the application starts -- try closing it and re-running it to see the time update. But you'll notice that the time doesn't update yet -- we'll do that next.

The correct time (at least it was when I took the screenshot)

Updating the time using timers

To update the timer we need to run our time fetching and formatting code on a regular interval (every second). There are two options for implementing this

  1. using a timer which fires every 1 second triggering our time method
  2. using a long-running thread, which calculates the time with a delay (sleep) between each update

In Qt timers are handled on the GUI thread main loop, meaning that each time the timer is triggered the GUI is blocked while the function is executed. If that function is long running this can become noticeable in the UI. In that case, using a thread makes more sense. But here, our time fetching and formatting code is very quick -- there will be no noticeable delay. For that reason, in this example we'll use a simple timer.

setProperty

Based on the code we have so far, the simplest approach to updating the time automatically is to just take our update code, wrap it inside a function and then call that function repeatedly using a timer. The following code shows this approach in action, using a QTimer with an interval of 1000 msecs (1 second).

main.py

python import sys from PyQt5.QtGui import QGuiApplication from PyQt5.QtQml import QQmlApplicationEngine from PyQt5.QtCore import QTimer from time import strftime, localtime app = QGuiApplication(sys.argv) engine = QQmlApplicationEngine() engine.quit.connect(app.quit) engine.load('main.qml') def update_time(): # Pass the current time to QML. curr_time = strftime("%H:%M:%S", localtime()) engine.rootObjects()[0].setProperty('currTime', curr_time) timer = QTimer() timer.setInterval(1000) # msecs 1000 = 1 sec timer.timeout.connect(update_time) timer.start() sys.exit(app.exec()) python import sys from PyQt5.QtGui import QGuiApplication from PyQt5.QtQml import QQmlApplicationEngine from PyQt5.QtCore import QTimer from time import strftime, localtime app = QGuiApplication(sys.argv) engine = QQmlApplicationEngine() engine.quit.connect(app.quit) engine.load('main.qml') def update_time(): # Pass the current time to QML. curr_time = strftime("%H:%M:%S", localtime()) engine.rootObjects()[0].setProperty('currTime', curr_time) timer = QTimer() timer.setInterval(1000) # msecs 1000 = 1 sec timer.timeout.connect(update_time) timer.start() sys.exit(app.exec_()) python import sys from PyQt6.QtGui import QGuiApplication from PyQt6.QtQml import QQmlApplicationEngine from PyQt6.QtCore import QTimer from time import strftime, localtime app = QGuiApplication(sys.argv) engine = QQmlApplicationEngine() engine.quit.connect(app.quit) engine.load('main.qml') def update_time(): # Pass the current time to QML. curr_time = strftime("%H:%M:%S", localtime()) engine.rootObjects()[0].setProperty('currTime', curr_time) timer = QTimer() timer.setInterval(1000) # msecs 1000 = 1 sec timer.timeout.connect(update_time) timer.start() update_time() # initial startup sys.exit(app.exec()) python import sys from PySide6.QtGui import QGuiApplication from PySide6.QtQml import QQmlApplicationEngine from PySide6.QtCore import QTimer from time import strftime, localtime app = QGuiApplication(sys.argv) engine = QQmlApplicationEngine() engine.quit.connect(app.quit) engine.load('main.qml') def update_time(): # Pass the current time to QML. curr_time = strftime("%H:%M:%S", localtime()) engine.rootObjects()[0].setProperty('currTime', curr_time) timer = QTimer() timer.setInterval(1000) # msecs 1000 = 1 sec timer.timeout.connect(update_time) timer.start() update_time() # initial startup sys.exit(app.exec_())

If you run this you'll see the time updating correctly.

You may also notice that when the application is first run the time displays as '00:00:00' (the default value) for a second. That is because the UI is rendered before the first interval timer executes. You can avoid this by adding a call to update_time() just before app.exec() is called, e.g.

python update_time() # initial startup sys.exit(app.exec()) python update_time() # initial startup sys.exit(app.exec_())

Now, when the app launches it will be showing the correct time immediately.

Using signals

While this approach of setting properties from the Python code works well for this small example it's not ideal as your applications grow in size. By hooking your Python code to change specific properties in your QML you are tying your Python code to the structure of the UI. That makes it easy to break things when restructuring your applications. Just like in the Qt Widgets API you can use Qt signals to avoid this problem: your code can emit signals without needing to know where they will be received, or how they will be used -- and you can even hook a single signal up to multiple receivers. This keeps your logic and UI code nicely decoupled.

If you're not familiar with Qt signals, take a look at our Signals, Slots & Events tutorials.

Let's rework our example to make use of Qt signals in Python & QML to achieve the same result.

First we must define our signals in the main.py file. Signals can only be defined on objects that are subclassed from QObject so we'll need to implement a small class. This is also a logical place to put our time-handling code to keep things nicely self-contained. We'll also define our signal for passing the current time to QML.

Multiple signals can be handled under a single QObject class and it often makes sense to use a single class for simplicity.

main.py

python import sys from PyQt5.QtGui import QGuiApplication from PyQt5.QtQml import QQmlApplicationEngine from PyQt5.QtCore import QTimer, QObject, pyqtSignal from time import strftime, localtime app = QGuiApplication(sys.argv) engine = QQmlApplicationEngine() engine.quit.connect(app.quit) engine.load('main.qml') class Backend(QObject): updated = pyqtSignal(str, arguments=['time']) def __init__(self): super().__init__() # Define timer. self.timer = QTimer() self.timer.setInterval(1000) # msecs 1000 = 1 sec self.timer.timeout.connect(self.update_time) self.timer.start() def update_time(self): # Pass the current time to QML. curr_time = strftime("%H:%M:%S", localtime()) self.updated.emit(curr_time) # Define our backend object, which we pass to QML. backend = Backend() engine.rootObjects()[0].setProperty('backend', backend) # Initial call to trigger first update. Must be after the setProperty to connect signals. backend.update_time() sys.exit(app.exec()) python import sys from PySide2.QtGui import QGuiApplication from PySide2.QtQml import QQmlApplicationEngine from PySide2.QtCore import QTimer, QObject, Signal from time import strftime, localtime app = QGuiApplication(sys.argv) engine = QQmlApplicationEngine() engine.quit.connect(app.quit) engine.load('main.qml') class Backend(QObject): updated = Signal(str, arguments=['time']) def __init__(self): super().__init__() # Define timer. self.timer = QTimer() self.timer.setInterval(1000) # msecs 1000 = 1 sec self.timer.timeout.connect(self.update_time) self.timer.start() def update_time(self): # Pass the current time to QML. curr_time = strftime("%H:%M:%S", localtime()) self.updated.emit(curr_time) # Define our backend object, which we pass to QML. backend = Backend() engine.rootObjects()[0].setProperty('backend', backend) # Initial call to trigger first update. Must be after the setProperty to connect signals. backend.update_time() sys.exit(app.exec_()) python import sys from PyQt6.QtGui import QGuiApplication from PyQt6.QtQml import QQmlApplicationEngine from PyQt6.QtCore import QTimer, QObject, pyqtSignal from time import strftime, localtime app = QGuiApplication(sys.argv) engine = QQmlApplicationEngine() engine.quit.connect(app.quit) engine.load('main.qml') class Backend(QObject): updated = pyqtSignal(str, arguments=['time']) def __init__(self): super().__init__() # Define timer. self.timer = QTimer() self.timer.setInterval(1000) # msecs 1000 = 1 sec self.timer.timeout.connect(self.update_time) self.timer.start() def update_time(self): # Pass the current time to QML. curr_time = strftime("%H:%M:%S", localtime()) self.updated.emit(curr_time) # Define our backend object, which we pass to QML. backend = Backend() engine.rootObjects()[0].setProperty('backend', backend) # Initial call to trigger first update. Must be after the setProperty to connect signals. backend.update_time() sys.exit(app.exec()) python import sys from PySide6.QtGui import QGuiApplication from PySide6.QtQml import QQmlApplicationEngine from PySide6.QtCore import QTimer, QObject, Signal from time import strftime, localtime app = QGuiApplication(sys.argv) engine = QQmlApplicationEngine() engine.quit.connect(app.quit) engine.load('main.qml') class Backend(QObject): updated = Signal(str, arguments=['time']) def __init__(self): super().__init__() # Define timer. self.timer = QTimer() self.timer.setInterval(1000) # msecs 1000 = 1 sec self.timer.timeout.connect(self.update_time) self.timer.start() def update_time(self): # Pass the current time to QML. curr_time = strftime("%H:%M:%S", localtime()) self.updated.emit(curr_time) # Define our backend object, which we pass to QML. backend = Backend() engine.rootObjects()[0].setProperty('backend', backend) # Initial call to trigger first update. Must be after the setProperty to connect signals. backend.update_time() sys.exit(app.exec_())

While this looks like a lot of changes, the majority of the code is exactly the same, just reorganized to put everything under the container class. Everything in __init__ will be run when we create an instance of the Backend class using backend = Backend().

The signal definition (repeated below) creates a signal which accepts a single parameter -- a string. This will be sent with the signal to the receivers. The arguments= parameter is used to define the names under which the arguments will be known in QML (if using keyword arguments).

python updated = pyqtSignal(str, arguments=['time']) python updated = Signal(str, arguments=['time'])

You'll also notice that we pass our backend object through to QML. This allows the signal we've just implemented to be used from the QML code and hooked up to an appropriate target.

python engine.rootObjects()[0].setProperty('backend', backend)

As before we need to implement the property in QML which these will set. Previously when defining our property to receive the formatted time string, we used a string type. This isn't appropriate for the Backend object, as it's not a string. To receive the Backend object (which is a QObject) from Python we need to use the QtObject type.

main.qml

qml ... property string currTime: "00:00:00" property QtObject backend ...

There are not that many types. QML converts python base types into bool, int, double, string, list, QtObject and var. The var type is a generic handler which can handle any Python type.

To receive the signal itself, we need to define a Connections object, setting it's target as our backend property (in QML).

main.qml

qml ApplicationWindow { ... Connections { target: backend } ... }

We can now implement any other logic we link inside this Connections object to handle the signals on the backend object. Let's create a signal handler to handle our updated signal. Signal handlers are automatically named using the capitalized form of the signal name, preceded by lowercase on. Underscores and existing capitalization are ignored.

Python name QML name mySignal onMySignal mysignal onMysignal my_signal onMy_signal

main.qml

qml ApplicationWindow { ... Connections { target: backend function onUpdated(msg) { currTime = msg; } ... }

The above code shows the signal handler for the updated signal, named onUpdated. This receives the current time as a string (named msg) and sets that onto the QML property currTime. As before, setting this property automatically updates the associated text label.

If you run the application now, you'll see the time updating exactly the same as before!

We could replace the Python time formatting with formatting code in Javascript inside QML if we wanted and send a timestamp as a signal. In fact, you can get the time and define timers in QML too!

Removing the window decorations

To create a desktop-widget like application you can hide the window decorations on your QML app. This removes the title bar and buttons for closing/minimizing the app. However, you can still close the window from the taskbar if you need to. Make the following changes to the top of the QML file, setting the flags property and positioning the widget into the bottom right of the display.

main.qml

qml ... ApplicationWindow { visible: true width: 400 height: 600 x: screen.desktopAvailableWidth - width - 12 y: screen.desktopAvailableHeight - height - 48 title: "Clock" flags: Qt.FramelessWindowHint | Qt.Window ...

The code sets x, y for the window and adds the flag Qt.Window to make the window frameless. The Qt.Window flag ensures that even though the window is frameless, we still get an entry on the taskbar. Run it, and you will see the window we've created.

The final view with the updating clock and no window decorations

In the next tutorial we'll expand on this simple clock by using image manipulations, transitions and animations to build a fully-functional analog clock.

The complete final code

Below is the complete final code for PyQt5, PySide2, PyQt6 and PySide6.

main.py

python import sys from PyQt5.QtGui import QGuiApplication from PyQt5.QtQml import QQmlApplicationEngine from PyQt5.QtCore import QTimer, QObject, pyqtSignal from time import strftime, localtime app = QGuiApplication(sys.argv) engine = QQmlApplicationEngine() engine.quit.connect(app.quit) engine.load('main.qml') class Backend(QObject): updated = pyqtSignal(str, arguments=['time']) def __init__(self): super().__init__() # Define timer. self.timer = QTimer() self.timer.setInterval(1000) # msecs 1000 = 1 sec self.timer.timeout.connect(self.update_time) self.timer.start() def update_time(self): # Pass the current time to QML. curr_time = strftime("%H:%M:%S", localtime()) self.updated.emit(curr_time) # Define our backend object, which we pass to QML. backend = Backend() engine.rootObjects()[0].setProperty('backend', backend) # Initial call to trigger first update. Must be after the setProperty to connect signals. backend.update_time() sys.exit(app.exec()) python import sys from PySide2.QtGui import QGuiApplication from PySide2.QtQml import QQmlApplicationEngine from PySide2.QtCore import QTimer, QObject, Signal from time import strftime, localtime app = QGuiApplication(sys.argv) engine = QQmlApplicationEngine() engine.quit.connect(app.quit) engine.load('main.qml') class Backend(QObject): updated = Signal(str, arguments=['time']) def __init__(self): super().__init__() # Define timer. self.timer = QTimer() self.timer.setInterval(1000) # msecs 1000 = 1 sec self.timer.timeout.connect(self.update_time) self.timer.start() def update_time(self): # Pass the current time to QML. curr_time = strftime("%H:%M:%S", localtime()) self.updated.emit(curr_time) # Define our backend object, which we pass to QML. backend = Backend() engine.rootObjects()[0].setProperty('backend', backend) # Initial call to trigger first update. Must be after the setProperty to connect signals. backend.update_time() sys.exit(app.exec()) python import sys from PyQt5.QtGui import QGuiApplication from PyQt5.QtQml import QQmlApplicationEngine from PyQt5.QtCore import QTimer, QObject, pyqtSignal from time import strftime, localtime app = QGuiApplication(sys.argv) engine = QQmlApplicationEngine() engine.quit.connect(app.quit) engine.load('main.qml') class Backend(QObject): updated = pyqtSignal(str, arguments=['time']) def __init__(self): super().__init__() # Define timer. self.timer = QTimer() self.timer.setInterval(1000) # msecs 1000 = 1 sec self.timer.timeout.connect(self.update_time) self.timer.start() def update_time(self): # Pass the current time to QML. curr_time = strftime("%H:%M:%S", localtime()) self.updated.emit(curr_time) # Define our backend object, which we pass to QML. backend = Backend() engine.rootObjects()[0].setProperty('backend', backend) # Initial call to trigger first update. Must be after the setProperty to connect signals. backend.update_time() sys.exit(app.exec()) python import sys from PySide2.QtGui import QGuiApplication from PySide2.QtQml import QQmlApplicationEngine from PySide2.QtCore import QTimer, QObject, Signal from time import strftime, localtime app = QGuiApplication(sys.argv) engine = QQmlApplicationEngine() engine.quit.connect(app.quit) engine.load('main.qml') class Backend(QObject): updated = Signal(str, arguments=['time']) def __init__(self): super().__init__() # Define timer. self.timer = QTimer() self.timer.setInterval(1000) # msecs 1000 = 1 sec self.timer.timeout.connect(self.update_time) self.timer.start() def update_time(self): # Pass the current time to QML. curr_time = strftime("%H:%M:%S", localtime()) self.updated.emit(curr_time) # Define our backend object, which we pass to QML. backend = Backend() engine.rootObjects()[0].setProperty('backend', backend) # Initial call to trigger first update. Must be after the setProperty to connect signals. backend.update_time() sys.exit(app.exec_())

main.qml

qml import QtQuick 2.15 import QtQuick.Controls 2.15 ApplicationWindow { visible: true width: 400 height: 600 x: screen.desktopAvailableWidth - width - 12 y: screen.desktopAvailableHeight - height - 48 title: "Clock" flags: Qt.FramelessWindowHint | Qt.Window property string currTime: "00:00:00" property QtObject backend Rectangle { anchors.fill: parent Image { sourceSize.width: parent.width sourceSize.height: parent.height source: "./images/background.png" loading="lazy" width="564" height="1003" fillMode: Image.PreserveAspectCrop } Rectangle { anchors.fill: parent color: "transparent" Text { anchors { bottom: parent.bottom bottomMargin: 12 left: parent.left leftMargin: 12 } text: currTime // used to be; text: "16:38:33" font.pixelSize: 48 color: "white" } } } Connections { target: backend function onUpdated(msg) { currTime = msg; } } }

Now you have your basic QML application, you should experiment with customizing and changing the behavior. Try changing the background image, modifying the text color or sending different (or multiple bits) of information from Python to your app.

See the complete PyQt5 tutorial, from first steps to complete applications with Python & Qt5.

Categories: FLOSS Project Planets

EuroPython: Presenting our EuroPython 2021 logo

Planet Python - Wed, 2021-04-07 06:17

Over the last couple of weeks, we have worked with our designer Jessica Peña to come up with a logo which reflects both our desire to come together online during the pandemic and shows how well our community is interconnected around the world.

Here's our brand new logo for EuroPython 2021 Online:

Hope you like it 😃

We will soon make EuroPython 2021 merchandise available with the new logo in our EuroPython merch shop, so you can order t-shirts, sweatshirts, caps and mugs to show your support and love for the conference.

Enjoy,
EuroPython 2021 Team
EuroPython Society
https://www.europython-society.org/

Categories: FLOSS Project Planets

Pages