Browse Source

Use dataclass and Path, add lint and unit tests

master
Jakub Valenta 1 year ago
parent
commit
7f69598c75
  1. 7
      .gitignore
  2. 37
      Makefile
  3. 15
      Pipfile
  4. 197
      Pipfile.lock
  5. 44
      README.md
  6. 9
      setup.cfg
  7. 15
      setup.py
  8. 0
      tomboy_to_orgmode/tests/__init__.py
  9. 18
      tomboy_to_orgmode/tests/test_data/61a04ed8-9192-462e-9e79-fa361ca460da.note
  10. 7
      tomboy_to_orgmode/tests/test_data/c46ab1bb-3248-47d8-a955-03983cfb6fb8.note
  11. 16
      tomboy_to_orgmode/tests/test_data/f1bd2fec-aa44-447c-85cc-24661a39e71f.note
  12. 14
      tomboy_to_orgmode/tests/test_data/foo/dc74b051-e719-49fa-b742-bcad2d89bdb3.note
  13. 45
      tomboy_to_orgmode/tests/test_tomboy_to_orgmode.py
  14. 67
      tomboy_to_orgmode/tomboy_to_orgmode.py
  15. 15
      tox.ini

7
.gitignore

@ -1,6 +1,9 @@
*.DS_Store
*.egg-info
*.pyc
.mypy_cache
.pytest_cache
.tox
__pycache__
build
dist
*.DS_Store
*.egg-info

37
Makefile

@ -0,0 +1,37 @@
_python_pkg = tomboy_to_orgmode
_executable = tomboy-to-orgmode
.PHONY: run
run: ## Run Tomboy to Org-mode
"./$(_executable)"
.PHONY: setup
setup: ## Create Pipenv virtual environment and install dependencies.
pipenv --three --site-packages
pipenv install
.PHONY: setup-dev
setup-dev: ## Install development dependencies
pipenv install --dev
.PHONY: test
test: ## Run unit tests
pipenv run python -m unittest
.PHONY: lint
lint: ## Run linting
pipenv run flake8 $(_python_pkg)
pipenv run mypy $(_python_pkg) --ignore-missing-imports
pipenv run isort -c $(_python_pkg)
.PHONY: tox
tox: ## Test with tox
tox -r
.PHONY: reformat
reformat: ## Reformat Python code using Black
black -l 79 --skip-string-normalization $(_python_pkg)
.PHONY: help
help:
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-16s\033[0m %s\n", $$1, $$2}'

15
Pipfile

@ -0,0 +1,15 @@
[[source]]
name = "pypi"
url = "https://pypi.org/simple"
verify_ssl = true
[dev-packages]
"flake8" = "*"
isort = "*"
mypy = "*"
types-pytz = "*"
[packages]
beautifulsoup4 = "*"
lxml = "*"
pytz = "*"

197
Pipfile.lock

@ -0,0 +1,197 @@
{
"_meta": {
"hash": {
"sha256": "2663b66a77e50ca94001a6a7e2ae54d6a4f3b3c85b8f44e44f8680d7d93985b3"
},
"pipfile-spec": 6,
"requires": {},
"sources": [
{
"name": "pypi",
"url": "https://pypi.org/simple",
"verify_ssl": true
}
]
},
"default": {
"beautifulsoup4": {
"hashes": [
"sha256:9a315ce70049920ea4572a4055bc4bd700c940521d36fc858205ad4fcde149bf",
"sha256:c23ad23c521d818955a4151a67d81580319d4bf548d3d49f4223ae041ff98891"
],
"index": "pypi",
"version": "==4.10.0"
},
"lxml": {
"hashes": [
"sha256:079f3ae844f38982d156efce585bc540c16a926d4436712cf4baee0cce487a3d",
"sha256:0fbcf5565ac01dff87cbfc0ff323515c823081c5777a9fc7703ff58388c258c3",
"sha256:122fba10466c7bd4178b07dba427aa516286b846b2cbd6f6169141917283aae2",
"sha256:1b38116b6e628118dea5b2186ee6820ab138dbb1e24a13e478490c7db2f326ae",
"sha256:1b7584d421d254ab86d4f0b13ec662a9014397678a7c4265a02a6d7c2b18a75f",
"sha256:26e761ab5b07adf5f555ee82fb4bfc35bf93750499c6c7614bd64d12aaa67927",
"sha256:289e9ca1a9287f08daaf796d96e06cb2bc2958891d7911ac7cae1c5f9e1e0ee3",
"sha256:2a9d50e69aac3ebee695424f7dbd7b8c6d6eb7de2a2eb6b0f6c7db6aa41e02b7",
"sha256:3082c518be8e97324390614dacd041bb1358c882d77108ca1957ba47738d9d59",
"sha256:33bb934a044cf32157c12bfcfbb6649807da20aa92c062ef51903415c704704f",
"sha256:3439c71103ef0e904ea0a1901611863e51f50b5cd5e8654a151740fde5e1cade",
"sha256:36108c73739985979bf302006527cf8a20515ce444ba916281d1c43938b8bb96",
"sha256:39b78571b3b30645ac77b95f7c69d1bffc4cf8c3b157c435a34da72e78c82468",
"sha256:4289728b5e2000a4ad4ab8da6e1db2e093c63c08bdc0414799ee776a3f78da4b",
"sha256:4bff24dfeea62f2e56f5bab929b4428ae6caba2d1eea0c2d6eb618e30a71e6d4",
"sha256:4c61b3a0db43a1607d6264166b230438f85bfed02e8cff20c22e564d0faff354",
"sha256:542d454665a3e277f76954418124d67516c5f88e51a900365ed54a9806122b83",
"sha256:5a0a14e264069c03e46f926be0d8919f4105c1623d620e7ec0e612a2e9bf1c04",
"sha256:5c8c163396cc0df3fd151b927e74f6e4acd67160d6c33304e805b84293351d16",
"sha256:64812391546a18896adaa86c77c59a4998f33c24788cadc35789e55b727a37f4",
"sha256:66e575c62792c3f9ca47cb8b6fab9e35bab91360c783d1606f758761810c9791",
"sha256:6f12e1427285008fd32a6025e38e977d44d6382cf28e7201ed10d6c1698d2a9a",
"sha256:74f7d8d439b18fa4c385f3f5dfd11144bb87c1da034a466c5b5577d23a1d9b51",
"sha256:7610b8c31688f0b1be0ef882889817939490a36d0ee880ea562a4e1399c447a1",
"sha256:76fa7b1362d19f8fbd3e75fe2fb7c79359b0af8747e6f7141c338f0bee2f871a",
"sha256:7728e05c35412ba36d3e9795ae8995e3c86958179c9770e65558ec3fdfd3724f",
"sha256:8157dadbb09a34a6bd95a50690595e1fa0af1a99445e2744110e3dca7831c4ee",
"sha256:820628b7b3135403540202e60551e741f9b6d3304371712521be939470b454ec",
"sha256:884ab9b29feaca361f7f88d811b1eea9bfca36cf3da27768d28ad45c3ee6f969",
"sha256:89b8b22a5ff72d89d48d0e62abb14340d9e99fd637d046c27b8b257a01ffbe28",
"sha256:92e821e43ad382332eade6812e298dc9701c75fe289f2a2d39c7960b43d1e92a",
"sha256:b007cbb845b28db4fb8b6a5cdcbf65bacb16a8bd328b53cbc0698688a68e1caa",
"sha256:bc4313cbeb0e7a416a488d72f9680fffffc645f8a838bd2193809881c67dd106",
"sha256:bccbfc27563652de7dc9bdc595cb25e90b59c5f8e23e806ed0fd623755b6565d",
"sha256:c1a40c06fd5ba37ad39caa0b3144eb3772e813b5fb5b084198a985431c2f1e8d",
"sha256:c47ff7e0a36d4efac9fd692cfa33fbd0636674c102e9e8d9b26e1b93a94e7617",
"sha256:c4f05c5a7c49d2fb70223d0d5bcfbe474cf928310ac9fa6a7c6dddc831d0b1d4",
"sha256:cdaf11d2bd275bf391b5308f86731e5194a21af45fbaaaf1d9e8147b9160ea92",
"sha256:ce256aaa50f6cc9a649c51be3cd4ff142d67295bfc4f490c9134d0f9f6d58ef0",
"sha256:d2e35d7bf1c1ac8c538f88d26b396e73dd81440d59c1ef8522e1ea77b345ede4",
"sha256:d916d31fd85b2f78c76400d625076d9124de3e4bda8b016d25a050cc7d603f24",
"sha256:df7c53783a46febb0e70f6b05df2ba104610f2fb0d27023409734a3ecbb78fb2",
"sha256:e1cbd3f19a61e27e011e02f9600837b921ac661f0c40560eefb366e4e4fb275e",
"sha256:efac139c3f0bf4f0939f9375af4b02c5ad83a622de52d6dfa8e438e8e01d0eb0",
"sha256:efd7a09678fd8b53117f6bae4fa3825e0a22b03ef0a932e070c0bdbb3a35e654",
"sha256:f2380a6376dfa090227b663f9678150ef27543483055cc327555fb592c5967e2",
"sha256:f8380c03e45cf09f8557bdaa41e1fa7c81f3ae22828e1db470ab2a6c96d8bc23",
"sha256:f90ba11136bfdd25cae3951af8da2e95121c9b9b93727b1b896e3fa105b2f586"
],
"index": "pypi",
"version": "==4.6.3"
},
"pytz": {
"hashes": [
"sha256:83a4a90894bf38e243cf052c8b58f381bfe9a7a483f6a9cab140bc7f702ac4da",
"sha256:eb10ce3e7736052ed3623d49975ce333bcd712c7bb19a58b9e2089d4057d0798"
],
"index": "pypi",
"version": "==2021.1"
},
"soupsieve": {
"hashes": [
"sha256:052774848f448cf19c7e959adf5566904d525f33a3f8b6ba6f6f8f26ec7de0cc",
"sha256:c2c1c2d44f158cdbddab7824a9af8c4f83c76b1e23e049479aa432feb6c4c23b"
],
"markers": "python_version >= '3.6'",
"version": "==2.2.1"
}
},
"develop": {
"flake8": {
"hashes": [
"sha256:07528381786f2a6237b061f6e96610a4167b226cb926e2aa2b6b1d78057c576b",
"sha256:bf8fd333346d844f616e8d47905ef3a3384edae6b4e9beb0c5101e25e3110907"
],
"index": "pypi",
"version": "==3.9.2"
},
"isort": {
"hashes": [
"sha256:9c2ea1e62d871267b78307fe511c0838ba0da28698c5732d54e2790bf3ba9899",
"sha256:e17d6e2b81095c9db0a03a8025a957f334d6ea30b26f9ec70805411e5c7c81f2"
],
"index": "pypi",
"version": "==5.9.3"
},
"mccabe": {
"hashes": [
"sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42",
"sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"
],
"version": "==0.6.1"
},
"mypy": {
"hashes": [
"sha256:088cd9c7904b4ad80bec811053272986611b84221835e079be5bcad029e79dd9",
"sha256:0aadfb2d3935988ec3815952e44058a3100499f5be5b28c34ac9d79f002a4a9a",
"sha256:119bed3832d961f3a880787bf621634ba042cb8dc850a7429f643508eeac97b9",
"sha256:1a85e280d4d217150ce8cb1a6dddffd14e753a4e0c3cf90baabb32cefa41b59e",
"sha256:3c4b8ca36877fc75339253721f69603a9c7fdb5d4d5a95a1a1b899d8b86a4de2",
"sha256:3e382b29f8e0ccf19a2df2b29a167591245df90c0b5a2542249873b5c1d78212",
"sha256:42c266ced41b65ed40a282c575705325fa7991af370036d3f134518336636f5b",
"sha256:53fd2eb27a8ee2892614370896956af2ff61254c275aaee4c230ae771cadd885",
"sha256:704098302473cb31a218f1775a873b376b30b4c18229421e9e9dc8916fd16150",
"sha256:7df1ead20c81371ccd6091fa3e2878559b5c4d4caadaf1a484cf88d93ca06703",
"sha256:866c41f28cee548475f146aa4d39a51cf3b6a84246969f3759cb3e9c742fc072",
"sha256:a155d80ea6cee511a3694b108c4494a39f42de11ee4e61e72bc424c490e46457",
"sha256:adaeee09bfde366d2c13fe6093a7df5df83c9a2ba98638c7d76b010694db760e",
"sha256:b6fb13123aeef4a3abbcfd7e71773ff3ff1526a7d3dc538f3929a49b42be03f0",
"sha256:b94e4b785e304a04ea0828759172a15add27088520dc7e49ceade7834275bedb",
"sha256:c0df2d30ed496a08de5daed2a9ea807d07c21ae0ab23acf541ab88c24b26ab97",
"sha256:c6c2602dffb74867498f86e6129fd52a2770c48b7cd3ece77ada4fa38f94eba8",
"sha256:ceb6e0a6e27fb364fb3853389607cf7eb3a126ad335790fa1e14ed02fba50811",
"sha256:d9dd839eb0dc1bbe866a288ba3c1afc33a202015d2ad83b31e875b5905a079b6",
"sha256:e4dab234478e3bd3ce83bac4193b2ecd9cf94e720ddd95ce69840273bf44f6de",
"sha256:ec4e0cd079db280b6bdabdc807047ff3e199f334050db5cbb91ba3e959a67504",
"sha256:ecd2c3fe726758037234c93df7e98deb257fd15c24c9180dacf1ef829da5f921",
"sha256:ef565033fa5a958e62796867b1df10c40263ea9ded87164d67572834e57a174d"
],
"index": "pypi",
"version": "==0.910"
},
"mypy-extensions": {
"hashes": [
"sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d",
"sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"
],
"version": "==0.4.3"
},
"pycodestyle": {
"hashes": [
"sha256:514f76d918fcc0b55c6680472f0a37970994e07bbb80725808c17089be302068",
"sha256:c389c1d06bf7904078ca03399a4816f974a1d590090fecea0c63ec26ebaf1cef"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==2.7.0"
},
"pyflakes": {
"hashes": [
"sha256:7893783d01b8a89811dd72d7dfd4d84ff098e5eed95cfa8905b22bbffe52efc3",
"sha256:f5bc8ecabc05bb9d291eb5203d6810b49040f6ff446a756326104746cc00c1db"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==2.3.1"
},
"toml": {
"hashes": [
"sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b",
"sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"
],
"markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==0.10.2"
},
"types-pytz": {
"hashes": [
"sha256:28fb1c0f77f59aebe9b792d073ebfbbbf7b329f9d4af6a6079713a618a1c0f31",
"sha256:448828a06f2aaa840e57364d866c661645a045e532f817e4f10c8c3ab2b66651"
],
"index": "pypi",
"version": "==2021.1.2"
},
"typing-extensions": {
"hashes": [
"sha256:49f75d16ff11f1cd258e1b988ccff82a3ca5570217d7ad8c5f48205dd99a677e",
"sha256:d8226d10bc02a29bcc81df19a26e56a9647f8b0a6d4a83924139f4a8b01f17b7",
"sha256:f1d25edafde516b146ecd0613dabcc61409817af4766fbbcfb8d1ad4ec441a34"
],
"version": "==3.10.0.2"
}
}
}

44
README.md

@ -1,17 +1,17 @@
# Tomboy to org-mode
# Tomboy to Org-mode
Convert Tomboy notes to an Emacs org-mode file.
Convert Tomboy notes to an Emacs Org-mode file.
## Installation
```
``` shell
$ pip install --user .
```
The main executable will then be available globally:
```
$ tomboy-to-orgmode -h
``` shell
$ tomboy-to-orgmode --help
```
## Usage
@ -23,16 +23,44 @@ The resulting org-mode file will be written to standard output.
Example:
```
``` shell
$ tomboy-to-orgmode ~/.local/share/tomboy > notes.org
```
You can try the script with the test data included in this repository:
``` shell
$ tomboy-to-orgmode tomboy_to_orgmode/tests/test_data
```
## Help
``` shell
$ tomboy-to-orgmode --help
```
$ tomboy-to-orgmode -h
## Development
### Installation
``` shell
make setup-dev
```
### Testing and linting
``` shell
make test
make lint
```
### Help
``` shell
make help
```
## Contributing
__Feel free to remix this piece of software.__ See [NOTICE](./NOTICE) and [LICENSE](./LICENSE) for license information.
__Feel free to remix this project__ under the terms of the [Apache License,
Version 2.0](http://www.apache.org/licenses/LICENSE-2.0).

9
setup.cfg

@ -0,0 +1,9 @@
[isort]
combine_as_imports = true
default_section = THIRDPARTY
include_trailing_comma = true
known_first_party = tomboy_to_orgmode
line_length = 79
multi_line_output = 5
atomic = true
skip = .tox

15
setup.py

@ -10,36 +10,29 @@ with open(path.join(here, 'README.md'), encoding='utf-8') as f:
setup(
name='tomboy-to-orgmode',
version='1.0.1',
description='Convert Tomboy notes to an Emacs org-mode file.',
long_description=long_description,
url='https://lab.saloun.cz/jakub/tomboy-to-orgmode',
author='Jakub Valenta',
author_email='jakub@jakubvalenta.cz',
license='Apache Software License',
classifiers=[
'Development Status :: 3 - Alpha',
'Intended Audience :: Developers',
'License :: OSI Approved :: Apache Software License',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
],
keywords='',
packages=find_packages(),
install_requires=[
'attrs',
'beautifulsoup4',
'lxml',
'pytz',
],
entry_points={
'console_scripts': [
'tomboy-to-orgmode=tomboy_to_orgmode.tomboy_to_orgmode:main',

0
tomboy_to_orgmode/tests/__init__.py

18
tomboy_to_orgmode/tests/test_data/61a04ed8-9192-462e-9e79-fa361ca460da.note

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<note version="0.3" xmlns:link="http://beatniksoftware.com/tomboy/link" xmlns:size="http://beatniksoftware.com/tomboy/size" xmlns="http://beatniksoftware.com/tomboy">
<title>Basic note</title>
<text xml:space="preserve"><note-content version="0.1">Foo
bar
baz</note-content></text>
<last-change-date>2018-04-22T17:38:05.0000000+00:00</last-change-date>
<last-metadata-change-date>2018-04-22T17:38:05.0000000+00:00</last-metadata-change-date>
<create-date>2000-01-01T00:00:00.0000000+01:00</create-date>
<cursor-position>0</cursor-position>
<width>0</width>
<height>0</height>
<x>-1</x>
<y>-1</y>
<open-on-startup>False</open-on-startup>
</note>

7
tomboy_to_orgmode/tests/test_data/c46ab1bb-3248-47d8-a955-03983cfb6fb8.note

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<note version="0.3" xmlns:link="http://beatniksoftware.com/tomboy/link" xmlns:size="http://beatniksoftware.com/tomboy/size" xmlns="http://beatniksoftware.com/tomboy">
<title>Note with missing date</title>
<text xml:space="preserve"><note-content version="0.1">Spam
</note-content></text>
</note>

16
tomboy_to_orgmode/tests/test_data/f1bd2fec-aa44-447c-85cc-24661a39e71f.note

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<note version="0.3" xmlns:link="http://beatniksoftware.com/tomboy/link" xmlns:size="http://beatniksoftware.com/tomboy/size" xmlns="http://beatniksoftware.com/tomboy">
<title>Note with first line of text same as title</title>
<text xml:space="preserve"><note-content version="0.1">Note with first line of text same as title
</note-content></text>
<last-change-date>2018-07-13T08:26:16.0000000+00:00</last-change-date>
<last-metadata-change-date>2018-07-13T08:26:16.0000000+00:00</last-metadata-change-date>
<create-date>2000-01-01T00:00:00.0000000+01:00</create-date>
<cursor-position>0</cursor-position>
<width>0</width>
<height>0</height>
<x>-1</x>
<y>-1</y>
<open-on-startup>False</open-on-startup>
</note>

14
tomboy_to_orgmode/tests/test_data/foo/dc74b051-e719-49fa-b742-bcad2d89bdb3.note

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<note version="0.3" xmlns:link="http://beatniksoftware.com/tomboy/link" xmlns:size="http://beatniksoftware.com/tomboy/size" xmlns="http://beatniksoftware.com/tomboy">
<title>Nested note with missing text</title>
<text xml:space="preserve"><note-content version="0.1"></note-content></text>
<last-change-date>2018-07-13T08:26:16.0000000+00:00</last-change-date>
<last-metadata-change-date>2018-07-13T08:26:16.0000000+00:00</last-metadata-change-date>
<create-date>2000-01-01T00:00:00.0000000+01:00</create-date>
<cursor-position>0</cursor-position>
<width>0</width>
<height>0</height>
<x>-1</x>
<y>-1</y>
<open-on-startup>False</open-on-startup>
</note>

45
tomboy_to_orgmode/tests/test_tomboy_to_orgmode.py

@ -0,0 +1,45 @@
from io import StringIO
from pathlib import Path
from unittest import TestCase
from tomboy_to_orgmode.tomboy_to_orgmode import tomboy_to_orgmode
class TestTomboyToOrgmode(TestCase):
def test_tomboy_to_orgmode(self):
path = Path(__file__).parent / 'test_data'
out = StringIO()
tomboy_to_orgmode(path, out)
out.seek(0)
self.assertEqual(
out.read(),
'''* Note with missing date
Spam
<2021-09-17 Fri>
* Nested note with missing text
<2018-07-13 Fri>
* Note with first line of text same as title
<2018-07-13 Fri>
* Basic note
Foo
bar
baz
<2018-04-22 Sun>
''',
)

67
tomboy_to_orgmode/tomboy_to_orgmode.py

@ -1,69 +1,62 @@
import argparse
import glob
import operator
import os.path
import re
import sys
import pytz
from dataclasses import dataclass
from datetime import datetime
from typing import Iterator
from pathlib import Path
from typing import IO, List
import attr
import pytz
from bs4 import BeautifulSoup
@attr.s
@dataclass
class Note:
title = attr.ib()
text = attr.ib()
timestamp = attr.ib()
title: str
text: str
timestamp: datetime
def find_notes_paths(dirpath: str) -> Iterator[str]:
globpattern = os.path.join(dirpath, '**/*.note')
yield from sorted(glob.glob(globpattern, recursive=True))
def find_notes_paths(path: Path) -> List[Path]:
return sorted(path.glob('**/*.note'))
def stub_timestamp():
patched = datetime.now().replace(tzinfo=pytz.UTC)
return datetime.strftime(patched, '%Y-%m-%dT%H:%M:%S%z')
def parse_timestamp(s: str) -> datetime:
simpler = re.sub(r'\.\d+(\S\d+)\:(\d+)$', '\\1\\2', s)
return datetime.strptime(simpler, '%Y-%m-%dT%H:%M:%S%z')
def parse_note(path: str) -> Note:
with open(path, 'rb') as f:
def parse_note(path: Path) -> Note:
with path.open('rb') as f:
doc = BeautifulSoup(f, 'xml')
raw_title = doc.find(name='title').text
raw_text = doc.find(name='text').text
raw_text_lines = raw_text.splitlines()
if raw_text_lines[0] == raw_title:
if raw_text_lines and raw_text_lines[0] == raw_title:
raw_text = '\n'.join(raw_text_lines[1:])
raw_timestamp = doc.find(name='last-change-date').text
lcd = doc.find(name='last-change-date')
raw_timestamp = lcd.text if lcd else stub_timestamp()
last_change_date = doc.find(name='last-change-date')
if last_change_date:
timestamp = parse_timestamp(last_change_date.text)
else:
timestamp = datetime.now().replace(tzinfo=pytz.UTC)
return Note(
title=raw_title.strip(),
text=raw_text.strip(),
timestamp=parse_timestamp(raw_timestamp)
timestamp=timestamp,
)
def format_orgmode_entry(note: Note) -> str:
content = '{text}\n\n<{timestamp}>'.format(
text=note.text,
timestamp=note.timestamp.strftime('%Y-%m-%d %a')
)
return '* {title}\n\n{content}\n'.format(
title=note.title,
content=content
)
timestamp_str = note.timestamp.strftime('%Y-%m-%d %a')
content = f'{note.text}\n\n<{timestamp_str}>'
return f'* {note.title}\n\n{content}\n'
def tomboy_to_orgmode(dirpath: str):
paths = list(find_notes_paths(dirpath))
def tomboy_to_orgmode(path: Path, out: IO = sys.stdout):
paths = find_notes_paths(path)
if not paths:
print('No .note files found in {}'.format(dirpath), file=sys.stderr)
print(f'No .note files found in {path}', file=sys.stderr)
sys.exit(1)
notes = (parse_note(x) for x in paths)
notes_from_newest = reversed(
@ -71,7 +64,7 @@ def tomboy_to_orgmode(dirpath: str):
)
orgmode_entries = (format_orgmode_entry(x) for x in notes_from_newest)
for orgmode_entry in orgmode_entries:
print(orgmode_entry)
print(orgmode_entry, file=out)
def main():
@ -79,10 +72,12 @@ def main():
description='Tomboy to org-mode: Convert tomboy notes to an .org file'
)
parser.add_argument(
dest='inputdir', help='path to the directory with the .note files')
dest='inputdir', help='path to the directory with the .note files'
)
args = parser.parse_args()
tomboy_to_orgmode(args.inputdir)
path = Path(args.inputdir)
tomboy_to_orgmode(path)
if __name__ == '__main__':

15
tox.ini

@ -0,0 +1,15 @@
[tox]
envlist = py39, lint
skip_missing_interpreters = True
[testenv]
commands = python -m unittest
[testenv:lint]
deps = flake8
mypy
isort
commands =
flake8 tomboy_to_orgmode
mypy tomboy_to_orgmode --ignore-missing-imports
isort -c tomboy_to_orgmode
Loading…
Cancel
Save