From 882fb6f424ebdeb138fa4cb043eee8ebd35a5afe Mon Sep 17 00:00:00 2001 From: Dima Gerasimov Date: Sat, 8 Sep 2018 11:01:12 +0300 Subject: [PATCH 1/5] initial --- .gitignore | 178 ++++++++++++++++++++++++++++++++++++++++++++++ calls/__init__.py | 0 calls/__main__.py | 0 ci.sh | 10 +++ run | 6 ++ 5 files changed, 194 insertions(+) create mode 100644 .gitignore create mode 100644 calls/__init__.py create mode 100644 calls/__main__.py create mode 100755 ci.sh create mode 100755 run diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..236a11e --- /dev/null +++ b/.gitignore @@ -0,0 +1,178 @@ + +# Created by https://www.gitignore.io/api/python,emacs + +### Emacs ### +# -*- mode: gitignore; -*- +*~ +\#*\# +/.emacs.desktop +/.emacs.desktop.lock +*.elc +auto-save-list +tramp +.\#* + +# Org-mode +.org-id-locations +*_archive + +# flymake-mode +*_flymake.* + +# eshell files +/eshell/history +/eshell/lastdir + +# elpa packages +/elpa/ + +# reftex files +*.rel + +# AUCTeX auto folder +/auto/ + +# cask packages +.cask/ +dist/ + +# Flycheck +flycheck_*.el + +# server auth directory +/server/ + +# projectiles files +.projectile + +# directory configuration +.dir-locals.el + +### Python ### +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +### Python Patch ### +.venv/ + +### Python.VirtualEnv Stack ### +# Virtualenv +# http://iamzed.com/2009/05/07/a-primer-on-virtualenv/ +[Bb]in +[Ii]nclude +[Ll]ib +[Ll]ib64 +[Ll]ocal +[Ss]cripts +pyvenv.cfg +pip-selfcheck.json + + +# End of https://www.gitignore.io/api/python,emacs diff --git a/calls/__init__.py b/calls/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/calls/__main__.py b/calls/__main__.py new file mode 100644 index 0000000..e69de29 diff --git a/ci.sh b/ci.sh new file mode 100755 index 0000000..8309482 --- /dev/null +++ b/ci.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +cd "$(this_dir)" || exit + +. ~/bash_ci + +ci_run mypy calls +ci_run pylint -E calls + +ci_report_errors diff --git a/run b/run new file mode 100755 index 0000000..4f3de36 --- /dev/null +++ b/run @@ -0,0 +1,6 @@ +#!/bin/bash +set -eu + +cd "$(dirname "$0")" + +python3 -m calls From bea84cbd33d88b7aa35ded570e2b37432b2582c9 Mon Sep 17 00:00:00 2001 From: Dima Gerasimov Date: Sat, 8 Sep 2018 11:42:20 +0300 Subject: [PATCH 2/5] initial --- calls/__init__.py | 43 +++++++++++++++++++++++++++++++++++++++++++ calls/__main__.py | 4 ++++ 2 files changed, 47 insertions(+) diff --git a/calls/__init__.py b/calls/__init__.py index e69de29..cd0ea67 100644 --- a/calls/__init__.py +++ b/calls/__init__.py @@ -0,0 +1,43 @@ +BPATH = "/L/backups/SMSBackupRestore" +import re +import pytz +_RE = re.compile(r'calls-\d+.xml') + +from typing import Dict, List, NamedTuple, Iterator, Iterable +from datetime import datetime + +class Call(NamedTuple): + dt: datetime + duration_s: int + who: str + + @property + def summary(self) -> str: + return f"talked with {self.who} for {self.duration_s}" + + +def _extract_calls(fname: str) -> Iterator[Call]: + from lxml import etree # type: ignore + tr = etree.parse(fname) + for cxml in tr.findall('call'): + # TODO we've got local tz herer, not sure if useful.. + # ok, so readable date is local datetime, cahnging throughout the backup + dt = pytz.utc.localize(datetime.utcfromtimestamp(int(cxml.get('date')) / 1000)) + yield Call( + dt=dt, + duration_s=int(cxml.get('duration')), + who=cxml.get('contact_name') # TODO number if contact is unavail?? + # TODO type? must be missing/outgoing/incoming + ) + +def get_calls(): + import os + calls: Dict[datetime, Call] = {} + for n in sorted([x for x in os.listdir(BPATH) if _RE.match(x)]): + # for c in _extract_calls(os.path.join(BPATH, n)): + # cc = calls.get(c.dt, None) + # if cc is not None and cc != c: + # print(f"WARNING: {cc} vs {c}") + calls.update({c.dt: c for c in _extract_calls(os.path.join(BPATH, n))}) + # always replacing with latter is good, we get better contact names + return sorted(calls.values(), key=lambda c: c.dt) diff --git a/calls/__main__.py b/calls/__main__.py index e69de29..211cde4 100644 --- a/calls/__main__.py +++ b/calls/__main__.py @@ -0,0 +1,4 @@ +from calls import get_calls + +for c in get_calls(): + print(c) From 68401a530c6f00bbf2fddd48496bab9849561e3a Mon Sep 17 00:00:00 2001 From: Dima Gerasimov Date: Sat, 8 Sep 2018 11:49:26 +0300 Subject: [PATCH 3/5] seconds --- calls/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/calls/__init__.py b/calls/__init__.py index cd0ea67..a9cd217 100644 --- a/calls/__init__.py +++ b/calls/__init__.py @@ -13,7 +13,7 @@ class Call(NamedTuple): @property def summary(self) -> str: - return f"talked with {self.who} for {self.duration_s}" + return f"talked with {self.who} for {self.duration_s} secs" def _extract_calls(fname: str) -> Iterator[Call]: From 36fbb3aa691047a032c0bf8e3db0cc1df27cb9f5 Mon Sep 17 00:00:00 2001 From: Dima Gerasimov Date: Sat, 22 Sep 2018 09:27:24 +0100 Subject: [PATCH 4/5] fix path to calls --- calls/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/calls/__init__.py b/calls/__init__.py index a9cd217..d620b76 100644 --- a/calls/__init__.py +++ b/calls/__init__.py @@ -1,4 +1,4 @@ -BPATH = "/L/backups/SMSBackupRestore" +BPATH = "/L/backups/smscalls" import re import pytz _RE = re.compile(r'calls-\d+.xml') From 3b525b39aa14c815412618b9ffa44efcd7e89d59 Mon Sep 17 00:00:00 2001 From: Dima Gerasimov Date: Wed, 8 May 2019 20:42:14 +0100 Subject: [PATCH 5/5] simplify provider --- calls/__init__.py | 21 +++++++++++++-------- calls/__main__.py | 4 ---- ci.sh | 10 ---------- run | 6 ------ 4 files changed, 13 insertions(+), 28 deletions(-) delete mode 100644 calls/__main__.py delete mode 100755 ci.sh delete mode 100755 run diff --git a/calls/__init__.py b/calls/__init__.py index d620b76..587d71d 100644 --- a/calls/__init__.py +++ b/calls/__init__.py @@ -1,10 +1,13 @@ -BPATH = "/L/backups/smscalls" -import re -import pytz -_RE = re.compile(r'calls-\d+.xml') - +import os +from pathlib import Path from typing import Dict, List, NamedTuple, Iterator, Iterable from datetime import datetime +import pytz + +from lxml import etree # type: ignore + +BPATH = Path("/L/backups/smscalls") + class Call(NamedTuple): dt: datetime @@ -17,7 +20,6 @@ class Call(NamedTuple): def _extract_calls(fname: str) -> Iterator[Call]: - from lxml import etree # type: ignore tr = etree.parse(fname) for cxml in tr.findall('call'): # TODO we've got local tz herer, not sure if useful.. @@ -31,9 +33,8 @@ def _extract_calls(fname: str) -> Iterator[Call]: ) def get_calls(): - import os calls: Dict[datetime, Call] = {} - for n in sorted([x for x in os.listdir(BPATH) if _RE.match(x)]): + for n in sorted(BPATH.glob('calls-*.xml')): # for c in _extract_calls(os.path.join(BPATH, n)): # cc = calls.get(c.dt, None) # if cc is not None and cc != c: @@ -41,3 +42,7 @@ def get_calls(): calls.update({c.dt: c for c in _extract_calls(os.path.join(BPATH, n))}) # always replacing with latter is good, we get better contact names return sorted(calls.values(), key=lambda c: c.dt) + + +def test(): + assert len(get_calls()) > 10 diff --git a/calls/__main__.py b/calls/__main__.py deleted file mode 100644 index 211cde4..0000000 --- a/calls/__main__.py +++ /dev/null @@ -1,4 +0,0 @@ -from calls import get_calls - -for c in get_calls(): - print(c) diff --git a/ci.sh b/ci.sh deleted file mode 100755 index 8309482..0000000 --- a/ci.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash - -cd "$(this_dir)" || exit - -. ~/bash_ci - -ci_run mypy calls -ci_run pylint -E calls - -ci_report_errors diff --git a/run b/run deleted file mode 100755 index 4f3de36..0000000 --- a/run +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash -set -eu - -cd "$(dirname "$0")" - -python3 -m calls