Sunday, 19 December 2021

Note to self: Don't slack out because "it's just a prototype"

At least when it's near-trivial to come up with some good design concerns, applying them is effortless...

... well, it turns out just now that about 5 minutes of thinking could have saved - albeit hypothetical - hours of a future DB migration. Even thinking about it I lost like a good 10 minutes :)

There are mitigating circumstances (it's just a "plug-in" until it turns out whether it's worth buying the proper dedicated tech or not - maybe won't ever be needed), but things could be much better too easily.

A poor design/bad implementation can spread in the form of bad practice afterwards... better choices are less likely to end up doing that. 

Even if not doing two ful lrounds, think 1½ times at least 😏

Sunday, 14 November 2021

When you don't know something, but ...

 ... virtually nobody uses it.

Should remind myself that one GitHub search  can save a lot of sanity for the rest of the day :) Before I get stuck in "how come I never heard about it? what else don't I know? Google up something else to be worried about + repeat  👍" mode.

So this thing from the defer module was mentioned in relation to the Python generators' .send() method .. hm ... actually now I (believe I) see that's a package! Last released in 2012. Right, good. Move on.

https://github.com/search?q=inline_callbacks+language%3Apy&type=code

Thursday, 4 November 2021

Not posting too often anyway these days :)

Doing some katas, prime factorization of n! is once again a small fun problem to have a go at. I wonder how many equal solutions are out there :) anyway, creating a max prime divisor map instead of the standard Eratosthenes' was an interesting twist of mine (?) so I thought I'd capture it. For the betterment of my audience of 0 people I guess : ))

from collections import Counter

from typing import Dict, List, Tuple
from functools import lru_cache
import math


def max_prime_divisors(n) -> List[int]:
    # A slight variation of Erathosthenes' algorithm

    # Find and return max_prime_divisor[i], i = 0..n
    # true divisors: 1 and n itself are excluded
    # could be nicer with numpy arrays? :)
    ans = [None] * (n + 1)

    for k in range(2, len(ans) // 2 + 1):
        if ans[k] is None:
            i = k * 2
            while i < len(ans):
                ans[i] = k
                i += k

    return ans


def decomp_nr(n, mpd) -> Dict[int, int]:
    # return value is in prime -> count form
    ans = []
    while mpd[n]:
        d = mpd[n]
        ans.append(d)
        n = n // d
    if n >= 1:
        ans.append(n)

    return Counter(ans)


def format_decomp(d):
    factors = [f"{key}^{count}" if count > 1 else f"{key}"
               for key, count in sorted(d.items())]
    return " * ".join(factors)


def decomp(n):
    # decompose factorial
    mpd = max_prime_divisors(n)

    total_decomp = sum([decomp_nr(k, mpd) for k in range(2, n + 1)], Counter())

    # print("tdc is:", total_decomp)

    return format_decomp(total_decomp)
 
---
 

Update: hm... and despite its appeal to me, that wasn't fast enough :) then went the one with much fewer tiny reusable cogs, and sorted things out.


I'll decide later whether to decide now or later that I'm disappointed. Possibly I'm not :)

 
--- 
 
from collections import Counter
from typing import Dict, List, Tuple, Optional
from functools import lru_cache
import math


def erathosthenes(n) -> List[bool]:
# return is_prime[i], i = 0..n
ans = [True] * (n + 1)

# by convention
ans[0] = False
ans[1] = False

for k in range(2, len(ans) // 2 + 1):
if ans[k]:
i = k * 2
while i < len(ans):
ans[i] = False
i += k

return ans


def decomp_n_fac(n, erat: List[bool]) -> Dict[int, int]:
ans = {}

for p in range(n + 1):
exp = 0

if not erat[p]:
continue

p_pow = p
while p_pow <= n:
exp += n // p_pow
p_pow *= p

ans[p] = exp

return ans


def format_decomp(d):
factors = [f"{key}^{count}" if count > 1 else f"{key}"
for key, count in sorted(d.items())]
return " * ".join(factors)


def decomp(n):
# decompose factorial
erat_map = erathosthenes(n)

total_decomp = decomp_n_fac(n, erat_map)

return format_decomp(total_decomp)
 

 


Python + mutable return + caching: careful

Let's say

from functools import lru_cache                                         
@lru_cache(5) def cached(n): return {}

Beware then, as:

In [3]: cached(1) == cached(1)                                                  
Out[3]: True

In [4]: cached(1) is cached(1)                                                  
Out[4]: True

In [5]: cached(1)[2] = 3                                                        

In [6]: cached(1)                                                               
Out[6]: {2: 3} 
 
So I suppose - further from the attention paid with parameter default mutability - there are times when it's a good idea to put in the effort and return immutable results whenever there's the slightest chance of caching right at the moment or later on (and being inattentive :) never happens, of course).

Friday, 22 October 2021

No exception "bubbling up" from PySide slots

Demo code:

from PySide2.QtCore import Signal
from PySide2.QtWidgets import QApplication, QDialog


class MyDialog(QDialog):

mySignal = Signal()


def mySignal_handler():
raise Exception("bocs")


app = QApplication()
dialog = MyDialog()
dialog.mySignal.connect(mySignal_handler)
dialog.mySignal.connect(mySignal_handler)

try:
dialog.mySignal.emit()
except Exception as ex:
print("It is still the same exception context.")

Now try to guess the output ... :)

Monday, 5 April 2021

Today's dilemma: PyCharm hints unregister as a typo

 


OK, so of course since it's a completely irrelevant one, I dug into the problem relatively heavily ... cause what else would you do? :D

And here's one debate (2011) with a lot of interesting comments:

meaning - "Unregister" vs "Deregister" - English Language & Usage Stack Exchange


One pulls some good logic in:



it's convention in programming to call an object that hasn't been 'initialised' as 'uninitialised', not 'deinitialised'.

And since what's deregistered has already been registered, it wouldn't be in the same shoes as those things which never had been registered, and would thus be called unregistered.

But then there's some properly defying statistic there ...!
https://i.stack.imgur.com/cMMOS.png



As evidenced, unregister received a substantial boost shortly after the dot-com boom/bust of the late 90s, while deregister usage has been more or less the same throughout.

[...]

Additionally, both the
un- and de- prefixes can be defined as a reversal of action.

Despite the similarities, I'd go with popular usage and use unregister.

I really like that approach in a way. Quantified. Cold, hard facts in this very emotional problem that gets so many carried away. Numbers do tell a lot. Personally, I always 'knew' unregister to be The Word, but as I noticed due to the PyCharm editor hint, I could have equally naturally said deregister right now (outside the context)... so let's move over this bad infection.

Let's get up to date and context specific:

Final word: GitHub says ... yes!

Search · unregister · GitHub vs. Search · deregister · GitHub!

n

Unregister 👍

Deregister 👎

Repos

196

95

Commits

10M+

1.8M+

 

Without looking at the further candidate metrics, I think there's a clear winner here. And that is, the procrastination of actual work ;)

 

Thursday, 4 February 2021

"Look twice"

Yes, it might matter when errors occur, so I keep checking my store account.

Apparently it's the top one :)


(Time travelling me back to the question of line/bar chart x axis coordinate interpretation ...)

Bug or not, it indeed does good to my self-confidence when I receive slightly bogus intel about my tiny bogus app's bugs (just caught and fixed one after breakfast ... and surely not the one manifesting on the chart <sigh>).

Thanks guys, hope you saw mine, no worries there'll be a next anyway if you missed out & good morning to you too ... 8-]

Wednesday, 3 February 2021

Do delete unused multipass instances

aka 'Completely stupid moves with Snapcraft #1'

You can easily fill up your drive whilst experimenting with Snapcraft if you are as wise as me.

Snapcraft (currently?) relies by default on a virtualization software also by Canonical Ltd., called Multipass.

This will seemingly thrive off pretty big files (I believe I mostly used base18 in my snaps), likely full installations of Ubuntu18. 

I would have expected nothing like to happen when I started deleting my unused multipass machines, but each took ~ 10 GB, despite being almost identical.

Most of them were just results of not caring about snap naming from the first steps ... =b

In short:

multipass list

will give you the snaps, including e.g., having forgotten to use --purge when deleting:

snapcraft-my-snap-name           Deleted           --               Not Available
snapcraft-testapp                Deleted           --               Not Available

now, at this point one might be inclined to delete and purge them well:

multipass delete snapcraft-my-snap-name --purge

and walk away happily with ~ 20 GB (or more) of free space again.

Sunday, 31 January 2021

Wednesday, 27 January 2021

For the "am I crazy" moments with Cython

NB it isn't necessarily a good idea to do something like x = str(x) in Cython.

Keep things with their types associated with variables unchanged, or incomprehensible TypeErrors might keenly jump to help you get your well deserved early dementia.


Thursday, 14 January 2021

Pair programming - the untold truth

It probably is the best alibi to cover for the unstoppable urge of talking to yourself while programming. Well, though - just given that - you aren't necessarily crazy :)

Having throughly studied about 1% of a very prestiguous article, I conclude

"deep, transcendental"

"could actually be a sign of high cognitive functioning"

"might reflect the reality of a genius"

Calm down, that's all we are folks, even if pair programming with an invisible rubber duck at home. Makes sense.


Sunday, 10 January 2021

Saturday, 2 January 2021

And the text editors ... well, they, too

Of course the more advanced/popular text editors for programmers didn't stand a chance when audited for security in 2018.

https://threatpost.com/researchers-show-how-popular-text-editors-can-be-attacked-via-third-party-plugins/130559/

But did anything really change since then? Maybe I just don't to know :)