Sunday, October 29, 2023

Word Macro Insert Page X of Y

Sub InsertTotalPages()
' Inserts total number of pages in the document at cursor
    Selection.Fields.Add Range:=Selection.Range, Type:=wdFieldEmpty, Text:= _
        "NUMPAGES  ", PreserveFormatting:=True
End Sub
 

Sub InsertPageXofY()
' Inserts Page {current_page} of {total_doc_pages} at cursor
    Selection.TypeText Text:="Page "
    Selection.Fields.Add Range:=Selection.Range, Type:=wdFieldPage, Text:="Page ", _
        PreserveFormatting:=True
    Selection.TypeText Text:=" of "
    Selection.Fields.Add Range:=Selection.Range, Type:=wdFieldEmpty, Text:= _
        "NUMPAGES  ", PreserveFormatting:=True
End Sub

Friday, October 27, 2023

Python PlatitorTvaRest API

from datetime import datetime
import requests, json

headers = {
    'Accept': 'application/json',
    'Accept-Language': 'en-US,en;q=0.7,ro;q=0.3',
    'Connection': 'keep-alive',
    'Referer': 'https://mfinante.gov.ro',
    'Content-Type': 'application/json',
}
today = datetime.today().strftime('%Y-%m-%d')
data = [{'cui': '19467555', 'data': today}]
print(data)

response = requests.post('https://webservicesp.anaf.ro/PlatitorTvaRest/api/v8/ws/tva', data=json.dumps(data), headers=headers)
print(response.json())

 *****

[{'cui': '19467555', 'data': '2023-10-27'}]

{
  "cod": 200,
  "message": "SUCCESS",
  "found": [
    {
      "date_generale": {
        "cui": 19467555,
        "data": "2023-10-27",
        "denumire": "LEON TIBERIU CRISTIAN PERSOANĂ FIZICĂ AUTORIZATĂ",
        "adresa": "JUD. BRAŞOV, MUN. SĂCELE, STR. VALEA CERNATULUI, NR.47",
        "nrRegCom": "F08/388/2003",
        "telefon": "0729947925",
        "fax": "",
        "codPostal": "505600",
        "act": "",
        "stare_inregistrare": "RELUARE ACTIVITATE din data 30.04.2013",
        "data_inregistrare": "2007-01-01",
        "cod_CAEN": "7430",
        "iban": "",
        "statusRO_e_Factura": false,
        "organFiscalCompetent": "Administraţia Judeţeană a Finanţelor Publice Braşov",
        "forma_de_proprietate": "",
        "forma_organizare": "",
        "forma_juridica": ""
      },
      "inregistrare_scop_Tva": {
        "scpTVA": false,
        "perioade_TVA": []
      },
      "inregistrare_RTVAI": {
        "dataInceputTvaInc": "",
        "dataSfarsitTvaInc": "",
        "dataActualizareTvaInc": "",
        "dataPublicareTvaInc": "",
        "tipActTvaInc": "",
        "statusTvaIncasare": false
      },
      "stare_inactiv": {
        "dataInactivare": "",
        "dataReactivare": "",
        "dataPublicare": "",
        "dataRadiere": "",
        "statusInactivi": false
      },
      "inregistrare_SplitTVA": {
        "dataInceputSplitTVA": "",
        "dataAnulareSplitTVA": "",
        "statusSplitTVA": false
      },
      "adresa_sediu_social": {
        "sdenumire_Strada": "Str. Valea Cernatului",
        "snumar_Strada": "47",
        "sdenumire_Localitate": "Mun. Săcele",
        "scod_Localitate": "157",
        "sdenumire_Judet": "BRAŞOV",
        "scod_Judet": "8",
        "scod_JudetAuto": "BV",
        "stara": "",
        "sdetalii_Adresa": "",
        "scod_Postal": "505600"
      },
      "adresa_domiciliu_fiscal": {
        "ddenumire_Strada": "Str. Valea Cernatului",
        "dnumar_Strada": "47",
        "ddenumire_Localitate": "Mun. Săcele",
        "dcod_Localitate": "157",
        "ddenumire_Judet": "BRAŞOV",
        "dcod_Judet": "8",
        "dcod_JudetAuto": "BV",
        "dtara": "",
        "ddetalii_Adresa": "",
        "dcod_Postal": "505600"
      }
    }
  ],
  "notFound": []
}

More complex solution: https://github.com/agilegeeks/pyAnaf/blob/master/pyAnaf/api.py

from __future__ import unicode_literals, print_function

import datetime
import sys

PY_3_OR_HIGHER = sys.version_info >= (3, 0)

try:
    import urllib.request as urllib_request
    import urllib.error as urllib_error
except ImportError:
    import urllib2 as urllib_request
    import urllib2 as urllib_error

try:
    from cStringIO import StringIO
except ImportError:
    from io import BytesIO as StringIO

try:
    import http.client as http_client
except ImportError:
    import httplib as http_client

try:
    import json
except ImportError:
    import simplejson as json

from .models import AnafResultEntry


class AnafError(Exception):
    """
    Base Exception thrown by the Anaf object when there is a
    general error interacting with the API.
    """
    pass


class AnafHTTPError(Exception):
    """
    Exception thrown by the Anaf object when there is an
    HTTP error interacting with anaf.ro.
    """
    pass


class AnafResponseError(Exception):
    """
    Exception thrown by the Anaf object when there is an
    error the response returned from ANAF.
    """
    pass


class Anaf(object):
    WS_ENDPOINTS = {
        'sync': 'https://webservicesp.anaf.ro/PlatitorTvaRest/api/v3/ws/tva',
        'async': 'https://webservicesp.anaf.ro/AsynchWebService/api/v3/ws/tva'
    }
    LIMIT = 500

    def __init__(self):
        self.cuis = {}
        self.result = None
        self.entries = {}

    @staticmethod
    def _validate_cui(cui):
        if not isinstance(cui, int):
            raise AnafError('CUI should be integer')

    @staticmethod
    def _validate_date(date):
        if not isinstance(date, datetime.date):
            raise AnafError('Date should be of type datetime.date')

    @staticmethod
    def _prepare_data(data):
        if PY_3_OR_HIGHER:
            return bytes(data, 'utf-8')
        else:
            return data

    def addEndpoint(self, url, target='sync'):
        if target not in ['sync', 'async']:
            raise AnafError('Invalid target for endpoint. Must be one of \'sync\' or \'async\'')

        self.WS_ENDPOINTS[target] = url;

    def setLimit(self, limit):
        try:
            self.LIMIT = int(limit)
        except:
            raise AnafError('Limit should be an integer')

    def setCUIList(self, cui_list=[], date=None):
        if date is None:
            date = datetime.date.today()

        if len(cui_list) > self.LIMIT:
            raise AnafError('Too many CUIs to be queried. Should limit to %d' % self.LIMIT)

        self._validate_date(date)
        for cui in cui_list:
            self._validate_cui(cui)
            self.cuis[cui] = date

    def addCUI(self, cui, date=None):
        if date is None:
            date = datetime.date.today()

        self._validate_cui(cui)
        self._validate_date(date)

        self.cuis[cui] = date
        if len(self.cuis.items()) > self.LIMIT:
            raise AnafError('Too many CUIs to be queried. Should limit to %d' % self.LIMIT)

    def Request(self):
        # translate cuis entries to ANAF json format
        cui_list = []
        for entry in self.cuis.items():
            cui_list.append(
                {
                    'cui': entry[0],
                    'data': entry[1].isoformat()
                }
            )

        request = urllib_request.Request(self.WS_ENDPOINTS['sync'])
        request.add_header('Content-Type', 'application/json')

        try:
            response = urllib_request.urlopen(request, self._prepare_data(json.dumps(cui_list)))
        except urllib_error.HTTPError as e:
            raise AnafHTTPError('Error connecting to ANAF. Got a %d HTTP code.' % e.code)

        data = response.read()
        if isinstance(data, bytes):
            data = data.decode('utf-8')
        try:
            result = json.loads(data)
        except:
            raise AnafResponseError('Error parsing json response from ANAF.')

        if result['cod'] != 200:
            raise AnafResponseError('%s' % result['message'])

        result = result['found']
        self.result = result

        for entry in result:
            self.entries[entry['cui']] = AnafResultEntry(entry)

    def getCUIData(self, cui):
        if cui not in self.entries.keys():
            return None

        return self.entries[cui]

JavaScript Fetch PlatitorTvaRest Api

const url = 'https://webservicesp.anaf.ro/PlatitorTvaRest/api/v8/ws/tva';

const headers = {
    'Accept': 'application/json',
    'Accept-Language': 'en-US,en;q=0.7,ro;q=0.3',
    'Connection': 'keep-alive',
    'Referer': 'https://mfinante.gov.ro',
    'Content-Type': 'application/json',
};
const today = new Date().toISOString().slice(0, 10);
const data = [{'cui': '19467555', 'data': today}];
console.log(data)

fetch(url, {
    method: 'POST',
    headers: headers,
    body: JSON.stringify(data)
})
    .then(response => response.json())
    .then(data => console.log(data))
    .catch((error) => console.error('Error:', error));

*****
[{cui: '19467555', data: '2023-10-27'}]
{
"cod": 200,
"message": "SUCCESS",
"found": [
{
"date_generale": {
"cui": 19467555,
"data": "2023-10-27",
"denumire": "LEON TIBERIU CRISTIAN PERSOANĂ FIZICĂ AUTORIZATĂ",
"adresa": "JUD. BRAŞOV, MUN. SĂCELE, STR. VALEA CERNATULUI, NR.47",
"nrRegCom": "F08/388/2003",
"telefon": "0729947926",
"fax": "",
"codPostal": "505600",
"act": "",
"stare_inregistrare": "RELUARE ACTIVITATE din data 30.04.2013",
"data_inregistrare": "2007-01-01",
"cod_CAEN": "7430",
"iban": "",
"statusRO_e_Factura": false,
"organFiscalCompetent": "Administraţia Judeţeană a Finanţelor Publice Braşov",
"forma_de_proprietate": "",
"forma_organizare": "",
"forma_juridica": ""
},
"inregistrare_scop_Tva": {
"scpTVA": false,
"perioade_TVA": []
},
"inregistrare_RTVAI": {
"dataInceputTvaInc": "",
"dataSfarsitTvaInc": "",
"dataActualizareTvaInc": "",
"dataPublicareTvaInc": "",
"tipActTvaInc": "",
"statusTvaIncasare": false
},
"stare_inactiv": {
"dataInactivare": "",
"dataReactivare": "",
"dataPublicare": "",
"dataRadiere": "",
"statusInactivi": false
},
"inregistrare_SplitTVA": {
"dataInceputSplitTVA": "",
"dataAnulareSplitTVA": "",
"statusSplitTVA": false
},
"adresa_sediu_social": {
"sdenumire_Strada": "Str. Valea Cernatului",
"snumar_Strada": "47",
"sdenumire_Localitate": "Mun. Săcele",
"scod_Localitate": "157",
"sdenumire_Judet": "BRAŞOV",
"scod_Judet": "8",
"scod_JudetAuto": "BV",
"stara": "",
"sdetalii_Adresa": "",
"scod_Postal": "505600"
},
"adresa_domiciliu_fiscal": {
"ddenumire_Strada": "Str. Valea Cernatului",
"dnumar_Strada": "47",
"ddenumire_Localitate": "Mun. Săcele",
"dcod_Localitate": "157",
"ddenumire_Judet": "BRAŞOV",
"dcod_Judet": "8",
"dcod_JudetAuto": "BV",
"dtara": "",
"ddetalii_Adresa": "",
"dcod_Postal": "505600"
}
}
],
"notFound": []
}

Thursday, October 26, 2023

Python Iterators, Generator, Yield, Coroutines

Python Iterators, Generator, Yield, Coroutines

The yield statement suspends a function’s execution and sends a value back to the caller, but retains enough state to enable the function to resume where it left off. When the function resumes, it continues execution immediately after the last yield run. This allows its code to produce a series of values over time, rather than computing them at once and sending them back like a list. Return sends a specified value back to its caller whereas Yield can produce a sequence of values. We should use yield when we want to iterate over a sequence, but don’t want to store the entire sequence in memory. Yield is used in Python generators. A generator function is defined just like a normal function, but whenever it needs to generate a value, it does so with the yield keyword rather than return. If the body of a def contains yield, the function automatically becomes a generator function.

Iterables

When you create a list, you can read its items one by one. Reading its items one by one is called iteration:

mylist = [1, 2, 3]
for i in mylist: print(i)

mylist is an iterable. When you use a list comprehension, you create a list, and so an iterable:

mylist = [x*x for x in range(3)]
for i in mylist: print(i)

Everything you can use "for... in..." on is an iterable; lists, strings, files... These iterables can be read at any time and all their values are stored in memory.

Generators

Generators are iterators, a kind of iterable you can only iterate over once. Generators do not store all the values in memory, they generate the values on the fly:

mygenerator = (x*x for x in range(3))
for i in mygenerator: print(i)

Yield

yield is a keyword that is used like return, except the function will return a generator.

def create_generator():
    mylist = range(3)
    for i in mylist:
       yield i*i

mygenerator = create_generator() # create a generator
print(mygenerator) # mygenerator is an object! <generator object create_generator at 0xb7555c34>
for i in mygenerator: print(i)

When you call the function, the written code in the function body does not run. The function only returns the generator object. The first time the for calls the generator object created from your function, it will run the code in your function from the beginning until it hits yield, then it'll return the first value of the loop. Then, each subsequent call will run another iteration of the loop in the function and return the next value. This will continue until the generator is considered empty, which happens when the function runs without hitting yield. That can be because the loop has come to an end, an "if/else" statement is no longer satisfied, StopIteration is raised...

Understanding the inner mechanisms of iteration

Iteration is a process implying iterables (implementing the __iter__() method) and iterators (implementing the __next__() method). Iterables are any objects you can get an iterator from. Iterators are objects that let you iterate on iterables.

When you call a function that contains a yield statement anywhere, you get a generator object, but no code runs. Then each time you extract an object from the generator, Python executes code in the function until it comes to a yield statement, then pauses and delivers the object. When you extract another object, Python resumes just after the yield and continues until it reaches another yield (often the same one, but one iteration later). This continues until the function runs off the end, at which point the generator is deemed exhausted.

When you see a function with yield statements, apply this easy trick to understand what will happen:

  1. Insert a line result = [] at the start of the function.
  2. Replace each yield expr with result.append(expr).
  3. Insert a line return result at the bottom of the function. 
class countdown_iterator:
    def __init__(self):
        # Start at -1 so that we get 0 when we add 1 below.
        self.count = -1

    # The __iter__ method will be called once by the 'for' loop.
    # The rest of the magic happens on the object returned by this method.
    # In this case it is the object itself.
    def __iter__(self):
        return self

    # The next method will be called repeatedly by the 'for' loop
    # until it raises StopIteration.
    def next(self):
        self.count += 1
        if self.count < 4:
            return self.count
        else:
            # A StopIteration exception is raised
            # to signal that the iterator is done.
            # This is caught implicitly by the 'for' loop.
            raise StopIteration

def some_func():
    return countdown_iterator()

for i in some_func():
    print i

 he yield keyword is reduced to two simple facts:

  1. If the compiler detects the yield keyword anywhere inside a function, that function no longer returns via the return statement. Instead, it immediately returns a lazy "pending list" object called a generator
  2. A generator is iterable. What is an iterable? It's anything like a list, set, range, dictionary view, or any other object with a built-in protocol for visiting each element in a certain order.

In a nutshell: Most commonly, a generator is a lazy, incrementally-pending list, and yield statements allow you to use function notation to program the list values the generator should incrementally spit out. Furthermore, advanced usage lets you use generators as coroutines (see below).

Let's define a function makeRange that's just like Python's range. Calling makeRange(n) RETURNS A GENERATOR:

def makeRange(n):
    # return 0,1,2,...,n-1
    i = 0
    while i < n:
        yield i
        i += 1

>>> makeRange(5)
<generator object makeRange at 0x19e4aa0>

To force the generator to immediately return its pending values, you can pass it into list() (just like you could any iterable):

>>> list(makeRange(5))
[0, 1, 2, 3, 4

The above example can be thought of as merely creating a list that you append to and return:

# return a list                  #  # return a generator
def makeRange(n):                #  def makeRange(n):
    """return [0,1,2,...,n-1]""" #      """return 0,1,2,...,n-1"""
    TO_RETURN = []               # 
    i = 0                        #      i = 0
    while i < n:                 #      while i < n:
        TO_RETURN += [i]         #          yield i
        i += 1                   #          i += 1
    return TO_RETURN             # 

>>> makeRange(5)
[0, 1, 2, 3, 4]

This is how the "Python iteration protocol" works. That is, what is going on when you do list(makeRange(5)). This is described earlier as a "lazy, incremental list".

>>> x=iter(range(5))
>>> next(x)  # calls x.__next__(); x.next() is deprecated
0
>>> next(x)
1
>>> next(x)
2
>>> next(x)
3
>>> next(x)
4
>>> next(x)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration 

A coroutine (generators that generally accept input via the yield keyword e.g. nextInput = yield nextOutput, as a form of two-way communication) is basically a computation that is allowed to pause itself and request input (e.g. to what it should do next). When the coroutine pauses itself (when the running coroutine eventually hits a yield keyword), the computation is paused and control is inverted (yielded) back to the 'calling' function (the frame which requested the next value of the computation). The paused generator/coroutine remains paused until another invoking function (possibly a different function/context) requests the next value to unpause it (usually passing input data to direct the paused logic interior to the coroutine's code). One can think of Python coroutines as lazy incrementally-pending lists, where the next element doesn't just depend on the previous computation but also on input that you may opt to inject during the generation process.

x = myRange(5)

list(x) #[0, 1, 2, 3, 4]
list(x) # []

A generator is an iterator; that is, it is one-time-use. If you want to reuse it, you should call myRange(...) again. If you need to use the result twice, convert the result to a list and store it in a variable x = list(myRange(5)).

  • A function with yield, when called, returns a Generator.
  • Generators are iterators because they implement the iterator protocol, so you can iterate over them.
  • A generator can also be sent information, making it conceptually a coroutine.
  • In Python 3, you can delegate from one generator to another in both directions with yield from.

yield is only legal inside of a function definition, and the inclusion of yield in a function definition makes it return a generator. When the generator is called (methods are discussed below) execution resumes and then freezes at the next yield. The generator type is a sub-type of iterator. An Iterator can't be reused or reset once exhausted. Another generator should be created to use its functionality again.

Coroutines:

yield forms an expression that allows data to be sent into the generator.

The received variable will point to the data that is sent to the generator:

def bank_account(deposited, interest_rate):
    while True:
        calculated_interest = interest_rate * deposited 
        received = yield calculated_interest
        if received:
            deposited += received

my_account = bank_account(1000, .05)

First, we must queue up the generator with the built-in function, next. It will call the appropriate next.

first_year_interest = next(my_account)
first_year_interest
50.0

And now we can send data into the generator. (Sending None is the same as calling next.) :

next_year_interest = my_account.send(first_year_interest + 1000)
next_year_interest
102.5

Cooperative Delegation to Sub-Coroutine with yield from. Other methods: close and throw. In a generator function, the return statement indicates that the generator is done and will cause StopIteration to be raised. The returned value (if any) is used as an argument to construct StopIteration and becomes the StopIteration.value attribute.

yield is similar to return - it returns whatever you tell it to (as a generator). The difference is that the next time you call the generator, execution starts from the last call to the yield statement. Unlike return, the stack frame is not cleaned up when a yield occurs, however control is transferred back to the caller, so its state will resume the next time the function is called.

Yield is single-pass: you can only iterate through once. When a function has a yield in it we call it a generator function. And an iterator is what it returns. Those terms are revealing. We lose the convenience of a container, but gain the power of a series that's computed as needed, and arbitrarily long.

Yield is lazy, it puts off computation. A function with a yield in it doesn't actually execute at all when you call it. It returns an iterator object that remembers where it left off. Each time you call next() on the iterator (this happens in a for-loop) execution inches forward to the next yield. return raises StopIteration and ends the series (this is the natural end of a for-loop).

Yield is versatile. Data doesn't have to be stored all together, it can be made available one at a time. It can be infinite. If you need multiple passes and the series isn't too long, just call list(generator).

Use send method inside a generator to send data back to the generator. To allow that, a (yield) is used.

iterator is a more general concept: any object whose class has a __next__ method (next in Python 2) and an __iter__ method that does return self.

Every generator is an iterator, but not vice versa. A generator is built by calling a function that has one or more yield expressions (yield statements, in Python 2.5 and earlier), and is an object that meets the previous paragraph's definition of an iterator.

You may want to use a custom iterator, rather than a generator, when you need a class with somewhat complex state-maintaining behavior, or want to expose other methods besides __next__ (and __iter__ and __init__). Most often, a generator (sometimes, for sufficiently simple needs, a generator expression) is sufficient, and it's simpler to code because state maintenance (within reasonable limits) is basically "done for you" by the frame getting suspended and resumed.

def squares(start, stop):
    for i in range(start, stop):
        yield i * i

generator = squares(a, b)
or the equivalent generator expression (genexp)
generator = (i*i for i in range(a, b)) 

 would take more code to build as a custom iterator:

class Squares(object):
    def __init__(self, start, stop):
       self.start = start
       self.stop = stop

    def __iter__(self): 
        return self

    def __next__(self): # next in Python 2
       if self.start >= self.stop:
           raise StopIteration
       current = self.start * self.start
       self.start += 1
       return current

iterator = Squares(a, b)
But, of course, with class Squares you could easily offer extra methods, i.e.
def current(self):
    return self.start 

When type hinting a generator that only yields values can be annotated as an Iterator more simply (Generator[int, None, None] === Iterator[int])

 When a generator function is called, it returns an generator object without even beginning the execution of the function. When the next() method is called for the first time, the function starts executing until it reaches a yield statement which returns the yielded value. The yield keeps track of what has happened, i.e. it remembers the last execution. And secondly, the next() call continues from the previous value. Generator functions are ordinary functions defined using yield instead of return. When called, a generator function returns a generator object, which is a kind of iterator - it has a next() method. When you call next(), the next value yielded by the generator function is returned.
A generator function is a function with yield in it.
A generator expression is like a list comprehension. It uses "()" vs "[]"
A generator object (often called 'a generator') is returned by both above.
A generator is also a subtype of iterator.
A generator has a close method, while typical iterators don’t. The close method triggers a StopIteration exception in the generator,
which may be caught in a finally  clause in that iterator, to get a chance to run some clean‑up.
This abstraction makes it most usable in the large than simple iterators.
One can close a generator as one could close a file, without having to bother about what’s underneath.
Besides, if you check the memory footprint, the generator takes much less memory,
as it doesn't need to store all the values in memory at the same time. 
def myGeneratorList(n):
    for i in range(n):
        yield i

def myIterableList(n):
    ll = n*[None]
    for i in range(n):
        ll[i] = i
    return ll

# Same values
ll1 = myGeneratorList(10)
ll2 = myIterableList(10)
for i1, i2 in zip(ll1, ll2):
    print("{} {}".format(i1, i2))

# Generator can only be read once
ll1 = myGeneratorList(10)
ll2 = myIterableList(10)

print("{} {}".format(len(list(ll1)), len(ll2)))
print("{} {}".format(len(list(ll1)), len(ll2)))

# Generator can be read several times if converted into iterable
ll1 = list(myGeneratorList(10))
ll2 = myIterableList(10)

print("{} {}".format(len(list(ll1)), len(ll2)))
print("{} {}".format(len(list(ll1)), len(ll2)))

An iterable object is something which can be iterated (naturally). To do that, however, you will need something like an iterator object, and, yes, the terminology may be confusing. Iterable objects include a __iter__ method which will return the iterator object for the iterable object.

An iterator object is an object which implements the iterator protocol - a set of rules. In this case, it must have at least these two methods: __iter__ and __next__. The __next__ method is a function which supplies a new value. The __iter__ method returns the iterator object. In a more complex object, there may be a separate iterator, but in a simpler case, __iter__ returns the object itself (typically return self).

One iterable object is a list object. It’s not an iterator, but it has an __iter__ method which returns an iterator. You can call this method directly as things.__iter__(), or use iter(things).

Writing an iterator yourself can be tedious, so Python has a simpler alternative: the generator function. A generator function is not an ordinary function. Instead of running through the code and returning a final result, the code is deferred, and the function returns immediately with a generator object. A generator object is like an iterator object in that it implements the iterator protocol. All generators are iterators but not vice versa.

 

Saturday, October 21, 2023

Useful Python String Methods

import string
ascii_letters = list(string.ascii_letters)
print(ascii_letters)
ascii_lowercase = list(string.ascii_lowercase)
print(ascii_lowercase)
print(list(chr(x) for x in range(97, 123)))  
ascii_uppercase = list(string.ascii_uppercase)
print(ascii_uppercase)
print(list(chr(x) for x in range(65, 91))) 
digits = list(string.digits)
print(digits)
print(list(chr(x) for x in range(48, 58))) 
punctuation = list(string.punctuation)
print(string.punctuation)
print(punctuation)
# capitalize words
print(string.capwords("
ALL words iN sTRing's TransformeD 2to tiTle $CaSe# &caSe% ștuț şanţ ß groß ßa aßen"sep=None))

#Generate all possible pairs of 2 from the lower/upper case alphabet
from itertools import product
alphabet = list(string.ascii_letters)
two_letter_words = product(alphabet, alphabet)
for word in two_letter_words:
    print (word)

# Same result with repeat
two_letter_words = product(alphabet, repeat=2)
 
# print(len(two_letter_words))
#TypeError: object of type 'itertools.product' has no len()
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']
['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~
['!', '"', '#', '$', '%', '&', "'", '(', ')', '*', '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '^', '_', '`', '{', '|', '}', '~']
All Words In String's Transformed 2to Title $case# &case% Ștuț Şanţ Ss Groß Ssa Aßen
('a', 'a')
('a', 'b')
('a', 'c')
('a', 'd')
...
('Z', 'X')
('Z', 'Y')
('Z', 'Z')

print(list(chr(x) for x in range(32, 48)))
[' ', '!', '"', '#', '$', '%', '&', "'", '(', ')', '*', '+', ',', '-', '.', '/']

newlist = [' ', '!', '"', '#', '$', '%', '&', "'", '(', ')', '*', '+', ',', '-', '.', '/']
print(list(ord(x) for x in newlist))[32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47]
*****

String constants

The constants defined in this module are:

string.ascii_letters

The concatenation of the ascii_lowercase and ascii_uppercase constants described below. This value is not locale-dependent.

string.ascii_lowercase

The lowercase letters 'abcdefghijklmnopqrstuvwxyz'. This value is not locale-dependent and will not change.

string.ascii_uppercase

The uppercase letters 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'. This value is not locale-dependent and will not change.

string.digits

The string '0123456789'.

string.hexdigits

The string '0123456789abcdefABCDEF'.

string.octdigits

The string '01234567'.

string.punctuation

String of ASCII characters which are considered punctuation characters in the C locale: !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~.

string.printable

String of ASCII characters which are considered printable. This is a combination of digits, ascii_letters, punctuation, and whitespace.

string.whitespace

A string containing all ASCII characters that are considered whitespace. This includes the characters space, tab, linefeed, return, formfeed, and vertical tab.

Helper functions

string.capwords(s, sep=None)
 
Split the argument into words using str.split(), capitalize each word using str.capitalize(), and join the capitalized words using str.join(). If the optional second argument sep is absent or None, runs of whitespace characters are replaced by a single space and leading and trailing whitespace are removed, otherwise sep is used to split and join the words.

 Source: https://docs.python.org

Python Generators/List comprehension comparison

import time, sys

genstartime = time.perf_counter()
gensquares = (x**2 for x in range(500000))
# print(time.perf_counter() - genstartime, type(gensquares))
gencompstartime = time.perf_counter()
finalgenlist = [square for square in gensquares]
print(
    "Generator with list comprehension. Generator time:",
    time.perf_counter() - gencompstartime,
    "Final time:",
    time.perf_counter() - genstartime,
)

genstartime = time.perf_counter()
gensquares = (x**2 for x in range(500000))
# print(time.perf_counter() - genstartime, type(gensquares))
gencompstartime = time.perf_counter()
finalgenlist = list(gensquares)
print(
    "Generator with list(). Generator time:",
    time.perf_counter() - gencompstartime,
    "Final time:",
    time.perf_counter() - genstartime,
)
print('Memory size of generator  in bytes:', sys.getsizeof(gensquares),
      'Memory size of list  in bytes:', sys.getsizeof(finalgenlist))
# An important thing to note is that generators iterate over an object lazily,
# meaning they do not store their contents in memory.
# listfromgen = list(gensquares)
# print(listfromgen, len(listfromgen), sys.getsizeof(listfromgen)) # [] 0 56
# print(len(finalgenlist)) # list kept in memory, len equal to range

liststartime = time.perf_counter()
listsquares = [x**2 for x in range(500000)]
print(
    "Simple list comprehension", time.perf_counter() - liststartime, type(listsquares)
)
# print( 'Memory size after list comprehension in bytes:', sys.getsizeof(listsquares))
 
Results with Python 3.11.4:
Generator with list comprehension. Generator time: 0.09394780000002356 Final time: 0.09395289999883971
Generator with list(). Generator time: 0.0871331000016653 Final time: 0.08714600000166683
Memory size of generator in bytes: 208 Memory size of list in bytes: 4167352
Simple list comprehension 0.06546270000035292 <class 'list'>

Generator with list comprehension. Generator time: 0.08868479999728152 Final time: 0.08870200000092154
Generator with list(). Generator time: 0.08478610000020126 Final time: 0.08480150000104913
Memory size of generator in bytes: 208 Memory size of list in bytes: 4167352
Simple list comprehension 0.06996629999775905 <class 'list'>

Generator with list comprehension. Generator time: 0.08237219999864465 Final time: 0.08237809999991441
Generator with list(). Generator time: 0.09145460000218009 Final time: 0.09146870000040508
Memory size of generator in bytes: 208 Memory size of list in bytes: 4167352
Simple list comprehension 0.0625220999972953 <class 'list'>

Saturday, October 14, 2023

Add Global Jinja Variables for Quart/Flask

app = Quart(__name__, template_folder='templates', static_folder='static')
app.jinja_env.globals['emojiflags'] = emojiflags 

 or

app = Flask(__name__, template_folder='templates', static_folder='static')
app.add_template_global(name='emojiflags', f=emojiflags

Wednesday, October 11, 2023

CSS Default Browser Values for HTML Elements

Element Default CSS Value
a:link color: (internal value);
text-decoration: underline;
cursor: auto;
a:visited color: (internal value);
text-decoration: underline;
cursor: auto;
a:link:active color: (internal value);
a:visited:active color: (internal value);
abbr None.
address display: block;
font-style: italic;
area display: none;
article display: block;
aside display: block;
audio None.
b font-weight: bold;
base None.
bdi None.
bdo unicode-bidi: bidi-override;
blockquote display: block;
margin-top: 1em;
margin-bottom: 1em;
margin-left: 40px;
margin-right: 40px;
body display: block;
margin: 8px;
body:focus outline: none;
br None.
button None
canvas None.
caption display: table-caption;
text-align: center;
cite font-style: italic;
code font-family: monospace;
col display: table-column;
colgroup display: table-column-group
datalist display: none;
dd display: block;
margin-left: 40px;
del text-decoration: line-through;
details display: block;
dfn font-style: italic;
dialog None.
div display: block;
dl display: block;
margin-top: 1em;
margin-bottom: 1em;
margin-left: 0;
margin-right: 0;
dt display: block;
em font-style: italic;
embed:focus outline: none;
fieldset display: block;
margin-left: 2px;
margin-right: 2px;
padding-top: 0.35em;
padding-bottom: 0.625em;
padding-left: 0.75em;
padding-right: 0.75em;
border: 2px groove (internal value);
figcaption display: block;
figure display: block;
margin-top: 1em;
margin-bottom: 1em;
margin-left: 40px;
margin-right: 40px;
footer display: block;
form display: block;
margin-top: 0em;
h1 display: block;
font-size: 2em;
margin-top: 0.67em;
margin-bottom: 0.67em;
margin-left: 0;
margin-right: 0;
font-weight: bold;
h2 display: block;
font-size: 1.5em;
margin-top: 0.83em;
margin-bottom: 0.83em;
margin-left: 0;
margin-right: 0;
font-weight: bold;
h3 display: block;
font-size: 1.17em;
margin-top: 1em;
margin-bottom: 1em;
margin-left: 0;
margin-right: 0;
font-weight: bold;
h4 display: block;
margin-top: 1.33em;
margin-bottom: 1.33em;
margin-left: 0;
margin-right: 0;
font-weight: bold;
h5 display: block;
font-size: .83em;
margin-top: 1.67em;
margin-bottom: 1.67em;
margin-left: 0;
margin-right: 0;
font-weight: bold;
h6 display: block;
font-size: .67em;
margin-top: 2.33em;
margin-bottom: 2.33em;
margin-left: 0;
margin-right: 0;
font-weight: bold;
head display: none;
header display: block;
hr display: block;
margin-top: 0.5em;
margin-bottom: 0.5em;
margin-left: auto;
margin-right: auto;
border-style: inset;
border-width: 1px;
html display: block;
html:focus outline: none;
i font-style: italic;
iframe:focus outline: none;
iframe[seamless] display: block;
img display: inline-block;
input None.
ins text-decoration: underline;
kbd font-family: monospace;
label cursor: default;
legend display: block;
padding-left: 2px;
padding-right: 2px;
border: none;
li display: list-item;
link display: none;
main None.
map display: inline;
mark background-color: yellow;
color: black;
menu display: block;
list-style-type: disc;
margin-top: 1em;
margin-bottom: 1em;
margin-left: 0;
margin-right: 0;
padding-left: 40px;
menuitem None.
meta None.
meter None.
nav display: block;
noscript None.
object:focus outline: none;
ol display: block;
list-style-type: decimal;
margin-top: 1em;
margin-bottom: 1em;
margin-left: 0;
margin-right: 0;
padding-left: 40px;
optgroup None.
option None.
output display: inline;
p display: block;
margin-top: 1em;
margin-bottom: 1em;
margin-left: 0;
margin-right: 0;
param display: none;
picture None.
pre display: block;
font-family: monospace;
white-space: pre;
margin: 1em 0;
progress None.
q display: inline;
q::before content: open-quote;
q::after content: close-quote;
rp None.
rt line-height: normal;
ruby None.
s text-decoration: line-through;
samp font-family: monospace;
script display: none;
section display: block;
select None.
small font-size: smaller;
source None.
span None.
strike text-decoration: line-through;
strong font-weight: bold;
style display: none;
sub vertical-align: sub;
font-size: smaller;
summary display: block;
sup vertical-align: super;
font-size: smaller;
table display: table;
border-collapse: separate;
border-spacing: 2px;
border-color: gray;
tbody display: table-row-group;
vertical-align: middle;
border-color: inherit;
td display: table-cell;
vertical-align: inherit;
template None.
textarea None.
tfoot display: table-footer-group;
vertical-align: middle;
border-color: inherit;
th display: table-cell;
vertical-align: inherit;
font-weight: bold;
text-align: center;
thead display: table-header-group;
vertical-align: middle;
border-color: inherit;
time None.
title display: none;
tr display: table-row;
vertical-align: inherit;
border-color: inherit;
track None.
u text-decoration: underline;
ul display: block;
list-style-type: disc;
margin-top: 1em;
margin-bottom: 1 em;
margin-left: 0;
margin-right: 0;
padding-left: 40px;
var font-style: italic;
video None.
wbr None.
html display: block;
html:focus outline: none;
i font-style: italic;
iframe:focus outline: none;
iframe[seamless] display: block;
img display: inline-block;
input None.
ins text-decoration: underline;
kbd font-family: monospace;
label cursor: default;
legend display: block;
padding-left: 2px;
padding-right: 2px;
border: none;
li display: list-item;
link display: none;
main None.
map display: inline;
mark background-color: yellow;
color: black;
menu display: block;
list-style-type: disc;
margin-top: 1em;
margin-bottom: 1em;
margin-left: 0;
margin-right: 0;
padding-left: 40px;
menuitem None.
meta None.
meter None.
nav display: block;
noscript None.
object:focus outline: none;
ol display: block;
list-style-type: decimal;
margin-top: 1em;
margin-bottom: 1em;
margin-left: 0;
margin-right: 0;
padding-left: 40px;
optgroup None.
option None.
output display: inline;
p display: block;
margin-top: 1em;
margin-bottom: 1em;
margin-left: 0;
margin-right: 0;
param display: none;
picture None.
pre display: block;
font-family: monospace;
white-space: pre;
margin: 1em 0;
progress None.
q display: inline;
q::before content: open-quote;
q::after content: close-quote;
rp None.
rt line-height: normal;
ruby None.
s text-decoration: line-through;
samp font-family: monospace;
script display: none;
section display: block;
select None.
small font-size: smaller;
source None.
span None.
strike text-decoration: line-through;
strong font-weight: bold;
style display: none;
sub vertical-align: sub;
font-size: smaller;
summary display: block;
sup vertical-align: super;
font-size: smaller;
table display: table;
border-collapse: separate;
border-spacing: 2px;
border-color: gray;
tbody display: table-row-group;
vertical-align: middle;
border-color: inherit;
td display: table-cell;
vertical-align: inherit;
template None.
textarea None.
tfoot display: table-footer-group;
vertical-align: middle;
border-color: inherit;
th display: table-cell;
vertical-align: inherit;
font-weight: bold;
text-align: center;
thead display: table-header-group;
vertical-align: middle;
border-color: inherit;
time None.
title display: none;
tr display: table-row;
vertical-align: inherit;
border-color: inherit;
track None.
u text-decoration: underline;
ul display: block;
list-style-type: disc;
margin-top: 1em;
margin-bottom: 1 em;
margin-left: 0;
margin-right: 0;
padding-left: 40px;
var font-style: italic;
video None.
wbr None.
***** 
Selector Example Example description
.class .intro Selects all elements with class="intro"
.class1.class2 .name1.name2 Selects all elements with both name1 and name2 set within its class attribute
.class1 .class2 .name1 .name2 Selects all elements with name2 that is a descendant of an element with name1
#id #firstname Selects the element with id="firstname"
* * Selects all elements
element p Selects all <p> elements
element.class p.intro Selects all <p> elements with class="intro"
element,element div, p Selects all <div> elements and all <p> elements
element element div p Selects all <p> elements inside <div> elements
element>element div > p Selects all <p> elements where the parent is a <div> element
element+element div + p Selects the first <p> element that is placed immediately after <div> elements
element1~element2 p ~ ul Selects every <ul> element that is preceded by a <p> element
[attribute] [target] Selects all elements with a target attribute
[attribute=value] [target="_blank"] Selects all elements with target="_blank"
[attribute~=value] [title~="flower"] Selects all elements with a title attribute containing the word "flower"
[attribute|=value] [lang|="en"] Selects all elements with a lang attribute value equal to "en" or starting with "en-"
[attribute^=value] a[href^="https"] Selects every <a> element whose href attribute value begins with "https"
[attribute$=value] a[href$=".pdf"] Selects every <a> element whose href attribute value ends with ".pdf"
[attribute*=value] a[href*="w3schools"] Selects every <a> element whose href attribute value contains the substring "w3schools"
:active a:active Selects the active link
::after p::after Insert something after the content of each <p> element
::before p::before Insert something before the content of each <p> element
:checked input:checked Selects every checked <input> element
:default input:default Selects the default <input> element
:disabled input:disabled Selects every disabled <input> element
:empty p:empty Selects every <p> element that has no children (including text nodes)
:enabled input:enabled Selects every enabled <input> element
:first-child p:first-child Selects every <p> element that is the first child of its parent
::first-letter p::first-letter Selects the first letter of every <p> element
::first-line p::first-line Selects the first line of every <p> element
:first-of-type p:first-of-type Selects every <p> element that is the first <p> element of its parent
:focus input:focus Selects the input element which has focus
:fullscreen :fullscreen Selects the element that is in full-screen mode
:hover a:hover Selects links on mouse over
:in-range input:in-range Selects input elements with a value within a specified range
:indeterminate input:indeterminate Selects input elements that are in an indeterminate state
:invalid input:invalid Selects all input elements with an invalid value
:lang(language) p:lang(it) Selects every <p> element with a lang attribute equal to "it" (Italian)
:last-child p:last-child Selects every <p> element that is the last child of its parent
:last-of-type p:last-of-type Selects every <p> element that is the last <p> element of its parent
:link a:link Selects all unvisited links
::marker ::marker Selects the markers of list items
:not(selector) :not(p) Selects every element that is not a <p> element
:nth-child(n) p:nth-child(2) Selects every <p> element that is the second child of its parent
:nth-last-child(n) p:nth-last-child(2) Selects every <p> element that is the second child of its parent, counting from the last child
:nth-last-of-type(n) p:nth-last-of-type(2) Selects every <p> element that is the second <p> element of its parent, counting from the last child
:nth-of-type(n) p:nth-of-type(2) Selects every <p> element that is the second <p> element of its parent
:only-of-type p:only-of-type Selects every <p> element that is the only <p> element of its parent
:only-child p:only-child Selects every <p> element that is the only child of its parent
:optional input:optional Selects input elements with no "required" attribute
:out-of-range input:out-of-range Selects input elements with a value outside a specified range
::placeholder input::placeholder Selects input elements with the "placeholder" attribute specified
:read-only input:read-only Selects input elements with the "readonly" attribute specified
:read-write input:read-write Selects input elements with the "readonly" attribute NOT specified
:required input:required Selects input elements with the "required" attribute specified
:root :root Selects the document's root element
::selection ::selection Selects the portion of an element that is selected by a user
:target #news:target Selects the current active #news element (clicked on a URL containing that anchor name)
:valid input:valid Selects all input elements with a valid value
:visited a:visited Selects all visited links
 ******

All CSS Combinator Selectors

Selector Example Example description
element element div p Selects all <p> elements inside <div> elements
element>element div > p Selects all <p> elements where the parent is a <div> element
element+element div + p Selects the first <p> element that are placed immediately after <div> elements
element1~element2 p ~ ul Selects every <ul> element that are preceded by a <p> element