Feeds

Louis-Philippe Véronneau: Grading using the Wacom Intuos S

Planet Debian - Sun, 2022-01-09 16:30

I've been teaching economics for a few semesters already and, slowly but surely, I'm starting to get the hang of it. Having to deal with teaching remotely hasn't been easy though and I'm really hoping the winter semester will be in-person again.

Although I worked way too much last semester1, I somehow managed to transition to using a graphics tablet. I bought a Wacom Intuos S tablet (model CTL-4100) in late August 2021 and overall, I have been very happy with it. Wacom Canada offers a small discount for teachers and I ended up paying 115 CAD (~90 USD) for the tablet, an overall very reasonable price.

Unsurprisingly, the Wacom support on Linux is very good and my tablet worked out of the box. The only real problem I had was by default, the tablet sometimes boots up in Android mode, making it unusable. This is easily solved by pressing down on the pad's first and last buttons for a few seconds, until the LED turns white.

The included stylus came with hard plastic nibs, but I find them too slippery. I eventually purchased hard felt nibs, which increase the friction and makes for a more paper-like experience. They are a little less durable, but I wrote quite a fair bit and still haven't gone through a single one yet.

Learning curve

Learning how to use a graphical tablet took me at least a few weeks! When writing on a sheet of paper, the eyes see what the hand writes directly. This is not the case when using a graphical tablet: you are writing on a surface and see the result on your screen, a completely different surface. This dissociation takes a bit of practise to master, but after going through more than 300 pages of notes, it now feels perfectly normal.

Here is a side-by-side comparison of my very average hand-writing2:

  1. on paper
  2. using the tablet, the first week
  3. using the tablet, after a couple of months

I still prefer the result of writing on paper, but I think this is mostly due to me not using the pressure sensitivity feature. The support in xournal wasn't great, but now that I've tried it in xournalpp (more on this below), I think I will be enabling it in the future. The result on paper is also more consistent, but I trust my skills will improve over time.

Use case

The first use case I have for the tablet is grading papers. I've been asking my students to submit their papers via Moodle for a few semesters already, but until now, I was grading them using PDF comments. The experience wasn't great3 and was rather slow compared to grading physical copies.

I'm also a somewhat old-school teacher: I refuse to teach using slides. Death by PowerPoint is real. I write on the blackboard a lot4 and I find it much easier to prepare my notes by hand than by typing them, as the end result is closer to what I actually end up writing down on the board.

Writing notes by hand on sheets of paper is a chore too, especially when you revisit the same materiel regularly. Being able to handwrite digital notes gives me a lot more flexibility and it's been great.

So far, I have been using xournal to write notes and grade papers, and although it is OK, it has a bunch of quirks I dislike. I was waiting for xournalpp to be packaged in Debian, and it now is5! I'm looking forward to using it next semester.

Towards a better computer monitor

I have also been feeling the age of my current computer monitor. I am currently using an old 32" 1080p TV from LG and up until now, I had been able to deal with the drawbacks. The colors are pretty bad and 1080p for such a large display isn't great, but I got used to it.

What I really noticed when I started using my graphics tablet was the input lag. It's bad enough that there's a clear jello effect when writing and it eventually gives me a headache. It's so bad I usually prefer to work on my laptop, which has a nicer but noticeably smaller panel.

I'm currently looking to replace this aging TV6 by something more modern. I have been waiting out since I would like to buy something that will last me another 10 years if possible. Sadly, 32" high refresh rate 4K monitors aren't exactly there yet and I haven't found anything matching my criteria. I would probably also need a new GPU, something that is not easy to come by these days.

  1. I worked at two colleges at the same time, teaching 2 different classes (one of which I was giving for the first time...) to 6 groups in total. I averaged more than 60h per week for sure. 

  2. Yes, I only write in small caps. Students love it, as it's much easier to read on the blackboard. 

  3. Although most PDF readers support displaying comments, some of my more clueless students still had trouble seeing them and I had to play tech support more than I wanted. 

  4. Unsurprisingly, my students also love it. One of the most common feedback I get at the end of the semester is they hate slides too and are very happy I'm one of the few teachers who writes on the board. 

  5. Many thanks to Barak A. Pearlmutter for maintaining this package. 

  6. It dates back from 2010, when my mom replaced our old CRT by a flat screen. FullHD TVs were getting affordable and I wasn't sad to see our tiny 20-something inches TV go. I eventually ended up with the LG flatscreen a few years later when I moved out in my first apartment and my mom got something better. 

Categories: FLOSS Project Planets

ItsMyCode: [Solved] NameError: name ‘pd’ is not defined

Planet Python - Sun, 2022-01-09 15:26

ItsMyCode |

In Python,  NameError: name ‘pd’ is not defined occurs when you import the pandas library but fail to provide the alias as pd while importing it.

In this article, let us look at what is NameError name pd is not defined and how to resolve this error with examples.

Solution NameError: name ‘pd’ is not defined

Let us take a simple example to reproduce this error. In the below example, we have imported the pandas library and created a pandas DataFrame.

# import pandas library import pandas import numpy as np # create pandas DataFrame df = pd.DataFrame(np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]), columns=['a', 'b', 'c']) # print dataframe print(df)

Output

Traceback (most recent call last): File "C:\Personal\IJS\Code\main.py", line 6, in <module> df = pd.DataFrame(np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]), NameError: name 'pd' is not defined. Did you mean: 'id'?

When we run the code, we get  NameError: name ‘pd’ is not defined  since we did not provide an alias while importing the pandas library.

There are multiple ways to resolve this issue. Let us look at all the approaches to solve the NameError.

Method 1 – Importing pandas with Alias as pd

The simplest way to resolve this error is by providing an alias as pd while importing the pandas library. Let’s fix our code by providing an alias and see what happens.

# import pandas library import pandas as pd import numpy as np # create pandas DataFrame df = pd.DataFrame(np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]), columns=['a', 'b', 'c']) # print dataframe print(df)

Output

a b c 0 1 2 3 1 4 5 6 2 7 8 9

The syntax “import pandas as pd” is commonly used because it offers a more concise way to call pandas functions, and the code is more readable as we do not have to type “pandas” each time.

Method 2 – Importing all the functions from pandas

There might be a situation where you need to import all the functions from the pandas library, and to do that, we will be using the below syntax.

from pandas import *

In this case, you do not need any reference to call any functions of pandas. You can directly call the methods without using an alias, and in this example we can directly create the DataFrame as shown below.

# import pandas library from pandas import * import numpy as np # create pandas DataFrame df = DataFrame(np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]), columns=['a', 'b', 'c']) # print dataframe print(df)

Output

a b c 0 1 2 3 1 4 5 6 2 7 8 9 Method 3 – Importing pandas package without an alias

Another way is to import a complete pandas package and call the functions directly with the pandas name without defining an alias.

# import pandas library import pandas import numpy as np # create pandas DataFrame df = pandas.DataFrame(np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]), columns=['a', 'b', 'c']) # print dataframe print(df)

Output

a b c 0 1 2 3 1 4 5 6 2 7 8 9

In the above example, we import the complete pandas library and use pandas.DataFrame() method to create pandas DataFrame.

Note: If you are running the code in Jupyter notebook, ensure that you run the cell where you have imported the pandas and then run the rest of the code.

The post [Solved] NameError: name ‘pd’ is not defined appeared first on ItsMyCode.

Categories: FLOSS Project Planets

ItsMyCode: [Solved] NameError: name &#8216;np&#8217; is not defined

Planet Python - Sun, 2022-01-09 15:06

ItsMyCode |

In Python,  NameError: name ‘np’ is not defined occurs when you import the NumPy library but fail to provide the alias as np while importing it.

In this article, let us look at what is NameError name np is not defined and how to resolve this error with examples.

Solution NameError: name ‘np’ is not defined

Let us take a simple example to reproduce this error. In the below example, we have imported the NumPy library and defined a NumPy array. 

# import numpy library import numpy # define numpy array array = np.array([[12, 33], [21, 45]]) # print values in array format print(array)

Output

Traceback (most recent call last): File "C:\Personal\IJS\Code\main.py", line 5, in <module> array = np.array([[12, 33], [21, 45]]) NameError: name 'np' is not defined

When we run the code, we get  NameError: name ‘np’ is not defined  since we did not provide an alias while importing the NumPy library.

There are multiple ways to resolve this issue. Let us look at all the approaches to solve the NameError.

Method 1 – Importing NumPy with Alias as np

The simplest way to resolve this error is by providing an alias as np while importing the NumPy library. Let’s fix our code by providing an alias and see what happens.

# import numpy library import numpy as np # define numpy array array = np.array([[12, 33], [21, 45]]) # print values in array format print(array)

Output

[[12 33] [21 45]]

The syntax “import numpy as np” is commonly used because it offers a more concise way to call NumPy functions, and the code is more readable as we do not have to type “numpy” each time.

Method 2 – Importing all the functions from NumPy

There might be a situation where you need to import all the functions from the NumPy library, and to do that, we will be using the below syntax.

from numpy import *

In this case, you do not need any reference to call any functions of NumPy. You can directly call the methods without using an alias, as shown below.

# import numpy library from numpy import * # define numpy array array = array([[12, 33], [21, 45]]) # print values in array format print(array)

Output

[[12 33] [21 45]] Method 3 – Importing NumPy package without an alias

Another way is to import a complete NumPy package and call the functions directly with the NumPy name without defining an alias.

# import numpy library import numpy # define numpy array array = numpy.array([[12, 33], [21, 45]]) # print values in array format print(array)

Output

[[12 33] [21 45]]

In the above example, we import the complete NumPy library and use numpy.array() method to create an array.

The post [Solved] NameError: name ‘np’ is not defined appeared first on ItsMyCode.

Categories: FLOSS Project Planets

ItsMyCode: ValueError: If using all scalar values, you must pass an index

Planet Python - Sun, 2022-01-09 12:58

ItsMyCode |

If you pass all scalar values while creating pandas Dataframe in Python, you will encounter “ValueError: If using all scalar values, you must pass an index

In this tutorial, we will learn what is ValueError: If using all scalar values, you must pass an index error means and how to resolve this ValueError in your program with examples.

Let us take a simple example to reproduce this issue.

# import pandas library import pandas as pd #define scalar values a = 1 b = 2 c = 3 d = 4 # creating DataFrame from scalar values df = pd.DataFrame({'A': a, 'B': b, 'C': c, 'D': d}) print(df)

Output

raise ValueError("If using all scalar values, you must pass an index") ValueError: If using all scalar values, you must pass an index

In the above example, we have declared scalar value and attempted to create a pandas DataFrame by passing a scalar value. 

When we run the code, Python will raise ValueError: If using all scalar values, you must pass an index

How to fix ValueError: If using all scalar values, you must pass an index?

The most common way to create DataFrames in Python is by using lists and dictionaries. There are three ways to fix the error. Let us look at each of them with examples.

Method 1: Transform Scalar Values to List

The simplest way is to transform the scalar values into a list and pass it to a DataFrame, as shown below.

# import pandas library import pandas as pd #define scalar values a = 1 b = 2 c = 3 d = 4 # creating DataFrame by transforming Scalar Values to List df = pd.DataFrame({'A': [a], 'B': [b], 'C': [c], 'D': [d]}) print(df)

Output

A B C D 0 1 2 3 4 Method 2: Place Scalar Values into Dictionary 

Another way is to place the scalar values into the dictionary and pass it to Pandas DataFrame as shown below.

# import pandas library import pandas as pd #define scalar values a = 1 b = 2 c = 3 d = 4 # storing the dictionary of scalar values p_dict = {'A':1, 'B':2, 'C':3, 'D':4} # creating DataFrame by passing dictionary into List df = pd.DataFrame(p_dict) print(df)

Output

A B C D 0 1 2 3 4 Method 3: Pass Scalar Values and Pass Index

We can even pass an index with scalar values to DataFrame. When you pass an index, pandas will treat your dictionary keys as column names and the values as what the column should contain for each of the values in the index.

# import pandas library import pandas as pd # define scalar values a = 1 b = 2 c = 3 d = 4 # creating DataFrame from scalar values and passing index df = pd.DataFrame({'A': a, 'B': b, 'C': c, 'D': d}, index=[0]) print(df)

Output

A B C D 0 1 2 3 4

The post ValueError: If using all scalar values, you must pass an index appeared first on ItsMyCode.

Categories: FLOSS Project Planets

ItsMyCode: No handles with labels found to put in legend

Planet Python - Sun, 2022-01-09 11:22

ItsMyCode |

In Python matplotlib No handles with labels found to put in legend occur if you have not defined the label parameters whenever you plot the figure and try to call the plt.legend() method.

The matplotlib.pyplot  is a state-based interface to matplotlib and provides a way to plot interactive figures in Python.  

We can use matplotlib.pyplot.legend() method to place a legend on the axes.

However, if we do not add the labels parameter and then call the matplotlib.pyplot.legend() function, you will get No handles with labels found to put in legend. 

If you are using the latest version of Python, then the error would be No artists with labels found to put in legend. Note that artists whose label start with an underscore are ignored when legend() is called with no argument.

import numpy as np import matplotlib.pyplot as plt x = np.linspace(0, 20, 2000) y1 = np.sin(x) y2 = np.arcsin(x) plt.plot(x, y1) plt.plot(x, y2) plt.legend() plt.show()

Output

No handles with labels found to put in legend.Note that artists whose label start with an underscore are ignored when legend() is called with no argument.

Another way you get this error is if you call the legend method before plotting it. Ensure to verify your code and call the legend function after completing the plotting.

Solution – No handles with labels found to put in legend

Now that we know why the error occurs, let us see how to resolve the error and plot the legends correctly.

There are three different ways to call the matplotlib.pyplot.legend() method in Python.

Calling legend() without any arguments

If you want the legends to be detected automatically, you can call legend() method without passing any arguments. This will automatically detect the legend elements, including the labels, and plot them for you.

import numpy as np import matplotlib.pyplot as plt x = np.linspace(0, 8, 1000) y1 = np.sin(x) y2 = np.arcsin(x) plt.plot(x, y1, label='sin') plt.plot(x, y2, label='arcsin') plt.legend() plt.show()

Output

Passing labels as arguments to legend() method

You can pass the labels as an argument to the legend() method as iterable of strings. 

Each string is used as a label for the elements in the order they were created.

import numpy as np import matplotlib.pyplot as plt x = np.linspace(0, 8, 1000) y1 = np.sin(x) plt.plot([4, 7, 9]) plt.plot(x, y1, '-b') plt.legend(['Line1', 'Line2']) plt.show() Note: This is not the recommended approach since the relationship between the elements and the passed labels exist only through the order it created and can lead to confusion. Passing handles and labels as a parameter to legend() method

If we need complete control, we can pass the elements followed by the iterable of strings as labels explicitly to the legend() function.

import numpy as np import matplotlib.pyplot as plt x = np.linspace(0, 8, 1000) y1 = [4, 7, 9] y2 = np.sin(x) y3 = np.arcsin(x) line, = plt.plot(y1) sine, = plt.plot(x, y2) arcsine, = plt.plot(x, y3) plt.legend(handles = [line, sine, arcsine], labels = ['Line', 'Sine', 'Arcsine']) plt.show()

Reference: Stackoverflow, Educative

The post No handles with labels found to put in legend appeared first on ItsMyCode.

Categories: FLOSS Project Planets

Sebastian Pölsterl: scikit-survival 0.17 released

Planet Python - Sun, 2022-01-09 10:45

This release adds support for scikit-learn 1.0, which includes support for feature names. If you pass a pandas dataframe to fit, the estimator will set a feature_names_in_ attribute containing the feature names. When a dataframe is passed to predict, it is checked that the column names are consistent with those passed to fit. The example below illustrates this feature.

For a full list of changes in scikit-survival 0.17.0, please see the release notes.

Installation

Pre-built conda packages are available for Linux, macOS, and Windows via

conda install -c sebp scikit-survival

Alternatively, scikit-survival can be installed from source following these instructions.

Feature Names Support

Prior to scikit-survival 0.17, you could pass a pandas dataframe to estimators’ fit and predict methods, but the estimator was oblivious to the feature names accessible via the dataframe’s columns attribute. With scikit-survival 0.17, and thanks to scikit-learn 1.0, feature names will be considered when a dataframe is passed.

Let’s illustrate feature names support using the Veteran’s Lung Cancer dataset.

from sksurv.datasets import load_veterans_lung_cancer X, y = load_veterans_lung_cancer() X.head(3) Age_in_years Celltype Karnofsky_score Months_from_Diagnosis Prior_therapy Treatment 0 69.0 squamous 60.0 7.0 no standard 1 64.0 squamous 70.0 5.0 yes standard 2 38.0 squamous 60.0 3.0 no standard

The original data has 6 features, three of which contain strings, which we encode as numeric using OneHotEncoder.

from sksurv.preprocessing import OneHotEncoder transform = OneHotEncoder() Xt = transform.fit_transform(X)

Transforms now have a get_feature_names_out() method, which will return the name of features after the transformation.

transform.get_feature_names_out() array(['Age_in_years', 'Celltype=large', 'Celltype=smallcell', 'Celltype=squamous', 'Karnofsky_score', 'Months_from_Diagnosis', 'Prior_therapy=yes', 'Treatment=test'], dtype=object)

The transformed data returned by OneHotEncoder is again a dataframe, which can be used to fit Cox’s proportional hazards model.

from sksurv.linear_model import CoxPHSurvivalAnalysis model = CoxPHSurvivalAnalysis().fit(Xt, y)

Since we passed a dataframe, the feature_names_in_ attribute will contain the names of the dataframe used when calling fit.

model.feature_names_in_ array(['Age_in_years', 'Celltype=large', 'Celltype=smallcell', 'Celltype=squamous', 'Karnofsky_score', 'Months_from_Diagnosis', 'Prior_therapy=yes', 'Treatment=test'], dtype=object)

This is used during prediction to check that the data matches the format of the training data. For instance, when passing a raw numpy array instead of a dataframe, a warning will be issued.

pred = model.predict(Xt.values) UserWarning: X does not have valid feature names, but CoxPHSurvivalAnalysis was fitted with feature names

Moreover, it will also check that the order of columns matches.

X_reordered = pd.concat( (Xt.drop("Age_in_years", axis=1), Xt.loc[:, "Age_in_years"]), axis=1 ) pred = model.predict(X_reordered) FutureWarning: The feature names should match those that were passed during fit. Starting version 1.2, an error will be raised. Feature names must be in the same order as they were in fit.

For more details on feature names support, have a look at the scikit-learn release highlights.

Categories: FLOSS Project Planets

2022 resolution: become machine independent again

Planet KDE - Sun, 2022-01-09 10:39

I change jobs frequently, I travel a lot, I work in the operating system space so I like to try out new distros, installers, recovery measures… In addition, even when I am at home, in Málaga or Los Llanos De Aridane, Canary Islands, I like to take notes and write at different places since I find little inspiration at my office…

All these factors together means that I end up having several machines: laptops, convertibles, tablets, phone, RPis… and with various machines it comes the information, configurations and applications hell.

The mess

There used to be a time when I had the discipline to keep my information well managed as well as separated between work, personal related and junk. The result was that when travelling, I used to carry a single machine.

Those days are long time gone.

When working for companies that gave me a working laptop, I kept telling myself that carrying several machines was the price to pay for complying with the corporate policies. The reality was that those corporate policies were to a great extent useless, either because they did not consider remote work properly or because it considered the laptop as “part of the trusted network”, a secured node. We know it is not.

When working as contractor-consultant, the situation should have improved. It did in some aspects but not in others. The number of applications I needed to install exploded, so it did the effort to keep information segmented and on sync. The life expectancy of the machines shorten due to travelling a lot and my passion for carrying small convertibles/tablets to take notes and drawing wherever I go ended up cancelling all the benefits of me having a single machine to work on job related and personal matters while considering it an untrusted node at the corporate policy at the time.

The awakening

The pandemic has work against me. Such a long time without really travelling (beyond my two locations) had as a consequence that some of my good habits to keep the “machine independent” challenge under control were gone. I realized it when, despite carrying 3 machines in my first business trip since the pandemic started, back in November 2021. I still could not access to a couple of places because I did not have the credentials available or they were not up-to-date. My backpack was ridiculously heavy and I still could not perform some basic personal activities.

How could I let my self, a professional, get to this point?

In addition, I am increasingly worried about data privacy. I have taken several steps the last couple of years in this front, but for every step in the right direction I perform, I end up taking one in the wrong one. It is so hard to come into good terms with data privacy nowadays… The effort and knowledge required is simply too high for a regular citizen. I feel in this front like I did back in the days I started using Open Source. Like back then, I feel the world is against me. But I lack now the same energy level I had. A sign of getting old, I guess.

2022 resolution

So one of my 2022 resolutions is to go back 10 years, when I managed to carry a single laptop in several weeks long trips and not being obsessed with loosing or breaking it. It is a good resolution, isn’t it? Good for my back, reduce the time at security checks at airports… And I resolved to achieve this goal while increasing the levels of respect for my own data privacy.

I understand it is going to be a hell of an effort, specially considering that I do not have all the time in the world and I am technically limited.

Actions: phase 1

So I am taking a few actions this first quarter:

  1. Centralize all my credentials, including moving away from browser password managers. After thinking about it, I have come to the conclusion that, in my case, this should be the first step. I use Firefox in 95% of the cases, but I cannot depend any more on browser password managers and encrypted .txt files. I am going for Bitwarden as solution for a bunch of reasons. One is essential: I can manage corporate and personal credentials simultaneously using a multiplatform client as well as a plugin for Firefox. I am halfway through on this action. How can a normal person end up with so many credentials? It is crazy.
  2. Install the same distro on as many of my machines as possible. In my case, openSUSE Leap. I will leave one for playing around with distros, especially openSUSE Tumbleweed. This will be my solution to avoid the “application (version) hell” and unify how I do some things, like the next one. Android, you suck at this, by the way.
  3. Unify how I create backups and centralize where I store them. Although I am not fully convinced yet of this approach, I am going for a small, low power consumption, home server and external SSD drives connected to it. I will be able to use the same backup solution for all my machines, encrypt them in the same way, store them in a structured way…. It will be a great improvement compared to the current situation.
    1. Having a home server increases the management effort and brings new challenges due to the single point of failure concept. Time will tell if these risks are worth taking it for somebody like me.
    2. As home server I bought a Slimbook Zero. What a nice price beauty!
  4. Copy my critical information to the home server and keep it on sync. The idea is not to move the information to the home server at first but to have it there synchronized whenever I can. I have information stored in laptops, SSD drives… but also in various cloud service providers. This task is not going to be easy, given that I store information that is 20 years old.
    1. The first action is to install Nextcloud in the home server. I will need help on this one because the LAMP stack is not my thing. The Nextcloud documentation is good, but learning about the LAMP stack is not in my ToDo this year. Learning how to use and manage Nextcloud is. Hey, my time is very limited and the LAMP stack is so increasingly broken…
    2. The second action is to have git installed in the home server so I can sync all the git repos I have in the different machines. This is specially relevant for me despite not being a coder because I use zim-wiki to manage my personal information for many years, using git as backend. I will cry of joy when this is done and I have all my notes accessible from any machine with a single pull command. I cannot wait.
    3. The third action will be to keep what I currently store in GDrive on sync with the home server. Will I be able to stop using GDrive as store unit by the end of this 2022? Given the existing level of integration I have with my phone, tablet and Remarkable2, it would represent a great achievement, specially considering that. I am a GMail user (IMAP with KMail) and heavy Google Calendar user, which makes this goal even harder.
Phase 2: validate these actions as remote user

The next step is to prove myself that the above decisions and actions makes sense for a heavy traveller like myself. I will need to, at least:

  • Make the home server accessible remotely in a secure way, avoiding turning it into the single point of failure, which takes me to the following actions.
  • Find a second remotely and accessible storage unit for the key encrypted backups. If I loose the home server, specially while travelling, I need a solution to restore the data in a reasonable amount of time. Should that second unit be one of my laptops or should I find a cloud provider? Maybe both?
  • I will need to add a UPS to the equation for the home server and the home router to reduce the risks associated to power peaks or short outages.
  • I will need a new plan to deal with my laptop being stolen or broken while travelling so I can be productive again in a matter of hours.
  • I will need to contemplate the scenario where I get an electricity or connectivity outage at home that leaves the home server unavailable until I am back home.

It seems that the pandemic will play in my favour for once, Most of my business trips has been cancelled this 2022Q1 so I will have some time to prepare these measures.

Additional actions

I will need to store all the existing information from the different home directories and SSD drives into Nextcloud and make them consumable from any of the machines. For instance…years of mails…. oh dear, this will be tough.

Information from other cloud/web services should follow, like WordPress, Miro, social media… This point is in better shape that it was three or four years back. I have taken some actions to prevent the increasing spreading of personal information. Again, the goal at this point is to have such information also stored in my home server with a reasonable level of synchronicity not to use it a default storage unit.

Another step is to centralize the most relevant configurations applied to the different machines. After being a KDE, RSS or a Firefox user for so long, for instance, I have very specific configurations I use to remain productive.

As a consequence of these actions I plan to take, I should be to be able to decommission machines as well as spin off new ones faster and with less effort than today.

If I manage to do all the above this 2022, who knows, maybe I will be in a good position to move away from GMail and GCalendar as main mailing and calendaring solutions in 2023, keeping as backup/sync options with other services.

Conclusion

As many of you, I am not very good at achieving my New Year Resolutions. The most likely scenario will be one in which, as the existing pain reduces, I will increasingly forget about the pending points enumerated above.

Knowing myself, I decided to write this post, so you can remind me about this resolution when you see me or talk to me. Social/peer pressure is a very good incentive, in my experience. This post will also increase my level of shame when I read it back next year, while thinking in my 2023 resolutions. Yes, I am taking drastic measures here.

Dear reader, help me! I am such a capital sinner (laziness).

Ah, and remember, more is less. If you buy a new laptop, decommission the old one and give it to somebody that will not request support from you.

Categories: FLOSS Project Planets

ItsMyCode: [Solved] Python can’t Multiply Sequence by non-int of type &#8216;str&#8217;

Planet Python - Sun, 2022-01-09 06:35

ItsMyCode |

The TypeError: can’t multiply sequence by non-int of type ‘str’ occurs if we multiply a string by another string without converting into an integer or floating-point.

In this tutorial, we will learn what exactly TypeError: can’t multiply sequence by non-int of type ‘str’ error means and how to resolve this TypeError in your program with examples.

TypeError: can’t multiply sequence by non-int of type ‘str’

Python is one of the best programming languages because of its features and simplicity. One such fantastic feature in Python is we can multiply strings with numbers.

Multiplying string with an integer

Let’s take an example to demonstrate multiplying string with numbers.

The other popular programming languages will never let you to multiple strings and integers. However, we can perform a multiplication between string and integer in Python. After the multiplication, the string is repeated for n times, as shown below.

text = "ItsMyCode" n = 3 print(text*n)

Output

ItsMyCodeItsMyCodeItsMyCode

Here the string “ItsMyCode” is repeated multiplied by three and repeated three times in the output.

If we try to multiply the string with another string then the Python interpreter will throw TypeError: can’t multiply sequence by non-int of type ‘str’.

Multiplying string with another string

You cannot multiply a string with a non-integer value in Python. If we multiply a string with another string without converting to integer or floating point, we get an error can’t multiply sequence by non-int of type ‘str’.

Let us take a simple example of multiplying two numbers.

num1 ='5' num2 ='6' output =num1 * num2 print(output)

Output

Traceback (most recent call last): File "C:\Personal\IJS\Code\main.py", line 3, in <module> output =num1 * num2 TypeError: can't multiply sequence by non-int of type 'str'

Even though the number entered here is equal to the integer values, the Python interpreter will still consider it as a string and raise a TypeError.

The simplest way to resolve this issue is by converting both the strings into an integer and then performing a multiplication operation, as shown below.

num1 ='5' num2 ='6' output = int(num1) * int(num2) print(output)

Output

30 Solution TypeError: can’t multiply sequence by non-int of type ‘str’

Now we know that TypeError: can’t multiply sequence by non-int of type str is caused by multiplying a string with another string. Let us see how we can resolve this error with an example.

Usually, we get this error when we receive input from the user, and the input() method alway returns the data in a string format.

Consider we have to calculate the total tax amount paid based on the distance traveled and the fare price.

In the above example, we are reading the fare price and distance data as user input, and we are calculating the tax amount by multiplying the (fare_price * distance)*(tax_percentage/100)

Even though the user inputs valid data, the input() method returns a string, meaning that fare_price and distance values are in string format. Hence we end up multiplying two strings resulting in the TypeError: can’t multiply sequence by non-int of type ‘str’.

tax_percentage = 5 fare_price = input("Please enter the fare amount charged ") distance = input("Please enter the distance travelled to calculate the total fare - ") total_fare = (fare_price * distance) * (5/100) print(total_fare)

Output

Please enter the fare amount charged 100 Please enter the distance travelled to calculate the total fare - 5 Traceback (most recent call last): File "C:\Personal\IJS\Code\main.py", line 4, in <module> total_fare = (fare_price * distance) * 0.05 TypeError: can't multiply sequence by non-int of type 'str'

The best way to resolve this error is to convert the user input string to a floating-point using the float() method. 

This allows us to multiply the order_value and discount because both are floating-point numbers.

tax_percentage = 5 fare_price = float(input("Please enter the fare amount charged ")) distance = float(input("Please enter the distance travelled to calculate the total fare - ")) total_fare = (fare_price * distance) * (5/100) print(total_fare)

Output

Please enter the fare amount charged 250.50 Please enter the distance travelled to calculate the total fare - 3.4 42.585 Note: We cannot multiply strings with floating-point numbers,if we do Python interpreter will throw TypeError: can't multiply sequence by non-int of type 'float'. Hence in the above example we have to convert both the inputs into floating-point and then perform multiplication. Conclusion

We cannot multiply strings with any non integers values such as float, string etc. If we multiply a string with another string without converting into an integer we get TypeError: can’t multiply sequence by non-int of type 'str'

In order to solve this issue, TypeError: can’t multiply sequence by non-int of type ‘str’ ensure that either you are performing a multiplication between string and integer or alternatively you can convert all the string values into a floating-point number before performing any calculations. 

The post [Solved] Python can’t Multiply Sequence by non-int of type ‘str’ appeared first on ItsMyCode.

Categories: FLOSS Project Planets

Features VS Stability: KDE!

Planet KDE - Sun, 2022-01-09 06:11
Saturday night, a lighter kind of video. 💸💸 Help me contribute to KDE and do these videos: 💸💸 Patreon: https://www.patreon.com/niccolove Youtube: https://www.youtube.com/channel/UCONH73CdRXUjlh3-DdLGCPw/join Paypal: https://paypal.me/niccolove Stay in the loop: https://t.me/veggeroblog My website is https://niccolo.venerandi.com and if you want to contact me, my telegram handle is [at] veggero.
Categories: FLOSS Project Planets

Juri Pakaste: Async Swift and ArgumentParser

Planet Python - Sun, 2022-01-09 05:00

Swift 5.5 brought us async functions. ArgumentParser is the most popular way to write command line interfaces with Swift. Swift 5.5 supports an asynchronous main function, but ArgumentParser does not, as of version 1.0.2.

To bridge this gap, you can call ArgumentParser manually from your asynchronous main function, like this:

import ArgumentParser struct MyCommand: ParsableCommand { @Argument var arg: String // Usually you'd write a `run` function, but it has to be synchronous. func runAsync() async throws { /* … */ } } @main enum Main { static func main() async throws { let args = Array(CommandLine.arguments.dropFirst()) do { let command = try MyCommand.parse(args) try await command.runAsync() } catch { MyCommand.exit(withError: error) } } }
Categories: FLOSS Project Planets

ItsMyCode: TypeError: list indices must be integers or slices, not str

Planet Python - Sun, 2022-01-09 02:35

ItsMyCode |

If you are accessing the elements of a list in Python, you need to access it using its index position or slices. However, if you try to access a list value using a string Python will raise TypeError: list indices must be integers or slices, not str exception.

In this tutorial, we will learn what “list indices must be integers or slices, not str” error means and how to resolve this TypeError in your program with examples.

TypeError: list indices must be integers or slices, not str

Lists are always indexed using a valid index number, or we can use slicing to get the elements of the list. Below is an example of indexing a list.

# Example 1: of list indexing my_list = [1, 2, 3, 4, 5, 6, 7, 8] print(my_list[5]) # Example 2: of list slicing fruits = ["Apple", "Orange", "Lemon", "Grapes"] print("Last 2 fruits is", fruits[2:4])

Output

6 Last 2 fruits is ['Lemon', 'Grapes']

The first example is we use an integer as an index to get the specific element of a list.

In the second example, we use a Python slicing technique by defining a start point and end-point to retrieve the sublist from the main list.

Now that we know how to access the elements of the list, there are several scenarios where developers tend to make mistakes, and we get a TypeError. Let us take a look at each scenario with examples.

Scenario 1: Reading string input from a user

It’s the most common scenario where we do not convert the input data into a valid type in Menu-driven programs, leading to TypeError. Let us take an example to reproduce this issue.

Consider an ATM menu-driven example where the user wants to perform certain operations by providing the input to the program.

menu = ["Deposit Cash", "Withdraw Case", "Check Balance", "Exit"] choice = input( 'Choose what would you like to perform (Valid inputs 0, 1, 2, 3)') print(menu[choice])

Output

Choose what would you like to perform (Valid inputs 0, 1, 2, 3)2 Traceback (most recent call last): File "C:\Personal\IJS\Code\main.py", line 13, in <module> print(menu[choice]) TypeError: list indices must be integers or slices, not str

When the user inputs any number from 0 to 3, we get TypeError: list indices must be integers or slices, not str, because we are not converting the input variable “choice” into an integer, and the list is indexed using a string.

We can resolve the TypeError by converting the user input to an integer, and we can do this by wrapping the int() method to the input, as shown below.

menu = ["Deposit Cash", "Withdraw Case", "Check Balance", "Exit"] choice = int(input( 'Choose what would you like to perform (Valid inputs 0, 1, 2, 3) - ' )) print(menu[choice])

Output

Choose what would you like to perform (Valid inputs 0, 1, 2, 3) - 2 Check Balance Scenario 2: Trying to access Dictionaries list elements using a string

Another reason we get TypeError while accessing the list elements is if we treat the lists as dictionaries. 

In the below example, we have a list of dictionaries, and each list contains the actor and name of a movie.

actors = [ { 'name': "Will Smith", 'movie': "Pursuit of Happiness" }, { 'name': "Brad Pitt", 'movie': "Ocean's 11" }, { 'name': "Tom Hanks", 'movie': "Terminal" }, { 'name': "Leonardo DiCaprio", 'movie': "Titanic" }, { 'name': "Robert Downey Jr", 'movie': "Iron Man" }, ] actor_name = input('Enter the actor name to find a movie - ') for i in range(len(actors)): if actor_name.lower() in actors['name'].lower(): print('Actor Name: ', actors['name']) print('Movie: ', actors['movie']) break else: print('Please choose a valid actor')

Output

Enter the actor name to find a movie - Brad Pitt Traceback (most recent call last): File "C:\Personal\IJS\Code\program.py", line 27, in <module> if actor_name.lower() in actors['name'].lower(): TypeError: list indices must be integers or slices, not str

We need to display the movie name when the user inputs the actor name.

When we run the program, we get TypeError: list indices must be integers or slices, not str because we are directly accessing the dictionary items using the key, but the dictionary is present inside a list. 

If we have to access the particular value from the dictionary, it can be done using the following syntax.

list_name[index_of_dictionary]['key_within_dictionary']

We can resolve this issue by properly iterating the dictionaries inside the list using range() and len() methods and accessing the dictionary value using a proper index and key, as shown below.

actors = [ { 'name': "Will Smith", 'movie': "Pursuit of Happiness" }, { 'name': "Brad Pitt", 'movie': "Ocean's 11" }, { 'name': "Tom Hanks", 'movie': "Terminal" }, { 'name': "Leonardo DiCaprio", 'movie': "Titanic" }, { 'name': "Robert Downey Jr", 'movie': "Iron Man" }, ] actor_name = input('Enter the actor name to find a movie - ') for i in range(len(actors)): if actor_name.lower() in actors[i]['name'].lower(): print('Actor Name: ', actors[i]['name']) print('Movie: ', actors[i]['movie']) break else: print('Please choose a valid actor')

Output

Enter the actor name to find a movie - Brad Pitt Actor Name: Brad Pitt Movie: Ocean's 11 Conclusion

The TypeError: list indices must be integers or slices, not str occurs when we try to index the list elements using string. The list elements can be accessed using the index number (valid integer), and if it is a dictionary inside a list, we can access using the syntax list_name[index_of_dictionary]['key_within_dictionary']

The post TypeError: list indices must be integers or slices, not str appeared first on ItsMyCode.

Categories: FLOSS Project Planets

Russell Coker: Video Conferencing (LCA)

Planet Debian - Sun, 2022-01-09 02:20

I’ve just done a tech check for my LCA lecture. I had initially planned to do what I had done before and use my phone for recording audio and video and my PC for other stuff. The problem is that I wanted to get an external microphone going and plugging in a USB microphone turned off the speaker in the phone (it seemed to direct audio to a non-existent USB audio output). I tried using bluetooth headphones with the USB microphone and that didn’t work. Eventually a viable option seemed to be using USB headphones on my PC with the phone for camera and microphone. Then it turned out that my phone (Huawei Mate 10 Pro) didn’t support resolutions higher than VGA with Chrome (it didn’t have the “advanced” settings menu to select resolution), this is probably an issue of Android build features. So the best option is to use a webcam on the PC, I was recommended a Logitech C922 but OfficeWorks only has a Logitech C920 which is apparently OK.

The free connection test from freeconference.com [1] is good for testing out how your browser works for videoconferencing. It tests each feature separately and is easy to run.

After buying the C920 webcam I found that it sometimes worked and sometimes caused a kernel panic like the following (partial panic log included for the benefit of people Googling this Logitech C920 problem):

[95457.805417] BUG: kernel NULL pointer dereference, address: 0000000000000000 [95457.805424] #PF: supervisor read access in kernel mode [95457.805426] #PF: error_code(0x0000) - not-present page [95457.805429] PGD 0 P4D 0 [95457.805431] Oops: 0000 [#1] SMP PTI [95457.805435] CPU: 2 PID: 75486 Comm: v4l2src0:src Not tainted 5.15.0-2-amd64 #1 Debian 5.15.5-2 [95457.805438] Hardware name: HP ProLiant ML110 Gen9/ProLiant ML110 Gen9, BIOS P99 02/17/2017 [95457.805440] RIP: 0010:usb_ifnum_to_if+0x3a/0x50 [usbcore] ... [95457.805481] Call Trace: [95457.805484] [95457.805485] usb_hcd_alloc_bandwidth+0x23d/0x360 [usbcore] [95457.805507] usb_set_interface+0x127/0x350 [usbcore] [95457.805525] uvc_video_start_transfer+0x19c/0x4f0 [uvcvideo] [95457.805532] uvc_video_start_streaming+0x7b/0xd0 [uvcvideo] [95457.805538] uvc_start_streaming+0x2d/0xf0 [uvcvideo] [95457.805543] vb2_start_streaming+0x63/0x100 [videobuf2_common] [95457.805550] vb2_core_streamon+0x54/0xb0 [videobuf2_common] [95457.805555] uvc_queue_streamon+0x2a/0x40 [uvcvideo] [95457.805560] uvc_ioctl_streamon+0x3a/0x60 [uvcvideo] [95457.805566] __video_do_ioctl+0x39b/0x3d0 [videodev]

It turns out that Ubuntu Launchpad bug #1827452 has great information on this problem [2]. Apparently if the device decides it doesn’t have enough power then it will reconnect and get a different USB bus device number and this often happens when the kernel is initialising it. There’s a race condition in the kernel code in which the code to initialise the device won’t realise that the device has been detached and will dereference a NULL pointer and then mess up other things in USB device management. The end result for me is that all USB devices become unusable in this situation, commands like “lsusb” hang, and a regular shutdown/reboot hangs because it can’t kill the user session because something is blocked on USB.

One of the comments on the Launchpad bug is that a powered USB hub can alleviate the problem while a USB extension cable (which I had been using) can exacerbate it. Officeworks currently advertises only one powered USB hub, it’s described as “USB 3” but also “maximum speed 480 Mbps” (USB 2 speed). So basically they are selling a USB 2 hub for 4* the price that USB 2 hubs used to sell for.

When debugging this I used the “cheese” webcam utility program and ran it in a KVM virtual machine. The KVM parameters “-device qemu-xhci -usb -device usb-host,hostbus=1,hostaddr=2” (where 1 and 2 are replaced by the Bus and Device numbers from “lsusb”) allow the USB device to be passed through to the VM. Doing this meant that I didn’t have to reboot my PC every time a webcam test failed.

For audio I’m using the Sades Wand gaming headset I wrote about previously [3].

Related posts:

  1. Bandwidth for Video Conferencing For the Linux Users of Victoria (LUV) I’ve run video...
  2. Sound Device Order with ALSA One problem I have had with my new Dell PowerEdge...
  3. Ffmpeg and Video on a Viewty Phone I recently decided to copy some of my FLV (Flash...
Categories: FLOSS Project Planets

qml-doxygen: qml-lsp's qml - doxygen cousin

Planet KDE - Sun, 2022-01-09 02:03
The Cool Now

With the infrastructure I built in qml-lsp for parsing and analysing QML files, I thought “hm, since doxyqml is just a glorified qml parser –> c++ header file converter, wouldn't it be trivial to write the same thing in go reusing qml-lsp's infrastructure?” And that's exactly what I did. I wrote a 130-line program that faithfully replicated doxyqml's functionality in Go.

By virtue of being a Go program that calls on a pretty optimised parser in C, it ended up being a little over 10 times faster than doxyqml on my system.

I wasn't done there.

I thought “hmm, couldn't I reuse the semantic analysis I did for qml-lsp to improve the output a bit?”

So, that's pretty much what I did.

Currently, the most notable improvement over doxyqml is in producing a better superclass for the output:

doxyqml, with aliased import (import foo as bar):

class Avatar : public QtQuick.Controls.Control {

doxyqml, without aliased import:

class Avatar : Control {

One isn't valid C++ (I'm surprised Doxygen takes it at all), and the other fails to specifically name where Control comes from, leading to issues with Doxygen trying to locate the superclass.

qml-doxygen reuses the semantic analysis from qml-lsp to generate the following output, whether the import is aliased or not:

class Avatar : public QtQuick::Controls::Control {

It's both valid C++, and tells Doxygen exactly where the name is coming from.

The Roadmap

The next thing I'm planning to do is to resolve the concrete type of an alias property, so that documentation generation for aliases can be improved without developers needing to explicitly tell the computer what type the alias points to.

I may also add the ability to “splat” grouped properties with a special sigil, so that something like readonly property AvatarGroup actions: AvatarGroup { } can be expanded into the properties of the AvatarGroup by qml-doxygen, resulting in better documentation.

Tags: #libre

Categories: FLOSS Project Planets

François Marier: Removing an alias/domain from a Let's Encrypt certificate managed by certbot

Planet Debian - Sun, 2022-01-09 01:00

I recently got an error during a certbot renewal:

Challenge failed for domain echo.fmarier.org Failed to renew certificate jabber-gw.fmarier.org with error: Some challenges have failed. The following renewals failed: /etc/letsencrypt/live/jabber-gw.fmarier.org/fullchain.pem (failure) 1 renew failure(s), 0 parse failure(s)

due to the fact that I had removed the DNS entry for echo.fmarier.org.

I tried to find a way to remove that name from the certificate before renewing it, but it seems like the only way to do it is to create a new certificate without that alternative name.

First, I looked for the domains included in the certificate:

$ certbot certificates ... Certificate Name: jabber-gw.fmarier.org Serial Number: 31485424904a33fb2ab43ab174b4b146512 Key Type: RSA Domains: jabber-gw.fmarier.org echo.fmarier.org fmarier.org Expiry Date: 2022-01-04 05:28:57+00:00 (VALID: 29 days) Certificate Path: /etc/letsencrypt/live/jabber-gw.fmarier.org/fullchain.pem Private Key Path: /etc/letsencrypt/live/jabber-gw.fmarier.org/privkey.pem

Then, deleted the existing certificate:

$ certbot delete jabber-gw.fmarier.org

and finally created a new certificate with all other names except for the obsolete one:

$ certbot certonly -d jabber-gw.fmarier.org -d fmarier.org --duplicate
Categories: FLOSS Project Planets

Russ Allbery: Review: Redemptor

Planet Debian - Sat, 2022-01-08 22:19

Review: Redemptor, by Jordan Ifueko

Series: Raybearer #2 Publisher: Amulet Books Copyright: 2021 ISBN: 1-68335-720-5 Format: Kindle Pages: 328

Redemptor is the second half of a duology that started with Raybearer. You could read the first book without the second, but reading the second without the first will not make much sense. I'm going to be a bit elliptical in my plot description since there's a lot of potential for spoilers for the first book.

Tarisai has reached a point of stability and power, but she's also committed herself to a goal, one that will right a great historical and ongoing injustice. She's also now in a position to both notice and potentially correct numerous other injustices in the structure of her society, and plans to start by defending those closest to her. But in the midst of her opening gambit to save someone she believes is unjustly imprisoned, the first murderous undead child appears, attacking both Tarisai's fragile sense of security and her self-esteem and self-worth. Before long, she's drowning in feelings of inadequacy and isolation, and her grand plans for reordering the world have turned into an anxiety loop of self-flagellating burnout.

I so much wanted to like this book. Argh.

I think I see what Ifueko was aiming for, and it's a worthy topic for a novel. In Raybearer, Tarisai got the sort of life that she previously could only imagine, but she's also the sort of person who shoulders massive obligations. Imposter syndrome, anxiety, overwork, and burnout are realistic risks, and are also important topics to write about. There are some nicely subtle touches buried in this story, such as the desire of her chosen family to have her present and happy without entirely understanding why she isn't, and without seeing the urgency that she sees in the world's injustice. The balancing act of being effective without overwhelming oneself is nearly impossible, and Tarisai has very little preparation or knowledgeable support.

But this story is told with the subtlety of a sledgehammer, and in a way that felt forced rather than arising naturally from the characters. If the point of emphasis had been a disagreement with her closest circle over when and how much the world should be changed, I think this would be a better book. In the places where this drives the plot, it is a better book. But Ifueko instead externalizes anxiety and depression in the form of obviously manipulative demonic undead children who (mostly) only Tarisai can see, and it's just way too much. Her reactions are manipulated and sometimes externally imposed in a way that turns what should have been a character vs. self plot into a character vs. character plot in which the protagonist is very obviously making bad decisions and the antagonist is an uninteresting cliche.

The largest problem I had with this book is that I found it thuddingly obvious, in part because the plot felt like it was on narrowly constrained rails to ensure it hit all of the required stops. When the characters didn't want the plot to go somewhere, they're sidelined, written out of the story, or otherwise forcibly overridden. Tarisai has to feel isolated, so all the people who, according to the events of the previous book and the established world-building rules, would not let her be isolated are pushed out of her life. When this breaks the rules of magic in this world, those rules are off-handedly altered. Characters that could have had their own growth arcs after Raybearer become static and less interesting, since there's no room for them in the plot. Instead, we get all new characters, which gives Redemptor a bit of a cast size problem.

Underneath this, there is an occasional flash of great writing. Ifueko chooses to introduce a dozen mostly-new characters to an already large cast and I was still able to mostly keep them straight, which shows real authorial skill. She is very good with short bursts of characterization to make new characters feel fresh and interesting. Even the most irritating of the new characters (Crocodile, whose surprise twist I thought was obvious and predictable) is an interesting archetype to explore in a book about activism and activist burnout. I can see some pieces of a better book here. But I desperately wanted something to surprise me, for Tarisai or one of the other characters to take the plot in some totally unexpected direction the way that Raybearer did. It never happened.

That leads directly to another complaint: I liked Raybearer in part because of the freshness of a different mythological system and a different storytelling tradition than what we typically get in fantasy novels. I was hoping for more of the same in Redemptor, which meant I was disappointed when I got a mix of Christianity and Greek mythology.

As advertised by Raybearer, the central mythological crisis of Redemptor concerns the Underworld. This doesn't happen until about 80% into the book (which is also a bit of a problem; the ending felt rushed given how central it was to the plot), so I can't talk about it in detail without spoiling it. But what I think I can say is that unfortunately the religious connotations of the title are not an accident. Rather than something novel that builds on the excellent idea of the emi-ehran spirit animal, there is a lot of Christ symbolism mixed with an underworld that could have come from an Orpheus retelling. There's nothing inherently wrong with this (although the Christian bits landed poorly for me), but it wasn't what I was hoping for from the mythology of this world.

I rarely talk much about the authors in fiction reviews. I prefer to let books stand on their own without trying too hard to divine the author's original intentions. But here, I think it's worth acknowledging Ifueko's afterword in which she says that writing Redemptor in the middle of a pandemic, major depression, and the George Floyd protests was the most difficult thing she'd ever done. I've seen authors write similar things in afterwords when the effect on the book was minimal or invisible, but I don't think that was the case here. Redemptor is furious, anxious, depressed, and at points despairing, and while it's okay for novels to be all of those things when it's under the author's control, here they felt like emotions that were imposed on the story from outside.

Raybearer was an adventure story about found family and ethics that happened to involve a lot of politics. Redemptor is a story about political activism and governance, but written in a universe whose bones are set up for an adventure story. The mismatch bothered me throughout; not only did these not feel like the right characters to tell this story with, but the politics were too simple, too morally clear-cut, and too amenable to easy solutions for a good political fantasy. Raybearer focused its political attention on colonialism. That's a deep enough topic by itself to support a duology (or more), but Redemptor adds in property rights, land reform, economic and social disparity, unfair magical systems, and a grab bag of other issues, and it overwhelms the plot. There isn't space and time to support solutions with sufficient complexity to satisfyingly address the problems. Ifueko falls back on benevolent dictator solutions, and I understand why, but that's not the path to a satisfying resolution in an overtly political fantasy.

This is the sort of sequel that leaves me wondering if I can recommend reading the first book and not the second, and that makes me sad. Redemptor is not without its occasional flashes of brilliance, but I did not have fun reading this book and I can't recommend the experience. That said, I think this is a book problem, not an author problem; I will happily read Ifueko's next novel, and I suspect it will be much better.

Rating: 5 out of 10

Categories: FLOSS Project Planets

Matthew Garrett: Pluton is not (currently) a threat to software freedom

Planet Debian - Sat, 2022-01-08 19:59
At CES this week, Lenovo announced that their new Z-series laptops would ship with AMD processors that incorporate Microsoft's Pluton security chip. There's a fair degree of cynicism around whether Microsoft have the interests of the industry as a whole at heart or not, so unsurprisingly people have voiced concerns about Pluton allowing for platform lock-in and future devices no longer booting non-Windows operating systems. Based on what we currently know, I think those concerns are understandable but misplaced.

But first it's helpful to know what Pluton actually is, and that's hard because Microsoft haven't actually provided much in the way of technical detail. The best I've found is a discussion of Pluton in the context of Azure Sphere, Microsoft's IoT security platform. This, in association with the block diagrams on page 12 and 13 of this slidedeck, suggest that Pluton is a general purpose security processor in a similar vein to Google's Titan chip. It has a relatively low powered CPU core, an RNG, and various hardware cryptography engines - there's nothing terribly surprising here, and it's pretty much the same set of components that you'd find in a standard Trusted Platform Module of the sort shipped in pretty much every modern x86 PC. But unlike Titan, Pluton seems to have been designed with the explicit goal of being incorporated into other chips, rather than being a standalone component. In the Azure Sphere case, we see it directly incorporated into a Mediatek chip. In the Xbox Series devices, it's incorporated into the SoC. And now, we're seeing it arrive on general purpose AMD CPUs.

Microsoft's announcement says that Pluton can be shipped in three configurations:as the Trusted Platform Module; as a security processor used for non-TPM scenarios like platform resiliency; or OEMs can choose to ship with Pluton turned off. What we're likely to see to begin with is the former - Pluton will run firmware that exposes a Trusted Computing Group compatible TPM interface. This is almost identical to the status quo. Microsoft have required that all Windows certified hardware ship with a TPM for years now, but for cost reasons this is often not in the form of a separate hardware component. Instead, both Intel and AMD provide support for running the TPM stack on a component separate from the main execution cores on the system - for Intel, this TPM code runs on the Management Engine integrated into the chipset, and for AMD on the Platform Security Processor that's integrated into the CPU package itself.

So in this respect, Pluton changes very little; the only difference is that the TPM code is running on hardware dedicated to that purpose, rather than alongside other code. Importantly, in this mode Pluton will not do anything unless the system firmware or OS ask it to. Pluton cannot independently block the execution of any other code - it knows nothing about the code the CPU is executing unless explicitly told about it. What the OS can certainly do is ask Pluton to verify a signature before executing code, but the OS could also just verify that signature itself. Windows can already be configured to reject software that doesn't have a valid signature. If Microsoft wanted to enforce that they could just change the default today, there's no need to wait until everyone has hardware with Pluton built-in.

The two things that seem to cause people concerns are remote attestation and the fact that Microsoft will be able to ship firmware updates to Pluton via Windows Update. I've written about remote attestation before, so won't go into too many details here, but the short summary is that it's a mechanism that allows your system to prove to a remote site that it booted a specific set of code. What's important to note here is that the TPM (Pluton, in the scenario we're talking about) can't do this on its own - remote attestation can only be triggered with the aid of the operating system. Microsoft's Device Health Attestation is an example of remote attestation in action, and the technology definitely allows remote sites to refuse to grant you access unless you booted a specific set of software. But there are two important things to note here: first, remote attestation cannot prevent you from booting whatever software you want, and second, as evidenced by Microsoft already having a remote attestation product, you don't need Pluton to do this! Remote attestation has been possible since TPMs started shipping over two decades ago.

The other concern is Microsoft having control over the firmware updates. The context here is that TPMs are not magically free of bugs, and sometimes these can have security consequences. One example is Infineon TPMs producing weak RSA keys, a vulnerability that could be rectified by a firmware update to the TPM. Unfortunately these updates had to be issued by the device manufacturer rather than Infineon being able to do so directly. This meant users had to wait for their vendor to get around to shipping an update, something that might not happen at all if the machine was sufficiently old. From a security perspective, being able to ship firmware updates for the TPM without them having to go through the device manufacturer is a huge win.

Microsoft's obviously in a position to ship a firmware update that modifies the TPM's behaviour - there would be no technical barrier to them shipping code that resulted in the TPM just handing out your disk encryption secret on demand. But Microsoft already control the operating system, so they already have your disk encryption secret. There's no need for them to backdoor the TPM to give them something that the TPM's happy to give them anyway. If you don't trust Microsoft then you probably shouldn't be running Windows, and if you're not running Windows Microsoft can't update the firmware on your TPM.

So, as of now, Pluton running firmware that makes it look like a TPM just isn't a terribly interesting change to where we are already. It can't block you running software (either apps or operating systems). It doesn't enable any new privacy concerns. There's no mechanism for Microsoft to forcibly push updates to it if you're not running Windows.

Could this change in future? Potentially. Microsoft mention another use-case for Pluton "as a security processor used for non-TPM scenarios like platform resiliency", but don't go into any more detail. At this point, we don't know the full set of capabilities that Pluton has. Can it DMA? Could it play a role in firmware authentication? There are scenarios where, in theory, a component such as Pluton could be used in ways that would make it more difficult to run arbitrary code. It would be reassuring to hear more about what the non-TPM scenarios are expected to look like and what capabilities Pluton actually has.

But let's not lose sight of something more fundamental here. If Microsoft wanted to block free operating systems from new hardware, they could simply mandate that vendors remove the ability to disable secure boot or modify the key databases. If Microsoft wanted to prevent users from being able to run arbitrary applications, they could just ship an update to Windows that enforced signing requirements. If they want to be hostile to free software, they don't need Pluton to do it.

(Edit: it's been pointed out that I kind of gloss over the fact that remote attestation is a potential threat to free software, as it theoretically allows sites to block access based on which OS you're running. There's various reasons I don't think this is realistic - one is that there's just way too much variability in measurements for it to be practical to write a policy that's strict enough to offer useful guarantees without also blocking a number of legitimate users, and the other is that you can just pass the request through to a machine that is running the appropriate software and have it attest for you. The fact that nobody has actually bothered to use remote attestation for this purpose even though most consumer systems already ship with TPMs suggests that people generally agree with me on that)

comments
Categories: FLOSS Project Planets

Brett Cannon: Unravelling `from` for `raise` statements

Planet Python - Sat, 2022-01-08 18:07

As part of my series on Python&aposs syntax, I want to tackle the from clause for raise statements. In case you&aposre unfamiliar, raise A from B causes B to be assigned to A.__cause__ which lets chained tracebacks exist (as well as __context__, but that&aposs not relevant to today&aposs topic). There is a restriction that only instances of exceptions can be assigned to __cause__, and if you specify an exception class then it gets instantiated before assignment. Trying to assign anything else triggers a TypeError.

So the first question is how much checking do we need to do for the from clause&aposs object to make sure it meets the requirement of being an (eventual) exception instance?

>>> exc1 = Exception() >>> exc1.__cause__ = 42 Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: exception cause must be None or derive from BaseException >>> exc1.__cause__ = Exception Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: exception cause must be None or derive from BaseException >>> exc1.__cause__ = Exception() >>>Exploring restrictions when assigning to BaseException.__cause__

It appears that only assigning an instance of an exception to __cause__ is allowed. This is convenient as we don&apost have to do the check for something not being an exception instance. But it&aposs also inconvenient as we do have to instantiate any exception class ourselves. What this says to me is the following:

  1. Assigning an exception instance is fine.
  2. Assigning a non-exception-related object is "fine" because the exception object will raise the exception.
  3. Assigning an exception class is problematic, and so we will have to handle the instantiation.

So how do we detect if an object is an exception class but not an instance? To tell if an object is a class, it needs to be an instance of type (as inspect.issclass() shows us); isinstance(obj, type). To tell if something is an exception instance, it needs to be an instance of BaseException; isinstance(obj, BaseException). And to tell if a class is an exception class, we need to know if one of its subclasses is BaseException; issubclass(obj, BaseException). Now one thing to note is issubclass() will raise a TypeError if you pass anything that isn&apost a class as its first argument; isinstance() does not have the inverse issue of passing in a class as its first argument.

Oh, and we also have to make sure the object we are raising is also appropriately instantiated before we attempt any assignment to __cause__. That adds an extra wrinkle to this problem as it means we will have to raise the TypeError when the to-be-raised exception isn&apost an exception-related object.

This can all be summarized by the following function:

def exception_instance(obj): if isinstance(obj, BaseException): return obj elif isinstance(obj, type) and issubclass(obj, BaseException): return obj() else: raise TypeError("exceptions must derive from BaseException")Utility function for getting an exception instance

When we unravel raise A from B, we can inline the logic and simplify it a bit:

  1. If we have an exception class, instantiate it.
  2. If we have a non-exception object for the raise clause, raise TypeError.
  3. Rely on the fact that assigning anything other than an exception instance to __cause__ raises the appropriate TypeError for us.

This lets us unravel raise A from B to:

_raise = A if isinstance(_raise, type) and issubclass(_raise, BaseException): _raise = _raise() elif not isinstance(_raise, BaseException): raise TypeError("exceptions must derive from BaseException") _from = B if isinstance(_from, type) and issubclass(_from, BaseException): _from = _from() _raise.__cause__ = _from raise _raiseUnravelling raise A from B

In the general case of raise A we don&apost have to do any of this as it&aposs part of Python&aposs semantics to handle the class-to-instance scenario.

Categories: FLOSS Project Planets

Jonathan Dowland: 2021 in Fiction

Planet Debian - Sat, 2022-01-08 16:32

Following on from last year's round-up of my reading, here's a look at the fiction I enjoyed in 2021.

I managed to read 42 books in 2021, up from 31 last year. That's partly to do with buying an ereader: 33/36% of my reading (by pages/by books) was ebooks. I think this demonstrates that ebooks have mostly complemented paper books for me, rather than replacing them.

My book of the year (although it was published in 2019) was This is How You Lose the Time War by Amal El-Mohtar and Max Gladstone: A short epistolary love story between warring time travellers and quite unlike anything else I've read for a long time. Other notables were The Glass Hotel by Emily St John Mandel and Robot by Adam Wiśniewski-Snerg.

The biggest disappointment for me was The Ministry for the Future by Kim Stanley Robinson (KSR), which I haven't even finished. I love KSRs writing: I've written about him many times on this blog, at least in 2002, 2006 and 2009, I think I've read every other novel he's published and most of his short stories. But this one was too much of something for me. He's described this novel a the end-point of a particular journey and approach to writing he's taken, which I felt relieved to learn, assuming he writes any more novels (and I really hope that he does) they will likely be in a different "mode".

My "new author discovery" for 2021 was Chris Beckett: I tore through Two Tribes and America City before promptly buying all his other work. He fits roughly into the same bracket as Adam Roberts and Christopher Priest, two of my other favourite authors.

5 of the books I read (12%) were from my "backlog" of already-purchased physical books. I'd like to try and reduce my Backlog further so I hope to push this figure up next year.

I made a small effort to read more diverse authors this year. 24% of the books I read (by book count and page count) were by women. 15% by page count were (loosely) BAME (19% by book count). Again I'd like to increase these numbers modestly in 2022.

Unlike 2020, I didn't complete any short story collections in 2021! This is partly because there was only one issue of Interzone published in all of 2021, a double-issue which I haven't yet finished. This is probably a sad date point in terms of Interzone's continued existence, but it's not dead yet.

Categories: FLOSS Project Planets

Pages