Blog‎ > ‎

Python 3 vs 2, Ipaddress, Programming, Let's Encrypt ACMEv2

posted Jul 28, 2018, 11:17 PM by Sami Lehtinen   [ updated Jul 28, 2018, 11:17 PM ]
  • What you can't do with Python 2, but can do with Python 3. Still wondering why some people refuse to use Python 3. Let's see if that list got anything I didn't know, but need at some level. I'm naturally using advanced unpacking and keyword arguments, because those are just too useful to be ignored. Some people argue that it's better to have different functions / methods, for different parameters. But I don't personally like that too much, unless it's something obvious. Even then I prefer to have the main code and then just 'handles' for the rest of stuff. Chained exceptions is also way too useful to ignore. All of my code naturally uses that. OSError and other exception subclases. Yet at times it might bite you, if you've defined exception handling for a few common subclasses and then you'll get something you didn't expect to happen. Well. That's also one of the reasons why I write generic exception handler, which fails and rollback whatever was happening, in case of unhandled exception. Yet of course it's bad code, if exceptions aren't handed properly. In this way, there's always rollback catch all fallback. It's quite rare that there's unknown exception which still means that everything is ok, and process should be continued. I don't remember having that kind of fail in production for several years. It's also obvious that all this stuff gets logged in detail. Everything is an iterator and no more comparison of everything ot everything, is pretty obvious. Yield from is something I didn't actually know. There's subtle but important difference between append and extend on lists. I'm almost always using append. Because I'm often having lists of lists. Coroutine and asyncio, I'm naturally aware of it, but I haven't written any production code with it yet. Fault handler is something I haven't yet needed, but it seems to be really useful when needed, a key tool like signal lib, when needed. Ipaddress is something I've used. It's especially handy when dealing with subnets and IPv6 addresses in different formats. functools.lru_cache - Sure, but I've got my pyclockpro, which utilizes better CLOCK-Pro eviction algorithm which is better than the LRU obviously used by the lru_cache. Enum is quite handy.
  • As bonus the Python Ipaddress library does compression and exploding correctly. Unlike the ridiculously bad clearly custom code which OVH used in their control panel, which I blogged about and did the thing incorrectly. It was like fail, fail fail, burn with fire. Function annotations, that's sometimes very useful. I've used that a lot. Pathlib is also pretty obvious choice.
  • I'm currently just working on code, where it's hard to decide if it's one item and many process steps, or if it's list of data, which goes then through set of steps. Haven't yet decided which one is best for the specific case. Often I prefer by item processing, but if the items got interlinked meaning, then it's becomes much easier and clearer to handle those as group / list. Which passes multiple steps. This is also important because otherwise maintaining inter item state might become a horrible mess. Of it get's complex enough, then naturally there will be classes for each item type and data structure, instead of simple lists, tuples, dicts or named tuples. Using lists also easily leads to 'magic numbers'. Which is naturally very hard for anyone else, and for yourself too to handle after a while. Sometimes when stuff isn't just properly labeled or named. It's easy to come up with numbers. But it's hard to maintain such code in future. Especially if those field numbers will be changed at some point. Numbering itself isn't a bad thing. Oh, you're talking about field 132 that's just as good as talking about EBELP or MOA. Of course position enumerators can and should be used to add names, when applicable. About coroutines and async io, because networking is often handled by something else, and I'm handling already parsed messages. I'll do just fine with multiprocessing & multi-threading. Yet the 'slow' database access could be probably written using asyncio, but it might make the code bit more complex than using just imap. Because performance (so far) is hardly a problem, I haven't really put thought into that. Simplicity, clarity and reliability are much more important. I haven't completely internalized what's the benefit over enumerations over dictionaries. Except of course improving code readability in many cases, which is important factor alone. Enumerators fall in category, that you could use those, just so you can say you're using those. But the actual benefits should be pretty slim. One of things, which can be solved using just so many different ways. Which way is preferred, it depends. Mostly I've used enumerate with for loops.
  • ACME v2 Let's Encrypt protocol - Awesome, it's becoming IETF RFC standard.