Wednesday, March 27, 2024

Hidden APIs

www.synonyms.com from Wordnet

curl 'https://www.synonyms.com/gw.php' --compressed -X POST -H 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:124.0) Gecko/20100101 Firefox/124.0' -H 'Accept: application/json, text/javascript, */*; q=0.01' -H 'Accept-Language: en-US,en;q=0.7,ro;q=0.3' -H 'Accept-Encoding: gzip, deflate, br' -H 'Content-Type: application/x-www-form-urlencoded' -H 'X-Requested-With: XMLHttpRequest' -H 'Origin: https://www.synonyms.com' -H 'DNT: 1' -H 'Sec-GPC: 1' -H 'Connection: keep-alive' -H 'Referer: https://www.synonyms.com/synonym/download' -H 'Sec-Fetch-Mode: cors' -H 'Sec-Fetch-Site: same-origin' -H 'Pragma: no-cache' -H 'Cache-Control: no-cache' -H 'TE: trailers' --data-raw 'action=get_vis_syn&term=downtown'

Response: {"id":"_root_","name":"downtown","children":[{"id":159594131,"name":"","children":[{"id":295258892,"name":"business district","children":[],"data":{"$type":"circle","$dim":15,"is_synset_node":false,"$color":"#BCE099"}}],"data":{"definition":"the central area or commercial center of a town or city","synonymno":46309,"is_synset_node":true,"$color":"#BCE099"}}],"data":{"$type":"triangle","$color":"#CCC","$dim":15,"is_synset_node":true}}

vocabulary.com / random corpus examples

https://corpus.vocabulary.com/api/1.0/examples/random.json?maxResults=64&query=downtown&startOffset=0


Monday, March 25, 2024

Extract source file embedded in sdlxliff with Python

import base64
import sys
import xml.etree.ElementTree as ET
import re

def convert(doc_text, file_out):
    with open(file_out, 'wb') as o:
        for line in doc_text.split('\r\n'):
            str = base64.b64decode(line)
            o.write(bytes(str))

def extract(file_in):
    tree = ET.parse(file_in)
    root = tree.getroot()
    re_result = re.search('{(.+)}', root.tag)
    ns = re_result.group(1)
    counter = 0
    for doc in root.findall('.//{' + ns + '}internal-file'):
        file_out = file_in + '_' + str(counter) + '.zip'
        convert(doc.text, file_out)
        counter += 1
            
for arg in sys.argv[1:]:
    extract(arg)

 https://github.com/TomasoAlbinoni/sdlxliff_extractor

Tuesday, March 5, 2024

Barebone Quart API from Sqlite DB

import asyncio
import sqlite3
from quart import Quart

app = Quart(__name__)

async def connect_db():
    conn = sqlite3.connect("your_database.db")
    conn.row_factory = sqlite3.Row
    return conn

async def fetch_data(column1):
    async with connect_db() as conn:
        cursor = conn.cursor()
        cursor.execute("SELECT ?, column2 FROM your_table", (column1,))
        data = cursor.fetchall()
    return [dict(row) for row in data]

@app.route("/api/data/<column_name>")
async def get_data(column_name):
    data = await fetch_data(column_name)
    return data  # Return the list of dictionaries directly

if __name__ == "__main__":
    app.run(debug=True)

Here, the get_data function directly returns the list of dictionaries obtained from the database, and Quart automatically handles the serialization to JSON format before sending the response.

However, using jsonify offers some advantages:

  • Consistency: It provides a consistent way to handle different data structures, ensuring they are all converted to JSON format correctly.
  • Customization: It allows for additional options like specifying status codes, setting custom headers, or customizing the JSON serialization if needed.

Therefore, while jsonify isn't strictly required in this case, it can improve code clarity and maintainability, especially for larger projects or when dealing with diverse data structures.

or with jsonify (not necessary)

import asyncio
import sqlite3
from quart import Quart, jsonify

app = Quart(__name__)

async def connect_db():
    conn = sqlite3.connect("your_database.db")
    conn.row_factory = sqlite3.Row
    return conn

async def fetch_data(column1):
    async with connect_db() as conn:
        cursor = conn.cursor()
        cursor.execute("SELECT ?, column2 FROM your_table", (column1,))  # Dynamic query
        data = cursor.fetchall()
    return [dict(row) for row in data]

@app.route("/api/data/<column_name>")
async def get_data(column_name):
    data = await fetch_data(column_name)
    return jsonify(data)

if __name__ == "__main__":
    app.run(debug=True)

How to Use:

Now, you would access the API by providing the first column name as part of the URL. For example:

  • /api/data/name (assuming the first column is named "name")
  • /api/data/age (assuming the first column is named "age")

Informații E-Factura

Ministerul Finanţelor anunţă lansarea versiunii simplificate a aplicaţiei e-Factura. Ministrul de resort, Marcel Boloş, spune că aceasta este în primul rând utilă celor aproximativ 670.000 contribuabili mici care au nevoie de un format gratuit şi uşor de folosit.

”În continuarea eforturilor de digitalizare şi simplificare a procedurilor fiscale, Ministerul Finanţelor anunţă lansarea versiunii simplificate a aplicaţiei e-Factura”, anunţă ministerul, potrivit News.ro

Versiunea îmbunătăţită vine cu o interfaţă intuitivă şi funcţionalităţi mai uşor de utilizat, astfel încât fiecare utilizator să poată emite facturi în conformitate cu cerinţele fiscale într-un mod rapid şi eficient.

„Aşa cum am mai spus, fiecare îmbunătăţire adoptată a ţinut cont de nevoile semnalate de contribuabili. Am tot avut întâlniri cu reprezentaţii mediului de afaceri şi una dintre solicitările lor a fost aceasta. Versiunea simplificată a aplicaţiei e-Factura vine cu o serie de avantaje şi funcţionalităţi care vor face gestionarea facturilor mai uşoară şi mai accesibilă pentru toţi utilizatorii. Ne-am gândit în primul rând la cei aproximativ 670.000 contribuabili mici care trebuie să utilizeze sistemul şi au nevoie de o aplicaţie gratuită, intuitivă şi uşor de folosit. De asemenea, aplicaţia extinsă este acum disponibilă şi în limba engleză, urmând ca în perioada următoare să fie tradusă şi cea simplificată”, a explicat ministrul Marcel Boloş.

Aplicaţia web de completare a facturii într-un format simplificat răspunde solicitărilor venite din partea micorintreprinderilor, ce nu utilizează în mod curent elemente operaţionale complexe.

A fost redesenată pentru a include automat ghidaje (i.e. codul tipului facturii este prestabilit la 380, codul monedei este exclusiv RON) şi bife pentru a afişa elementele de identificare obligatorii în funcţie de categoria de plătitor de TVA.

Au fost restrânse nomenclatoarele de TVA la cele utilizate frecvent pentru tranzacţii domestice şi incluse procentele de taxă sub format selectabil.

De asemenea, o nouă facilitate importantă adăugată sistemului este aplicaţia extinsă în limba engleză pentru contribuabilii nerezidenţi înregistraţi în scopuri de TVA ce au obligaţia de raportare a facturilor emise pentru livrări/prestări pe teritoriul României.

În situaţia în care sistemul naţional privind factura electronică RO e-Factura nu este funcţional timp de minimum 24 de ore, obligaţia de transmitere prevăzută la art.10 alin.(1) din Ordonanţa de urgenţă a Guvernului nr.120/2021 se suspendă până la repunerea în funcţiune a sistemului.

Termenul-limită pentru transmiterea facturilor emise, pentru livrările de bunuri şi prestările de servicii care au locul livrării sau prestării în România, în sistemul naţional privind factura electronică RO e-Factura este de 5 zile lucrătoare (n.r. de la 1 iulie sunt 5 zile calendaristice) de la data emiterii facturii, dar nu mai târziu de 5 zile lucrătoare de la data-limită prevăzută pentru emiterea facturii la art.319 alin.(16) din Codul fiscal.

În perioada 1 ianuarie - 31 martie 2024, nerespectarea termenului limită pentru transmiterea facturilor în sistemul naţional privind factura electronică RO e-Factura nu se sancţionează.

e-Factura va fi mai ușor de folosit, spune ANAF, care face o aplicație care se adresează afacerilor mici, cu puține facturi pe lună. Aplicația poate fi accesată de marți dimineață, 5 martie 2024.

„Cuprinde doar elementele informaționale de bază, face în mod automat și selecția tipului de factură. Pentru că se agresează atât categoriei, cât și celor neplătitori de TVA. Se aplică o bifă, practic este intuitiv aici, nu mai este lăsat la libera alegere”.

Aplicația simplificată e-Factura a fost creată pentru cele peste 400.000 de afaceri mici, care emit puține facturi pe lună și nu au nevoie de informații suplimentare, cum ar fi referințe de lot sau de comandă pentru produse. Doar elementele obligatorii. Astfel că nu va fi nevoie de un soft diferit de facturare, iar procesul va dura foarte puțin, spun reprezentanții ANAF.

Aplicația va fi disponibilă pe site-ul Ministerul de Finanțe și va avea un buton separat, dar rămâne și aplicația obișnuită e-Factura.

„Numărul lor este destul de consistent, mai ales al celor care încă nu înțeleg că trebuie să utilizeze e-Factura și din calculele noastre undeva între 150.000 și 200.000. Aceștia sunt primii care vor primit aceste note de conformare. În caz contrar, riscă amenzi”. Până pe 31 martie, cei care nu transmit facturi în noul sistem nu vor fi sancționați. Ministerul analizează acum posibilitatea ca acest termen de grație să se amâne până pe 1 iulie, însă nu a fost luată o decizie până acum.

-----

De la 1 ianuarie 2024 în relaţia business-to-business (B2B), până în prezent, aproximativ 40 milioane de facturi au fost înregistrate cu succes în sistemul e-Factura, în valoare totală de 397 miliarde de lei.

Un aspect important pe care l-au semnalat contribuabilii a fost imposibilitatea accesării sistemului în situaţiile în care au loc lucrări de mentenanţă la nivelul Spaţiului Privat Virtual (SPV). În acest sens, utilizarea e-Factura se poate face acum direct de pe site-ul ANAF. Trebuie însă ca utilizatorul să aibă cont în SPV, unde s-a înregistrat în baza certificatului digital.

Potrivit comunicatului de pe site-ul ministerului, în situaţia în care sistemul naţional privind factura electronică RO e-Factura nu este funcțional timp de minimum 24 de ore, obligația de transmitere prevăzută la art.10 alin.(1) din Ordonanţa de urgenţă a Guvernului nr.120/2021 se suspendă până la repunerea în funcţiune a sistemului.

Termenul-limită pentru transmiterea facturilor emise, pentru livrările de bunuri și prestările de servicii care au locul livrării sau prestării în România, în sistemul național privind factura electronică RO e-Factura este de 5 zile lucrătoare (n.r. de la 1 iulie sunt 5 zile calendaristice) de la data emiterii facturii, dar nu mai târziu de 5 zile lucrătoare de la data-limită prevăzută pentru emiterea facturii la art.319 alin.(16) din Codul fiscal.

În perioada 1 ianuarie - 31 martie 2024, nerespectarea termenului limită pentru transmiterea facturilor în sistemul național privind factura electronică RO e-Factura nu se sancționează.

-----

Ultima noutate în ce privește e-Factura este că în sfârșit se poate face automat conversia din XML în PDF, printr-o simplă apăsare de buton. Ministrul a insistat mult pentru asta. Până acum conversia se făcea manual, iar Finanțele au raportat și un milion de facturi pe zi. Sursele noastre din Ministerul Finanțelor spun că îmbunătățirile pentru această schimbare majoră de sistem de raportare a facturilor, care a luat pe toată lumea prin surprindere, se realizează constant.

Trecerea la sistemul unic de raportare a facturilor în mediu electronic la ANAF a întâmpinat o serie de probleme în aplicare, de la 1 ianuarie, când e-Factura a devenit obligatorie în relațiile comerciale dintre firme.

E-Factura se aplică încă din 2022 pe relația firme - guvern. Dacă firmele mari sau cele care au business cu statul erau obișnuite cu birocrația și au găsit soluții să folosească sistemul așa cum a fost făcut inițial, trecerea la acest sistem pentru toate firmele a arătat slăbiciuni ale acestuia.

A fost introdusă autofacturarea. Apoi, conform unui comunicat transmis de Ministerul Finanțelor, începând cu 16 ianuarie 2024, sistemul e-Factura nu va mai permite introducerea facturilor duplicat. Această măsură vine să crească acuratețea și integritatea datelor înregistrate în sistem.
După încărcarea facturii fără Spațiul Privat Virtual, s-a mai introdus filtrarea pe categorii. Furnizorii de servicii de contabilitate au cerut să poată filtra facturile în baza anumitor criterii specifice. Această facilitate a fost introdusă printr-o modificare la apelul de listă facturi disponibile de la serviciile web apelabile automat prin API.

În final, a fost introdusă conversia automată din XML în PDF

e-Factura

a devenit obligatorie de la 1 ianuarie 2024. Nedepunerea ei în sistemul ANAF nu produce încă efecte, dar ar putea fi sancționată cu amendă, de la 1 aprilie.  De la 1 iulie, toate facturile dintre firme se vor transmite explusiv prin acest sistem. În jur de 120.000 de firme au depus până acum e-Factura, dintr-un total de aproximativ 700.000.
 
20.03.2024 - Până în 31 mai, ca urmare a faptului că încă sunt 74.000 de plătitori de TVA care nu folosesc e-Factura. Vor primi notificări. Cu data de 1 iulie amenda este de 15% din valoarea facturii, a spus Marcel Boloș, ministrul Finanțelor. Perioada în care nu sunt aplicate sancțiuni pentru nerespectarea obligației de a transmite facturile emise și în sistemul e-Factură  va fi extinsă până la 31 mai, a spus ministrul Finanțelor, Marcel Boloș pentru profit.ro.Marcel Boloș, ministrul Finanțelor, lua deja în calcul o potențială amânare a termenului de la care încep să fie aplicate sancțiuni pentru neraportarea și în sistemul eFactura a facturilor emise, în termenul de 5 zile stabilit.

Ministerul Finanțelor analiza situația e-Factura și lua în calcul o potențială amânare a termenului de la care încep să fie aplicate sancțiuni pentru neraportarea și în sistemul eFactura a facturilor emise. Până acum, sancțiunile erau suspendate până la 1 aprilie.

În sistemul e-Factura sunt raportate în prezent aproximativ o treime din numărul total de facturi la care estimează autoritățile că trebuie să se ajungă, dacă raportează toți cei care au obligația.

Până în 31 mai, ca urmare a faptului că încă sunt 74.000 de plătitori de TVA care nu folosesc e-Factura. Vor primi notificări. Cu data de 1 iulie amenda este de 15% din valoarea facturii, a spus Marcel Boloș, ministrul Finanțelor. Perioada în care nu sunt aplicate sancțiuni pentru nerespectarea obligației de a transmite facturile emise și în sistemul e-Factură va fi extinsă până la 31 mai, a spus ministrul Finanțelor, Marcel Boloș pentru profit.ro. Marcel Boloș, ministrul Finanțelor, lua deja în calcul o potențială amânare a termenului de la care încep să fie aplicate sancțiuni pentru neraportarea și în sistemul eFactură a facturilor emise, în termenul de 5 zile stabilit. Ministerul Finanțelor analizea situația e-Factura și lua în calcul o potențială amânare a termenului de la care încep să fie aplicate sancțiuni pentru neraportarea și în sistemul eFactură a facturilor emise. Până acum, sancțiunile erau suspendate până la 1 aprilie. În sistemul e-Factura sunt raportate în prezent aproximativ o treime din numărul total de facturi la care estimează autoritățile că trebuie să se ajungă, dacă raportează toți cei care au obligația.

Citește mai mult la: https://www.digi24.ro/digieconomic/financiar/decizie-bolos-nu-se-mai-dau-amenzi-pentru-e-factura-de-la-1-aprilie-13691

Informaţiile publicate pe site-ul Digi Economic pot fi preluate, în conformitate cu legislația aplicabilă, doar în limita a 120 de caractere.

-----

 

Tuesday, November 14, 2023

Server Send Events Stream SSE + Javascript

from quart import abort, make_response, request, Quart

app = Quart(__name__)
@app.get("/sse")
async def sse():
    if "text/event-stream" not in request.accept_mimetypes:
        abort(400)
    response = await make_response(
        send_events(),
        {
            'Content-Type': 'text/event-stream',
            'Cache-Control': 'no-cache',
            'Transfer-Encoding': 'chunked',
        },
    )
    response.timeout = None  # Disable the timeout for this streaming response
    return response
 
<script>
        document.addEventListener('DOMContentLoaded', (event) => {
            const eventSource = new EventSource('/sse');
            eventSource.onmessage = function(event) {
                console.log('New message:', event.data);
                // You can update the DOM here
            };
            eventSource.onopen = function(event) {
                console.log('Connection to server opened.');
            };
            eventSource.onerror = function(event) {
                console.error('EventSource failed.');
            };
            // To close the connection when the window is closed
            window.onbeforeunload = () => {
                eventSource.close();
            };
        });
    </script>
 
With parameters:
from quart import Quart, request, abort, make_response
from dataclasses import dataclass

app = Quart(__name__)

@dataclass
class ServerSentEvent:
data: str
event: str | None = None
id: int | None = None
retry: int | None = None

def encode(self) -> bytes:
message = f"data: {self.data}"
if self.event is not None:
message = f"{message}\nevent: {self.event}"
if self.id is not None:
message = f"{message}\nid: {self.id}"
if self.retry is not None:
message = f"{message}\nretry: {self.retry}"
message = f"{message}\n\n"
return message.encode('utf-8')

@app.get("/chat-updates")
async def chat_updates():
if "text/event-stream" not in request.accept_mimetypes:
abort(400)

friends = request.args.get('friends', default='false') == 'true'
format = request.args.get('format', default='simple')

async def send_events():
while True:
# Your logic to get updates, possibly filtering based on the query parameters
data = ... # Replace with your data retrieval logic
event = ServerSentEvent(data)
yield event.encode()

response = await make_response(
send_events(),
{
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Transfer-Encoding': 'chunked',
},
)
response.timeout = None
return response

# Run the app
if __name__ == "__main__":
app.run()
Javascript:
<script>
const params = new URLSearchParams({
friends: 'true',
format: 'detailed'
});

const url = `https://my-server/chat-updates?${params}`;
const eventSource = new EventSource(url);

eventSource.onmessage = function(event) {
// Handle incoming messages
console.log(event.data);
};

eventSource.onerror = function(error) {
// Handle any errors that occur
console.error("EventSource failed:", error);
}; 
</script>
 
// server.js
const http = require('http');
const es = require('event-stream');
// Create a HTTP server
const server = http.createServer((req, res) => {
// Check if the request path is /stream
if (req.url === '/stream') {
// Set the response headers
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive'
});
// Create a counter variable
let counter = 0;
// Create an interval function that sends an event every second
const interval = setInterval(() => {
// Increment the counter
counter++;
// Create an event object with name, data, and id properties
const event = {
name: 'message',
data: `Hello, this is message number ${counter}`,
id: counter
};
// Convert the event object to a string
const eventString = `event: ${event.name}\ndata: ${event.data}\nid: ${event.id}\n\n`;
// Write the event string to the response stream
res.write(eventString);
// End the response stream after 10 events
if (counter === 10) {
clearInterval(interval);
res.end();
}
}, 1000);
} else {
// Handle other requests
res.writeHead(404);
res.end('Not found');
}
});
// Listen on port 3000
server.listen(3000, () => {
console.log('Server listening on port 3000');
});
 
// client.js
// Fetch the event stream from the server
fetch('/stream')
.then(response => {
// Get the readable stream from the response body
const stream = response.body;
// Get the reader from the stream
const reader = stream.getReader();
// Define a function to read each chunk
const readChunk = () => {
// Read a chunk from the reader
reader.read()
.then(({
value,
done
}
) =>
{
// Check if the stream is done
if (done) {
// Log a message
console.log('Stream finished');
// Return from the function
return;
}
// Convert the chunk value to a string
const chunkString = new TextDecoder().decode(value);
// Log the chunk string
console.log(chunkString);
// Read the next chunk
readChunk();
})
.catch(error => {
// Log the error
console.error(error);
});
};
// Start reading the first chunk
readChunk();
})
.catch(error => {
// Log the error
console.error(error);
});
  
 
from flask import Flask, Response, render_template
import itertools
import time

app = Flask(__name__)

@app.route('/')
def index():
return render_template('index.html')

@app.route('/connect')
def publish_hello():
def stream():
for idx in itertools.count():
msg = f"data: <p>This is {idx}.</p>\n\n"
yield msg
time.sleep(1)
return Response(stream(), mimetype="text/event-stream")

Htmx

<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/htmx.org@1.8.6"></script>
<script src="https://unpkg.com/htmx.org/dist/ext/sse.js"></script>
</head>
<body>
<div hx-ext="sse" sse-connect="/connect" sse-swap="message">
Contents of this box will be updated in real time with every SSE message received from the server.
</div>
</body>
</html>
 
In this example, the Flask app sends a message to the HTMX client every second. The message is wrapped in an HTML paragraph tag and sent as an SSE event. The HTMX client listens to the SSE endpoint and updates the contents of the HTML element with the sse-swap attribute with the message received from the server.
Streaming data from Flask to HTMX using Server-Side Events (SSE) | mathspp 
 // Client-side Javascript in the HTML 
var targetContainer = document.getElementById("this-div");
var eventSource = new EventSource("/stream");
eventSource.onmessage = function(e) {
targetContainer.innerHTML = e.data;
};

Generator + SSE: So why are Python generators good with SSE? It’s simply because they can keeping looping and yielding data and handing it to the client very seamlessly. Here is a simple Python implementation of SSE in Flask:

@route("/stream")
def stream():
def eventStream():
while True:
# Poll data from the database
# and see if there's a new message
if len(messages) > len(previous_messages):
yield "data:
{}\n\n".format(messages[len(messages)-1)])"

return Response(eventStream(), mimetype="text/event-stream")

This is a simple hypothetical event source that checks if there’s a new inbox message and yield the new message. For the browser to acknowledge a server-sent message, you’ll have to comply to this format:

"data: <any_data>\n\n"

You have the option to also send with the data the event and id.

"id: <any_id>\nevent: <any_message>\ndata: <any_data>\n\n"

Note that the fields do not have to be in any order as long as there is a newline (\n) for each field and two (\n\n) at the end of them. With additional event field, you can have more control how you push data to the browser.

// Client-side Javascript in the HTMLvar targetContainer = document.getElementById("this-div");
var eventSource = new EventSource("/stream");
eventSource.addEventListener = (<any_message>, function(e) {
targetContainer.innerHTML = e.data;

if (e.data > 20) {
targetContainer.style.color = "red";
}
};

This will basically render the DOM with the latest data on the specified event message and change the color to “red” when it exceeds 20.

https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#receiving_events_from_the_server

Warning: When not used over HTTP/2, SSE suffers from a limitation to the maximum number of open connections, which can be especially painful when opening multiple tabs, as the limit is per browser and is set to a very low number (6).
The issue has been marked as "Won't fix" in Chrome and Firefox.
This limit is per browser + domain, which means that you can open 6 SSE connections
across all of the tabs to www.example1.com and another 6 SSE connections to www.example2.com (per Stackoverflow). When using HTTP/2, the maximum number of simultaneous HTTP streams is negotiated between the server and the client (defaults to 100). 

Fields
Each message received has some combination of the following fields, one per line:

event
    A string identifying the type of event described. If this is specified, an event will be dispatched on the browser to the listener for the specified event name; the website source code should use addEventListener() to listen for named events. The onmessage handler is called if no event name is specified for a message.

data
    The data field for the message. When the EventSource receives multiple consecutive lines that begin with data:, it concatenates them, inserting a newline character between each one. Trailing newlines are removed.

id
    The event ID to set the EventSource object's last event ID value.

retry
    The reconnection time. If the connection to the server is lost, the browser will wait for the specified time before attempting to reconnect. This must be an integer, specifying the reconnection time in milliseconds. If a non-integer value is specified, the field is ignored.

All other field names are ignored.

Sunday, November 5, 2023

Select and Delete Duplicates from Sqlite Table

Select duplicates from table PonsApimetaDE with columns DE, meta

SELECT DE, meta, COUNT(*)
FROM PonsApimetaDE
GROUP BY DE, meta
HAVING COUNT(*) > 1

Delete duplicates from table PonsApimetaDE with columns DE, meta

DELETE FROM PonsApimetaDE
WHERE rowid NOT IN (
  SELECT MIN(rowid)
  FROM PonsApimetaDE
  GROUP BY DE, meta
)

Delete duplicates from table

CREATE TABLE temp_table as SELECT DISTINCT * FROM source_table;
DELETE FROM source_table;
INSERT INTO source_table SELECT * FROM temp_table
DROP TABLE temp_table

Create index for table PonsApimetaDE with columns DE, meta

CREATE UNIQUE INDEX "idxuniquemetaDE" ON "PonsApimetaDE" (
  "DE"  ASC,
  "meta"  ASC
)

*****

SELECT * FROM table
WHERE rowid > (
  SELECT MIN(rowid) FROM table p2
  WHERE table.column1 = p2.column1
  AND table.column2 = p2.column2
);

DELETE FROM table
WHERE rowid > (
  SELECT MIN(rowid) FROM table p2
  WHERE table.column1 = p2.column1
  AND table.column2 = p2.column2
);

p2 is an alias for the table table in the subquery. This alias is used to make it easier to reference the table table in the subquery without having to type out the entire table name each time.

The purpose of this DELETE statement is to delete all rows from the table table where the column1 and column2 are the same as other rows, but only if the current row's rowid is greater than the smallest rowid with the same column1 and column2.

Here's a breakdown of the query:

The DELETE FROM table statement tells SQLite to delete all rows from the table table that meet the conditions specified in the WHERE clause.

The WHERE rowid > (subquery) clause restricts the rows to be deleted based on their rowid.

The subquery (SELECT MIN(rowid) FROM table p2 WHERE table.column1 = p2.column1 AND table.column2 = p2.column2) calculates the smallest rowid in the table table that has the same column1 and column2 as the current row.

The p2 alias in the subquery allows us to reference the table table without having to type out the entire table name each time.

In summary, this query will delete all duplicate rows from the table table, leaving only one row per unique combination of column1 and column2.

Saturday, November 4, 2023

Mongoose Custom Validator String or Number

const mongoose = require('mongoose');
const { Schema } = mongoose;

main().catch(err => console.log(err));

async function main() {
  await mongoose.connect('mongodb://127.0.0.1:27017/test');
  // use `await mongoose.connect('mongodb://user:password@127.0.0.1:27017/test');`
//   if your database has auth enabled
}
 
const stringornumbervalidator = function(value) {
  return typeof value === 'string' || typeof value === 'number';
};

const MySchema = new Schema({
  myField: {
    type: Schema.Types.Mixed,
    validate: {
      validator: stringornumbervalidator,
      message: 'Value should be either a string or a number'
    }
  }
});

const MyModel = mongoose.model('MyModel', MySchema);

Python Asynchronous Context Manager PlayGround

class AsyncContextManager:
    global correlationMap
    global requestId
    async def __aenter__(self) -> Literal['Waited']: # enter the async context manager
        print('>Entering the async context manager') # report a message
        await asyncio.sleep(0.05) # block for a moment
        return 'Waited'
    async def __aexit__(self, exc_type, exc, tb) -> Literal['Exited']: # exit the async context manager
        print('>Exiting the async context manager') # send a message
        await asyncio.sleep(0.05) # block for a moment
        return 'Exited'
    async def getresult(self):
        await asyncio.sleep(0.05)
        # print('Running inside the context manager')
        return correlationMap[requestId]
    async def dummyasync() -> Literal['Dummy function']:
        print(f"Dummy function started")
        await asyncio.sleep(0.1)
        return 'Dummy function' 
 
async with AsyncContextManager():
    app.add_background_task(callback)
    app.add_background_task(checkResult)
    while responsefirstcall.text == 'Waiting...':
        correlationMap[requestId] = await AsyncContextManager().getresult()
        print('correlationMap before loop: ' + str(correlationMap[requestId]))
            while correlationMap[requestId] == 'Waiting...':
                await asyncio.sleep(0.2)
                print('checkResult inside while loop: ' + str(response.text[:-1]))
                correlationMap[requestId] = await AsyncContextManager().getresult()
                print('Check result inside while loop: ' + str(correlationMap[requestId][:-1]) + ' ' + str(time.strftime("%A %d:%m:%Y %H:%M:%S UTC%z", time.localtime())))
try:
                            # response: httpx.Response = await client.get(f'http://{externalip}:5000/checkResult')
                            if correlationMap[requestId] != 'Waiting...':
                            # if response.text != 'Waiting...': # print('Not Waiting...')
                                # etransdomain = scripts.etrans.etrans(sourcelang, [targetlang], 'SPD', searchformterm).domain
                                # rows.append('E-Translate domain: ' + etransdomain)
                                rows.append('E-Translate')
                                rows.append(correlationMap[requestId].replace('\n', ''))
                                # rows.append(response.text.replace('\n', ''))
                                print(rows)
                                break
                            # else:
                            #     continue
                        except Exception as exc:
                            print(exc)
                            await asyncio.sleep(0.1)
                            rows.append('E-Translate')
                            rows.append('Error')
                            break
 
if rows: print("list is not empty")

Future

Future is simply an abstraction of value that may be not computed yet and will be available eventually. It's a simple container that only does one thing - whenever the value is set, fire all registered callbacks.

If you want to obtain that value, you register a callback via add_done_callback() method.

But unlike in Promise, the actual computation is done externally - and that external code has to call set_result() method to resolve the future.

Coroutine

Coroutine is the object very similar to Generator.

A generator is typically iterated within for loop. It yields values and, starting from PEP342 acceptance, it receives values.

A coroutine is typically iterated within the event loop in depths of asyncio library. A coroutine yields Future instances. When you are iterating over a coroutine and it yields a future, you shall wait until this future is resolved. After that you shall send the value of future into the coroutine, then you receive another future, and so on.

An await expression is practically identical to yield from expression, so by awaiting other coroutine, you stop until that coroutine has all its futures resolved, and get coroutine's return value. The Future is one-tick iterable and its iterator returns actual Future - that roughly means that await future equals yield from future equals yield future.

Task

Task is Future which has been actually started to compute and is attached to event loop. So it's special kind of Future (class Task is derived from class Future), which is associated with some event loop, and it has some coroutine, which serves as Task executor.

Task is usually created by event loop object: you give a coroutine to the loop, it creates Task object and starts to iterate over that coroutine in manner described above. Once the coroutine is finished, Task's Future is resolved by coroutine's return value.

You see, the task is quite similar to JS Promise - it encapsulates background job and its result.

Coroutine Function and Async Function

Coroutine func is a factory of coroutines, like generator function to generators. Notice the difference between Python's coroutine function and Javascript's async function - JS async function, when called, creates a Promise and its internal generator immediately starts being iterated, while Python's coroutine does nothing, until Task is created upon it.