Feeds

Migrating dinner plans

Planet KDE - Mon, 2022-11-28 18:00

It’s fall, the leaves are on the ground, there are pumpkins on the table (and my local vegetable farm has blogged that the seasons are so screwed up due to climate change that it is no longer predictable which veggies show up when) and so, stew and hearty soup season is upon us.

“If I was to become a vegetarian, what kind of stew would we eat?” was a question kid[1] (the only one still at home) put to me. Good question. I have vague ideas about lentils and celery root and beans and tahin, but nothing as concrete as my beef stew recipe (1 chunk of cow, 1 bottle of beer, 6 onions, 1 potato and seasoning). It bears investigating.

Since kid[0] left the house – and they were the principled vegetarian here – we’ve relapsed to flexitarian habits, 1 meat, 6 vegetarian dinners a week with an accidentally-vegan thrown in with some regularity.

As an odd coincidence, both SMBC and my (paper!) paper NRC published something about eating invasive species this week. Household consensus is that if the cook cuts themself while making dinner, it’s still vegetarian.

I’ll leave you with a concrete recipe (if you come over this evening, this is what’s for dinner).

  • 1 pumpkin
  • 6 carrots
  • 2 potatoes
  • 2 bouillion cubes
  • 1 tablespoon curry powder, the nasty yellowish stuff from the supermarket
  • 2 tablespoons dried parsley or chives

Put all but the parsley in a big pot. Add water to just about cover the veggies. Boil softly for 20-25 minutes. Staafmix the heck out of it (um .. puree? I have not used this particular kitchen utensil in an English-speaking kitchen, so I wouldn’t know what verb to use for “apply a staafmixer until smooth”). Stir in the parsley.

Serve with fresh-baked bread.

Categories: FLOSS Project Planets

Andy Wingo: are ephemerons primitive?

GNU Planet! - Mon, 2022-11-28 16:11

Good evening :) A quick note, tonight: I've long thought that ephemerons are primitive and can't be implemented with mark functions and/or finalizers, but today I think I have a counterexample.

For context, one of the goals of the GC implementation I have been working on on is to replace Guile's current use of the Boehm-Demers-Weiser (BDW) conservative collector. Of course, changing a garbage collector for a production language runtime is risky, and for Guile one of the mitigation strategies for this work is that the new collector is behind an abstract API whose implementation can be chosen at compile-time, without requiring changes to user code. That way we can first switch to BDW-implementing-the-new-GC-API, then switch the implementation behind that API to something else.

Abstracting GC is a tricky problem to get right, and I thank the MMTk project for showing that this is possible -- you have user-facing APIs that need to be implemented by concrete collectors, but also extension points so that the user can provide some compile-time configuration too, for example to provide field-tracing visitors that take into account how a user wants to lay out objects.

Anyway. As we discussed last time, ephemerons are usually have explicit support from the GC, so we need an ephemeron abstraction as part of the abstract GC API. The question is, can BDW-GC provide an implementation of this API?

I think the answer is "yes, but it's very gnarly and will kill performance so bad that you won't want to do it."

the contenders

Consider that the primitives that you get with BDW-GC are custom mark functions, run on objects when they are found to be live by the mark workers; disappearing links, a kind of weak reference; and finalizers, which receive the object being finalized, can allocate, and indeed can resurrect the object.

BDW-GC's finalizers are a powerful primitive, but not one that is useful for implementing the "conjunction" aspect of ephemerons, as they cannot constrain the marker's idea of graph connectivity: a finalizer can only prolong the life of an object subgraph, not cut it short. So let's put finalizers aside.

Weak references have a tantalizingly close kind of conjunction property: if the weak reference itself is alive, and the referent is also otherwise reachable, then the weak reference can be dereferenced. However this primitive only involves the two objects E and K; there's no way to then condition traceability of a third object V to E and K.

We are left with mark functions. These are an extraordinarily powerful interface in BDW-GC, but somewhat expensive also: not inlined, and going against the grain of what BDW-GC is really about (heaps in which the majority of all references are conservative). But, OK. They way they work is, your program allocates a number of GC "kinds", and associates mark functions with those kinds. Then when you allocate objects, you use those kinds. BDW-GC will call your mark functions when tracing an object of those kinds.

Let's assume firstly that you have a kind for ephemerons; then when you go to mark an ephemeron E, you mark the value V only if the key K has been marked. Problem solved, right? Only halfway: you also have to handle the case in which E is marked first, then K. So you publish E to a global hash table, and... well. You would mark V when you mark a K for which there is a published E. But, for that you need a hook into marking V, and V can be any object...

So now we assume additionally that all objects are allocated with user-provided custom mark functions, and that all mark functions check if the marked object is in the published table of pending ephemerons, and if so marks values. This is essentially what a proper ephemeron implementation would do, though there are some optimizations one can do to avoid checking the table for each object before the mark stack runs empty for the first time. In this case, yes you can do it! Additionally if you register disappearing links for the K field in each E, you can know if an ephemeron E was marked dead in a previous collection. Add a pre-mark hook (something BDW-GC provides) to clear the pending ephemeron table, and you are in business.

yes, but no

So, it is possible to implement ephemerons with just custom mark functions. I wouldn't want to do it, though: missing the mostly-avoid-pending-ephemeron-check optimization would be devastating, and really what you want is support in the GC implementation. I think that for the BDW-GC implementation in whippet I'll just implement weak-key associations, in which the value is always marked strongly unless the key was dead on a previous collection, using disappearing links on the key field. That way a (possibly indirect) reference from a value V to a key K can indeed keep K alive, but oh well: it's a conservative approximation of what should happen, and not worse than what Guile has currently.

Good night and happy hacking!

Categories: FLOSS Project Planets

Sam Hartman: Introducing Carthage

Planet Debian - Mon, 2022-11-28 15:59

For the past four years, I’ve been working on Carthage, a free-software Infrastructure as Code framework. We’ve finally reached a point where it makes sense to talk about Carthage and what it can do. This is the first in a series of blog posts to introduce Carthage, discuss what it can do and show how it works.

Why Another IAC Framework

It seems everywhere you look, there are products designed to support the IAC pattern. On the simple side, you could check a Containerfile into Git. Products like Terraform and Vagrant allow you to template cloud infrastructure and VMs. There are more commercial offerings than I can keep up with.

We were disappointed by what was out there when we started Carthage. Other products have improved, but for many of our applications we’re happy with what Carthage can build. The biggest challenge we ran into is that products wanted us to specify things at the wrong level. For some of our cyber training work we wanted to say things like “We want 3 blue teams, each with a couple defended networks, a red team, and some neutral infrastructure for red to exploit.” Yet the tools we were trying to use wanted to lay things out at the individual machine/container level. We found ourselves contemplating writing a program to generate input for some other IAC tool.

Things were worse for our internal testing. Sometimes we’d be shipping hardware to a customer. But sometimes we’d be virtualizing that build out in a lab. Sometimes we’d be doing a mixture. So we wanted to completely separate the descriptions of machines, networks, and software from any of the information about whether that was realized on hardware, VMs, containers, or a mixture.

Dimensional Breakdown

In discussing Carthage with Enrico Zini, he pointed me at Cognitive Dimensions of notation as a way to think about how Carthage approaches the IAC problem. I’m more interested in the idea of breaking down a design along the idea of dimensions that allow examining the design space than I am particular adherence to Green’s original dimensions.

Low Viscosity, High Abstraction Reuse

One of the guiding principles is that we want to be able to reuse different components at different scales and in different environments. These include being able to do things like:

  • Define an operation like “Update a Debian system” and apply that in several environments including as part of building a base VM or container image, applying to an independently managed machine, or applying to a micro service container that does not run services like ssh or systemd.

  • Defining a role like DNS server that can be applied to a dedicated machine only having that role, to a traditional server with multiple roles, or in a micro service environment.

  • Allowing people to write groups of functionality that can be useful in descriptions of a small number of machines, but can also be reused in large environments like modeling of cyber infrastructure to defend. In the small environments, things are simplified, but in larger environments integration like directories, authentication infrastructure and the like is needed.

  • Allow grouping of functionality at multiple levels. So far I have talked about grouping of software to be installed on a single machine or container. We also want to allow groups of containers (pods or otherwise), groups of machines, groups of networks, or even enclaves (think a model of an entire company or section of a company). Each kind of grouping needs to be parametric and reusable.

Hidden Dependencies

To accomplish these abstraction goals, dependencies need to be non-local. For example, a software role might need to integrate with a directory if a directory is present in the environment. When writing the role, no one is going to know which directory to use, nor whether a directory is present. Taking that as an explicit input into the role is error-prone when the role is combined into large abstract units (bigger roles or collections of machines). Instead it is better to have a non-local dependency, and to find the directory if it is available. We accomplish this using dependency injection.

In addition to being non-local, dependencies are sometimes hidden. It is very easy to overwhelm our cognitive capacity with even a fairly simple IAC description. An effective notation allows us to focus on the parts that matter when working with a particular part of the description. I’ve found hiding dependencies, especially indirect dependencies, to be essential in building complex descriptions.

Obviously, tools are required for examining these dependencies as part of debugging.

First Class Modeling

Clearly one of the goals of IAC descriptions is to actually build and manage infrastructure. It turns out that there are all sorts of things you want to do with the description well before you instantiate the infrastructure. You might want to query the description to build network diagrams, understand interdependencies, or even build inventory/bill of materials. We often find ourselves building Ansible inventory, switch configurations, DNS zones, and all sorts of configuration artifacts. These artifacts may be installed into infrastructure that is instantiated by the description, but they may be consumed in other ways. Allowing the artifacts to be consumed externally means that you can avoid pre-commitment and focus on whatever part of the description you originally want to work on. You may use an existing network at first. Later the IAC description may replace that, or perhaps it never will.

As a result, Carthage separates modeling from instantiation. The model can generally be built and queried without needing to interact with clouds, VMs, or containers. We’ve actually found it useful to build Carthage layouts that cannot ever be fully instantiated, for example because they never specify details like whether a model should be instantiated on a container or VM, or what kind of technology will realize a modeled network. This allows developing roles before the machines that use them or focusing on how machines will interact and how the network will be laid out before the details of installing on specific hardware.

The modeling separation is by far the difference I value most between Carthage and other systems.

A Tool for Experts.

In Neal Stephenson’s essay “In the Beginning… Was the Command Line”, Stephenson points out that the kind of tools experts need are not the same tools that beginners need. The illustration of why a beginner might not be satisfied with a Hole Hog drill caught my attention. Carthage is a tool for experts. Despite what cloud providers will tell you, IAC is not easy. Doubly so when you start making reusable components. Trying to hide that or focus on making things easy to get started can make it harder for experts to efficiently solve the problems they are facing. When we have faced trade offs between making Carthage easy to pick up and making it powerful for expert users, we have chosen to support the experts.

That said, Carthage today is harder to pick up than it needs to be. It’s a relatively new project with few external users as of this time. Our documentation and examples need improvement, just like every project at this level of maturity. Similarly, as the set of things people try to do expand, we will doubtless run into bugs that our current test cases don’t cover. So Carthage absolutely will get easier to learn and use than it is today.

Also, we’ve already had success building beginner-focused applications on top of Carthage. For our cyber training, we built web applications on top of Carthage that made rebuilding and exploring infrastructure easy. We’ve had success using relatively understood tools like Ansible as integration and customization points for Carthage layouts. But in all these cases, when the core layout had significant reusable components and significant complexity in the networking, only an IAC expert was going to be able to maintain and develop that layout.

What Carthage can do.

Carthage has a number of capabilities today. One of Carthage’s strengths is its extensible design. Abstract interfaces make it easy to add new virtualization platforms, cloud services, and support for various ways of managing real hardware. This approach has been validated by incrementally adding support for virtualization architectures and cloud services. As development has progressed, adding new integrations continues to get faster because we are able to reuse existing infrastructure.

Today, Carthage can model:

  • Machines
  • Networks
  • Dynamically compose groupings of the above
  • Generate model level artifacts
    • Ansible inventory
    • Various DNS integrations
    • Various switch configurations

Carthage has excellent facilities for dealing with images on which VMs and Containers can be based, although it does have a bit of a Debian/Ubuntu bias in how it thinks about images:

  • Building base images from a tool like debootstrap
  • Customizing these images
  • Converting into VM images for kvm, VMware, and AWS
  • Building from scratch OCI images for Podman, Docker and k8s
  • Adding layers to existing OCI images

When instantiating infrastructure, Carthage can work with:

  • systemd nspawn containers
  • Podman (Docker would be easy)
  • Libvirt
  • VMware
  • With the AWS plugin, EC2 VMs and networking

We have also looked at Oracle Cloud and I believe Openstack, although that code is not merged.

Future posts will talk about core Carthage concepts and how to use Carthage to build infrastructure.



comments
Categories: FLOSS Project Planets

Łukasz Langa: I built an AM5 PC for Python-related things

Planet Python - Mon, 2022-11-28 15:21

16 cores, 128 GB of RAM, an RTX 3090. Sounds great but… don’t be an early adopter. While I’m pretty stoked about what this new machine lets me accomplish, it was quite painful to get it running.

Categories: FLOSS Project Planets

Talking Drupal: Talking Drupal #375 - Being A Creative Director

Planet Drupal - Mon, 2022-11-28 14:00

Today we are talking about Being a Creative Director with Randy Oest.

For show notes visit: www.talkingDrupal.com/375

Topics
  • What is a Creative Director?
  • How is being a CD at a technical company different?
  • Do Drupal CD’s need additional skills?
  • Sometimes things get lost in translation between design and development how do you bridge that gap?
  • How do you mentor?
  • How do you interview for creative positions?
  • Do you hire developers too?
  • Optimal makeup for a team.
  • Guiding the Four Kitchen’s team
  • Inpiration
Resources Hosts

Nic Laflin - www.nLighteneddevelopment.com @nicxvan John Picozzi - www.epam.com @johnpicozzi Randy Oest - randyoest.com @amazingrando

MOTW Correspondent

Martin Anderson-Clutz - @mandclu ECA ECA is a powerful, versatile, and user-friendly rules engine for Drupal 9+. The core module is a processor that validates and executes event-condition-action plugins. Integrated with graphical user interfaces like BPMN.iO, Camunda, ECA Core Modeller or other possible future modellers, ECA is a robust system for building conditionally triggered action sets.

Categories: FLOSS Project Planets

Steve Kemp: I put an LSP in your LISP ..

Planet Debian - Mon, 2022-11-28 11:45

I recently wrote about yet another lisp I'd been having fun with.

Over the past couple of years I've played with a few toy scripting languages, or random interpreters, and this time I figured I'd do something beyond the minimum, by implementing the Language Server Protocol.

In brief the language server protocol (LSP) is designed to abstract functionality that might be provided by an editor, or IDE, into a small "language server". If the language-server knows how to jump to definitions, provide completion, etc, etc, then the editor doesn't need to implement those things for NN different languages - it just needs to launch and communicate with something that does know how to do the job.

Anyway LSP? LISP? Only one letter different, so that's practically enough reason to have a stab at it.

Thankfully I found a beautiful library that implements a simple framework allowing the easy implementation of a golang-based LSP-serverÖ

Using that I quickly hacked up a server that can provide:

  • Overview of all standard-library functions, on hover.
  • Completion of all standard-library functions.

I've tested this in both GNU Emacs and Neovim, so that means I'm happy I support all editors! (More seriously if it works in two then that probably means that the LSP stuff should work elsewhere too.)

Here's what the "help on hover" looks like, within Emacs:

Vim looks similar but you have to press K to see the wee popup. Still kinda cute, and was a good experiment.

Categories: FLOSS Project Planets

John Goerzen: Flying Joy

Planet Debian - Mon, 2022-11-28 11:04

Wisdom from my 5-year-old: When flying in a small plane, it is important to give your dolls a headset and let them see out the window, too!

Moments like this make me smile at being a pilot dad.

A week ago, I also got to give 8 children and one adult their first ever ride in any kind of airplane, through EAA’s Young Eagles program. I got to hear several say, “Oh wow! It’s SO beautiful!” “Look at all the little houses!”

And my favorite: “How can I be a pilot?”

Categories: FLOSS Project Planets

Łukasz Langa: Weekly Report August 1 - 7

Planet Python - Mon, 2022-11-28 10:07

This week I spent helping 3.11.0rc1 get released. This included both reviewing PRs and helping release blockers get resolved. There were two in particular that I spent most time on so I’ll talk briefly about them now.

Categories: FLOSS Project Planets

Real Python: How to Get a List of All Files in a Directory With Python

Planet Python - Mon, 2022-11-28 09:00

Getting a list of all the files and folders in a directory is a natural first step for many file-related operations in Python. When looking into it, though, you may be surprised to find various ways to go about it.

When you’re faced with many ways of doing something, it can be a good indication that there’s no one-size-fits-all solution to your problems. Most likely, every solution will have its own advantages and trade-offs. This is the case when it comes to getting a list of the contents of a directory in Python.

In this tutorial, you’ll be focusing on the most general-purpose techniques in the pathlib module to list items in a directory, but you’ll also learn a bit about some alternative tools.

Source Code: Click here to download the free source code, directories, and bonus materials that showcase different ways to list files and folders in a directory with Python.

Before pathlib came out in Python 3.4, if you wanted to work with file paths, then you’d use the os module. While this was very efficient in terms of performance, you had to handle all the paths as strings.

Handling paths as strings may seem okay at first, but once you start bringing multiple operating systems into the mix, things get more tricky. You also end up with a bunch of code related to string manipulation, which can get very abstracted from what a file path is. Things can get cryptic pretty quickly.

Note: Check out the downloadable materials for some tests that you can run on your machine. The tests will compare the time it takes to return a list of all the items in a directory using methods from the pathlib module, the os module, and even the future Python 3.12 version of pathlib. That new version includes the well-known walk() function, which you won’t cover in this tutorial.

That’s not to say that working with paths as strings isn’t feasible—after all, developers managed fine without pathlib for many years! The pathlib module just takes care of a lot of the tricky stuff and lets you focus on the main logic of your code.

It all begins with creating a Path object, which will be different depending on your operating system (OS). On Windows, you’ll get a WindowsPath object, while Linux and macOS will return PosixPath:

>>>>>> import pathlib >>> desktop = pathlib.Path("C:/Users/RealPython/Desktop") >>> desktop WindowsPath("C:/Users/RealPython/Desktop") >>>>>> import pathlib >>> desktop = pathlib.Path("/home/RealPython/Desktop") >>> desktop PosixPath('/home/RealPython/Desktop')

With these OS-aware objects, you can take advantage of the many methods and properties available, such as ones to get a list of files and folders.

Note: If you’re interested in learning more about pathlib and its features, then check out Python 3’s pathlib Module: Taming the File System and the pathlib documentation.

Now, it’s time to dive into listing folder contents. Be aware that there are several ways to do this, and picking the right one will depend on your specific use case.

Getting a List of All Files and Folders in a Directory in Python

Before getting started on listing, you’ll want a set of files that matches what you’ll encounter in this tutorial. In the supplementary materials, you’ll find a folder called Desktop. If you plan to follow along, download this folder and navigate to the parent folder and start your Python REPL there:

Source Code: Click here to download the free source code, directories, and bonus materials that showcase different ways to list files and folders in a directory with Python.

You could also use your own desktop too. Just start the Python REPL in the parent directory of your desktop, and the examples should work, but you’ll have your own files in the output instead.

Note: You’ll mainly see WindowsPath objects as outputs in this tutorial. If you’re following along on Linux or macOS, then you’ll see PosixPath instead. That’ll be the only difference. The code you write is the same on all platforms.

If you only need to list the contents of a given directory, and you don’t need to get the contents of each subdirectory too, then you can use the Path object’s .iterdir() method. If your aim is to move through directories and subdirectories recursively, then you can jump ahead to the section on recursive listing.

The .iterdir() method, when called on a Path object, returns a generator that yields Path objects representing child items. If you wrap the generator in a list() constructor, then you can see your list of files and folders:

>>>>>> import pathlib >>> desktop = pathlib.Path("Desktop") >>> # .iterdir() produces a generator >>> desktop.iterdir() <generator object Path.iterdir at 0x000001A8A5110740> >>> # Which you can wrap in a list() constructor to materialize >>> list(desktop.iterdir()) [WindowsPath('Desktop/Notes'), WindowsPath('Desktop/realpython'), WindowsPath('Desktop/scripts'), WindowsPath('Desktop/todo.txt')]

Passing the generator produced by .iterdir() to the list() constructor provides you with a list of Path objects representing all the items in the Desktop directory.

As with all generators, you can also use a for loop to iterate over each item that the generator yields. This gives you the chance to explore some of the properties of each object:

>>>>>> desktop = pathlib.Path("Desktop") >>> for item in desktop.iterdir(): ... print(f"{item} - {'dir' if item.is_dir() else 'file'}") ... Desktop\Notes - dir Desktop\realpython - dir Desktop\scripts - dir Desktop\todo.txt - file Read the full article at https://realpython.com/get-all-files-in-directory-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: Sort a Pandas Series in Python

Planet Python - Mon, 2022-11-28 09:00

Pandas series is used to handle sequential data in python. In this article, we will discuss different ways to sort a pandas series in Python. 

Table of Contents
  1. Sort a series using the sort_values() method
  2. Sort a Series in Ascending Order in Python
  3. Sort a Pandas Series in Descending Order
  4. Sort a Series Having NaN Values in Python
  5. Sort a Series Inplace in Python
  6. Sort a Pandas Series Using a Key
  7. The sort_index() Method in Python
  8. Sort a Pandas Series by Index in Ascending Order
  9. Sort a Series by Index in Descending Order in Python
  10. Sort a Pandas Series by Index Having NaN Values
  11. Sort a Series by Index Inplace in Python
  12. Sort a Pandas Series by Index Using a Key in Python
  13. Conclusion
Sort a series using the sort_values() method

You can sort a pandas series using the sort_values() method. It has the following syntax.

Series.sort_values(*, axis=0, ascending=True, inplace=False, kind='quicksort', na_position='last', ignore_index=False, key=None)

Here, 

  • The axis parameter is used to decide if we want to sort a dataframe by a column or row. For series, the axis parameter is unused. It is defined just for the compatibility of the sort_values() method with pandas dataframes.
  • By default, the sort_values() method sorts a series in ascending order. If you want to sort a series in descending order, you can set the ascending parameter to True. 
  • After execution, the sort_values() method returns the sorted series. It doesn’t modify the original series. To sort and modify the original series instead of creating a new series, you can set the inplace parameter to True.
  • The kind parameter is used to determine the sorting algorithm. By default, the “quicksort” algorithm is used. If your data has a specific pattern where another sorting algorithm can be efficient, you can use  ‘mergesort’, ‘heapsort’, or ‘stable’ sorting algorithm.
  • The na_position parameter is used to determine the position of NaN values in the sorted series. By default, the NaN values are stored at the last of the sorted series. You can set the na_position parameter to “first” to store the NaN values at the top of the sorted series.  
  • When we sort a series, the index of all the values is shuffled when the values are sorted. Due to this, the indices in the sorted series are in no order. If you want to reset the indices after sorting, you can set the ignore_index parameter to True.
  • The key parameter is used to perform operations on the series before sorting. It takes a vectorized function as its input argument. The function provided to the key parameter must take a pandas series as its input argument and return a pandas series. Before sorting, the function is applied to the series. The values in the output of the function are then used to sort the series. 
Sort a Series in Ascending Order in Python

To sort a series in ascending order, you can use the sort_values() method on the series object as shown in the following example.

import pandas as pd numbers=[12,34,11,25,27,8,13] series=pd.Series(numbers) print("The original series is:") print(series) sorted_series=series.sort_values() print("The sorted series is:") print(sorted_series)

Output:

The original series is: 0 12 1 34 2 11 3 25 4 27 5 8 6 13 dtype: int64 The sorted series is: 5 8 2 11 0 12 6 13 3 25 4 27 1 34 dtype: int64

In the above example, we have first created a pandas series of 7 numbers. Then, we have sorted the series using the sort_values() method.

You can observe that the indices are also shuffled with the values in the series when it is sorted. To reset the index, you can set the ignore_index parameter to True as shown below.

import pandas as pd numbers=[12,34,11,25,27,8,13] series=pd.Series(numbers) print("The original series is:") print(series) sorted_series=series.sort_values(ignore_index=True) print("The sorted series is:") print(sorted_series)

Output:

The original series is: 0 12 1 34 2 11 3 25 4 27 5 8 6 13 dtype: int64 The sorted series is: 0 8 1 11 2 12 3 13 4 25 5 27 6 34 dtype: int64

In this example, you can observe that the series returned by the sort_values() method has indices starting from 0 till 6 instead of shuffled indices.

Sort a Pandas Series in Descending Order

To sort a pandas series in descending order, you can set the ascending parameter in the sort_values() parameter to False. After execution, the sort_values() method will return a series sorted in descending order. You can observe this in the following example.

import pandas as pd numbers=[12,34,11,25,27,8,13] series=pd.Series(numbers) print("The original series is:") print(series) sorted_series=series.sort_values(ascending=False,ignore_index=True) print("The sorted series is:") print(sorted_series)

Output:

The original series is: 0 12 1 34 2 11 3 25 4 27 5 8 6 13 dtype: int64 The sorted series is: 0 34 1 27 2 25 3 13 4 12 5 11 6 8 dtype: int64

In the above example, we have set the ascending parameter in the sort_values() method to False. Hence, after execution of the sort_values() method, we get a series that is sorted in descending order.

Sort a Series Having NaN Values in Python

To sort a pandas series with NaN values, you just need to invoke the sort_values() method on the pandas series as shown in the following example.

import pandas as pd import numpy as np numbers=[12,np.nan,11,np.nan,27,-8,13] series=pd.Series(numbers) print("The original series is:") print(series) series.sort_values(inplace=True,ignore_index=True) print("The sorted series is:") print(series)

Output:

The original series is: 0 12.0 1 NaN 2 11.0 3 NaN 4 27.0 5 -8.0 6 13.0 dtype: float64 The sorted series is: 0 -8.0 1 11.0 2 12.0 3 13.0 4 27.0 5 NaN 6 NaN dtype: float64

In this example, you can observe that the series contains NaN values. Hence, the sort_values() method puts the NaN values at the last of a sorted series by default. If you want the NaN values at the start of the sorted series, you can set the na_position parameter to “first” as shown below.

import pandas as pd import numpy as np numbers=[12,np.nan,11,np.nan,27,-8,13] series=pd.Series(numbers) print("The original series is:") print(series) series.sort_values(inplace=True,ignore_index=True,na_position="first") print("The sorted series is:") print(series)

Output:

The original series is: 0 12.0 1 NaN 2 11.0 3 NaN 4 27.0 5 -8.0 6 13.0 dtype: float64 The sorted series is: 0 NaN 1 NaN 2 -8.0 3 11.0 4 12.0 5 13.0 6 27.0 dtype: float64

In the above two examples, you can observe that the datatype of the series is set to float64 unlike the prior examples where the data type of the series was set to int64. This is due to the reason that NaN values are considered floating point data type in python. Hence, all the numbers are typecast to most compatible data type.

Sort a Series Inplace in Python

In the above examples, you can observe that the original series isn’t modified and we get a new sorted series. If you want to sort the series inplace, you can set the inplace parameter to True as shown below.

import pandas as pd numbers=[12,34,11,25,27,8,13] series=pd.Series(numbers) print("The original series is:") print(series) series.sort_values(inplace=True,ignore_index=True) print("The sorted series is:") print(series)

Output:

The original series is: 0 12 1 34 2 11 3 25 4 27 5 8 6 13 dtype: int64 The sorted series is: 0 8 1 11 2 12 3 13 4 25 5 27 6 34 dtype: int64

In this example, we have set the inplace parameter to True in the sort_values() method. Hence, after execution of the sort_values() method, the original series is sorted instead of creating a new pandas series. In this case, the sort_values() method returns None.

Sort a Pandas Series Using a Key

By default, the values in the series are used for sorting. Now, suppose that you want to sort the series based on the magnitude of the values instead of their actual values. For this, you can use the keys parameter.

We will pass the abs() function to the key parameter of the sort_values() method. After this, the values of the series will be sorted by their magnitude. You can observe this in the following example.

import pandas as pd numbers=[12,-34,11,-25,27,-8,13] series=pd.Series(numbers) print("The original series is:") print(series) series.sort_values(inplace=True,ignore_index=True,key=abs) print("The sorted series is:") print(series)

Output:

The original series is: 0 12 1 -34 2 11 3 -25 4 27 5 -8 6 13 dtype: int64 The sorted series is: 0 -8 1 11 2 12 3 13 4 -25 5 27 6 -34 dtype: int64

In this example, we have a series of positive and negative numbers. Now, to sort the pandas series using the absolute value of the numbers, we have used the key parameter in the sort_values() method. In the key parameter, we have passed the abs() function.

When the sort_values() method is executed, the elements of the series are first passed to the abs() function. The values returned by the abs() function are then used to compare the elements for sorting the series. This is why we get the series in which the elements are sorted by absolute value instead of actual value.

Suggested Reading: If you are into machine learning, you can read this article on regression in machine learning. You might also like this article on clustering mixed data types in Python.

The sort_index() Method in Python

Instead of sorting a series using the values, we can also sort it using the row indices. For this, we can use the sort_index() method. It has the following syntax.

Series.sort_index(*, axis=0, level=None, ascending=True, inplace=False, kind='quicksort', na_position='last', sort_remaining=True, ignore_index=False, key=None)

Here,

  • The axis parameter is unused in a similar manner to the sort_values() method.
  • The level parameter is used to sort the series by a certain index level when there are multilevel indices. To sort the series by multiple index levels in a specific order, you can pass the list of levels to the level parameter in the same order. 
  • By default, the series object is sorted by index values in ascending order. If you want the indices to be in descending order in the output dataframe, you can set the ascending parameter to False. 
  • After execution, the sort_values() method returns the sorted series. To sort and modify the original series by index instead of creating a new series, you can set the inplace parameter to True.
  • The kind parameter is used to determine the sorting algorithm. By default, the “quicksort” algorithm is used. If the index values are in a specific pattern where another sorting algorithm can be efficient, you can use  ‘mergesort’, ‘heapsort’, or ‘stable’ sorting algorithm.
  • The na_position parameter is used to determine the position of NaN indices in the sorted series. By default, the NaN indices are stored at the last of the sorted series. You can set the na_position parameter to “first” to store the NaN indices at the top of the sorted series.  
  • The sort_index() method sorts the indices in a specific order (ascending or descending). After sorting the indices, if you want to reset the index of the series, you set the ignore_index parameter to True. 
  • The key parameter is used to perform operations on the index of the series before sorting. It takes a vectorized function as its input argument. The function provided to the key parameter must take the index as its input argument and return a pandas series. Before sorting, the function is applied to the index. The values in the output of the function are then used to sort the series. 
Sort a Pandas Series by Index in Ascending Order

To sort a pandas series by index in ascending order, you can invoke the sort_index() method on the series object as shown in the following example.

import pandas as pd import numpy as np letters=["a","b","c","ab","abc","abcd","bc","d"] numbers=[3,23,11,14,16,2,45,65] series=pd.Series(letters) series.index=numbers print("The original series is:") print(series) sorted_series=series.sort_index() print("The sorted series is:") print(sorted_series)

Output:

The original series is: 3 a 23 b 11 c 14 ab 16 abc 2 abcd 45 bc 65 d dtype: object The sorted series is: 2 abcd 3 a 11 c 14 ab 16 abc 23 b 45 bc 65 d dtype: object

In this example, we have series of strings with numbers as index. As we have used the sort_index() method on the pandas series to sort it, the series is sorted by index values. Hence, we get a series where the index values are sorted.

After sorting, if you want to reset the index of the output dataframe, you can set the ignore_index parameter to True in the sort_index() method as shown below.

import pandas as pd import numpy as np letters=["a","b","c","ab","abc","abcd","bc","d"] numbers=[3,23,11,14,16,2,45,65] series=pd.Series(letters) series.index=numbers print("The original series is:") print(series) sorted_series=series.sort_index(ignore_index=True) print("The sorted series is:") print(sorted_series)

Output:

The original series is: 3 a 23 b 11 c 14 ab 16 abc 2 abcd 45 bc 65 d dtype: object The sorted series is: 0 abcd 1 a 2 c 3 ab 4 abc 5 b 6 bc 7 d dtype: object

In this example, we have set the ignore_index parameter to True in the sort_index() method. Hence, after sorting the series by original index values, the index of the series is reset.

Sort a Series by Index in Descending Order in Python

To sort a pandas series by index in descending order, you can set the ascending parameter in the sort_index() method to False as shown in the following example.

import pandas as pd import numpy as np letters=["a","b","c","ab","abc","abcd","bc","d"] numbers=[3,23,11,14,16,2,45,65] series=pd.Series(letters) series.index=numbers print("The original series is:") print(series) sorted_series=series.sort_index(ascending=False) print("The sorted series is:") print(sorted_series)

Output:

The original series is: 3 a 23 b 11 c 14 ab 16 abc 2 abcd 45 bc 65 d dtype: object The sorted series is: 65 d 45 bc 23 b 16 abc 14 ab 11 c 3 a 2 abcd dtype: object

In this example, we have set the ascending parameter in the sort_index() method to False. Hence, the series is sorted by index in descending order.

Sort a Pandas Series by Index Having NaN Values

To sort a series by index when there are NaN values in the index, you just need to invoke the sort_index() method on the pandas series as shown in the following example.

import pandas as pd import numpy as np letters=["a","b","c","ab","abc","abcd","bc","d"] numbers=[3,23,np.nan,14,16,np.nan,45,65] series=pd.Series(letters) series.index=numbers print("The original series is:") print(series) sorted_series=series.sort_index() print("The sorted series is:") print(sorted_series)

Output:

The original series is: 3.0 a 23.0 b NaN c 14.0 ab 16.0 abc NaN abcd 45.0 bc 65.0 d dtype: object The sorted series is: 3.0 a 14.0 ab 16.0 abc 23.0 b 45.0 bc 65.0 d NaN c NaN abcd dtype: object

In the above example, the index of the series contains NaN values. By default, the NaN values are stored at the last of the sorted series. If you want the NaN values at the start of the sorted series, you can set the na_position parameter to “first” as shown below.

import pandas as pd import numpy as np letters=["a","b","c","ab","abc","abcd","bc","d"] numbers=[3,23,np.nan,14,16,np.nan,45,65] series=pd.Series(letters) series.index=numbers print("The original series is:") print(series) sorted_series=series.sort_index(na_position="first") print("The sorted series is:") print(sorted_series)

Output:

The original series is: 3.0 a 23.0 b NaN c 14.0 ab 16.0 abc NaN abcd 45.0 bc 65.0 d dtype: object The sorted series is: NaN c NaN abcd 3.0 a 14.0 ab 16.0 abc 23.0 b 45.0 bc 65.0 d dtype: object

In this example, you can observe that we have set the na_position parameter to "first" in the sort_index() method. Hence, the elements having NaN values as their index are kept at the start of the sorted series returned by the sort_index() method.

Interesting read: Advantages of being a programmer.

Sort a Series by Index Inplace in Python

By default, the sort_index() method doesn’t sort the original series. It returns a new series sorted by index. If you want to modify the original series, you can set the inplace parameter to True in the sort_index() method as shown below.

import pandas as pd import numpy as np letters=["a","b","c","ab","abc","abcd","bc","d"] numbers=[3,23,np.nan,14,16,np.nan,45,65] series=pd.Series(letters) series.index=numbers print("The original series is:") print(series) series.sort_index(inplace=True) print("The sorted series is:") print(series)

Output:

The original series is: 3.0 a 23.0 b NaN c 14.0 ab 16.0 abc NaN abcd 45.0 bc 65.0 d dtype: object The sorted series is: 3.0 a 14.0 ab 16.0 abc 23.0 b 45.0 bc 65.0 d NaN c NaN abcd dtype: object

In this example, we have set the inplace parameter to True in the sort_index() method. Hence, the original series is sorted instead of creating a new series.

Sort a Pandas Series by Index Using a Key in Python

By using the key parameter, we can perform operations on the index of the series before sorting the series by index. For example, if you have negative numbers as the index in the series and you want to sort the series using the magnitude of the indices, you can pass the abs() function to the key parameter in the sort_index() method. 

import pandas as pd import numpy as np letters=["a","b","c","ab","abc","abcd","bc","d"] numbers=[3,23,-100,14,16,-3,45,65] series=pd.Series(letters) series.index=numbers print("The original series is:") print(series) series.sort_index(inplace=True,key=abs) print("The sorted series is:") print(series)

Output:

The original series is: 3 a 23 b -100 c 14 ab 16 abc -3 abcd 45 bc 65 d dtype: object The sorted series is: 3 a -3 abcd 14 ab 16 abc 23 b 45 bc 65 d -100 c dtype: object

In this example, we have a series having positive and negative numbers as indices. Now, to sort the pandas series using the absolute value of the indices, we have used the key parameter in the sort_index() method. In the key parameter, we have passed the abs() function.

When the sort_index() method is executed, the indices of the series are first passed to the abs() function. The values returned by the abs() function are then used to compare the indices for sorting the series. This is why we get the series in which the indices are sorted by absolute value instead of the actual value.

Conclusion

In this article, we have discussed how to sort a pandas series in Python. For this, we have used the sort_values() and sort_index() method. We have demonstrated different examples using different parameters of these methods.

I hope you enjoyed reading this article. To know more about pandas module, you can read this article on how to sort a pandas dataframe. You might also like this article on how to drop columns from a pandas dataframe.

Happy Learning!

The post Sort a Pandas Series in Python appeared first on PythonForBeginners.com.

Categories: FLOSS Project Planets

Mike Driscoll: PyDev of the Week: Yeray Diaz

Planet Python - Mon, 2022-11-28 08:35

This week we welcome Yeray Diaz (@yera_ee) as our PyDev of the Week! Yeray is a moderator on PyPI.org . Yeray also writes a blog and has several projects on his GitHub profile.

Let's take a few moments to get to know Yeray better!

Can you tell us a little about yourself (hobbies, education, etc):

I grew up in the Canary Islands which are off the coast of Morocco but are part of Spain. I was always fascinated by videogames being a fairly sickly kid that spent a lot of time at home. My father did not like video game consoles but he bought an Amstrad PC 1512 (yes, I'm that old) for work. That kind of forced me to learn computers if I ever wanted to play any video games. As computers became more powerful and complicated they kept requiring more skills until I became the resident computer expert in the family and eventually studied Computer Science in my local University.

Why did you start using Python?

I remember a friend from University introducing me to Python briefly, he just started up the REPL and typed 2 + 2 or something like that and showed me the python.org website. I tried to use it for one of my class projects but I didn't have time to complete it and when I retook the class I chose PHP because it was all the rage at the time. I eventually graduated and worked for a bit as a developer but entered a rebellious phase and decided to become a CG animator.

While I was working in the UK as at a games company called Frontier Developments they switched from 3D Studio Max to Maya. Maya had just added a Python API to interact with it and part of my job was to write scripts to help in animation tasks, so I read through the Python tutorial and really liked it as a language, particularly compared with PHP and the languages embedded in Maya and 3D Studio Max.

Around the same time someone was leaving Frontier Developments and was giving away a copy of a Python book, I can't remember which one, but it was thick and the cover was partly in Chinese although the text was completely in English. I read the whole book and started doing some more advanced stuff, eventually I discovered Django which I think was just getting really popular and decided to switch careers back to full time development with a focus in Python.

What other programming languages do you know and which is your favorite?

I've worked professionally with Ruby, Objective-C, JavaScript, and Typescript, all of which have things I like but none of them enough to say I enjoy working with. However, I discovered Elixir some years ago and it really did click for me. I really like its
pragmatism and directness which is something I really enjoy about Python but also the powerful concurrency model that the underlying Erlang VM provides. I wrote an article about their differences and similarities in case anyone's interested.

What projects are you working on now?

Unfortunately, I don't have a lot of time for Open Source these days, though my latest project is Sublime REST Client, a plugin for Sublime Text 4 that allows you to send HTTP requests directly from it by typing the HTTP verb and the payload.

Aside from that, I maintain a couple of libraries lunr.py and futureproof, although not as actively as I would like.

Which Python libraries are your favorite (core or 3rd party)?

I would say asyncio is my favourite core library, it was a massive breath of fresh air into the language and spawned many new frameworks and ideas. I wrote a series of introductory articles about it when it first came up which you can find on my Medium page.

My favourite 3rd party library is tough one to pick. It would probably be a three way tie between urllib3, pandas, and attrs. I've reached for those consistently over the years and have always been useful and solid in terms of performance and behaviour.

How did you become a moderator for PyPI?

During the development of what is now pypi.org, codename Warehouse, I read request from Nicole Harris, Warehouse's resident designer, for developers who would like to contribute in the Javascript side of things. Having worked with it and having some spare time I started contributing and slowly started to get involved with the PyPA.

Once the big switch happened we started getting issues unrelated to the Warehouse code and more to do with tasks typically reserved for admins. So the figure of a moderator was introduced and Dustin Ingram asked me if I'd like to be one so I accepted.

Is there anything else you’d like to say?

A while ago I realised that learning Python changed my life. Sounds a bit dramatic but it's true.

I learned Python right as it was gaining popularity, it allowed me to change careers and get my first development job in the UK as a Python programmer working on Django and slowly branched out to other areas of development because of Python's ecosystem and extensibility. The rich ecosystem and community were inviting and allowed me to progress further by contributing to Open Source which opened up even more avenues for me.

I'll always have a special connection with Python.

Thanks for doing the interview, Yeray!

The post PyDev of the Week: Yeray Diaz appeared first on Mouse Vs Python.

Categories: FLOSS Project Planets

Introducing KIO AFC

Planet KDE - Mon, 2022-11-28 07:00

A KIO worker for accessing iOS devices through the Apple File Conduit service.

Dolphin browsing the contents of an attached iPhone

While there have been several projects like this for both KDE 4 and Frameworks 5, this one has been written on top of the latest KIO classes and will be officially part of the next KDE Gear release. It is now part of the kio-extras module, which also houses the Android counterpart for transferring files over the MTP protocol.

Thanks to prior work in Solid, KDE’s hardware abstraction Framework, an iPhone plugged in to the computer will be shown in the Disks & Devices applet and Dolphin’s Places sidebar like any other external storage medium. I also submitted a small fix to UPower so that the device’s name rather than vendor and type is shown in the battery applet.

It supports browsing both the general file system as well as documents shared by apps through the House Arrest API. If you’re like me and prefer cable over cloud and wireless, please give it a try and report any bugs you might encounter! You just need to build the solid and kio-extras modules and make sure libimobiledevice-dev (naming will vary depending on your Linux distro) package is installed. You can also grab a build with this feature enabled fresh from the latest KDE neon Unstable edition or SUSE Krypton starting today.

If you don’t have any iOS device, you can still support KDE development by donating! ;)

Categories: FLOSS Project Planets

Salsa Digital Drupal-Related Articles: Juliane Erben and Alex Skrypnyk at DrupalSouth 2022

Planet Drupal - Mon, 2022-11-28 07:00
Julie and Alex's DrupalSouth 2022 presentation was on day 2 of the event. They took attendees through the process of building a new, high secure platform and website. View presentation description on DrupalSouth website
Categories: FLOSS Project Planets

Podcast.__init__: Build Better Machine Learning Models With Confidence By Adding Validation With Deepchecks

Planet Python - Sun, 2022-11-27 20:49
Machine learning has the potential to transform industries and revolutionize business capabilities, but only if the models are reliable and robust. Because of the fundamental probabilistic nature of machine learning techniques it can be challenging to test and validate the generated models. The team at Deepchecks understands the widespread need to easily and repeatably check and verify the outputs of machine learning models and the complexity involved in making it a reality. In this episode Shir Chorev and Philip Tannor explain how they are addressing the problem with their open source deepchecks library and how you can start using it today to build trust in your machine learning applications.Preamble

This is a cross-over episode from our new show The Machine Learning Podcast, the show about going from idea to production with machine learning.

Summary

Machine learning has the potential to transform industries and revolutionize business capabilities, but only if the models are reliable and robust. Because of the fundamental probabilistic nature of machine learning techniques it can be challenging to test and validate the generated models. The team at Deepchecks understands the widespread need to easily and repeatably check and verify the outputs of machine learning models and the complexity involved in making it a reality. In this episode Shir Chorev and Philip Tannor explain how they are addressing the problem with their open source deepchecks library and how you can start using it today to build trust in your machine learning applications.

Announcements
  • Hello and welcome to the Machine Learning Podcast, the podcast about machine learning and how to bring it from idea to delivery.
  • Do you wish you could use artificial intelligence to drive your business the way Big Tech does, but don’t have a money printer? Graft is a cloud-native platform that aims to make the AI of the 1% accessible to the 99%. Wield the most advanced techniques for unlocking the value of data, including text, images, video, audio, and graphs. No machine learning skills required, no team to hire, and no infrastructure to build or maintain. For more information on Graft or to schedule a demo, visit themachinelearningpodcast.com/graft today and tell them Tobias sent you.
  • Predibase is a low-code ML platform without low-code limits. Built on top of our open source foundations of Ludwig and Horovod, our platform allows you to train state-of-the-art ML and deep learning models on your datasets at scale. Our platform works on text, images, tabular, audio and multi-modal data using our novel compositional model architecture. We allow users to operationalize models on top of the modern data stack, through REST and PQL – an extension of SQL that puts predictive power in the hands of data practitioners. Go to themachinelearningpodcast.com/predibase today to learn more and try it out!
  • Data powers machine learning, but poor data quality is the largest impediment to effective ML today. Galileo is a collaborative data bench for data scientists building Natural Language Processing (NLP) models to programmatically inspect, fix and track their data across the ML workflow (pre-training, post-training and post-production) – no more excel sheets or ad-hoc python scripts. Get meaningful gains in your model performance fast, dramatically reduce data labeling and procurement costs, while seeing 10x faster ML iterations. Galileo is offering listeners a free 30 day trial and a 30% discount on the product there after. This offer is available until Aug 31, so go to themachinelearningpodcast.com/galileo and request a demo today!
  • Your host is Tobias Macey and today I’m interviewing Shir Chorev and Philip Tannor about Deepchecks, a Python package for comprehensively validating your machine learning models and data with minimal effort.
Interview
  • Introduction
  • How did you get involved in machine learning?
  • Can you describe what Deepchecks is and the story behind it?
  • Who is the target audience for the project?
    • What are the biggest challenges that these users face in bringing ML models from concept to production and how does DeepChecks address those problems?
  • In the absence of DeepChecks how are practitioners solving the problems of model validation and comparison across iteratiosn?
    • What are some of the other tools in this ecosystem and what are the differentiating features of DeepChecks?
  • What are some examples of the kinds of tests that are useful for understanding the "correctness" of models?
    • What are the methods by which ML engineers/data scientists/domain experts can define what "correctness" means in a given model or subject area?
  • In software engineering the categories of tests are tiered as unit -> integration -> end-to-end. What are the relevant categories of tests that need to be built for validating the behavior of machine learning models?
  • How do model monitoring utilities overlap with the kinds of tests that you are building with deepchecks?
  • Can you describe how the DeepChecks package is implemented?
    • How have the design and goals of the project changed or evolved from when you started working on it?
    • What are the assumptions that you have built up from your own experiences that have been challenged by your early users and design partners?
  • Can you describe the workflow for an individual or team using DeepChecks as part of their model training and deployment lifecycle?
  • Test engineering is a deep discipline in its own right. How have you approached the user experience and API design to reduce the overhead for ML practitioners to adopt good practices?
  • What are the interfaces available for creating reusable tests and composing test suites together?
  • What are the additional services/capabilities that you are providing in your commercial offering?
    • How are you managing the governance and sustainability of the OSS project and balancing that against the needs/priorities of the business?
  • What are the most interesting, innovative, or unexpected ways that you have seen DeepChecks used?
  • What are the most interesting, unexpected, or challenging lessons that you have learned while working on DeepChecks?
  • When is DeepChecks the wrong choice?
  • What do you have planned for the future of DeepChecks?
Contact Info Parting Question
  • From your perspective, what is the biggest barrier to adoption of machine learning today?
Closing Announcements
  • Thank you for listening! Don’t forget to check out our other shows. The Data Engineering Podcast covers the latest on modern data management. Podcast.__init__ covers the Python language, its community, and the innovative ways it is being used.
  • Visit the site to subscribe to the show, sign up for the mailing list, and read the show notes.
  • If you’ve learned something or tried out a project from the show then tell us about it! Email hosts@themachinelearningpodcast.com) with your story.
  • To help other people find the show please leave a review on iTunes and tell your friends and co-workers
Links

The intro and outro music is from Hitman’s Lovesong feat. Paola Graziano by The Freak Fandango Orchestra/CC BY-SA 3.0

Categories: FLOSS Project Planets

Matt Layman: Learn Python By Example - Currency Exchange

Planet Python - Sun, 2022-11-27 19:00
Learn Python By Example shows a simple Python exercise from Exercism. This problem illustrates numbers in Python and how to use the built-in math operators. Since this is the first video in this series, I also take a bit of time to show how to use Exercism along the way in case you would like to learn using Exercism as well.
Categories: FLOSS Project Planets

Python Circle: Selecting Linux kernel version during system booting process

Planet Python - Sun, 2022-11-27 16:39
How to revert to the previous kernel version of Ubuntu, Showing grub menu during boot-up process, selecting the desired kernel version from grub menu, permanently selecting the kernel version, updating grub file, Setting timeout in grub menu
Categories: FLOSS Project Planets

Python Circle: Avoid typing git credentials everytime. Use git credentials manager.

Planet Python - Sun, 2022-11-27 14:39
How to store the git credentials in git credentials manager, Using GCM to avoid typing the git credentials every time you run a git command, Different ways to store git username and passwords, increase the productivity by not typing git password everytime
Categories: FLOSS Project Planets

#! code: Drupal 9: Extending Drupal Base Classes Without Overriding Constructors

Planet Drupal - Sun, 2022-11-27 14:13

I have been using the Drupal dependency injection system for a while now, even giving talks and writing articles on the subject. As the release of Drupal 10 is just around the corner I have been thinking more about how to override dependencies to plugin classes.

I wanted to share a trick to overriding dependency injection that will make your life easier. The Drupal codebase itself does not use this trick, but it seems that many contributed modules have started to use this trick to create plugin classes.

In this article I will go through how to add dependency injection to Drupal classes in two different patterns.

The first pattern will create problems and will require quite a bit more typing and repeating of code. The second pattern is much easier to use and will make life easier going forward.

An Example Block

The following block of code shows a very basic Drupal Block class that doesn't do anything. This will be the basis of the rest of this article.

<?php namespace Drupal\mymodule\Plugin\Block; use Drupal\Core\Block\BlockBase; /** * Provides a 'TEST' block. * * @Block( * id = "mymodule_block", * label = "A testing block", * admin_label = @Translation("A testing block"), * ) */ class TestBlock extends BlockBase { /** * {@inheritdoc} */ public function build() { $build = []; return $build; } }

What I am going to do with this block is inject a service to perform route matching. In Drupal there are a couple of services to do this, but I will be using the current_route_match service to look for the service.

Read more.

Categories: FLOSS Project Planets

The Python Coding Blog: Write A Football Offside Rule Quiz in Python While Practising Object-Oriented Programming

Planet Python - Sun, 2022-11-27 06:55

Do you know the offside rule in football*? Or do you want to test whether someone else knows it well enough? Either way, it’s time to write an offside rule quiz in Python using object-oriented programming.

(*Some of you may call it “soccer”)

Here’s what the quiz will look like. The program presents you with 10 scenarios and you need to guess whether there’s an offside position. The program will then give you the correct answer and assigns a point if you got it right.

Each scenario shows the 22 players on the pitch with arrows to indicate which direction the team is attacking. The arrows showing teammates all point in the same direction. The team is attacking in this direction.

One player on the attacking team has the ball, which you can see as a white dot (of course). You’re presented with a snapshot at the time the player with the ball kicks it forward. Is it offside? You need to decide!

Article Summary

In this article, you’ll:

  • Create several Python classes to represent:
    • an Action (a snapshot of the players’ positions in a game)
    • a Player
    • a Goalkeeper
    • a Team
  • Practise creating data attributes (instance variables) and methods
  • Use inheritance
  • Link instances of one class with instances of another class
  • Learn the offside rule if you don’t know it already!

You can think of this article in one of two ways. You can either learn the offside rule in football by using object-oriented programming. Or you can learn object-oriented programming in Python through the offside rule in football!

Disclosure

I don’t particularly like watching football anymore. I used to when I was younger, but I can’t remember the last time I watched a game, in full or in part, which didn’t feature either of my children!

Also, I didn’t try to make the “graphics” look good in this quiz. You go ahead and make it look pretty if you want!

Planning The Program

Very roughly speaking, a player is in an offside position if he or she doesn’t have at least two opponent players in front of them when a teammate kicks the ball forward. It’s a bit more complex than this, but this will do for now. We’ll look at some of the special cases as we write the code.

Here’s the plan of what you’ll need the program to do:

  • Place 22 players randomly on a pitch, half facing one way and the other half facing the other way
  • Assign one team as the attacking team. Choose one of its players who will have the ball
  • Determine whether the frontmost player of the attacking team is in an offside position. You won’t worry about other subtleties, such as whether the player is actively participating in the action. That’s a subjective call. And, in any case, the program will only show a snapshot and not the whole action
  • Repeat the test several times to turn the program into a quiz

You’ll use Python’s turtle module to display the scenario. This module is in Python’s standard library. Don’t worry if you’ve never used this module. I’ll explain the bits you’ll need as you use them in this article. The “turtle” we’ll talk about is the object which will move across the screen.

You’ll use classes to represent various entities in this program. This article assumes some familiarity with object-oriented programming but not any high level of expertise. If you need to read more about defining and using classes in Python, you can read Chapter 7 in The Python Coding Book about Object-Oriented Programming before going ahead with this article.

The Offside Rule Quiz in Python: Getting Started

You’ll write your code in two separate files:

  • offside.py: This file will contain the classes you’ll define
  • offside_rule_quiz.py: This one will contain the code that runs the quiz. You’ll also use it to test your classes as you implement them

You can start by creating offside.py. You’ll start by defining the Action class which will take care of each action or scenario where you’ll need to decide whether there’s an offside position.

This class will also include the football pitch. This will be the screen you create using the turtle module. You can start writing the Action class in offside.py:

# offside.py import turtle class Action: pitch_size = 800, 600 pitch_colour = "forest green" def __init__(self): # Pitch is the turtle Screen object # (technically _Screen object, as Screen() is a # function, but we can ignore this subtlety) self.pitch = turtle.Screen() self.pitch.setup( Action.pitch_size[0], Action.pitch_size[1], ) self.pitch.bgcolor(Action.pitch_colour)

The class variables pitch_size and pitch_colour are the first things you add to the class. These will be the same for all Action instances. They’re not specific to each instance.

You also define the __init__() method to initialise an Action instance. This creates a screen using the turtle module which you assign to the attribute pitch.

setup() is a method from the turtle module which sets the size of the window you create. Since pitch_size is a class variable (or class attribute), you can use the name of the class to refer to it instead of self.

bgcolor() is another method in the turtle module which changes the window’s background colour.

Now, you can create a second file called offside_rule_quiz.py and create an instance of the Action class:

# offside_rule_quiz.py from offside import Action game = Action()

You’ll see a window flash briefly in front of your eyes when you run this script. That’s because your program creates the window using the turtle module but then terminates immediately. There’s nothing else in the program.

The turtle module has the function done() which runs the main loop of the animation. This will keep the window open and the program running until the window is closed:

# offside_rule_quiz.py import turtle from offside import Action game = Action() turtle.done()

This script will now show you the window with the green football pitch:

The Players: Creating a Player Class

You’ll need 22 players on the pitch. You can create a Player class to take care of this. The players need to be displayed as a symbol on the pitch. This is what the Turtle class is ideal for. Therefore, you can define the Player class to inherit from turtle.Turtle so that each Player instance is a Turtle instance with additional attributes:

# offside.py import random import turtle class Action: pitch_size = 800, 600 pitch_colour = "forest green" def __init__(self): # Pitch is the turtle Screen object # (technically _Screen object, as Screen() is a # function, but we can ignore this subtlety) self.pitch = turtle.Screen() self.pitch.setup( Action.pitch_size[0], Action.pitch_size[1], ) self.pitch.bgcolor(Action.pitch_colour) class Player(turtle.Turtle): def __init__(self, colour, direction): super().__init__() # Turtle methods self.penup() self.setheading(direction) self.color(colour) self.shape("triangle") # Methods specific to Player self.set_bounds() self.place_on_pitch() def set_bounds(self): """ Set the left, right, top, and bottom limits where a player can be located on the pitch. Leave a boundary at the edge of the pitch to avoid players being partially off the pitch """ pitch_half_width = Action.pitch_size[0] // 2 pitch_half_height = Action.pitch_size[1] // 2 self.left_bound = -int(pitch_half_width * 0.95) self.right_bound = int(pitch_half_width * 0.95) self.bottom_bound = -int(pitch_half_height * 0.95) self.top_bound = int(pitch_half_height * 0.95) def place_on_pitch(self): """Place player in a random position on the pitch""" self.setposition( random.randint(self.left_bound, self.right_bound), random.randint(self.bottom_bound, self.top_bound), )

Since Player inherits from turtle.Turtle, you call the initialisation method of the parent class using super().__init__(). You can then use methods from the Turtle class on self and new methods you define for Player.

The Turtle methods you’re using are:

  • penup(): raises the “drawing pen” so that when you move the Player (which is also a Turtle), it doesn’t draw any lines
  • setheading(): changes the direction the Player is facing
  • color(): changes the colour of the shape drawn on the screen. You probably guessed this without needing the explanation!
  • shape(): changes the shape which represents the object on the screen
  • setposition(): changes the x- and y-coordinates of the object on the screen. This method is used in place_on_pitch()

In the turtle module, the centre of the screen has the coordinates (0, 0). Therefore, negative numbers for x represent the left half of the screen and negative y values represent the bottom half of the screen.

You define two new methods in the Player class:

  • set_bounds(): determines the left, right, bottom, and top limits of the pitch where you can draw the player. You’ve left a small gap to prevent the player from being right at the edge of the screen/pitch
  • place_on_pitch(): places the player in a random position on the pitch, using the bounds calculated in set_bounds()

Remember that you should always use descriptive names for variables and methods (or functions). When naming a function or method, always start with a verb to clearly show what the function does.

You can test this code by adding a Player in offside_rule_quiz.py. This line is there just to test that everything works. You’ll need to remove it once you’ve tested this works, as you’ll be creating the players elsewhere in your code:

# offside_rule_quiz.py import turtle from offside import Action, Player game = Action() player = Player("orange", 180) turtle.done()

When you run offside_rule_quiz.py, you’ll see a single player on the pitch, shown as an arrow:

Before you move on to create the teams, let’s look at the code you just added. Could you have placed the code within the methods set_bounds() and place_on_pitch() directly in __init__()? Yes, you could have. These are design decisions that each programmer needs to make. There’s no clear right or wrong.

However, with practice and experience, you’ll get an intuition on whether to separate functionality into different methods. As a rule, if in doubt, it may be better to write separate methods rather than put everything in __init__() as you may want to re-use these methods later. As it happens, later you’ll see a benefit from having these as separate methods when we talk about the goalkeepers.

The Teams: Creating a Team Class

So far, you’ve got the “big picture” Action class and the Player class. You’ll need 22 players but split into two teams. So, you can now create a Team class to deal with anything relating to the teams as a whole.

You’ll need a link between the players and the team. You can create a players attribute in Team which could be a list containing all the players. But you can also create a team attribute in Player to identify which team a player belongs to. So, as you write the Team class, you’ll need to make a change to the Player class, too. You’ll add the team attribute to Player and add another parameter in its __init__() method:

# offside.py import random import turtle class Action: pitch_size = 800, 600 pitch_colour = "forest green" def __init__(self): # Pitch is the turtle Screen object # (technically _Screen object, as Screen() is a # function, but we can ignore this subtlety) self.pitch = turtle.Screen() self.pitch.setup( Action.pitch_size[0], Action.pitch_size[1], ) self.pitch.bgcolor(Action.pitch_colour) class Player(turtle.Turtle): def __init__(self, team, colour, direction): super().__init__() # Turtle methods self.penup() self.setheading(direction) self.color(colour) self.shape("triangle") # Attributes/Methods specific to Player self.team = team self.set_bounds() self.place_on_pitch() def set_bounds(self): """ Set the left, right, top, and bottom limits where a player can be located on the pitch. Leave a boundary at the edge of the pitch to avoid players being partially off the pitch """ pitch_half_width = Action.pitch_size[0] // 2 pitch_half_height = Action.pitch_size[1] // 2 self.left_bound = -int(pitch_half_width * 0.95) self.right_bound = int(pitch_half_width * 0.95) self.bottom_bound = -int(pitch_half_height * 0.95) self.top_bound = int(pitch_half_height * 0.95) def place_on_pitch(self): """Place player in a random position on the pitch""" self.setposition( random.randint(self.left_bound, self.right_bound), random.randint(self.bottom_bound, self.top_bound), ) class Team: def __init__(self, player_colour, end): self.player_colour = player_colour self.end = end # -1 if team playing left to right # 1 if team playing right to left self.players = [] self.direction = 90 + 90 * self.end self.create_team() def create_team(self): for _ in range(10): self.players.append( Player(self, self.player_colour, self.direction) )

You’ve added the parameter team in Player.__init__() and then made it an attribute by adding self.team = team.

You also define the Team class with two input parameters. However, there are more than two attributes in this class so far. Let’s look at them:

  • player_colour: a data attribute showing the colour used to display the player on the screen
  • end: a data attribute which will be either -1 or 1. end is -1 if the team is attacking from left to write and 1 if it’s attacking from right to left
  • players: a data attribute which starts as an empty list but which will be populated with Player instances
  • direction: a data attribute containing an angle showing the players’ orientation. The angle is 180º when end is 1 (facing to the left) and 0º when end is -1 (facing to the right)
  • create_team(): a method which creates Player instances and adds them to the players list.
    self, self.player_colour, and self.direction are passed as arguments when creating Player and they’re assigned to the parameters team, colour, and direction in Player.__init__()

Have you spotted the “typo” in the code above? Or something you’re sure must be a typo? There should be 11 players in a football team, not 10! You’ll deal with the goalkeeper a bit later. So, you’ll include only the 10 outfield players for the time being.

You can test this code works in offside_rule_quiz.py. As mentioned earlier, the lines you’re adding now are just there temporarily. You’ll remove them later:

# offside_rule_quiz.py import turtle from offside import Action, Team game = Action() first_team = Team("orange", -1) second_team = Team("light blue", 1) turtle.done()

When you run this script, you’ll see the two teams on the pitch, with all players in random positions:

Speeding up the process of drawing on the screen

You probably noticed that it took a while for each Player to be displayed in its random pitch position on the screen. Life’s too short. We can speed things up when using the turtle module through the pair of methods tracer() and update(). These are screen methods.

tracer(0) will stop displaying each step when moving turtles across the screen. update() will update the display by placing all turtles in their new positions instantaneously. You can think of this as getting the players to move in the background and then only showing them once they’ve reached their positions. This will speed up the animation considerably.

You can incorporate these methods in the Action class:

# offside.py import random import turtle class Action: pitch_size = 800, 600 pitch_colour = "forest green" def __init__(self): # Pitch is the turtle Screen object # (technically _Screen object, as Screen() is a # function, but we can ignore this subtlety) self.pitch = turtle.Screen() self.pitch.tracer(0) self.pitch.setup( Action.pitch_size[0], Action.pitch_size[1], ) self.pitch.bgcolor(Action.pitch_colour) def update(self): self.pitch.update() class Player(turtle.Turtle): # ... class Team: # ...

You set the tracer to zero when you create the Action instance, and you create an Action method called update() which calls the update() method in the turtle module.

Why not use the update() method in the turtle module directly? You can do so, but from the perspective of a programmer using the Action class, having an Action method will make more sense, and the user doesn’t need to know how you’ve implemented the Action class. Someone using this class doesn’t need to know that you have a pitch attribute containing the screen object from the turtle module!

Let’s test this with a small change in offside_rule_quiz.py:

# offside_rule_quiz.py import turtle from offside import Action, Team game = Action() first_team = Team("orange", -1) second_team = Team("light blue", 1) game.update() turtle.done()

When you run this script, you’ll see that all 20 players will appear instantly on the pitch!

The GoalKeepers: Creating a GoalKeeper Class

Let’s start with some honesty: you don’t need a GoalKeeper class. The offside rule doesn’t differentiate between goalkeepers and outfield players. So, you could just create 11 regular players and move on.

But why take a shortcut when the slightly longer route is so rich with “goodness”? And object-oriented programming makes it very easy to add a GoalKeeper class.

A goalkeeper is a player. So, you can use the Player class as a starting point and then make the few changes needed. In this case, the difference between a goalkeeper and an outfield player will be:

  • The goalkeeper wears a different colour
  • The goalkeeper’s random position on the pitch will be limited to a region close to their goal

So, you can create a GoalKeeper class which inherits from Player. (Note: when a section of code hasn’t changed since the previous sections in this article, I’ll show it as # ... to avoid very long code blocks repeating the same code over and over again):

# offside.py import random import turtle class Action: # ... class Player(turtle.Turtle): # ... class GoalKeeper(Player): def __init__(self, team, colour, direction): super().__init__(team, colour, direction) def set_bounds(self): """ Set the left, right, top, and bottom limits where a goalkeeper can be located on the pitch. Goalkeeper is located close to own goal """ pitch_half_width = Action.pitch_size[0] // 2 pitch_half_height = Action.pitch_size[1] // 2 self.left_bound, self.right_bound = sorted( [ self.team.end * pitch_half_width * 0.98, self.team.end * pitch_half_width * 0.85, ] ) self.bottom_bound = -pitch_half_height * 0.5 self.top_bound = pitch_half_height * 0.5 class Team: def __init__(self, player_colour, keeper_colour, end): self.player_colour = player_colour self.keeper_colour = keeper_colour self.end = end # -1 if team playing left to right # 1 if team playing right to left self.players = [] self.direction = 90 + 90 * self.end self.create_team() def create_team(self): self.players.append( GoalKeeper(self, self.keeper_colour, self.direction) ) for _ in range(10): self.players.append( Player(self, self.player_colour, self.direction) )

The Goalkeeper class is nearly identical to the Player class. The only difference is the set_bounds() method which overrides the one in Player. If the team is playing left to right, and therefore the team’s end attribute is -1, the left and right bounds for the goalkeeper will be in the half of the pitch represented by negative numbers. That’s the left-hand side. This ensures the goalkeeper is never placed too far from the goal.

However, if end is 1, which means the team is playing right to left, the left and right bounds between which the goalkeeper is randomly placed are on the right of the pitch. Note that you’re using the built-in sorted() function to make sure that the smallest number is always the first one in the list.

You also added a new parameter in Team.__init__(). This parameter is keeper_colour. You also converted it into a data attribute using self.keeper_colour = keeper_colour. Finally, you added the goalkeeper to the list of players in create_team().

Since Team.__init__() now has an extra parameter, you’ll need to add an extra colour when creating the teams in offside_rule_quiz.py to test your code:

# offside_rule_quiz.py import turtle from offside import Action, Team game = Action() first_team = Team("orange", "dark salmon", -1) second_team = Team("light blue", "dark blue", 1) game.update() turtle.done()

When you run this script, you’ll see all 22 players, including the two goalkeepers “wearing” different colours:

The Attacking Team: Deciding Which Team And Player Has The Ball

So far, you’ve created two teams with 11 players each. The teams are facing different directions and all their players are placed in random positions on the pitch.

However, in an action where you need to determine whether there’s an offside position, you need to know which team is attacking and which is defending. And one of the attacking team’s players must have the ball.

Let’s go back to the Action class and you can define three new methods:

  • create_teams()
  • choose_attacking_team()
  • place_ball()

To simplify the quiz, we’ll then add these methods to Action.__init__(), but you can also choose to call them from elsewhere in your code if you prefer:

# offside.py import random import turtle class Action: pitch_size = 800, 600 pitch_colour = "forest green" def __init__(self): # Pitch is the turtle Screen object # (technically _Screen object, as Screen() is a # function, but we can ignore this subtlety) self.pitch = turtle.Screen() self.pitch.tracer(0) self.pitch.setup( Action.pitch_size[0], Action.pitch_size[1], ) self.pitch.bgcolor(Action.pitch_colour) self.create_teams() self.choose_attacking_team() self.place_ball() def update(self): self.pitch.update() def create_teams(self): """Create two teams facing opposite directions""" self.left_to_right_team = Team( "orange", "dark salmon", -1 ) self.right_to_left_team = Team( "light blue", "dark blue", 1 ) def choose_attacking_team(self): """Pick which team is attacking in this action""" self.attacking_team_indicator = random.choice([-1, 1]) if self.attacking_team_indicator == -1: self.attacking_team = self.left_to_right_team self.defending_team = self.right_to_left_team else: self.attacking_team = self.right_to_left_team self.defending_team = self.left_to_right_team self.attacking_direction = ( 90 + 90 * self.attacking_team_indicator ) def place_ball(self): """ Assign ball to one of the players in the attacking team """ self.player_with_ball = random.choice( self.attacking_team.players ) ball = turtle.Turtle() ball.penup() ball.shape("circle") ball.color("white") ball.setposition(self.player_with_ball.position()) ball.setheading(self.attacking_direction) ball.forward(20) class Player(turtle.Turtle): # ... class GoalKeeper(Player): # ... class Team: # ... create_teams()

This method creates the two Team instances and assigns them to data attributes left_to_right_team and right_to_left_team. I’ve just hard-coded the colours in the code to keep things a bit simpler (as the code is already getting quite long). If you prefer to do something more clever in your code, please go ahead!

choose_attacking_team()

This method picks a random integer out of -1 and 1. If it picks -1, the team attacking is the one with the end attribute equal to -1. This is the team attacking from left to right. You create an attacking_team attribute which refers to the same Team object that left_to_right_team refers to. Note that you’re not creating a new object but merely adding another label to the same Team object.

You do the same with defending_team. Then you assign the same attributes to the opposite teams if the random number chosen is 1, meaning it’s the team playing right to left that’s attacking.

Finally, you set attacking_direction which is either 0º or 180º. You’re using the value of attacking_team_indicator which is either -1 or 1 to set this value. In the turtle module, 0º points right and 180º points left.

I have deliberately mixed styles in this method to demonstrate some of the choices you’ll need to make when writing code. Instead of using the trick with attacking_team_indicator to choose the attacking_direction, I could have added a line to each of the if and else clauses and set this value to 0º or 180º directly.

Similarly, we could have avoided using an if...else construct altogether by writing:

self.attacking_team, self.defending_team = [ self.left_to_right_team, self.right_to_left_team, ][:: self.attacking_team_indicator]

The list containing both teams is being either left unchanged or reversed using the slice [:: self.attacking_team_indicator] as attacking_team_indicator is either 1 or -1. However, this solution scores low on readability!

These are choices you will have to make when writing your own code. There’s no clear-cut rule on what’s readable and what isn’t. It’s a very subjective issue. Sometimes, it feels great to come up with some “clever” solution, like the slicing trick above. However, the more conventional approach may be preferable as it’s easier to read for others and for yourself in the future. Plus, it’s easier to debug.

You can also remove the one-liner setting attacking_direction, if you prefer, and replace it with two lines, one in the if block and one in the else block.

place_ball()

This method picks a random player from the attacking team, creates a new Turtle object to represent the ball, and places the ball at the “feet” of the chosen player. The only Turtle methods you’ve not seen already in this article are:

  • position(): returns the x- and y-coordinates of the Turtle
  • forward(): moves the Turtle in the direction it’s facing. The argument is the number of pixels the Turtle will move

You can simplify offside_rule_quiz.py to:

# offside_rule_quiz.py import turtle from offside import Action game = Action() game.update() turtle.done()

This gives you both teams, including one player who has the ball:

Last Two Defenders And Frontmost Attacker

Only three players matter when you need to determine whether there’s an offside situation. One of them is the attacking team’s player who’s furthest forward among his or her teammates. The other two are the two players on the defending team who are the furthest back. Often, the goalkeeper is one of these two players, but it doesn’t have to be so!

You can create two methods in the Team class: find_two_back_players_xpos() and find_front_player_xpos()

# offside.py import random import turtle class Action: # ... class Player(turtle.Turtle): # ... class GoalKeeper(Player): # ... class Team: def __init__(self, player_colour, keeper_colour, end): # ... def create_team(self): # ... def find_two_back_players_xpos(self): """ Find the back two players of the team. Takes into account whether team is playing right to left or left to right :return: pair of x-coordinates for the two back players :rtype: tuple[float] """ # sort using `xcor()`, lowest numbers first ordered_players = sorted( self.players, key=lambda player: player.xcor() ) back_two_indices = -1 - self.end, -self.end # if self.end is -1, then indices are 0 and 1, # so this represents the first two elements # (smallest `xcor()`, therefore furthest left) # if self.end is 1, then indices are -2 and -1, # so this represents the last two elements # (largest `xcor()`, therefore furthest right) return tuple( ordered_players[idx].xcor() for idx in back_two_indices ) def find_front_player_xpos(self): """ Find the frontmost player of the team. Takes into account whether team is playing right to left or left to right :return: x-coordinate of the forward-most player :rtype: float """ # sort using `xcor()`, lowest numbers first ordered_players = sorted( self.players, key=lambda player: player.xcor() ) front_one_index = min(self.end, 0) # if self.end is -1, index is -1 so represents the # last item in list (largest `xcor()`), therefore # furthest right # if self.end is 1, index is 0 so represents the # first item in list (smallest `xcor()`), therefore # furthest left return ordered_players[front_one_index].xcor()

I’ve included detailed docstrings for these functions and comments in the code to explain the algorithms used. Docstrings are the comments within the triple quoted strings that follow immediately after the function signature which document the function.

The important first step in both methods is to sort the list of players based on their x-coordinates. You achieve this using the built-in sorted() function with the key parameter. The lambda function used as the key allows sorted() to use the players’ x-coordinates, which is returned by the Turtle method xcor(), to sort the players.

Therefore, ordered_players is a list of all the players in the team ordered from left to right on the pitch. [Note: we could have used the list method sort() on self.players, too. I opted to create a new list in this case.]

find_two_back_players_xpos() then calculates the indices corresponding to the two back players. These will be either 0 and 1 or -2 and -1.

0 and 1 represent the first two elements in the list. These are the two players furthest to the left on the pitch. Therefore, they are the back two players for a team playing left to right. See the comments in the code for more detail.

-2 and -1 represent the last two elements in the list. These are the players furthest to the right. Therefore, they’re the back two players for the team playing right to left.

The method returns a tuple containing both x-coordinates. You’re using a comprehension to get the value of xcor() for the two players matching the indices you’ve just calculated.

Note that the code shown below is not a tuple comprehension:

(ordered_players[idx].xcor() for idx in back_two_indices)

The comprehension within parentheses () creates a generator. You’re converting this generator into a tuple using the tuple() call in find_two_back_players_xpos().

find_front_player_xpos() is similar but a bit simpler since it only needs to find one x-coordinate and it returns only one value.

Offside Or Not Offside?

And finally, you get to decide whether the action you’re dealing with is an offside position. The snapshot you’re considering is the point when the player with the ball kicks it forward. If the attacking player at the front doesn’t have at least two opponents in front of him or her, then it’s an offside position.

You can define the method is_offside() in Action to work out whether there’s an offside situation:

# offside.py import random import turtle class Action: pitch_size = 800, 600 pitch_colour = "forest green" def __init__(self): # ... def update(self): # ... def create_teams(self): # ... def choose_attacking_team(self): # ... def place_ball(self): # ... def is_offside(self): """ Check if scenario is offside or not :return: True if offside and False if not offside :rtype: bool """ # Check that front player is behind two back players front_player_pos = self.attacking_team.find_front_player_xpos() if self.attacking_team_indicator == -1: second_last_back_player_pos = min( self.defending_team.find_two_back_players_xpos() ) return front_player_pos > second_last_back_player_pos else: second_last_back_player_pos = max( self.defending_team.find_two_back_players_xpos() ) return front_player_pos < second_last_back_player_pos class Player(turtle.Turtle): # ... class GoalKeeper(Player): # ... class Team: # ...

This method gets the frontmost attacker’s x-position using attacking_team.find_front_player_xpos(). What happens next depends on whether the attacking team is attacking left to right or right to left. This is determined by the data attribute attacking_team_indicator, which is either -1 or 1.

As I mentioned earlier, you can find a “clever” solution that doesn’t need an if...else. However, the solution used here is more readable. There’s already a lot happening in this method as it is!

If the attacking team is attacking left to right, the defending team is playing right to left. Therefore, you want the smallest of the two x-coordinates to find the position of the second-last player. The attacker who’s furthest forward needs to be behind this defender. Therefore, if the x-coordinate of the frontmost attacker is larger than that of the second-last defender, it’s an offside situation. Remember that we’re currently considering an attacking team playing left to right. The method returns True. If the frontmost attacker’s x-coordinate is smaller than the second-last back player, the method returns False, or not offside!

The logic is reversed for the case when the attacking team is attacking right to left. You’ll need to digest these algorithms a bit and it will make sense!

You can make a small change to offside_rule_quiz.py to print out the value of game.is_offside():

# offside_rule_quiz.py import turtle from offside import Action game = Action() game.update() print(game.is_offside()) turtle.done()

When you run this script, you’ll see the snapshot of the action and either True or False will be printed in the output console depending on whether the situation is offside or not.

Special case 1: the frontmost attacker is the one with the ball

We need to take care of two special cases. If the frontmost attacker is the one who has the ball, then there is no offside situation. The offside rule only applies to a player who is in front of the ball. You can add a check to is_offside() to account for this situation by checking whether the x-coordinate of the frontmost attacking player is the same as the player who has the ball and return False (no offside) if it is.

Special case 2: the frontmost attacker is in their own half of the pitch

The offside rule doesn’t apply if the frontmost player is in his or her own half of the pitch when the ball is kicked towards them. Therefore, you can add another check to see whether the frontmost player’s x-coordinate is within the team’s own half and return False if it is.

Here are both additions to is_offside():

# offside.py import random import turtle class Action: pitch_size = 800, 600 pitch_colour = "forest green" def __init__(self): # ... def update(self): # ... def create_teams(self): # ... def choose_attacking_team(self): # ... def place_ball(self): # ... def is_offside(self): """ Check if scenario is offside or not :return: True if offside and False if not offside :rtype: bool """ # Check if frontmost attacker has the ball and kicks it # (or is exactly in line with player with ball–very low probability) if self.attacking_team.find_front_player_xpos() == self.player_with_ball.xcor(): return False # Check that front player is behind two back players front_player_pos = self.attacking_team.find_front_player_xpos() if self.attacking_team_indicator == -1: second_last_back_player_pos = min( self.defending_team.find_two_back_players_xpos() ) # Is attacker in own half if front_player_pos < 0: return False return front_player_pos > second_last_back_player_pos else: second_last_back_player_pos = max( self.defending_team.find_two_back_players_xpos() ) # Is attacker in own half if front_player_pos > 0: return False return front_player_pos < second_last_back_player_pos class Player(turtle.Turtle): # ... class GoalKeeper(Player): # ... class Team: # ... The Quiz: Finishing Touches To Turn This Into A Quiz

The main code is in place now. You can create a snapshot of an action between two teams and the program can determine whether it’s an offside situation.

There are still a few finishing touches to turn this into a quiz. You can work on these in small steps.

Label showing result in the game window

Let’s add a label to show whether there’s an offside situation directly on the screen. You can add a new Turtle object whose job will be to write text on the screen:

# offside.py import random import turtle class Action: pitch_size = 800, 600 pitch_colour = "forest green" def __init__(self): # Pitch is the turtle Screen object # (technically _Screen object, as Screen() is a # function, but we can ignore this subtlety) self.pitch = turtle.Screen() self.pitch.tracer(0) self.pitch.setup( Action.pitch_size[0], Action.pitch_size[1], ) self.pitch.bgcolor(Action.pitch_colour) self.create_teams() self.choose_attacking_team() self.place_ball() # Label to show whether scenario is offside or not offside self.label = turtle.Turtle() self.label.penup() self.label.sety(self.pitch_size[1] // 3) self.label.hideturtle() def update(self): # ... def create_teams(self): # ... def choose_attacking_team(self): # ... def place_ball(self): # ... def is_offside(self): # ... def display_result(self, result, colour): """ Show on screen whether scenario is offside or not offside """ self.label.color(colour) self.label.write( result, font=("Courier", 30, "bold"), align="center" ) class Player(turtle.Turtle): # ... class GoalKeeper(Player): # ... class Team: # ...

There are a few new Turtle methods you’ve not used before:

  • sety(): like setposition() but sets only the turtle’s y-coordinate
  • hideturtle(): hides the turtle so that only what it draws or writes is displayed, but not the turtle itself
  • write(): writes text on the screen. You can also use the optional font and align arguments

You can update offside_rule_quiz.py:

# offside_rule_quiz.py import turtle from offside import Action game = Action() game.update() if game.is_offside(): game.display_result("OFFSIDE", "red") else: game.display_result("NOT OFFSIDE", "white") turtle.done()

When you run this code, you’ll get a label in either red or white showing the outcome of the offside decision:

Text in title bar

We can add another method in Action which simply calls the title() method in the turtle module:

# offside.py # ... In Action class def write_title(self, text): """Write in title bar of `turtle` window""" self.pitch.title(text)

And you can put a placeholder line in offside_rule_quiz.py for now, which you’ll improve later:

# offside_rule_quiz.py import turtle from offside import Action game = Action() game.write_title("OFFSIDE RULE GAME | Test 1 | Points: 0") game.update() if game.is_offside(): game.display_result("OFFSIDE", "red") else: game.display_result("NOT OFFSIDE", "white") turtle.done()

The window now has the text you chose in the title bar:

Dialog to get user input

We need the player of the Offside Rule Python Game to be able to input whether they think the scenario presented is offside. The turtle module has a textinput() method which displays a dialog box and waits for the user input. You can write a method in the Action class to use textinput():

# offside.py # ... In Action class def register_user_input(self): """ Get user to input whether scenario is offside or not """ self.user_response = self.pitch.textinput( "Is this offside?", "Type Y for offside and N for not offside" ).lower()[0]

textinput() required two arguments:

  • The text in the title bar of the dialog window
  • The prompt to show the user

It returns a string with whatever the user typed in the dialog box. You’re making the output a bit more robust by changing to lowercase and fetching the first element of the string. This means that “Yes”, “yes”, “Y”, and “y” all return "y". (And so does “Yeti”!)

You’re storing the result in a new data attribute called user_response. You can call this method in offside_rule_quiz.py:

# offside_rule_quiz.py import turtle from offside import Action game = Action() game.write_title("OFFSIDE RULE GAME | Test 1 | Points: 0") game.update() game.register_user_input() if game.is_offside(): game.display_result("OFFSIDE", "red") else: game.display_result("NOT OFFSIDE", "white") turtle.done()

When you run the code, you’re shown a dialog to enter your user input:

However, the program doesn’t take the user input into account for now. Next, let’s assign points if you get the offside call right.

Points tally

Here are some changes to offside_rule_quiz.py:

# offside_rule_quiz.py import turtle from offside import Action points = 0 game = Action() game.write_title(f"OFFSIDE RULE GAME | Test 1 | Points: {points}") game.update() game.register_user_input() if game.is_offside(): if game.user_response == "y": points += 1 game.display_result("OFFSIDE", "red") else: # Not Offside if game.user_response == "n": points += 1 game.display_result("NOT OFFSIDE", "white") game.write_title(f"OFFSIDE RULE GAME | Test 1 | Points: {points}") turtle.done()

You’ll see the points change in the title bar after you answer, assuming you get the decision right, of course!

Rather than accessing the data attribute user_response directly and checking for equality with "y" or "n" in offside_rule_quiz.py, you could create another method in the Action class in offside.py to check the user response and return a Boolean. This would probably be a neater solution, as you’re avoiding the need for the user of the class to access the instance variable. I’ll leave this as an exercise for you!

Repeat tests

Finally, you can run the test several times rather than just once. You’ll add the points each time the player gets the offside decision right. You need one last method in Action to clear the screen and tidy up before the next test:

# offside.py # ... In Action class def clear(self): """Clear all turtles from the screen and memory""" self.pitch.clear()

You’re now ready to finish the quiz:

# offside_rule_quiz.py import turtle import time from offside import Action number_of_tests = 10 points = 0 for test in range(1, number_of_tests + 1): game = Action() game.write_title(f"OFFSIDE RULE GAME | Test {test} | Points: {points}") game.update() game.register_user_input() if game.is_offside(): if game.user_response == "y": points += 1 game.display_result("OFFSIDE", "red") else: # Not Offside if game.user_response == "n": points += 1 game.display_result("NOT OFFSIDE", "white") if test == number_of_tests: break for countdown in range(5, 0, -1): game.pitch.title( f"OFFSIDE RULE GAME | Test {test} | Points: {points} | Next test in {countdown}...") game.update() time.sleep(1) game.clear() game.write_title(f"You've scored {points} out of {number_of_tests}") turtle.done() Offside Rule Quiz in Python

And that brings us to an end. Here’s a video of what the game looks like in this final version:

The final full versions of both offside.py and offside_rule_quiz.py are in an appendix at the end.

All that’s left is to ensure you understand the offside rule perfectly!

Appendix: Final Version of Code For The Offside Rule Quiz in Python

The classes are defined in offside.py:

# offside.py import random import turtle class Action: pitch_size = 800, 600 pitch_colour = "forest green" def __init__(self): # Pitch is the turtle Screen object # (technically _Screen object, as Screen() is a # function, but we can ignore this subtlety) self.pitch = turtle.Screen() self.pitch.tracer(0) self.pitch.setup( Action.pitch_size[0], Action.pitch_size[1], ) self.pitch.bgcolor(Action.pitch_colour) self.create_teams() self.choose_attacking_team() self.place_ball() # Label to show whether scenario is offside or not offside self.label = turtle.Turtle() self.label.penup() self.label.sety(self.pitch_size[1] // 3) self.label.hideturtle() def update(self): self.pitch.update() def create_teams(self): """Create two teams facing opposite directions""" self.left_to_right_team = Team( "orange", "dark salmon", -1 ) self.right_to_left_team = Team( "light blue", "dark blue", 1 ) def choose_attacking_team(self): """Pick which team is attacking in this action""" self.attacking_team_indicator = random.choice([-1, 1]) if self.attacking_team_indicator == -1: self.attacking_team = self.left_to_right_team self.defending_team = self.right_to_left_team else: self.attacking_team = self.right_to_left_team self.defending_team = self.left_to_right_team self.attacking_direction = ( 90 + 90 * self.attacking_team_indicator ) def place_ball(self): """ Assign ball to one of the players in the attacking team """ self.player_with_ball = random.choice( self.attacking_team.players ) ball = turtle.Turtle() ball.penup() ball.shape("circle") ball.color("white") ball.setposition(self.player_with_ball.position()) ball.setheading(self.attacking_direction) ball.forward(20) def is_offside(self): """ Check if scenario is offside or not :return: True if offside and False if not offside :rtype: bool """ # Check if frontmost attacker has the ball and kicks it # (or is exactly in line with player with ball–very low probability) if self.attacking_team.find_front_player_xpos() == self.player_with_ball.xcor(): return False # Check that front player is behind two back players front_player_pos = self.attacking_team.find_front_player_xpos() if self.attacking_team_indicator == -1: second_last_back_player_pos = min( self.defending_team.find_two_back_players_xpos() ) # Is attacker in own half if front_player_pos < 0: return False return front_player_pos > second_last_back_player_pos else: second_last_back_player_pos = max( self.defending_team.find_two_back_players_xpos() ) # Is attacker in own half if front_player_pos > 0: return False return front_player_pos < second_last_back_player_pos def display_result(self, result, colour): """ Show on screen whether scenario is offside or not offside """ self.label.color(colour) self.label.write( result, font=("Courier", 30, "bold"), align="center" ) def write_title(self, text): """Write in title bar of `turtle` window""" self.pitch.title(text) def register_user_input(self): """ Get user to input whether scenario is offside or not """ self.user_response = self.pitch.textinput( "Is this offside?", "Type Y for offside and N for not offside" ).lower()[0] def clear(self): """Clear all turtles from the screen and memory""" self.pitch.clear() class Player(turtle.Turtle): def __init__(self, team, colour, direction): super().__init__() # Turtle methods self.penup() self.setheading(direction) self.color(colour) self.shape("triangle") # Attributes/Methods specific to Player self.team = team self.set_bounds() self.place_on_pitch() def set_bounds(self): """ Set the left, right, top, and bottom limits where a player can be located on the pitch. Leave a boundary at the edge of the pitch to avoid players being partially off the pitch """ pitch_half_width = Action.pitch_size[0] // 2 pitch_half_height = Action.pitch_size[1] // 2 self.left_bound = -int(pitch_half_width * 0.95) self.right_bound = int(pitch_half_width * 0.95) self.bottom_bound = -int(pitch_half_height * 0.95) self.top_bound = int(pitch_half_height * 0.95) def place_on_pitch(self): """Place player in a random position on the pitch""" self.setposition( random.randint(self.left_bound, self.right_bound), random.randint(self.bottom_bound, self.top_bound), ) class GoalKeeper(Player): def __init__(self, team, colour, direction): super().__init__(team, colour, direction) def set_bounds(self): """ Set the left, right, top, and bottom limits where a goalkeeper can be located on the pitch. Goalkeeper is located close to own goal """ pitch_half_width = Action.pitch_size[0] // 2 pitch_half_height = Action.pitch_size[1] // 2 self.left_bound, self.right_bound = sorted( [ self.team.end * pitch_half_width * 0.98, self.team.end * pitch_half_width * 0.85, ] ) self.bottom_bound = -pitch_half_height * 0.5 self.top_bound = pitch_half_height * 0.5 class Team: def __init__(self, player_colour, keeper_colour, end): self.player_colour = player_colour self.keeper_colour = keeper_colour self.end = end # -1 if team playing left to right # 1 if team playing right to left self.players = [] self.direction = 90 + 90 * self.end self.create_team() def create_team(self): self.players.append( GoalKeeper(self, self.keeper_colour, self.direction) ) for _ in range(10): self.players.append( Player(self, self.player_colour, self.direction) ) def find_two_back_players_xpos(self): """ Find the back two players of the team. Takes into account whether team is playing right to left or left to right :return: pair of x-coordinates for the two back players :rtype: tuple[float] """ # sort using `xcor()`, lowest numbers first ordered_players = sorted( self.players, key=lambda player: player.xcor() ) back_two_indices = -1 - self.end, -self.end # if self.end is -1, then indices are 0 and 1, # so this represents the first two elements # (smallest `xcor()`, therefore furthest left) # if self.end is 1, then indices are -2 and -1, # so this represents the last two elements # (largest `xcor()`, therefore furthest right) return tuple( ordered_players[idx].xcor() for idx in back_two_indices ) def find_front_player_xpos(self): """ Find the frontmost player of the team. Takes into account whether team is playing right to left or left to right :return: x-coordinate of the forward-most player :rtype: float """ # sort using `xcor()`, lowest numbers first ordered_players = sorted( self.players, key=lambda player: player.xcor() ) front_one_index = min(self.end, 0) # if self.end is -1, index is -1 so represents the # last item in list (largest `xcor()`), therefore # furthest right # if self.end is 1, index is 0 so represents the # first item in list (smallest `xcor()`), therefore # furthest left return ordered_players[front_one_index].xcor()

The quiz is in offside_rule_quiz.py:

# offside_rule_quiz.py import turtle import time from offside import Action number_of_tests = 10 points = 0 for test in range(1, number_of_tests + 1): game = Action() game.write_title(f"OFFSIDE RULE GAME | Test {test} | Points: {points}") game.update() game.register_user_input() if game.is_offside(): if game.user_response == "y": points += 1 game.display_result("OFFSIDE", "red") else: # Not Offside if game.user_response == "n": points += 1 game.display_result("NOT OFFSIDE", "white") if test == number_of_tests: break for countdown in range(5, 0, -1): game.pitch.title( f"OFFSIDE RULE GAME | Test {test} | Points: {points} | Next test in {countdown}...") game.update() time.sleep(1) game.clear() game.write_title(f"You've scored {points} out of {number_of_tests}") turtle.done() Get the latest blog updates

No spam promise. You’ll get an email when a new blog post is published

The post Write A Football Offside Rule Quiz in Python While Practising Object-Oriented Programming appeared first on The Python Coding Book.

Categories: FLOSS Project Planets

The Drop Times: Drupal Community Getting Ready to Celebrate the Arrival of Drupal 10

Planet Drupal - Sat, 2022-11-26 19:00
Drupal users are celebrating the arrival of Drupal 10. The Celebration is bringing a sense of excitement and optimism to the Drupal Community.
Categories: FLOSS Project Planets

Pages