Skip to content

Commit

Permalink
BACKPORT changes 1.6.0.b2:b3-->1.5.7.dev1 and sync betas:1.5.7.b3
Browse files Browse the repository at this point in the history
  • Loading branch information
ankostis committed May 14, 2017
2 parents 29f951d + e32645a commit 5af37da
Show file tree
Hide file tree
Showing 7 changed files with 142 additions and 55 deletions.
7 changes: 7 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@ The Dice:
timestamping_addresses --> tstamper_address ## Not a list anymore!
TstampReceiver.subject --> TstampSpec.subject_prefix ## Also used by `recv` cmd.

- feat: renamed command: ``project tstamp -- > project tsend``.
Now there is symmetricity between ``co2dice tstamp`` and ``co2dice project``
cmds::
tstamp send <--> project tsend
tstamp recv <--> project recv
- feat: new commands:

- ``tstamp recv``: Fetch tstamps from IMAP server and derive *decisions*
Expand Down
12 changes: 6 additions & 6 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
|co2mpas|: Vehicle simulator predicting NEDC |CO2| emissions from WLTP
######################################################################

:release: 1.5.7.dev1
:date: 2017-05-13 01:55:07
:release: 1.5.7.b3
:date: 2017-05-14 08:16:03
:home: http://co2mpas.io/
:repository: https://github.com/JRCSTU/CO2MPAS-TA
:pypi-repo: https://pypi.org/project/co2mpas/
Expand Down Expand Up @@ -346,7 +346,7 @@ Alternatively, open the CONSOLE and type the following command:
## Check co2mpas version.
$ co2mpas -V
co2mpas-1.5.7.dev1
co2mpas-1.5.7.b3
|co2mpas| command syntax
Expand Down Expand Up @@ -1348,7 +1348,7 @@ Install |co2mpas| package
Downloading http://pypi.co2mpas.io/packages/co2mpas-...
...
Installing collected packages: co2mpas
Successfully installed co2mpas-1.5.7.dev1
Successfully installed co2mpas-1.5.7.b3
.. Warning::
**Installation failures:**
Expand All @@ -1368,8 +1368,8 @@ Install |co2mpas| package
.. code-block:: console
> co2mpas -vV
co2mpas_version: 1.5.7.dev1
co2mpas_rel_date: 2017-05-13 01:55:07
co2mpas_version: 1.5.7.b3
co2mpas_rel_date: 2017-05-14 08:16:03
co2mpas_path: d:\co2mpas_ALLINONE-64bit-v1.4.1\Apps\WinPython\python-3.4.3\lib\site-packages\co2mpas
python_path: D:\co2mpas_ALLINONE-64bit-v1.4.1\WinPython\python-3.4.3
python_version: 3.4.3 (v3.4.3:9b73f1c3e601, Feb 24 2015, 22:44:40) [MSC v.1600 XXX]
Expand Down
4 changes: 2 additions & 2 deletions co2mpas/_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@


#: Authoritative project's PEP 440 version.
__version__ = version = "1.5.7.dev1" # Also update README.rst, CHANGES.rst,
__version__ = version = "1.5.7.b3" # Also update README.rst, CHANGES.rst,

#: Input/Output file's version.
__file_version__ = "2.2.6"
Expand All @@ -21,4 +21,4 @@

# Please UPDATE TIMESTAMP WHEN BUMPING VERSIONS AND BEFORE RELEASE.
#: Release date.
__updated__ = "2017-05-13 01:55:07"
__updated__ = "2017-05-14 08:16:03"
64 changes: 40 additions & 24 deletions co2mpas/sampling/cfgcmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,26 @@
from .._vendor import traitlets as trt


def prepare_matcher(terms, is_regex):
import re

def matcher(r):
if is_regex:
return re.compile(r, re.I).search
else:
return lambda w: r.lower() in w.lower()

matchers = [matcher(t) for t in terms]

def match(word):
return any(m(word) for m in matchers)

return match


class ConfigCmd(baseapp.Cmd):
"""
Commands to manage configuration-options loaded from filesystem.
Commands to manage configuration-options loaded from filesystem, cmd-line or defaults.
Read also the help message for `--config-paths` generic option.
"""
Expand Down Expand Up @@ -222,23 +239,24 @@ class DescCmd(baseapp.Cmd):
Describe config-params with their name '<class>.<param>' containing search-strings (case-insensitive).
SYNTAX
%(cmd_chain)s [OPTIONS] [<search-term--1>] ...
%(cmd_chain)s [OPTIONS] <search-term--1> [<search-term--2> ...]
- Use --verbose to view config-params on all intermediate classes.
"""

examples = trt.Unicode("""
To list just what matched:
%(cmd_chain)s --list 'criteria'
%(cmd_chain)s -l --cls 'config'
%(cmd_chain)s -l --regex '^t.+cmd'
To view help on specific parameters:
%(cmd_chain)s wait
%(cmd_chain)s -e 'rec.+wait'
To view help on full classes:
%(cmd_chain)s -ecl 'rec.+wait'
""")

list = trt.Bool(
help="Just list any matches."
).tag(config=True)
Expand All @@ -254,8 +272,8 @@ class DescCmd(baseapp.Cmd):
def __init__(self, **kwds):
import pandalone.utils as pndlu

super().__init__(
cmd_flags={
kwds.setdefault(
'cmd_flags', {
('l', 'list'): (
{type(self).__name__: {'list': True}},
pndlu.first_line(type(self).list.help)
Expand All @@ -270,21 +288,14 @@ def __init__(self, **kwds):
),
}
)
super().__init__(**kwds)

def run(self, *args):
import re
from toolz import dicttoolz as dtz

def matcher(r):
if self.regex:
return re.compile(r, re.I).search
else:
return lambda w: r.lower() in w.lower()

matchers = [matcher(t) for t in args]

def is_matching(word):
return any(m(word) for m in matchers)
if len(args) == 0:
raise CmdException('Cmd %r takes at least one <search-term>!'
% self.name)

## Prefer to modify `class_names` after `initialize()`, or else,
# the cmd options would be irrelevant and fatty :-)
Expand All @@ -299,15 +310,20 @@ def printer(ne, cls):
return cls.class_get_help()

else:
search_map = {'%s.%s' % (cls.__name__, attr): (cls, trait)
for cls in all_classes
for attr, trait in cls.class_traits(config=True).items()}

search_map = {
'%s.%s' % (cls.__name__, attr): (cls, trait)
for cls in all_classes
for attr, trait in
(cls.class_traits
if self.verbose
else cls.class_own_traits)(config=True).items()}

def printer(name, v):
cls, attr = v
return cls.class_get_trait_help(attr)

res_map = dtz.keyfilter(is_matching, search_map)

match = prepare_matcher(args, self.regex)
res_map = dtz.keyfilter(match, search_map)

for name, v in sorted(res_map.items()):
if self.list:
Expand Down
29 changes: 21 additions & 8 deletions co2mpas/sampling/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -1570,11 +1570,11 @@ class OpenCmd(_SubCmd):
%(cmd_chain)s [OPTIONS] <project>
"""
def run(self, *args):
self.log.info('Opening project %r...', args)
if len(args) != 1:
raise CmdException(
"Cmd %r takes exactly one argument as the project-name, received %r!"
% (self.name, args))
self.log.info('Opening project %r...', args)

projDB = self.projects_db
proj = projDB.proj_open(args[0])
Expand Down Expand Up @@ -1738,7 +1738,9 @@ class ReportCmd(_SubCmd):
- Eventually the *Dice Report* parameters will be time-stamped and disseminated to
TA authorities & oversight bodies with an email, to receive back
the sampling decision.
- To get report ready for sending it MANUALLY, use tstamp` sub-command.
- To send the report to the stamper, use `tsend` sub-command.
- To get report ready for sending it MANUALLY, use `tsend --dry-run`
instead.
"""

Expand Down Expand Up @@ -1773,6 +1775,13 @@ def run(self, *args):


class TstampCmd(_SubCmd):
"""Deprecated: renamed as `tsend`!"""
def run(self, *args):
raise CmdException("Cmd %r has been renamed to %r!"
% (self.name, 'tsend'))


class TsendCmd(_SubCmd):
"""
IRREVOCABLY send report to the time-stamp service, or print it for sending it manually (--dry-run).
Expand Down Expand Up @@ -1947,6 +1956,7 @@ def __init__(self, **kwds):
def run(self, *args):
from . import tstamp

self.log.info("Receiving emails for projects(s) %s: ...", args)
default_flow_style = None if self.verbose else False
warn = self.log.warning
rcver = tstamp.TstampReceiver(config=self.config)
Expand Down Expand Up @@ -1977,17 +1987,17 @@ def run(self, *args):
mid, pname)
continue

## Respect verbose flag for print-outs.
infos = rcver._get_recved_email_infos(mail, verdict)
yield _mydump({mid: infos}, default_flow_style=default_flow_style)

try:
proj.do_storedice(verdict=verdict)
#report = proj.result # Not needed, we already have verdict.
except Exception as ex:
self.log.error('Failed storing %s email, due to: %s',
mid, ex)

## Respect verbose flag for print-outs.
infos2 = rcver._get_recved_email_infos(mail, verdict)
yield _mydump({mid: infos2}, default_flow_style=default_flow_style)


class ExportCmd(_SubCmd):
"""
Expand Down Expand Up @@ -2154,10 +2164,11 @@ class BackupCmd(_SubCmd):
).tag(config=True)

def run(self, *args):
self.log.info('Archiving repo into %r...', args)
if len(args) > 1:
raise CmdException('Cmd %r takes one optional filepath, received %d: %r!'
% (self.name, len(args), args))
self.log.info('Archiving repo into %r...', args)

archive_fpath = args and args[0] or None
kwds = {}
if archive_fpath:
Expand All @@ -2178,6 +2189,8 @@ def run(self, *args):

all_subcmds = (LsCmd, InitCmd, OpenCmd,
AppendCmd, ReportCmd,
TstampCmd, TrecvCmd, TparseCmd,
TstampCmd, ## TODO: delete deprecated `projext tsend` cmd
TsendCmd,
TrecvCmd, TparseCmd,
StatusCmd,
ExportCmd, ImportCmd, BackupCmd)
48 changes: 33 additions & 15 deletions co2mpas/sampling/tstamp.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,8 +181,8 @@ def _is_all_latin(self, proposal):
value = proposal.value
if any(ord(c) >= 128 for c in value):
myname = type(self).__name__
raise trt.TraitError('%s.%s must not contain non-ASCII chars!'
% (myname, proposal.trait.name))
raise trt.TraitError('%s.%s must not contain non-ASCII chars: %s'
% (myname, proposal.trait.name, value))
return value

@property
Expand Down Expand Up @@ -478,7 +478,7 @@ class TstampReceiver(TstampSpec):
).tag(config=True)

email_criteria = trt.List(
trt.Unicode(),
trt.Unicode(), allow_none=True,
default_value=[
'From "[email protected]"',
'Subject "Proof of Posting Certificate"',
Expand All @@ -500,7 +500,7 @@ class TstampReceiver(TstampSpec):
are both compulsory;
- see https://tools.ietf.org/html/rfc3501#page-49 for more.
- More criteria are appended on runtime, ie `TstampSpec.subject_prefix`,
`wait_criteria` if --wait, and any args to `recv` command as ORed
`wait_criterio` if --wait, and any args to `recv` command as ORed
and searched as subject terms (i.e. the (projects-ids").
- If you want to fetch tstamps sent to `tstamp_recipients`,
either leave this empty, or set it to email-address of the sender:
Expand All @@ -509,7 +509,7 @@ class TstampReceiver(TstampSpec):
"""
).tag(config=True)

wait_criteria = trt.Unicode(
wait_criterio = trt.Unicode(
'NEW', allow_none=True,
help="""The RFC3501 IMAP search criteria for when IDLE-waiting, usually RECENT+UNSEEN messages."""
).tag(config=True)
Expand Down Expand Up @@ -561,6 +561,11 @@ class TstampReceiver(TstampSpec):
"""
).tag(config=True)

@trt.validate('subject_prefix', 'wait_criterio', 'before_date', 'after_date')
def _strip_trait(self, p):
v = p.value
return v and v.strip()

def _capture_stamper_msg_and_id(self, ts_msg: Text, ts_heads: Text) -> int:
stamper_id = msg = None
m = _stamper_id_regex.search(ts_heads)
Expand Down Expand Up @@ -779,32 +784,44 @@ def list_mailbox(self, directory='""', pattern='*'):
return ["Found %i mailboxes:" % len(res)] + res

def _prepare_search_criteria(self, is_wait, projects):
criteria = list(self.email_criteria)
if self.subject_prefix:
criteria.append('Subject "%s"' % self.subject_prefix)
if is_wait:
criteria.append(self.wait_criteria)

subj = self.subject_prefix
before, after = [self.before_date, self.after_date]
waitcrt = self.wait_criterio

if not self.email_criteria:
criteria = []
else:
criteria = [c and c.strip() for c in self.email_criteria]
criteria = [c for c in criteria if c]

if subj:
criteria.append('SUBJECT "%s"' % subj)

if is_wait and waitcrt:
criteria.append(waitcrt)

if before or after:
import parsedatetime as pdt

c = self.dates_locale and pdt.Constants(self.dates_locale)
cal = pdt.Calendar(c)

if before:
if before and before.strip():
criteria.append('SENTBEFORE "%s"' %
parse_as_RFC3501_date(cal, before))
if after:
if after and after.strip():
criteria.append('SINCE "%s"' %
parse_as_RFC3501_date(cal, after))

projects = [c and c.strip() for c in projects]
projects = list(set(c for c in projects if c))
if projects:
criteria.append(pairwise_ORed(projects,
lambda i: '(SUBJECT "%s")' % i))

criteria = [c.strip() for c in criteria]
criteria = [c if c.startswith('(') else '(%s)' % c for c in criteria]
criteria = [c if c.startswith('(') else '(%s)' % c
for c in criteria]
criteria = ' '.join(criteria)

return criteria
Expand Down Expand Up @@ -1105,7 +1122,8 @@ class SendCmd(baseapp.Cmd):
SYNTAX
%(cmd_chain)s [OPTIONS] [<report-file-1> ...]
- Do not use this command directly (unless experimenting) - prefer the `project tstamp` sub-command.
- Do not use this command directly (unless experimenting) - prefer
the `project tsend` sub-command.
- If '-' is given or no files at all, it reads from STDIN.
- Many options related to sending & receiving the email are expected to be stored in the config-file.
- Use --verbose to print the timestamped email.
Expand Down
Loading

0 comments on commit 5af37da

Please sign in to comment.