inetlab


Nameinetlab JSON
Version 0.1.5.7 PyPI version JSON
download
home_pagehttps://github.com/kign/pkg-inetlab
SummaryPython helper libraries for Web/GAE/Flask, HTML manipulation and command line tools
upload_time2022-06-24 03:23:24
maintainer
docs_urlNone
authorKonstantin Ignatiev
requires_python>=3.7
license
keywords
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # pkg-inetlab
Python helper libraries for Web/GAE/Flask, HTML manipulation and command line tools

This package combines many Python utilities I accumulated over the years and used in some of my projects. 
Some are outdated or serve some narrow purpose, other not quite complete. Use at your own risk!

Below if a brief description of the nodules included

* [pkg-inetlab](#pkg-inetlab)
   * [inetlab.auth](#inetlabauth)
   * [inetlab.sql](#inetlabsql)
   * [inetlab.gae](#inetlabgae)
   * [inetlab.gae](#inetlabgae-1)
   * [inetlab.cli](#inetlabcli)
      * [colorterm](#colorterm)
      * [genformatter](#genformatter)
      * [inputnums](#inputnums)
   * [inetlab.mail.xmail](#inetlabmailxmail)
   * [inetlab.html](#inetlabhtml)
      * [html2xml](#html2xml)
      * [htmlbuilder](#htmlbuilder)
      * [htmladdons](#htmladdons)
      * [inputlib](#inputlib)
      * [jsescape](#jsescape)

## inetlab.auth

Utilities to be used in a `flask` project to implement syndicated login (at this time, Microsoft and Google logins are supported).

There is a working usage example [available here](https://github.com/kign/url-shortener). Briefly, follow these steps:

1. Setup environment:

```python
from inetlab.auth import synauth, synlogin

synauth.setup_endpoints('home', 'user')
synlogin.setup_partners(google_client_id=os.getenv('GOOGLE_CLIENT_ID'),
                        microsoft_client_id=os.getenv('MS_CLIENT_ID'),
                        microsoft_client_secret=os.getenv('MS_CLIENT_SECRET'))

```

2. Create at least two main and three service URL endpoints

```
/home: <your home page>
/user: <landing page after authentication>
...............................
/auth: synauth.authoriz
/token: synauth.token
/logout: synauth.logout
```

3. On "log in" button click, redirect to a template ([like this](https://github.com/kign/url-shortener/blob/main/external/login.html)) with these parameters:

```python
from flask import session, url_for, render_template

state = str(uuid.uuid4())
sesson['state'] = state

render_template('home.html',
   ms_auth_url=synlogin.MSLogin.build_auth_url(
       authorized_url=url_for("authorized", _external=True),
       state=state),
   redirect_succ=url_for('home'),
   google_client_id=synlogin.GLogin.CLIENT_ID)
```

## inetlab.sql

This provides a wrapper to run MySQL queries via [SQLAlchemy](https://www.sqlalchemy.org/) interface.

```python
from inetlab.sql.sqldbconn import SQLDBConnector

db = SQLDBConnector(pool, engine_url, engine_url_dbg, echo=False)

db.execute("select col_a, col_b from mytable")

for col_a, col_b in conn:
    print(col_a, col_b)
```

Why wouldn't one use a python MySQL wrapper directly? Actually, SQLAlchemy is a recommended way to use Google's
[Cloud SQL](https://cloud.google.com/sql/docs), and it does seem to work best in my testing.

## inetlab.gae

This works with `inetlab.sql` to allocate connection in GAE + CloudSQL project.

```python
from inetlab.gae.gaedbconn import gae_engine_url
from inetlab.sql.sqldbconn import SQLDBConnector

# github.com/GoogleCloudPlatform/python-docs-samples/blob/master/cloud-sql/mysql/sqlalchemy/main.py
pool_config = {
    # [START cloud_sql_mysql_sqlalchemy_limit]
    # Pool size is the maximum number of permanent connections to keep.
    "pool_size": 5,
    # Temporarily exceeds the set pool_size if no connections are available.
    "max_overflow": 2,
    # The total number of concurrent connections for your application will be
    # a total of pool_size and max_overflow.
    # [END cloud_sql_mysql_sqlalchemy_limit]
    # [START cloud_sql_mysql_sqlalchemy_backoff]
    # SQLAlchemy automatically uses delays between failed connection attempts,
    # but provides no arguments for configuration.
    # [END cloud_sql_mysql_sqlalchemy_backoff]
    # [START cloud_sql_mysql_sqlalchemy_timeout]
    # 'pool_timeout' is the maximum number of seconds to wait when retrieving a
    # new connection from the pool. After the specified amount of time, an
    # exception will be thrown.
    "pool_timeout": 30,  # 30 seconds
    # [END cloud_sql_mysql_sqlalchemy_timeout]
    # [START cloud_sql_mysql_sqlalchemy_lifetime]
    # 'pool_recycle' is the maximum number of seconds a connection can persist.
    # Connections that live longer than the specified amount of time will be
    # reestablished
    "pool_recycle": 1800,  # 30 minutes
    # [END cloud_sql_mysql_sqlalchemy_lifetime]
}

engine_url, dbg_engine_url = gae_engine_url('my_database')
pool, sqla_session = SQLDBConnector.make_pool(engine_url, dbg_engine_url, True, **pool_config)

db = SQLDBConnector (pool)
db.set_dbg_connection_url(dbg_engine_url)

# if need to use SQLAlchemy...
myClass = sqla_session.query(MyClass).filter_by(id=id).one()

# if need to use MySQL directly...
db.execute("select col_a, col_b from mytable")
```

## inetlab.cli

Some utilities commonly used in command line Python scripts

### colorterm

This module provides (1) a convenient wrapper for `Terminal` class from [blessings](https://pypi.org/project/blessings/) module, 
and (2) a `blessings`-independent utility `add_coloring_to_emit_ansi` to use in conjunction with `logging`, like this:

```python
import logging
from inetlab.cli.colorterm import add_coloring_to_emit_ansi

logging.basicConfig(format="%(asctime)s.%(msecs)03d %(filename)s:%(lineno)d %(message)s",
                    level=logging.DEBUG, datefmt='%H:%M:%S')
logging.StreamHandler.emit = add_coloring_to_emit_ansi(logging.StreamHandler.emit)
```

### genformatter

Output tabular-formatted text, e.g.

```python
from inetlab.cli.genformatter import GenericFormatter
out = GenericFormatter("aligned,width=30")
out.writeheader(["x", "x^2", "x^3"])
for x in range(1,10) :
    out.writerow([x, x**2, x**3])
out.close ()
```

### inputnums

`input_numbers` allows one to make multiple selection from number of given choices, allowing for intervals (possible overlapping) 
and "except <...>" syntax.

```python
def input_numbers(prompt, n, flat: bool, extend=None) :
    """User can input any number or ranges between 1 and n, e.g.: 1,5,8-11

    It is also possible to use "except ..." syntax, e.g. "except 10, 15"

    Parameters:

        - flat (bool, default=False)   return flat list of numbers, not list of intervals

        - extend(array of strings, default=[])  provide additional list of valid entries, in addition to
            o numbers and intervalis
            o 'quit', 'all' or 'none' (case insensitive and could be shortened to 1-st letter)
    """
```

## inetlab.mail.xmail

General functionality for sending emails. Supports embedded images and sending via SMTP or GMail API.

```python
def send(subject, html, channel,
         send_from=None,
         send_to=None,
         send_cc=None,
         images=None,
         invoke_premailer=False,
         dry_run=None):
    """
    :param subject:     Email subject
    :param html:        Email content
    :param channel:     Email delivery channel, or save to file option (file=...)
    :param send_from:   Sender's email
    :param send_to:     Recipients' email(s). Could be array (see below) or string. If string, module pyparsing required
    :param send_cc:     CC email(s), comment above for send_to applies
    :param images:      List of embedded/attached images or other attached files
    :param invoke_premailer: apply Python module premailer tp HTML
    :param dry_run:     Dry run (nothing will be sent if True)
    :return: *Nothing*
    
    `images` could be either of :
       * List of files to attach (either images or not)
       * Dictionary ID => <binary content>; this could be embedded image if (A) <binary content> is in fact an image, 
             AND (B) `html` content has string "cid:{ID}" embedded somewhere
    """
```
Usage example:

```python
from inetlab.mail.xmail import send
import random

send(f"Testing email using inetlab.mail, random ID: {random.randrange(10 ** 6, 10 ** 7)}",
            f"""\
Hi!<br />
This is a test of <code>users.messages.send</code>.<br />
Below we embed image <b>{sample_file}</b>, check it out:<br />
<img src="cid:sample_file" /> <br />
Hope it worked!
""",
        '<username>:<password>>@smtp.some.server.com:465',
        send_from='my_email@example.com',
        send_to='John Doe <john.doe@example.org>',
        images={'sample_file': open(sample_file, 'rb').read()})
```

NOTES:

 * If you want to send emails from your GMail account, you have two options: (1) using SMTP which requires you to explicitly go to [this page](https://myaccount.google.com/lesssecureapps) allow access to "less secure" apps (and then it'll periodically revert to default, so once you see your SMTP authentication failing you'll need to do it again); or (2) use official GMail API, which requires you to register your "app" with Google's [GCloud](https://console.cloud.google.com/) and to authenticate your account in browser more or less every time you'll need to use it (thus preventing any background use).
 * You can specify addressees as an array `[(name1, address1),(name2, address2),...,(nameN, addressN)]` (any `name` could be `None`), or as comma-separated string `name1 <address1>, name2 <address2>,...` (name could have commans if quoted). If using later option, we'll use [pyparsing](https://pypi.org/project/pyparsing/) to parse.

## inetlab.html

Mostly outdated utilities for parsing and generating HTML. 

### html2xml

My preferred tool for parsing badly formatted HTML pages by translating them to proper XML fixing 
parsing issues as they occur. By no means universal or bullet-proof, but helps to quickly make a 
customized parser for a specific site.

### htmlbuilder

In the old days, used this handy library to easily generate HTML tags in Python code.
No longer useful.

### htmladdons

Similarly to `htmlbuilder`, generating more advanced HTML code. No longer useful.

### inputlib

Similarly to `htmlbuilder`, generating HTML forms. No longer useful.

### jsescape

Old utility for escaping strings in JavaScript code generated in Python. No longer useful.








            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/kign/pkg-inetlab",
    "name": "inetlab",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.7",
    "maintainer_email": "",
    "keywords": "",
    "author": "Konstantin Ignatiev",
    "author_email": "kostya@inet-lab.net",
    "download_url": "https://files.pythonhosted.org/packages/0c/d2/9288ba3b7c9e87c49ec259840963e8940216d6df10cab5ba1d70b1e6e9ea/inetlab-0.1.5.7.tar.gz",
    "platform": null,
    "description": "# pkg-inetlab\nPython helper libraries for Web/GAE/Flask, HTML manipulation and command line tools\n\nThis package combines many Python utilities I accumulated over the years and used in some of my projects. \nSome are outdated or serve some narrow purpose, other not quite complete. Use at your own risk!\n\nBelow if a brief description of the nodules included\n\n* [pkg-inetlab](#pkg-inetlab)\n   * [inetlab.auth](#inetlabauth)\n   * [inetlab.sql](#inetlabsql)\n   * [inetlab.gae](#inetlabgae)\n   * [inetlab.gae](#inetlabgae-1)\n   * [inetlab.cli](#inetlabcli)\n      * [colorterm](#colorterm)\n      * [genformatter](#genformatter)\n      * [inputnums](#inputnums)\n   * [inetlab.mail.xmail](#inetlabmailxmail)\n   * [inetlab.html](#inetlabhtml)\n      * [html2xml](#html2xml)\n      * [htmlbuilder](#htmlbuilder)\n      * [htmladdons](#htmladdons)\n      * [inputlib](#inputlib)\n      * [jsescape](#jsescape)\n\n## inetlab.auth\n\nUtilities to be used in a `flask` project to implement syndicated login (at this time, Microsoft and Google logins are supported).\n\nThere is a working usage example [available here](https://github.com/kign/url-shortener). Briefly, follow these steps:\n\n1. Setup environment:\n\n```python\nfrom inetlab.auth import synauth, synlogin\n\nsynauth.setup_endpoints('home', 'user')\nsynlogin.setup_partners(google_client_id=os.getenv('GOOGLE_CLIENT_ID'),\n                        microsoft_client_id=os.getenv('MS_CLIENT_ID'),\n                        microsoft_client_secret=os.getenv('MS_CLIENT_SECRET'))\n\n```\n\n2. Create at least two main and three service URL endpoints\n\n```\n/home: <your home page>\n/user: <landing page after authentication>\n...............................\n/auth: synauth.authoriz\n/token: synauth.token\n/logout: synauth.logout\n```\n\n3. On \"log in\" button click, redirect to a template ([like this](https://github.com/kign/url-shortener/blob/main/external/login.html)) with these parameters:\n\n```python\nfrom flask import session, url_for, render_template\n\nstate = str(uuid.uuid4())\nsesson['state'] = state\n\nrender_template('home.html',\n   ms_auth_url=synlogin.MSLogin.build_auth_url(\n       authorized_url=url_for(\"authorized\", _external=True),\n       state=state),\n   redirect_succ=url_for('home'),\n   google_client_id=synlogin.GLogin.CLIENT_ID)\n```\n\n## inetlab.sql\n\nThis provides a wrapper to run MySQL queries via [SQLAlchemy](https://www.sqlalchemy.org/) interface.\n\n```python\nfrom inetlab.sql.sqldbconn import SQLDBConnector\n\ndb = SQLDBConnector(pool, engine_url, engine_url_dbg, echo=False)\n\ndb.execute(\"select col_a, col_b from mytable\")\n\nfor col_a, col_b in conn:\n    print(col_a, col_b)\n```\n\nWhy wouldn't one use a python MySQL wrapper directly? Actually, SQLAlchemy is a recommended way to use Google's\n[Cloud SQL](https://cloud.google.com/sql/docs), and it does seem to work best in my testing.\n\n## inetlab.gae\n\nThis works with `inetlab.sql` to allocate connection in GAE + CloudSQL project.\n\n```python\nfrom inetlab.gae.gaedbconn import gae_engine_url\nfrom inetlab.sql.sqldbconn import SQLDBConnector\n\n# github.com/GoogleCloudPlatform/python-docs-samples/blob/master/cloud-sql/mysql/sqlalchemy/main.py\npool_config = {\n    # [START cloud_sql_mysql_sqlalchemy_limit]\n    # Pool size is the maximum number of permanent connections to keep.\n    \"pool_size\": 5,\n    # Temporarily exceeds the set pool_size if no connections are available.\n    \"max_overflow\": 2,\n    # The total number of concurrent connections for your application will be\n    # a total of pool_size and max_overflow.\n    # [END cloud_sql_mysql_sqlalchemy_limit]\n    # [START cloud_sql_mysql_sqlalchemy_backoff]\n    # SQLAlchemy automatically uses delays between failed connection attempts,\n    # but provides no arguments for configuration.\n    # [END cloud_sql_mysql_sqlalchemy_backoff]\n    # [START cloud_sql_mysql_sqlalchemy_timeout]\n    # 'pool_timeout' is the maximum number of seconds to wait when retrieving a\n    # new connection from the pool. After the specified amount of time, an\n    # exception will be thrown.\n    \"pool_timeout\": 30,  # 30 seconds\n    # [END cloud_sql_mysql_sqlalchemy_timeout]\n    # [START cloud_sql_mysql_sqlalchemy_lifetime]\n    # 'pool_recycle' is the maximum number of seconds a connection can persist.\n    # Connections that live longer than the specified amount of time will be\n    # reestablished\n    \"pool_recycle\": 1800,  # 30 minutes\n    # [END cloud_sql_mysql_sqlalchemy_lifetime]\n}\n\nengine_url, dbg_engine_url = gae_engine_url('my_database')\npool, sqla_session = SQLDBConnector.make_pool(engine_url, dbg_engine_url, True, **pool_config)\n\ndb = SQLDBConnector (pool)\ndb.set_dbg_connection_url(dbg_engine_url)\n\n# if need to use SQLAlchemy...\nmyClass = sqla_session.query(MyClass).filter_by(id=id).one()\n\n# if need to use MySQL directly...\ndb.execute(\"select col_a, col_b from mytable\")\n```\n\n## inetlab.cli\n\nSome utilities commonly used in command line Python scripts\n\n### colorterm\n\nThis module provides (1) a convenient wrapper for `Terminal` class from [blessings](https://pypi.org/project/blessings/) module, \nand (2) a `blessings`-independent utility `add_coloring_to_emit_ansi` to use in conjunction with `logging`, like this:\n\n```python\nimport logging\nfrom inetlab.cli.colorterm import add_coloring_to_emit_ansi\n\nlogging.basicConfig(format=\"%(asctime)s.%(msecs)03d %(filename)s:%(lineno)d %(message)s\",\n                    level=logging.DEBUG, datefmt='%H:%M:%S')\nlogging.StreamHandler.emit = add_coloring_to_emit_ansi(logging.StreamHandler.emit)\n```\n\n### genformatter\n\nOutput tabular-formatted text, e.g.\n\n```python\nfrom inetlab.cli.genformatter import GenericFormatter\nout = GenericFormatter(\"aligned,width=30\")\nout.writeheader([\"x\", \"x^2\", \"x^3\"])\nfor x in range(1,10) :\n    out.writerow([x, x**2, x**3])\nout.close ()\n```\n\n### inputnums\n\n`input_numbers` allows one to make multiple selection from number of given choices, allowing for intervals (possible overlapping) \nand \"except <...>\" syntax.\n\n```python\ndef input_numbers(prompt, n, flat: bool, extend=None) :\n    \"\"\"User can input any number or ranges between 1 and n, e.g.: 1,5,8-11\n\n    It is also possible to use \"except ...\" syntax, e.g. \"except 10, 15\"\n\n    Parameters:\n\n        - flat (bool, default=False)   return flat list of numbers, not list of intervals\n\n        - extend(array of strings, default=[])  provide additional list of valid entries, in addition to\n            o numbers and intervalis\n            o 'quit', 'all' or 'none' (case insensitive and could be shortened to 1-st letter)\n    \"\"\"\n```\n\n## inetlab.mail.xmail\n\nGeneral functionality for sending emails. Supports embedded images and sending via SMTP or GMail API.\n\n```python\ndef send(subject, html, channel,\n         send_from=None,\n         send_to=None,\n         send_cc=None,\n         images=None,\n         invoke_premailer=False,\n         dry_run=None):\n    \"\"\"\n    :param subject:     Email subject\n    :param html:        Email content\n    :param channel:     Email delivery channel, or save to file option (file=...)\n    :param send_from:   Sender's email\n    :param send_to:     Recipients' email(s). Could be array (see below) or string. If string, module pyparsing required\n    :param send_cc:     CC email(s), comment above for send_to applies\n    :param images:      List of embedded/attached images or other attached files\n    :param invoke_premailer: apply Python module premailer tp HTML\n    :param dry_run:     Dry run (nothing will be sent if True)\n    :return: *Nothing*\n    \n    `images` could be either of :\n       * List of files to attach (either images or not)\n       * Dictionary ID => <binary content>; this could be embedded image if (A) <binary content> is in fact an image, \n             AND (B) `html` content has string \"cid:{ID}\" embedded somewhere\n    \"\"\"\n```\nUsage example:\n\n```python\nfrom inetlab.mail.xmail import send\nimport random\n\nsend(f\"Testing email using inetlab.mail, random ID: {random.randrange(10 ** 6, 10 ** 7)}\",\n            f\"\"\"\\\nHi!<br />\nThis is a test of <code>users.messages.send</code>.<br />\nBelow we embed image <b>{sample_file}</b>, check it out:<br />\n<img src=\"cid:sample_file\" /> <br />\nHope it worked!\n\"\"\",\n        '<username>:<password>>@smtp.some.server.com:465',\n        send_from='my_email@example.com',\n        send_to='John Doe <john.doe@example.org>',\n        images={'sample_file': open(sample_file, 'rb').read()})\n```\n\nNOTES:\n\n * If you want to send emails from your GMail account, you have two options: (1) using SMTP which requires you to explicitly go to [this page](https://myaccount.google.com/lesssecureapps) allow access to \"less secure\" apps (and then it'll periodically revert to default, so once you see your SMTP authentication failing you'll need to do it again); or (2) use official GMail API, which requires you to register your \"app\" with Google's [GCloud](https://console.cloud.google.com/) and to authenticate your account in browser more or less every time you'll need to use it (thus preventing any background use).\n * You can specify addressees as an array `[(name1, address1),(name2, address2),...,(nameN, addressN)]` (any `name` could be `None`), or as comma-separated string `name1 <address1>, name2 <address2>,...` (name could have commans if quoted). If using later option, we'll use [pyparsing](https://pypi.org/project/pyparsing/) to parse.\n\n## inetlab.html\n\nMostly outdated utilities for parsing and generating HTML. \n\n### html2xml\n\nMy preferred tool for parsing badly formatted HTML pages by translating them to proper XML fixing \nparsing issues as they occur. By no means universal or bullet-proof, but helps to quickly make a \ncustomized parser for a specific site.\n\n### htmlbuilder\n\nIn the old days, used this handy library to easily generate HTML tags in Python code.\nNo longer useful.\n\n### htmladdons\n\nSimilarly to `htmlbuilder`, generating more advanced HTML code. No longer useful.\n\n### inputlib\n\nSimilarly to `htmlbuilder`, generating HTML forms. No longer useful.\n\n### jsescape\n\nOld utility for escaping strings in JavaScript code generated in Python. No longer useful.\n\n\n\n\n\n\n\n",
    "bugtrack_url": null,
    "license": "",
    "summary": "Python helper libraries for Web/GAE/Flask, HTML manipulation and command line tools",
    "version": "0.1.5.7",
    "split_keywords": [],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "md5": "a6d1b30ac4b05bd670cbdc4ad0d96392",
                "sha256": "28624b91dd0d82628273937ec4b394d47c0622dd4ea9032ec454b32339e5f715"
            },
            "downloads": -1,
            "filename": "inetlab-0.1.5.7-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "a6d1b30ac4b05bd670cbdc4ad0d96392",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.7",
            "size": 47918,
            "upload_time": "2022-06-24T03:23:23",
            "upload_time_iso_8601": "2022-06-24T03:23:23.193763Z",
            "url": "https://files.pythonhosted.org/packages/65/9f/e16271adcaaf9dc19a3409bbe26fe359dbafed1c28e8d53889fe8f1b73ae/inetlab-0.1.5.7-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "md5": "261839c58116b35b51366d9f266276f2",
                "sha256": "f9fac636d4a3f28d0c81ad006f28fac40594380522c5084ac62666a5df21507f"
            },
            "downloads": -1,
            "filename": "inetlab-0.1.5.7.tar.gz",
            "has_sig": false,
            "md5_digest": "261839c58116b35b51366d9f266276f2",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.7",
            "size": 46350,
            "upload_time": "2022-06-24T03:23:24",
            "upload_time_iso_8601": "2022-06-24T03:23:24.778195Z",
            "url": "https://files.pythonhosted.org/packages/0c/d2/9288ba3b7c9e87c49ec259840963e8940216d6df10cab5ba1d70b1e6e9ea/inetlab-0.1.5.7.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2022-06-24 03:23:24",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "github_user": "kign",
    "github_project": "pkg-inetlab",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "lcname": "inetlab"
}
        
Elapsed time: 0.52153s