Writing about learning Python and the odd bit of Linux related stuff I come across and find helpful. A bit about cycling. Long distance audax. The odd comment on unrelated ideas that I feel benefit from thinking about, writing down and sharing. That kind of thing. Enough is plenty. Good enough will do.
8309 words

Monday 11th January 2021

It's 1527hrs. Due back on the ward at 1550hrs. Having my break.

A patient died with C19 over the weekend. They were under 40. A member of staff also died over the weekend. Collapsed in reception when coming on shift. Died later in hospital. A brain anurism.

No doubt there are family and friends who will be feeling it this week. Dark days. Dark times.

Remember to look after yourself. Exercise. Cut down on consumption. Don't work overtime. Spend time with people you care about and enjoy being with.

Sunday 10th January 2021: Python Weekly Challenge

Today I came across Weekly Python ...

Python programming projects sent weekly to help you practice and perfect your programming skills while building your project portfolio.

There's a ton of such like out there and all vying for our attention. I like the understated and minimal style of this one. The first challenge was set just a week ago on. Listing all files in a directory.

Happy to have completed the beginner project. Went on and practised more by completing the beginner stretched goal. So far I have learned about using Pythons inbuilt os and argparse modules.

There's more to be rinsed from the challenge with the inclusion of intermediate and advanced projects and stretched goals.

For now though...

import argparse
import os

# Beginner project: Create a python script that will print the names of every file in the directory you run it from in alphabetical order. Only print the names of files and not include folders in the returned list. Make sure the list is printed with one file per line of output. 
# Beginner stretch Goal: Add a command-line argument to also include the names of every folder in the current working directory.

path = os.getcwd()
file_list = []

# block executed if no command line argument entered. Just files from the CWD are sent to Stdout.
for files in os.listdir(path):
    if os.path.isfile(os.path.join(path, files)):
        file_list.append(files)
file_list.sort()
for file in file_list:
    # to exclude hidden files
    if file[0] == '.':
        continue
    print(file)

# block executed if command line argument entered. Files and directories from the CWD are sent to Stdout.
parser = argparse.ArgumentParser()
parser.add_argument("--dir", help="Include the names of every directory in the current working directory.")
args = parser.parse_args()

if args.dir:
    dl = os.listdir(os.getcwd())
    dl.sort()
    for i in dl:
        # to exclude hidden files
        if i[0] == '.':
            continue
        print(i)

Saturday 9th January 2021

Wife got sent home from work on Tuesday having had a close contact with a manager who tested positive for C19. Told to arrange testing and isolate pending the result.

This meant the rest of the family also had to isolate until the result arrived. Not a big deal but something to be done.

I was rostered to be at work on Wednesday, Thursday and Friday night. Phoned in and was correctly advised to stay at home until wife's result was recieved. This is not to discount the box of the Lateral Flow Test Kits (LFTK) given to me by work to self test.

Following the 'rules' meant staying off work to wait for my wife's PCR results rather than using a LFTK to self test. Says something about the governments investment and confidence in them.

The PCR test kit arrived for my wife on Wednesday. Result received on Friday night at around 8.30 pm. Negative. Hurray! No suprise though. We have all been symptom free and feeling fine. Back to work on Monday.

Friday 8th January 2021

Just noticed a habitual response.

I was getting stuck with a coding problem. I was not applying much method to my attempts at solving the problem. Relying on what I already know (limited) or worse still what I think I know (fuzzy). Hit and hope. Cyclical failed attempts. Allowing my failure to get the final solution to overshadow progress I was making towards it. I don't like the feeling and thoughts that come with being stuck.

I apply a workaround. I look for a distraction. To avoid feeling and thinking like this. Not a solution or means to find a solution but a distraction. Writing. Eating and drinking. Exercise. Housework. Company. Those are just the good ones.

I get no further with solving the problem. I am wilfully distracted and not making progress. It does not feel great.

Substitute coding problem with some other challenge. Given lack of progress over time and and the same behaviour follows. Find a distraction to avoid the feeling of being stuck, procrastinate and eventually avoid. Conciously the work; subconciously the feelings that come with being stuck. Feeling inadequate. Not good enough.

The risk now is to give up. Perhaps rationlise why it made sense to give up (lost interest, bored, something else came along...) to feel a better about doing so. Self belief and efficacy erodes.

A different response to getting stuck then. Notice what's being tried. Notice what's working and what's not. Break the process down into steps. Take some notes. Improve debugging skills. That might help. Revisit the key topics involved. Stick with it. Pomorodo time and keep coming back. It can help to chunk up focus time and breaks.

If though still choosing to be distracted then at least notice that and from time to time choose one that will do no harm and perhaps even some good! Like journaling perhaps?

Thursday 7th January 2021

Letting go. The benefit being freedom to act without undue reference to what's already been, what we already know. A future of possibility and freshness opening up before us.

Helps to have an awareness of what we are holding onto. It can be tricky. Some things might help...

  1. Noticing habits. Behavioural and thinking.
  2. Noticing relationship patterns.
  3. Noticing distractons.
  4. Honesty about and ownership of the past.
  5. Learning about attachment theory.
  6. Meditation.
  7. Having courage to be vulnerable.
  8. Curiosity in the process.

Wednesday 6th January 2021

Defining and solving problems is something I could do better with. Adapting to circumstance is the default. Dealing with a problem or making something work despite the problem. A workaround.

I have been learning to code without using code to do anything useful. It's been interesting but...

Coding contrived apps and completing code challenges / exercises to learn the lexis, semantics and syntax of Python is losing it's appeal. Cloning apps and such like does not inspire. Whilst there may be nothing new under the sun and greatness may come from iteration, novelty attracts me.

It's important to let go of any notion that a problem is a deficit and something to ignore or tolerate. It helps to have that out the way so we can move onto...

step 1: Problem identification
Identify and define what the problem is. Thinking of problems in terms of goals and barriers may help. There may be more than one of each. The process may reveal the goal is simply a stepping stone. Defining the problem will help understand and make it easier to describe to others.

step 2: Structuring the problem
Developing a fuller picture of the goal(s) and the barrier(s) involved. This might not be necessary for simple problems.

Before step 3 (exploring solutions) a bit of time with the first two would be in order. Seems like the next post is beginning to take shape.

Tuesday 5th January 2021

I have been given a box of SARS-CoV-2 Antigen Rapid Qualitative Test Kits manufactured by Innova. The plan is to self test twice a week (only if asymptomatic) before going into work. The idea is that this will help reduce the spread of C19 among the staff and patient group. Sound good?

498,000 residents in the City of Liverpool were offered testing using the Innova Lateral Flow Device. 25 % of them underwent a Lateral Flow Test from 6 November and up to 9 December. A sample of around 6,000 users received a pair of Lateral Flow and Polymerase Chain Reaction (LFT and PCR) tests. PCR testing is considered the gold standard in testing for the SARS-CoV-2 virus

The Liverpool COVID-19 Community Testing Pilot Evaluation Interim evaluation report is available to download here.

The researchers found that the Innova LFT device identified two fifths of the PCR positive cases and potentially two thirds of people with higher viral loads (asymptomatic?), who are more likely to be infectious. This reveals that statements by DHSC that the Innova Lateral Flow test achieves ‘high accuracy’ and ‘78% sensitivity’ are not valid.

Fit for purpose? The UK Government has paid £496 million for these test kits. A sunk investment and potential undeclared conflicts of interest. The pantomine must go on.

Having been given the box there is the expecation that I comply with request to test. It is not 'mandatory' though I suspect nonconformity will be frowned on.

Monday January 4th 2021

Yeah. So it's now 1.22 am. On a break. Working nights. I work in a mental health hospital. I am a mental health nurse. I have been since 1989.

Not so many people back then had the earnest interest and recognition of mental health issues that is currently fashionable in England to proclaim. It's not unusual for some 'celebrity' to grab a bit of publicity talking about recovering from some mental health issue they have labelled themselves with.

Mental health can now to be anything from feeling a bit miserable to headline grabbing tragedies involving someone known to mental health services. Much of what gets labelled nowadays as mental (ill)health is a normal reaction to life. It's what happens. It's part of being a human. We mostly move on and get over it. Like a cold.

The benefit of pathologising human experience often gets no further than drug companies, private therapists, to the self help / mindfulness app makers and how to be happy book sellers. It lets governments off the hook for failing to build nations that put welfare and people before business interests and profit.

Mental health issues talked about by 'celebrities' seem to be mostly a product of lifestyle choices. It's an odd mix of poor me / look at me and you could have it to. I bet there are those that have given likes / thumbs up / kudos to others talking about some mental health issue on social media. Kind of missing the point but hey ho.

Sunday January 3rd 2020

It is 3.34 am. Night shift. On my break till 4.30 am. Not feeling it. Still need to get on and do stuff. Not motivated or inspired to do anything much at all. Where did this need to be doing stuff all the time come from?

Be the best version of yourself. As if there are different versions we can put on and take off at will. What about those who do not aspire or have ambition? The satisficers who are happy to make do. Those who feel content?

It's now 1.17 am on Monday. Still working nights. I slept during day between 10 am and 4 pm. It is a challenge to maintain routines and good habits switching between days and nights.

Saturday 2nd January 2021

Well here goes. Still find it 'fun' to start new habits at this time of year. See how long I keep up intentions and interests. Coding and cycling are two. Press ups. 50 done this morning. Prepare my own food more. There is the garden and house to attend to as ever. Relationships with family, friends, colleagues, patients and so on. Be someone other people like to be around. Meditation. Got in 30 minutes this morning. The list goes on.

To do as is typical or do something different this time round.

Instead of or as well as looking back on what has been in 2020 perhaps imagine what I would like that to include at the end of 2021. A reflection and projection.

I am writing this note using a Standard Notes extension Theo Chu wrote and put out to the world for free. It's excellent. Theo had not coded much before building this extension. It took him 300 hours. That's 21.5 full days or 37 eight hour days or to stretch it out to something like real life 60 five days without a day off. The documentation is very well done. Detail and presentation. Goes along with his role at Standard Notes; maintain technical documentation; research and learn concepts in privacy, security, and technology and explain them in simple, digestible articles.

The functionality of the extension is fairly intuiative. I am enjoying using it. Theo writes about the devlopment of the extension at 300 Hours of code: Building projects that solve problems.

I have over the last year been learning to code without much if any focus on solving problems. It's been fun. I have learned a lot and benefited from doing so. This year would be good to do something tangible with code. Being adaptable is problem solving. Perhaps problems to build solutions for might become more apparent by thinking about how I and/or others adapt our behaviour to make things work.

Signed up to a couple of online courses. Started NDG Linux Unhatched today. Working through the topics and finding I am familiar with most of tthem so faar. I shall be starting PCAP: Programming Essentials In Python English 1220b just as soon as a glitch with the website is sorted out.

It's 1742hrs. Working tonight. Time to get ready and go...

Friday January 1st 2021

Good day. Solved an error with the NextcloudPi install. It’s taken a while. Patience and choosing not to go for the nuclear option and reinstall has paid off.

I was unable to upload any files. This was web uploads, desktop client and Android. The message I got was...

Error: Cannot modify header information - headers already sent by (output started at /var/www/nextcloud/3rdparty/sabre/http/lib/Sapi.php:132) at /var/www/nextcloud/apps/dav/lib/Connector/Sabre/File.php#691

Current install is NextcloudC 20.0.3 / NextcloudPi v1.33.0. Nextcloud data on an external HD.

This seems to have fixed it for now:

  1. open /etc/php/7.3/fpm/php.ini
  2. edit the config value for upload_tmp_dir to the ncdata/tmp directory already in my external USB drive
  3. restart php-fpm with sudo service php7.3-fpm restart

3.2G of files synced this afternoon. Happy with that.

Got there from the pointers here and here.

And in other news welcome to 2021. Wishing the world well. Adapt and check your perspective.

Been out on the bike. Gave it a wash and clean. Oiled the chain. Pumped the tyres. Tuned up the gears. 25 miles with the gruelling Vigo Hill thrown in for good measure.

Dictionary Comprehension

I have have had a much harder time of wrangling dictionary comprehensions than necessary. Code block. Like writers block perhaps? Feeling a bit slow with being stuck for a while on a project stage.

A touch of cognitive overload. Some interesting ideas about this at Cognitive Load and Coding. Worth a read with some good references at the end to follow up. A progammers cognitve load was especially helpful. I have increased the font size in my IDE and enabled auto folding. Basic stuff I could have done ages ago if I'd have been curious enough.

Back pain. Change in routines blah blah blah... It's all transient so long as I don't give up. Take some respite and come back to the learning.

Made some progress yesterday. A new approach. Narrowed my focus. Completed some PyBites. Encouraged by solving a few of these I completed one on dictionary comprehensions. Pybites is handy to have on my list of go to places for learning Python.

I am hoping to help embed what I'm spending time learning by writing something about it here. First time trying. Hopefully I've understood it and I've written nothing here to misinform. Corrections are welcome. Here goes:

bites = {6: 'PyBites Die Hard',
         7: 'Parsing dates from logs',
         9: 'Palindromes',
         10: 'Practice exceptions',
         11: 'Enrich a class with dunder methods',
         12: 'Write a user validation function',
         13: 'Convert dict in namedtuple/json',
         14: 'Generate a table of n sequences',
         15: 'Enumerate 2 sequences',
         16: 'Special PyBites date generator',
         17: 'Form teams from a group of friends',
         18: 'Find the most common word',
         19: 'Write a simple property',
         20: 'Write a context manager',
         21: 'Query a nested data structure'}
exclude_bites = {6, 10, 16, 18, 21}


def filter_bites(bites=bites, bites_done=exclude_bites):
    """return the bites dict with the exclude_bites filtered out"""
    return {key: value for (key, value) in bites.items() if key not in bites_done}


print(filter_bites(bites, exclude_bites))

So what that does is to take a dictionary bites and a set exclude_bites. From them we return a new dictionary from the entries of the existing dictionary excluding entries whose key matches an element in the set.

return {key: value for (key, value) in bites.items() if key not in bites_done}

Which returns dictionary items -

{
7: 'Parsing dates from logs', 
9: 'Palindromes', 
11: 'Enrich a class with dunder methods', 
12: 'Write a user validation function', 
13: 'Convert dict in namedtuple/json', 
14: 'Generate a table of n sequences', 
15: 'Enumerate 2 sequences', 
17: 'Form teams from a group of friends', 
19: 'Write a simple property', 
20: 'Write a context manager'
}

Notice that dictionary items with a key that matches an element in the set {6, 10, 16, 18, 21}have been excluded.

Key can be generated from an immutable type int, float, decimal, complex, bool, string, tuple, range, frozenset, bytes. With this example the int is used (iterated) from the bites dictionary. The keys must also be hashable. For example a tuple with lists will not work as lists are mutable and therefore not hashable. A tuple of strings would be fine as strings are immutable.

Python dictionaries leverage hash tables. When we use a key that contains an unhashable type, i.e. a list, the underlying hash map cannot guarantee the key will map to the same bucket every single time. If we can't hash our key, we can't use it in our dictionary. The thing to remember is that Python dictionaries require hashable dict keys. Immutable keys is not enough. (nods*)

The value may be assigned to any iterable bites_items() in this case. It does not need to be immutable. It could also be assigned the same value for all keys. The condition to filter/sort simply follows the if statement. Here exclude_bites is called to check and iterate through .

Well I think that worked. Feel like I have furthered by understanding a bit. Yeah I know... practice more and do projects!

Run your own cloud with NextCloudPi.

I've gone down the route of self hosted cloud. Last year I decided to have a go with NextCloudPi. It took a few goes to get things right. From time to time it has gone a bit cranky and needed a bit of maintenance though no data has been lost and backups have worked as hoped for when needed. It's a working alternative to giving my data to someone else to look after and manage. A satisfying endeavour.

Needed a router that could configure Port Forwarding and NAT loopback. A Raspberry pi. I went with the 3+ with power supply. A couple of external hard drives (Seagate 1TB). A USB power hub. A USB stick (16G). I had a screen and keyboard for the RaspberryPi. It's handy though not entirely necessary.

The installation instructions here were helpful. Notable change was to not bother with an SD card. The 3+ will boot from a USB drive so just used that. I believe a USB stick is more reliable than an SD card for this purpose.

The database is on the USB stick. The data directory (my files/music etc) is on HD1 along with scheduled snapshots to revert back to if and when needed. The data is backed up to HD2 via synced snapshots from those on HD1. The database is also on a scheduled back up to this drive along with the configuration files for the NCP install. Instructions for doing this are here.

It totally serves the purpose I wanted it for. It's FOSS. Contacts, calendar and tasks synced between devices. Files accessible anywhere and backed up to external storage. I can stream my own music. There's the ongoing satisfaction of having it work. I love it! Big thanks to Nacho Parker at ownyourbits for the hard work of putting this out there.

NextCloudPi

Learning to code. You're good enough. A worthwhile effort.

So I have been learning to code using Python. It started as a distraction over the Christmas holidays in 2019. It's now November 2020. I've coded way more days than not over that time. #100 days straight? Most likely and more than once. Not been counting.

Coding exercises, tutorials, blogs, websites, podcasts and so on. Enjoyed reading posts on dev.to where I'm learning the language and getting a feel for the culture of the development world. There's much talk about impostor syndrome. Seems it pretty endemic. Not heard it referred to as much with reference to any other endeavour. Something perhaps to do with a lot of developers being self taught and/or that learning on the job is a prerequisite and necessity to stay match fit.

Getting stuck with things right now. Final stage of a 'hard' project on Jet Brains Academy and just not getting it. Learning Python (easy); learning to program (hard). Codecamp says I'm -

codecamp

Completing exercises and small projects is no longer enough to keep making progress. Shame as I was enjoying the illusion the pace had created! Deliberate practice might be what's needed from now.

Deliberate practice is not a comfortable activity. It requires sustained effort and concentration. The people who master the art of deliberate practice are committed to being lifelong learners—always exploring and experimenting and refining.

My interest is starting to wane. I've been avoiding getting on. Finding other distractions. Not having so much fun. Asking myself if I can even be bothered with it anymore. That could be the impostor syndrome in disguise. See you're already getting the traits! Perhaps it's not that you can't be bothered it's that you don't think you're good enough. Let that shit go!

Coding skill is an attribute I would like to have. Here's to the effort deliberate practice takes!

Monday 2nd November 2020

I have been using Standard Notes for a few years now. The functionality has improved progressively over this time. The latest update to the desktop client 3.5.1 has all notes decrypted and on display very quickly.

I moved over to Standard Notes having tried a number of other different note keeping apps. It was a laborious process transferring everything I had in Evernote. Worthwhile though and I have never looked back.

Standard Notes ticks boxes for privacy, longevity, FOSS and ownership of data. The simple UI and rendering is a plus. Syncing between devices is as expected. I only use a few extensions and those I do work great. Back up and restore has been flawless. Very reassuring.

I have been aware of Listed for a while. I like the platform. The simplicity. Not been minded to use it much though. Had a go now and then out of curiosity but nothing more. I have kept a blog for years using Wordpress. Neglected a blog for years might now be more accurate to say. Times have moved on. An over-engineered solution and way more than I use. The notion of posterity has kept it going. I shall archive, shut down and move on.

The intention now is to start using Standard Notes / Listed to support my learning to program using Python. I often read how easy it is to learn how to code using Python. Depends what your reference point is I guess. I've been at it since December 2019. No prior related experience. I have got to the point of understanding that learning Python is not the same as learning to program. That realisation is perhaps a useful measure of the level I am at with it. In that regard learning Python to an intermediate level has I suppose been quick and easy. To keep moving forward from this point is the aim.

So then posts here shall be about all that and the odd bit of Linux related stuff I come across and find helpful. Desktop (Ubuntu), mobile (Pine Phone) and Raspberry Pi. Maybe a bit about cycling. Long distance audax. Perhaps the odd comment on unrelated ideas that I'd feel some benefit from thinking about, writing down and sharing. That kind of thing.