alex-ber / alexberutils Goto Github PK
View Code? Open in Web Editor NEWAlexBerUtils is collection of the small utilities
License: BSD 2-Clause "Simplified" License
AlexBerUtils is collection of the small utilities
License: BSD 2-Clause "Simplified" License
from alexber.utils.parsers import safe_eval
safe_eval('%(message)s')
Expected: '%(message)s'.
I have my configuration file in conf directory.
I am expecting this code to work, but I'm getting HiYaPyCoInvocationException.
from argparse import ArgumentParser
import alexber.utils.init_app_conf as init_app_conf
argumentParser = ArgumentParser(conflict_handler='resolve')
argumentParser.add_argument("--general.config.file", nargs='?', dest='config_file', default='conf/config.yml',
const='conf/config.yml')
dd = init_app_conf.parse_config(argumentParser=argumentParser, args=args)
This is the output:
ERROR MainProcess [hiyapyco.__init__] file not found: config.yml (C:\dev\work\example\config.yml)
Traceback (most recent call last):
File "C:\dev\work\example\venv\lib\site-packages\hiyapyco\__init__.py", line 198, in __init__
with io.open(fn, 'r', encoding=self.encoding) as f:
FileNotFoundError: [Errno 2] No such file or directory: 'C:\\dev\\work\\example\\config.yml'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:\dev\work\example\runner.py", line 14, in run
_run(args=args)
File "C:\dev\work\example\app.py", line 44, in _run
dd = init_app_conf.parse_config(argumentParser=argumentParser, args=args)
File "C:\dev\work\example\venv\lib\site-packages\alexber\utils\init_app_conf.py", line 455, in parse_config
dd = parser.parse_config(argumentParser=argumentParser, args=args)
File "C:\dev\work\example\venv\lib\site-packages\alexber\utils\init_app_conf.py", line 260, in parse_config
sys_d, profiles, white_list, list_ensure, config_file = self._parse_sys_args(argumentParser=argumentParser,
File "C:\dev\work\example\venv\lib\site-packages\alexber\utils\init_app_conf.py", line 244, in _parse_sys_args
default_d = ymlparsers.load([str(full_path)])
File "C:\dev\work\example\venv\lib\site-packages\alexber\utils\ymlparsers.py", line 157, in load
hiyapyco = HiYaPyCo(*args, **kwargs)
File "C:\dev\work\example\venv\lib\site-packages\hiyapyco\__init__.py", line 210, in __init__
raise HiYaPyCoInvocationException(
hiyapyco.HiYaPyCoInvocationException: yaml file not found: 'config.yml'
Process finished with exit code 1
Bump versions of dependencies if needed.
Change setup.py.
As part of preparation of migrating to Python 3.8 I want to upgrade some dependencies.
Also pytest in use is old, so I will upgrade to the latest version.
Note, that all req-.txt remains unchanged. These files are used in setup.py.
requirements-.txt file are used to create reproducible environment, so if you are not using them directly their changes will not effect you.
I have found regression in email.message.EmailMessage. This changes how e-mail is looks like when generated using EmailMessage.
I’m creating it as following:
from email.message import EmailMessage as _EmailMessage
from email.policy import SMTPUTF8 as _SMTPUTF8
msg = _EmailMessage(policy=_SMTPUTF8)
msg['Subject'] = self.get_subject()
msg.set_content(body.getvalue(), subtype='html')
Note: bodyText has lines that are longer than 78 not counting the end of line character(s).
Quote: max_line_length
The maximum length of any line in the serialized output, not counting the end of line character(s). Default is 78, per RFC 5322. A value of 0 or None indicates that no line wrapping should be done at all.
https://docs.python.org/3/library/email.policy.html#module-email.policy
At Python 3.7 this code generate msg with header that has
('Content-Type', 'text/html; charset="utf-8"'), ('Content-Transfer-Encoding', '7bit')
At Python 3.8 this same code generate msg with header that has
('Content-Type', 'text/html; charset="utf-8"'), ('Content-Transfer-Encoding', 'quoted-printable')
This effectively breaks the line apart.
I’m fixing the code to:
from email.message import EmailMessage as _EmailMessage
from email.policy import SMTPUTF8 as _SMTPUTF8
msg = _EmailMessage(policy=_SMTPUTF8)
msg['Subject'] = self.get_subject()
msg.set_content(body.getvalue(), subtype='html', cte='8bit')
I’m using 8bit and not 7bit because I want to support Unicode character (in my example, there is no surrogate pair, so it was resolved to 7bit). See the code below, it will be more clear.
The cause of the change is in the file email.contentmanager
This is the Python 3.7 function:
def _encode_text(string, charset, cte, policy):
lines = string.encode(charset).splitlines()
linesep = policy.linesep.encode('ascii')
def embedded_body(lines): return linesep.join(lines) + linesep
def normal_body(lines): return b'\n'.join(lines) + b'\n'
if cte==None:
# Use heuristics to decide on the "best" encoding.
try:
return '7bit', normal_body(lines).decode('ascii')
except UnicodeDecodeError:
pass
if (policy.cte_type == '8bit' and
max(len(x) for x in lines) <= policy.max_line_length):
return '8bit', normal_body(lines).decode('ascii', 'surrogateescape')
sniff = embedded_body(lines[:10])
sniff_qp = quoprimime.body_encode(sniff.decode('latin-1'),
policy.max_line_length)
sniff_base64 = binascii.b2a_base64(sniff)
# This is a little unfair to qp; it includes lineseps, base64 doesn't.
if len(sniff_qp) > len(sniff_base64):
cte = 'base64'
else:
cte = 'quoted-printable'
if len(lines) <= 10:
return cte, sniff_qp
if cte == '7bit':
data = normal_body(lines).decode('ascii')
elif cte == '8bit':
data = normal_body(lines).decode('ascii', 'surrogateescape')
elif cte == 'quoted-printable':
data = quoprimime.body_encode(normal_body(lines).decode('latin-1'),
policy.max_line_length)
elif cte == 'base64':
data = _encode_base64(embedded_body(lines), policy.max_line_length)
else:
raise ValueError("Unknown content transfer encoding {}".format(cte))
return cte, data
Note the lines
if cte==None:
# Use heuristics to decide on the "best" encoding.
This is Python 3.8 function:
def _encode_text(string, charset, cte, policy):
lines = string.encode(charset).splitlines()
linesep = policy.linesep.encode('ascii')
def embedded_body(lines): return linesep.join(lines) + linesep
def normal_body(lines): return b'\n'.join(lines) + b'\n'
if cte==None:
# Use heuristics to decide on the "best" encoding.
if max((len(x) for x in lines), default=0) <= policy.max_line_length:
try:
return '7bit', normal_body(lines).decode('ascii')
except UnicodeDecodeError:
pass
if policy.cte_type == '8bit':
return '8bit', normal_body(lines).decode('ascii', 'surrogateescape')
sniff = embedded_body(lines[:10])
sniff_qp = quoprimime.body_encode(sniff.decode('latin-1'),
policy.max_line_length)
sniff_base64 = binascii.b2a_base64(sniff)
# This is a little unfair to qp; it includes lineseps, base64 doesn't.
if len(sniff_qp) > len(sniff_base64):
cte = 'base64'
else:
cte = 'quoted-printable'
if len(lines) <= 10:
return cte, sniff_qp
if cte == '7bit':
data = normal_body(lines).decode('ascii')
elif cte == '8bit':
data = normal_body(lines).decode('ascii', 'surrogateescape')
elif cte == 'quoted-printable':
data = quoprimime.body_encode(normal_body(lines).decode('latin-1'),
policy.max_line_length)
elif cte == 'base64':
data = _encode_base64(embedded_body(lines), policy.max_line_length)
else:
raise ValueError("Unknown content transfer encoding {}".format(cte))
return cte, data
note, the lines:
if cte==None:
# Use heuristics to decide on the "best" encoding.
if max((len(x) for x in lines), default=0) <= policy.max_line_length:
The line in bold was added in Python 3.8.
Because I do have long lines the try block that tries 7bit and 8bit is skipped in Python 3.8
And it is resolved as quoted-printable.
https://stackoverflow.com/questions/2699287/what-is-path-useful-for
https://docs.python.org/3/reference/import.html#package-path-rules
Changed in version 3.3: Parent packages are automatically imported.
https://docs.python.org/3/library/importlib.html#importlib.import_module
from importlib import import_module
from pkgutil import iter_modules
def walk_modules(path):
"""Loads a module and all its submodules from the given module path and
returns them. If *any* module throws an exception while importing, that
exception is thrown back.
"""
mods = []
mod = import_module(path)
mods.append(mod)
if hasattr(mod, '__path__'):
for _, subpath, ispkg in iter_modules(mod.__path__):
fullpath = path + '.' + subpath
if ispkg:
mods += walk_modules(fullpath)
else:
submod = import_module(fullpath)
mods.append(submod)
return mods
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.