├── .gitmodules ├── doc ├── phf.png ├── _static │ ├── .gitignore │ └── custom.css ├── _templates │ └── .gitignore ├── _build │ └── .gitignore ├── sphinx-apidoc-command.txt ├── devel-filter-example.rst ├── bibolamazi-user-manual.rst.not-used ├── modules.rst.not-used ├── bibolamazi.core.bibusercache.rst ├── bibolamazi.filters.util.rst ├── credits-contact.rst ├── bibolamazi.core.bibfilter.rst ├── filter-packages.rst ├── index.rst ├── bibolamazi.core.rst ├── create-filter-package.rst ├── download-and-install.rst └── using-bibolamazi-app.rst ├── bibolamazi ├── __init__.py ├── filters │ ├── util │ │ └── __init__.py │ ├── __init__.py │ ├── echo.py │ └── shorten_authors_etal.py ├── core │ ├── version.py │ └── __init__.py └── init.py ├── gui ├── bibolamazi_gui │ ├── __init__.py │ ├── qtauto │ │ ├── __init__.py │ │ ├── .gitattributes │ │ ├── .gitignore │ │ ├── ui_helpbrowser.py │ │ ├── ui_overlistbuttonwidget.py │ │ ├── ui_searchwidget.py │ │ ├── ui_filterpackagepatheditor.py │ │ ├── ui_githubauthenticationdialog.py │ │ ├── ui_sourcelisteditor.py │ │ ├── ui_favoritesoverbtns.py │ │ ├── ui_githubreposelector.py │ │ ├── ui_filterinstanceeditor.py │ │ └── ui_startupwidget.py │ ├── version.py │ ├── pic │ │ ├── ok.png │ │ ├── file.png │ │ ├── save.png │ │ ├── refresh.png │ │ ├── bibolamazi.png │ │ ├── bookmark.png │ │ ├── closehide.png │ │ ├── lstbtnadd.png │ │ ├── lstbtnedit.png │ │ ├── question.png │ │ ├── remoterepos.ai │ │ ├── rightarrow.png │ │ ├── settings.png │ │ ├── lstbtnremove.png │ │ ├── bibolamazi_icon.png │ │ ├── configlocalrepos.ai │ │ ├── generalsettings.ai │ │ ├── github_generate_new_personal_access_token.png │ │ ├── github_generate_new_personal_access_token.xcf │ │ ├── github_generate_new_personal_access_token_details.png │ │ ├── github_generate_new_personal_access_token_details.xcf │ │ ├── github_generate_new_personal_access_token_generatebtn.png │ │ ├── github_generate_new_personal_access_token_generatebtn.xcf │ │ ├── github_generate_new_personal_access_token_details-scaled.xcf │ │ ├── generalsettings.svg │ │ ├── configlocalrepos.svg │ │ └── remoterepos.svg │ ├── Makefile │ ├── bibolamazi_res.qrc │ ├── helpbrowser.ui │ ├── overlistbuttonwidget.ui │ ├── searchwidget.ui │ ├── filterpackagepatheditor.ui │ ├── sourcelisteditor.ui │ ├── githubauthenticationdialog.ui │ ├── filterpackagepatheditor.py │ ├── buttontabsmanager.py │ ├── filterinstanceeditor.ui │ ├── githubreposelector.ui │ ├── favoritesoverbtns.ui │ ├── uiutils.py │ ├── bibolamazi_gui.py │ ├── githubauthenticationdialog.py │ ├── bibconfigsynthigh.py │ └── githubreposelector.py ├── bibolamazi_icon.icns ├── bibolamazi_icon.ico ├── data │ ├── icons │ │ └── hicolor │ │ │ ├── 32x32 │ │ │ └── apps │ │ │ │ └── bibolamazigui.png │ │ │ ├── 48x48 │ │ │ └── apps │ │ │ │ └── bibolamazigui.png │ │ │ ├── 64x64 │ │ │ └── apps │ │ │ │ └── bibolamazigui.png │ │ │ └── 256x256 │ │ │ └── apps │ │ │ └── bibolamazigui.png │ └── bibolamazigui.desktop ├── MANIFEST.in ├── README.txt ├── bin │ └── bibolamazi_gui └── setup.py ├── test ├── full_cases │ ├── more_filters │ │ ├── __init__.py │ │ ├── add_book_entry.py │ │ └── add_constant_field.py │ ├── test7_jobname.aux │ ├── test7_jobname.tex │ ├── srcbib │ │ ├── fail02.bib │ │ ├── specialtests.bib │ │ ├── testremote.bib │ │ ├── fail01.bib │ │ └── fail03.bib │ ├── test5_job.tex │ ├── test6.bibolamazi.bib │ ├── test5_job.aux │ ├── test9.bibolamazi.bib │ └── test7.bibolamazi.bib ├── test_bibolamazi_bibfilters_factory.py ├── helper_mk_pyentry.py ├── showcache.py ├── test_filters_citeinspirehep.py ├── helpers.py ├── test_filters_nameinitials.py ├── test_filters_citedoi.py └── test_full_cases.py ├── phf.png ├── bibolamazi.pdf ├── bibolamazi.png ├── xtras ├── HelpButtonColors.ai ├── bibolamazi_icon.png └── bibolamazi_icon.xcf ├── MANIFEST.in ├── .gitignore ├── .travis.yml ├── bibolamazi_3rdparty.py ├── pip_requirements.txt ├── .github └── workflows │ └── build-binaries.yml ├── bin └── bibolamazi ├── README.md └── setup.py /.gitmodules: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /doc/phf.png: -------------------------------------------------------------------------------- 1 | ../phf.png -------------------------------------------------------------------------------- /bibolamazi/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /doc/_static/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /doc/_templates/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /gui/bibolamazi_gui/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /bibolamazi/filters/util/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /gui/bibolamazi_gui/qtauto/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /test/full_cases/more_filters/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /doc/_build/.gitignore: -------------------------------------------------------------------------------- 1 | html 2 | latex 3 | doctrees 4 | -------------------------------------------------------------------------------- /doc/sphinx-apidoc-command.txt: -------------------------------------------------------------------------------- 1 | sphinx-apidoc -o . ../core/ 2 | -------------------------------------------------------------------------------- /gui/bibolamazi_gui/qtauto/.gitattributes: -------------------------------------------------------------------------------- 1 | *_rc.py binary 2 | -------------------------------------------------------------------------------- /gui/bibolamazi_gui/qtauto/.gitignore: -------------------------------------------------------------------------------- 1 | #ui_*.py 2 | #*_rc.py 3 | -------------------------------------------------------------------------------- /gui/bibolamazi_gui/version.py: -------------------------------------------------------------------------------- 1 | ../../bibolamazi/core/version.py -------------------------------------------------------------------------------- /phf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phfaist/bibolamazi/HEAD/phf.png -------------------------------------------------------------------------------- /bibolamazi.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phfaist/bibolamazi/HEAD/bibolamazi.pdf -------------------------------------------------------------------------------- /bibolamazi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phfaist/bibolamazi/HEAD/bibolamazi.png -------------------------------------------------------------------------------- /gui/bibolamazi_icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phfaist/bibolamazi/HEAD/gui/bibolamazi_icon.icns -------------------------------------------------------------------------------- /gui/bibolamazi_icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phfaist/bibolamazi/HEAD/gui/bibolamazi_icon.ico -------------------------------------------------------------------------------- /xtras/HelpButtonColors.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phfaist/bibolamazi/HEAD/xtras/HelpButtonColors.ai -------------------------------------------------------------------------------- /xtras/bibolamazi_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phfaist/bibolamazi/HEAD/xtras/bibolamazi_icon.png -------------------------------------------------------------------------------- /xtras/bibolamazi_icon.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phfaist/bibolamazi/HEAD/xtras/bibolamazi_icon.xcf -------------------------------------------------------------------------------- /gui/bibolamazi_gui/pic/ok.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phfaist/bibolamazi/HEAD/gui/bibolamazi_gui/pic/ok.png -------------------------------------------------------------------------------- /gui/bibolamazi_gui/pic/file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phfaist/bibolamazi/HEAD/gui/bibolamazi_gui/pic/file.png -------------------------------------------------------------------------------- /gui/bibolamazi_gui/pic/save.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phfaist/bibolamazi/HEAD/gui/bibolamazi_gui/pic/save.png -------------------------------------------------------------------------------- /gui/bibolamazi_gui/pic/refresh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phfaist/bibolamazi/HEAD/gui/bibolamazi_gui/pic/refresh.png -------------------------------------------------------------------------------- /gui/bibolamazi_gui/pic/bibolamazi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phfaist/bibolamazi/HEAD/gui/bibolamazi_gui/pic/bibolamazi.png -------------------------------------------------------------------------------- /gui/bibolamazi_gui/pic/bookmark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phfaist/bibolamazi/HEAD/gui/bibolamazi_gui/pic/bookmark.png -------------------------------------------------------------------------------- /gui/bibolamazi_gui/pic/closehide.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phfaist/bibolamazi/HEAD/gui/bibolamazi_gui/pic/closehide.png -------------------------------------------------------------------------------- /gui/bibolamazi_gui/pic/lstbtnadd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phfaist/bibolamazi/HEAD/gui/bibolamazi_gui/pic/lstbtnadd.png -------------------------------------------------------------------------------- /gui/bibolamazi_gui/pic/lstbtnedit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phfaist/bibolamazi/HEAD/gui/bibolamazi_gui/pic/lstbtnedit.png -------------------------------------------------------------------------------- /gui/bibolamazi_gui/pic/question.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phfaist/bibolamazi/HEAD/gui/bibolamazi_gui/pic/question.png -------------------------------------------------------------------------------- /gui/bibolamazi_gui/pic/remoterepos.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phfaist/bibolamazi/HEAD/gui/bibolamazi_gui/pic/remoterepos.ai -------------------------------------------------------------------------------- /gui/bibolamazi_gui/pic/rightarrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phfaist/bibolamazi/HEAD/gui/bibolamazi_gui/pic/rightarrow.png -------------------------------------------------------------------------------- /gui/bibolamazi_gui/pic/settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phfaist/bibolamazi/HEAD/gui/bibolamazi_gui/pic/settings.png -------------------------------------------------------------------------------- /gui/bibolamazi_gui/pic/lstbtnremove.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phfaist/bibolamazi/HEAD/gui/bibolamazi_gui/pic/lstbtnremove.png -------------------------------------------------------------------------------- /test/full_cases/test7_jobname.aux: -------------------------------------------------------------------------------- 1 | \relax 2 | \citation{arXiv:1211.1037} 3 | \citation{arXiv:1406.3618v1} 4 | \citation{other} 5 | -------------------------------------------------------------------------------- /gui/bibolamazi_gui/pic/bibolamazi_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phfaist/bibolamazi/HEAD/gui/bibolamazi_gui/pic/bibolamazi_icon.png -------------------------------------------------------------------------------- /gui/bibolamazi_gui/pic/configlocalrepos.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phfaist/bibolamazi/HEAD/gui/bibolamazi_gui/pic/configlocalrepos.ai -------------------------------------------------------------------------------- /gui/bibolamazi_gui/pic/generalsettings.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phfaist/bibolamazi/HEAD/gui/bibolamazi_gui/pic/generalsettings.ai -------------------------------------------------------------------------------- /gui/data/icons/hicolor/32x32/apps/bibolamazigui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phfaist/bibolamazi/HEAD/gui/data/icons/hicolor/32x32/apps/bibolamazigui.png -------------------------------------------------------------------------------- /gui/data/icons/hicolor/48x48/apps/bibolamazigui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phfaist/bibolamazi/HEAD/gui/data/icons/hicolor/48x48/apps/bibolamazigui.png -------------------------------------------------------------------------------- /gui/data/icons/hicolor/64x64/apps/bibolamazigui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phfaist/bibolamazi/HEAD/gui/data/icons/hicolor/64x64/apps/bibolamazigui.png -------------------------------------------------------------------------------- /gui/data/icons/hicolor/256x256/apps/bibolamazigui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phfaist/bibolamazi/HEAD/gui/data/icons/hicolor/256x256/apps/bibolamazigui.png -------------------------------------------------------------------------------- /gui/bibolamazi_gui/pic/github_generate_new_personal_access_token.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phfaist/bibolamazi/HEAD/gui/bibolamazi_gui/pic/github_generate_new_personal_access_token.png -------------------------------------------------------------------------------- /gui/bibolamazi_gui/pic/github_generate_new_personal_access_token.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phfaist/bibolamazi/HEAD/gui/bibolamazi_gui/pic/github_generate_new_personal_access_token.xcf -------------------------------------------------------------------------------- /gui/bibolamazi_gui/pic/github_generate_new_personal_access_token_details.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phfaist/bibolamazi/HEAD/gui/bibolamazi_gui/pic/github_generate_new_personal_access_token_details.png -------------------------------------------------------------------------------- /gui/bibolamazi_gui/pic/github_generate_new_personal_access_token_details.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phfaist/bibolamazi/HEAD/gui/bibolamazi_gui/pic/github_generate_new_personal_access_token_details.xcf -------------------------------------------------------------------------------- /doc/devel-filter-example.rst: -------------------------------------------------------------------------------- 1 | 2 | 3 | .. _devel-filter-example: 4 | 5 | Example of a custom filter 6 | ========================== 7 | 8 | 9 | .. include:: develfilterexample.py 10 | :literal: 11 | 12 | -------------------------------------------------------------------------------- /gui/MANIFEST.in: -------------------------------------------------------------------------------- 1 | include README.txt 2 | recursive-include data * 3 | include bibolamazi_gui.spec 4 | include bibolamazi_gui.icns 5 | include bibolamazi_gui.ico 6 | include MANIFEST.in 7 | include bin/bibolamazi_gui 8 | -------------------------------------------------------------------------------- /gui/bibolamazi_gui/pic/github_generate_new_personal_access_token_generatebtn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phfaist/bibolamazi/HEAD/gui/bibolamazi_gui/pic/github_generate_new_personal_access_token_generatebtn.png -------------------------------------------------------------------------------- /gui/bibolamazi_gui/pic/github_generate_new_personal_access_token_generatebtn.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phfaist/bibolamazi/HEAD/gui/bibolamazi_gui/pic/github_generate_new_personal_access_token_generatebtn.xcf -------------------------------------------------------------------------------- /gui/bibolamazi_gui/pic/github_generate_new_personal_access_token_details-scaled.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phfaist/bibolamazi/HEAD/gui/bibolamazi_gui/pic/github_generate_new_personal_access_token_details-scaled.xcf -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include README.md 2 | include doc/*.rst 3 | include doc/*.py 4 | include doc/*.png 5 | include doc/Makefile 6 | include doc/make.bat 7 | include pip_requirements.txt 8 | recursive-include doc/_static * 9 | recursive-include doc/_templates * 10 | -------------------------------------------------------------------------------- /gui/data/bibolamazigui.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Type=Application 3 | Encoding=UTF-8 4 | Name=Bibolamazi 5 | Comment=Prepare consistent BibTeX files for your LaTeX documents 6 | Exec=bibolamazi_gui %F 7 | Icon=bibolamazigui.png 8 | Categories=Office;Science; 9 | -------------------------------------------------------------------------------- /doc/bibolamazi-user-manual.rst.not-used: -------------------------------------------------------------------------------- 1 | 2 | Bibolamazi User's Manual 3 | ======================== 4 | 5 | .. toctree:: 6 | :maxdepth: 4 7 | 8 | introduction-to-bibolamazi 9 | using-bibolamazi 10 | using-bibolamazi-cmdl 11 | devel-filter 12 | credits-contact 13 | -------------------------------------------------------------------------------- /doc/modules.rst.not-used: -------------------------------------------------------------------------------- 1 | 2 | Documentation of Python Modules 3 | =============================== 4 | 5 | .. toctree:: 6 | :maxdepth: 4 7 | 8 | Core Bibolamazi Module 9 | 10 | .. toctree:: 11 | :maxdepth: 4 12 | 13 | Filter Utilities Package 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.pyc 3 | *.pyo 4 | .bzr 5 | .bzrignore 6 | build 7 | dist 8 | gui/_tmp_genfiles 9 | gui/build 10 | gui/dist 11 | *.bibolamazicache 12 | *.egg-info 13 | .cache 14 | test/_tmpdir 15 | BUILD_PIP_UPLOAD.txt 16 | bibolamazi_dup_aliases.tex 17 | x*test.bibolamazi.bib 18 | -------------------------------------------------------------------------------- /test/full_cases/test7_jobname.tex: -------------------------------------------------------------------------------- 1 | \documentclass{article} 2 | 3 | 4 | \begin{document} 5 | 6 | \cite{arXiv:1211.1037} 7 | 8 | \cite{arXiv:1406.3618v1} 9 | 10 | \cite{other} 11 | 12 | 13 | \end{document} 14 | 15 | %%% Local Variables: 16 | %%% mode: latex 17 | %%% TeX-master: t 18 | %%% End: 19 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # 2 | # Travis CI config file 3 | # 4 | 5 | language: python 6 | 7 | env: 8 | global: 9 | - BIBOLAMAZI_TESTS_SKIP_GITHUB_ACCESS=1 10 | 11 | python: 12 | - "3.6" 13 | - "3.7" 14 | - "3.8" 15 | - "3.9" 16 | 17 | install: 18 | - pip install -r pip_requirements.txt 19 | 20 | # command to run tests 21 | script: 22 | - PYTHONPATH=. pytest 23 | 24 | -------------------------------------------------------------------------------- /bibolamazi_3rdparty.py: -------------------------------------------------------------------------------- 1 | 2 | import sys as _sys 3 | import os.path as _ospath 4 | 5 | 6 | _curpath = _ospath.abspath(_ospath.dirname(_ospath.realpath(__file__))) 7 | _thirdparty = _ospath.join(_curpath, '3rdparty') 8 | 9 | 10 | _sys.path.append(_ospath.join(_thirdparty, 'pybtex')) 11 | _sys.path.append(_ospath.join(_thirdparty, 'arxiv2bib')) 12 | _sys.path.append(_ospath.join(_thirdparty, 'pylatexenc')) 13 | 14 | -------------------------------------------------------------------------------- /gui/README.txt: -------------------------------------------------------------------------------- 1 | 2 | --------------------------- 3 | GUI INTERFACE TO BIBOLAMAZI 4 | --------------------------- 5 | 6 | This directory contains instructions to build packages for the graphical interface for 7 | bibolamazi, written in PyQt5. 8 | 9 | To install the graphical interface, proceed as usual with `setup.py`. 10 | 11 | NOTE: There are several binary versions available for different platforms. See 12 | https://github.com/phfaist/bibolamazi/releases/ 13 | 14 | 15 | -------------------------------------------------------------------------------- /doc/_static/custom.css: -------------------------------------------------------------------------------- 1 | 2 | 3 | @import url('https://fonts.googleapis.com/css?family=IBM+Plex+Mono|IBM+Plex+Sans:400,400i,600,600i'); 4 | 5 | 6 | pre { 7 | padding: 7px 15px; 8 | } 9 | 10 | 11 | div.sphinxsidebar li.toctree-l1 { 12 | margin-bottom: 0.7em; 13 | } 14 | 15 | div.sphinxsidebar li.toctree-l1::before { 16 | content: '- '; 17 | width: 1em; 18 | margin-left: -1em; 19 | margin-right: 0em; 20 | padding: 0pt; 21 | display: inline-block; 22 | } 23 | -------------------------------------------------------------------------------- /pip_requirements.txt: -------------------------------------------------------------------------------- 1 | # 2 | # pybtex >= 0.23 for new pybtex.utils.OrderedCaseInsensitiveDict implementation 3 | # with __delitem__ 4 | # 5 | pybtex >= 0.23 6 | 7 | # 8 | # arxiv2bib. 9 | # 10 | arxiv2bib >= 1.0.2 11 | 12 | # 13 | # My own pylatexenc. 14 | # 15 | pylatexenc >= 2.10b 16 | 17 | # 18 | # `future` for both python2 & python3 support 19 | # 20 | future 21 | 22 | # 23 | # `appdirs` to find where to store config files and caches 24 | # 25 | appdirs 26 | 27 | # 28 | # `PyGithub` and `requests` 29 | # 30 | PyGithub 31 | requests[security] 32 | -------------------------------------------------------------------------------- /doc/bibolamazi.core.bibusercache.rst: -------------------------------------------------------------------------------- 1 | :mod:`bibolamazi.core.bibusercache` package 2 | =========================================== 3 | 4 | bibolamazi.core.bibusercache.tokencheckers module 5 | ------------------------------------------------- 6 | 7 | .. automodule:: bibolamazi.core.bibusercache.tokencheckers 8 | :members: 9 | :undoc-members: 10 | :show-inheritance: 11 | 12 | 13 | Module contents 14 | --------------- 15 | 16 | .. automodule:: bibolamazi.core.bibusercache 17 | :members: 18 | :undoc-members: 19 | :show-inheritance: 20 | -------------------------------------------------------------------------------- /doc/bibolamazi.filters.util.rst: -------------------------------------------------------------------------------- 1 | 2 | Python API: Filter Utilities Package 3 | ==================================== 4 | 5 | :mod:`bibolamazi.filters.util.arxivutil` Module 6 | ----------------------------------------------- 7 | 8 | .. automodule:: bibolamazi.filters.util.arxivutil 9 | :members: 10 | :undoc-members: 11 | :show-inheritance: 12 | 13 | :mod:`bibolamazi.filters.util.auxfile` Module 14 | --------------------------------------------- 15 | 16 | .. automodule:: bibolamazi.filters.util.auxfile 17 | :members: 18 | :undoc-members: 19 | :show-inheritance: 20 | 21 | -------------------------------------------------------------------------------- /doc/credits-contact.rst: -------------------------------------------------------------------------------- 1 | 2 | Credits, Copyright and Contact information 3 | ========================================== 4 | 5 | Copyright 6 | --------- 7 | 8 | Copyright (c) 2014 Philippe Faist 9 | 10 | Bibolamazi is developed and maintained by Philippe Faist. It is distributed under the `GNU 11 | General Public License (GPL)`_, Version 3 or higher. 12 | 13 | .. _GNU General Public License (GPL): http://www.gnu.org/copyleft/gpl.html 14 | 15 | 16 | Contact 17 | ------- 18 | 19 | Please contact me for any bug reports, or if you want to contribute. 20 | 21 | .. image:: phf.png 22 | 23 | 24 | -------------------------------------------------------------------------------- /test/full_cases/srcbib/fail02.bib: -------------------------------------------------------------------------------- 1 | 2 | 3 | % missing comma between properties 4 | 5 | @article{Landauer1961_5392446Erasure, 6 | author = {Landauer, Rolf}, 7 | doi = {10.1147/rd.53.0183} 8 | file = {:Users/philippe/ref/articles/Mendeley/Landauer - 1961 - Irreversibility and Heat Generation in the Computing Process.pdf:pdf}, 9 | issn = {0018-8646} 10 | journal = {IBM Journal of Research and Development}, 11 | keywords = {thermo}, 12 | mendeley-tags = {thermo}, 13 | month = {jul}, 14 | number = {3}, 15 | pages = {183--191} 16 | title = {{Irreversibility and Heat Generation in the Computing Process}}, 17 | volume = {5} 18 | year = {1961} 19 | } 20 | -------------------------------------------------------------------------------- /test/full_cases/srcbib/specialtests.bib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | @article{specialentries, 5 | abstract = {\c cedilla char is in name: Fran\c cois P\'erusse. You Like \b bars under \b letters?}, 6 | author = {Dupont, Jean and Xyz, Jo\~ao and \AA serlund, \O vjsesen and Dvo\v rak, Anotonin}, 7 | journal = {Nature}, 8 | month = jun, 9 | number = {9000}, 10 | pages = {161--163}, 11 | publisher = {Nature Publishing Group, a division of Macmillan Publishers Limited. All Rights Reserved.}, 12 | shorttitle = {Nature}, 13 | title = {{The \o verfluctuatio\~n hyp\o thesis v\^erified foor qu\`antum pr\o cesses}}, 14 | url = {http://dx.doi.org/10.1038/nature1234567}, 15 | volume = {476}, 16 | year = {2030} 17 | } 18 | 19 | -------------------------------------------------------------------------------- /.github/workflows/build-binaries.yml: -------------------------------------------------------------------------------- 1 | name: Build Binaries via PyInstaller 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | jobs: 7 | PyInstaller_for_windows: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - run: echo "🎉 The job was triggered by a ${{ github.event_name }} event." 11 | - uses: actions/checkout@v2 12 | - name: PyInstaller Windows 13 | uses: JackMcKew/pyinstaller-action-windows@main 14 | with: 15 | spec: bibolamazi_gui.spec 16 | requirements: ../pip_requirements.txt 17 | path: gui/ 18 | 19 | - uses: actions/upload-artifact@v2 20 | with: 21 | name: bibolamazi-win 22 | path: gui/dist/windows 23 | 24 | - run: echo "🍏 This job's status is ${{ job.status }}." 25 | -------------------------------------------------------------------------------- /test/full_cases/srcbib/testremote.bib: -------------------------------------------------------------------------------- 1 | 2 | % this bibtex file will be loaded by referring to the "raw view" directly on github 3 | 4 | @ARTICLE{2009arXiv0907.5238T, 5 | author = {{Tomamichel}, M. and {Colbeck}, R. and {Renner}, R.}, 6 | title = "{Duality Between Smooth Min- and Max-Entropies}", 7 | journal = {arXiv e-prints}, 8 | keywords = {Quantum Physics}, 9 | year = "2009", 10 | month = "Jul", 11 | eid = {arXiv:0907.5238}, 12 | pages = {arXiv:0907.5238}, 13 | archivePrefix = {arXiv}, 14 | eprint = {0907.5238}, 15 | primaryClass = {quant-ph}, 16 | adsurl = {https://ui.adsabs.harvard.edu/abs/2009arXiv0907.5238T}, 17 | adsnote = {Provided by the SAO/NASA Astrophysics Data System} 18 | } 19 | -------------------------------------------------------------------------------- /doc/bibolamazi.core.bibfilter.rst: -------------------------------------------------------------------------------- 1 | :mod:`bibolamazi.core.bibfilter` package 2 | ======================================== 3 | 4 | 5 | Module :mod:`bibolamazi.core.bibfilter` 6 | --------------------------------------- 7 | 8 | .. automodule:: bibolamazi.core.bibfilter 9 | :members: 10 | :undoc-members: 11 | :show-inheritance: 12 | 13 | 14 | bibolamazi.core.bibfilter.argtypes module 15 | ----------------------------------------- 16 | 17 | .. automodule:: bibolamazi.core.bibfilter.argtypes 18 | :members: 19 | :undoc-members: 20 | :show-inheritance: 21 | 22 | bibolamazi.core.bibfilter.factory module 23 | ---------------------------------------- 24 | 25 | .. automodule:: bibolamazi.core.bibfilter.factory 26 | :members: 27 | :undoc-members: 28 | :show-inheritance: 29 | -------------------------------------------------------------------------------- /test/test_bibolamazi_bibfilters_factory.py: -------------------------------------------------------------------------------- 1 | 2 | import unittest 3 | 4 | import bibolamazi.core.bibfilter.factory as bffactory 5 | 6 | 7 | class TestWorks(unittest.TestCase): 8 | 9 | def test_works_1(self): 10 | 11 | fi = bffactory.FilterInfo('arxiv') 12 | from bibolamazi.filters import arxiv 13 | 14 | self.assertTrue( id(fi.fmodule) == id(arxiv) ) 15 | 16 | 17 | def test_parses_options(self): 18 | 19 | arxivf = bffactory.make_filter('arxiv', '-sMode=eprint --unpublished-mode=unpublished-note') 20 | 21 | self.assertEqual(str(arxivf.mode), 'eprint') 22 | self.assertEqual(str(arxivf.unpublished_mode), 'unpublished-note') 23 | 24 | 25 | 26 | if __name__ == '__main__': 27 | from bibolamazi.core import blogger 28 | blogger.setup_simple_console_logging(level=1) 29 | unittest.main() 30 | -------------------------------------------------------------------------------- /test/full_cases/srcbib/fail01.bib: -------------------------------------------------------------------------------- 1 | 2 | 3 | % no comma after cite key 4 | 5 | 6 | @article{Brandao2015PNAS_secondlaws 7 | archivePrefix = {arXiv}, 8 | arxivId = {1305.5278}, 9 | author = {Brand{\~{a}}o, Fernando and Horodecki, Michał and Ng, Nelly and Oppenheim, Jonathan and Wehner, Stephanie}, 10 | doi = {10.1073/pnas.1411728112}, 11 | eprint = {1305.5278}, 12 | file = {:Users/philippe/ref/articles/Mendeley/Brand{\~{a}}o et al. - 2015 - The second laws of quantum thermodynamics.pdf:pdf}, 13 | issn = {0027-8424}, 14 | journal = {Proceedings of the National Academy of Sciences}, 15 | keywords = {thermo}, 16 | mendeley-tags = {thermo}, 17 | month = {feb}, 18 | number = {11}, 19 | pages = {201411728}, 20 | title = {{The second laws of quantum thermodynamics}}, 21 | url = {http://www.pnas.org/content/112/11/3275}, 22 | volume = {112}, 23 | year = {2015} 24 | } 25 | 26 | -------------------------------------------------------------------------------- /test/full_cases/srcbib/fail03.bib: -------------------------------------------------------------------------------- 1 | 2 | 3 | % extra comma at end 4 | 5 | @article{Bennett1993PRL_Teleportation, 6 | author = {Bennett, Charles H. and Brassard, Gilles and Cr{\'{e}}peau, Claude and Jozsa, Richard and Peres, Asher and Wootters, William K.}, 7 | doi = {10.1103/PhysRevLett.70.1895}, 8 | file = {:Users/philippe/ref/articles/Mendeley/Bennett et al. - 1993 - Teleporting an unknown quantum state via dual classical and Einstein-Podolsky-Rosen channels.pdf:pdf}, 9 | issn = {0031-9007}, 10 | journal = {Physical Review Letters}, 11 | month = {mar}, 12 | number = {13}, 13 | pages = {1895--1899}, 14 | publisher = {American Physical Society}, 15 | title = {{Teleporting an unknown quantum state via dual classical and Einstein-Podolsky-Rosen channels}}, 16 | url = {http://link.aps.org/doi/10.1103/PhysRevLett.70.1895}, 17 | volume = {70}, 18 | year = {1993}, 19 | } 20 | -------------------------------------------------------------------------------- /test/full_cases/test5_job.tex: -------------------------------------------------------------------------------- 1 | \documentclass[12pt,a4paper]{article} 2 | 3 | \usepackage{amsmath} 4 | \usepackage{amssymb} 5 | \usepackage{url} 6 | \usepackage{hyperref} 7 | \usepackage[utf8]{inputenc} 8 | 9 | \input{test5_duplicates.tex} 10 | 11 | \begin{document} 12 | 13 | 14 | \cite{ delRio2011Nature , Bell1964,Verlinde2011_entropic } 15 | 16 | \cite{aberg_2013_worklike} 17 | 18 | \cite{gour_measuring_2009_dupl} 19 | 20 | \cite{aberg_2009_cumul} 21 | 22 | \cite{dahlsten2011inadequacy} 23 | 24 | \cite{Dahlsten2009arXiv0908.0424D, 25 | Dahlsten2011NJP_inadequacy} 26 | 27 | \cite{specialentries} 28 | 29 | \cite{ aberg_2009_cumul 30 | , dahlsten2011inadequacy , 31 | aberg_2013_worklike } 32 | 33 | \vspace{1cm} 34 | 35 | \bibliographystyle{unsrturl} 36 | \bibliography{test5.bibolamazi} 37 | 38 | \end{document} 39 | 40 | %%% Local Variables: 41 | %%% mode: latex 42 | %%% TeX-master: t 43 | %%% End: 44 | -------------------------------------------------------------------------------- /gui/bibolamazi_gui/Makefile: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | QTAUTODIR = qtauto 5 | 6 | 7 | TARGETS = $(QTAUTODIR)/bibolamazi_res_rc.py \ 8 | $(QTAUTODIR)/ui_startupwidget.py \ 9 | $(QTAUTODIR)/ui_openbibfile.py \ 10 | $(QTAUTODIR)/ui_newbibolamazifiledialog.py \ 11 | $(QTAUTODIR)/ui_helpbrowser.py \ 12 | $(QTAUTODIR)/ui_sourcelisteditor.py \ 13 | $(QTAUTODIR)/ui_filterinstanceeditor.py \ 14 | $(QTAUTODIR)/ui_filterpackagepatheditor.py \ 15 | $(QTAUTODIR)/ui_overlistbuttonwidget.py \ 16 | $(QTAUTODIR)/ui_settingswidget.py \ 17 | $(QTAUTODIR)/ui_favoritesoverbtns.py \ 18 | $(QTAUTODIR)/ui_searchwidget.py \ 19 | $(QTAUTODIR)/ui_githubreposelector.py \ 20 | $(QTAUTODIR)/ui_githubauthenticationdialog.py 21 | 22 | 23 | all: $(TARGETS) 24 | 25 | clean: 26 | rm $(TARGETS) 27 | 28 | 29 | $(QTAUTODIR)/%_rc.py: %.qrc pic/* 30 | pyrcc5 -o $@ $< 31 | 32 | $(QTAUTODIR)/ui_%.py: %.ui 33 | pyuic5 --from-imports -o $@ $< 34 | -------------------------------------------------------------------------------- /gui/bibolamazi_gui/bibolamazi_res.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | pic/configlocalrepos.svg 4 | pic/remoterepos.svg 5 | pic/generalsettings.svg 6 | pic/question.png 7 | pic/rightarrow.png 8 | pic/bookmark.png 9 | pic/bibolamazi.svg 10 | pic/bibolamazi-darkmode.svg 11 | pic/settings.png 12 | pic/bibolamazi_icon.png 13 | pic/bibolamazi.png 14 | pic/closehide.png 15 | pic/file.png 16 | pic/lstbtnadd.png 17 | pic/lstbtnedit.png 18 | pic/lstbtnremove.png 19 | pic/ok.png 20 | pic/refresh.png 21 | pic/save.png 22 | pic/github_generate_new_personal_access_token.png 23 | pic/github_generate_new_personal_access_token_details.png 24 | pic/github_generate_new_personal_access_token_generatebtn.png 25 | 26 | 27 | -------------------------------------------------------------------------------- /doc/filter-packages.rst: -------------------------------------------------------------------------------- 1 | .. _filter-packages: 2 | 3 | Filter Packages 4 | =============== 5 | 6 | Bibolamazi filters are organized in *filter packages*. These are regular python 7 | packages whose modules can be invoked as filters. This is a directory 8 | containing a ``__init__.py`` file (which defines the directory as a python 9 | package) along with python files that define filters. (The ``__init__.py`` file 10 | is usually empty.) 11 | 12 | All built-in filters are part of the filter package ``bibolamazi.filters``. 13 | Additional filter packages can be imported for instance using the ``package:`` 14 | directive (see :ref:`package: directive 15 | `). 16 | 17 | It is very simple to create your own filter packages and provide your own 18 | filters. This section covers how filter packages can be imported, how to create 19 | your own filter packages, and how to write your own filters. 20 | 21 | 22 | .. toctree:: 23 | :maxdepth: 1 24 | 25 | import-filter-package 26 | create-filter-package 27 | devel-filter-easy 28 | devel-filter 29 | 30 | -------------------------------------------------------------------------------- /test/full_cases/more_filters/add_book_entry.py: -------------------------------------------------------------------------------- 1 | # 2 | # Simple example of a custom filter package 3 | # 4 | 5 | 6 | from pybtex.database import Entry, Person 7 | 8 | 9 | def bib_filter_bibolamazifile(bibolamazifile, author='One; Two; Three, Jr.', 10 | title='A nice title', year=2001): 11 | """ 12 | This filter adds to each entry (which is not a book) an additional field 13 | named `fieldname` set to the constant value `value`. 14 | 15 | * author : 16 | 17 | Specify the author list, separated by semicolons (e.g., "Maria Doe; 18 | John Doe") 19 | 20 | * title : 21 | 22 | The title of the book. 23 | 24 | * year (int) : 25 | 26 | The year the book was published. 27 | 28 | """ 29 | 30 | # set the field fieldname to the given value in all entries except books (for example) 31 | 32 | bibolamazifile.bibliographyData().entries['mybook'] = Entry( 33 | type_='book', 34 | persons=dict(author=[Person(a.strip()) for a in author.split(";")]), 35 | fields={'title': title, 'year': str(year)} 36 | ) 37 | -------------------------------------------------------------------------------- /test/full_cases/more_filters/add_constant_field.py: -------------------------------------------------------------------------------- 1 | # 2 | # Simple example of a custom filter package 3 | # 4 | 5 | 6 | 7 | def bib_filter_entry(entry, bibolamazifile, fieldname='processed_by', value='bibolamazi-program', 8 | make_value_caps=False): 9 | """ 10 | This filter adds to each entry (which is not a book) an additional field 11 | named `fieldname` set to the constant value `value`. 12 | 13 | Author: Philippe Faist 14 | 15 | Some more doc text goes here. 16 | 17 | Description: Add a fixed key=value pair to all 18 | non-book entries 19 | 20 | Arguments: 21 | 22 | * fieldname: the field name to insert (or replace) in all 23 | bibtex entries 24 | * value: the value to set the given field_name to, in 25 | all bibtex entries 26 | * make_value_caps: turn the value into upper-case letters 27 | """ 28 | 29 | # set the field fieldname to the given value in all entries except books (for example) 30 | 31 | if entry.type != 'book': 32 | if make_value_caps: 33 | value = value.upper() 34 | entry.fields[fieldname] = value 35 | 36 | -------------------------------------------------------------------------------- /gui/bibolamazi_gui/pic/generalsettings.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /gui/bibolamazi_gui/qtauto/ui_helpbrowser.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Form implementation generated from reading ui file 'helpbrowser.ui' 4 | # 5 | # Created by: PyQt5 UI code generator 5.7.1 6 | # 7 | # WARNING! All changes made in this file will be lost! 8 | 9 | from PyQt5 import QtCore, QtGui, QtWidgets 10 | 11 | class Ui_HelpBrowser(object): 12 | def setupUi(self, HelpBrowser): 13 | HelpBrowser.setObjectName("HelpBrowser") 14 | HelpBrowser.resize(600, 600) 15 | self.lyt = QtWidgets.QGridLayout(HelpBrowser) 16 | self.lyt.setContentsMargins(0, 0, 0, 0) 17 | self.lyt.setObjectName("lyt") 18 | self.tabs = QtWidgets.QTabWidget(HelpBrowser) 19 | self.tabs.setDocumentMode(True) 20 | self.tabs.setTabsClosable(True) 21 | self.tabs.setMovable(True) 22 | self.tabs.setObjectName("tabs") 23 | self.lyt.addWidget(self.tabs, 0, 0, 1, 1) 24 | 25 | self.retranslateUi(HelpBrowser) 26 | self.tabs.setCurrentIndex(-1) 27 | QtCore.QMetaObject.connectSlotsByName(HelpBrowser) 28 | 29 | def retranslateUi(self, HelpBrowser): 30 | _translate = QtCore.QCoreApplication.translate 31 | HelpBrowser.setWindowTitle(_translate("HelpBrowser", "Bibolamazi Help & Reference")) 32 | 33 | -------------------------------------------------------------------------------- /test/helper_mk_pyentry.py: -------------------------------------------------------------------------------- 1 | 2 | from __future__ import unicode_literals, print_function 3 | from future.utils import iteritems 4 | from builtins import str as unicodestr 5 | 6 | # monkey-patch pybtex 7 | import bibolamazi.init 8 | 9 | import sys 10 | import io 11 | import pybtex.database.input.bibtex as inputbibtex 12 | import pybtex.database.output.bibtex as outputbibtex 13 | 14 | import fileinput 15 | import json 16 | 17 | parser = inputbibtex.Parser() 18 | 19 | data = "" 20 | for x in fileinput.input(): data += x 21 | 22 | bib_data = None 23 | with io.StringIO(data) as stream: 24 | bib_data = parser.parse_stream(stream) 25 | 26 | 27 | def doentry(key, entry): 28 | 29 | persons = '{' 30 | for role in ('author', 'editor', ): 31 | if role in entry.persons: 32 | persons += (json.dumps(role)+": [" 33 | +",".join([ "Person("+json.dumps(unicodestr(x))+")" for x in entry.persons[role]]) 34 | +"],") 35 | persons += '}' 36 | 37 | print(" ({}, Entry({}, persons={}, fields={},),)," 38 | .format(json.dumps(key), 39 | json.dumps(entry.type), 40 | persons, 41 | json.dumps(dict(entry.fields),indent=8))) 42 | 43 | 44 | 45 | print("[") 46 | for key, entry in iteritems(bib_data.entries): 47 | doentry(key, entry) 48 | print("]") 49 | -------------------------------------------------------------------------------- /gui/bibolamazi_gui/helpbrowser.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | HelpBrowser 4 | 5 | 6 | 7 | 0 8 | 0 9 | 600 10 | 600 11 | 12 | 13 | 14 | Bibolamazi Help & Reference 15 | 16 | 17 | 18 | 0 19 | 20 | 21 | 0 22 | 23 | 24 | 0 25 | 26 | 27 | 0 28 | 29 | 30 | 31 | 32 | -1 33 | 34 | 35 | true 36 | 37 | 38 | true 39 | 40 | 41 | true 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /doc/index.rst: -------------------------------------------------------------------------------- 1 | .. Bibolamazi documentation master file, created by 2 | sphinx-quickstart on Mon Nov 10 19:01:26 2014. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | 7 | Welcome to Bibolamazi 8 | ===================== 9 | 10 | Bibolamazi lets you prepare consistent and uniform BibTeX files for your LaTeX 11 | documents. It lets you prepare your BibTeX entries as you would like them to 12 | be---adding missing or dropping irrelevant information, capitalizing names or 13 | turning them into initials, converting unicode characters to latex escapes, etc. 14 | 15 | Quick links: 16 | 17 | * :ref:`What is bibolamazi? ` 18 | 19 | * `Download latest release `_ 20 | 21 | * :ref:`Download & installation instructions ` 22 | 23 | * `Github repository `_ 24 | 25 | 26 | 27 | Table of Contents: 28 | 29 | .. toctree:: 30 | :maxdepth: 2 31 | 32 | introduction-to-bibolamazi 33 | download-and-install 34 | using-bibolamazi-app 35 | bibolamazi-config-section 36 | using-bibolamazi-cmdl 37 | filter-packages 38 | bibolamazi.core 39 | bibolamazi.filters.util 40 | credits-contact 41 | 42 | 43 | 44 | Indices and tables 45 | ================== 46 | 47 | * :ref:`genindex` 48 | * :ref:`modindex` 49 | * :ref:`search` 50 | 51 | 52 | Version 53 | ======= 54 | 55 | Documentation built from bibolamazi version |BIBOLAMAZI_VERSION|. 56 | -------------------------------------------------------------------------------- /doc/bibolamazi.core.rst: -------------------------------------------------------------------------------- 1 | Python API: Core Bibolamazi Module 2 | ================================== 3 | 4 | 5 | Module contents 6 | --------------- 7 | 8 | .. automodule:: bibolamazi.core 9 | :members: 10 | :undoc-members: 11 | :show-inheritance: 12 | 13 | Subpackages 14 | ----------- 15 | 16 | .. toctree:: 17 | :maxdepth: 1 18 | 19 | bibolamazi.core.bibfilter 20 | bibolamazi.core.bibusercache 21 | 22 | 23 | bibolamazi.core.argparseactions module 24 | -------------------------------------- 25 | 26 | .. automodule:: bibolamazi.core.argparseactions 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | 31 | bibolamazi.core.bibolamazifile module 32 | ------------------------------------- 33 | 34 | .. automodule:: bibolamazi.core.bibolamazifile 35 | :members: 36 | :undoc-members: 37 | :show-inheritance: 38 | 39 | bibolamazi.core.blogger module 40 | ------------------------------ 41 | 42 | .. automodule:: bibolamazi.core.blogger 43 | :members: 44 | :undoc-members: 45 | :show-inheritance: 46 | 47 | bibolamazi.core.butils module 48 | ----------------------------- 49 | 50 | .. automodule:: bibolamazi.core.butils 51 | :members: 52 | :undoc-members: 53 | :show-inheritance: 54 | 55 | bibolamazi.core.main module 56 | --------------------------- 57 | 58 | .. automodule:: bibolamazi.core.main 59 | :members: 60 | :undoc-members: 61 | :show-inheritance: 62 | 63 | bibolamazi.core.version module 64 | ------------------------------ 65 | 66 | .. automodule:: bibolamazi.core.version 67 | :members: 68 | :undoc-members: 69 | :show-inheritance: 70 | 71 | -------------------------------------------------------------------------------- /gui/bibolamazi_gui/overlistbuttonwidget.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | OverListButtonWidget 4 | 5 | 6 | 7 | 0 8 | 9 | 10 | 0 11 | 12 | 13 | 14 | 15 | 16 | :/pic/lstbtnadd.png:/pic/lstbtnadd.png 17 | 18 | 19 | 20 | 10 21 | 16 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | :/pic/lstbtnedit.png:/pic/lstbtnedit.png 31 | 32 | 33 | 34 | 10 35 | 16 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | :/pic/lstbtnremove.png:/pic/lstbtnremove.png 45 | 46 | 47 | 48 | 10 49 | 16 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /bin/bibolamazi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | ################################################################################ 4 | # # 5 | # This file is part of the Bibolamazi Project. # 6 | # Copyright (C) 2013 by Philippe Faist # 7 | # philippe.faist@bluewin.ch # 8 | # # 9 | # Bibolamazi is free software: you can redistribute it and/or modify # 10 | # it under the terms of the GNU General Public License as published by # 11 | # the Free Software Foundation, either version 3 of the License, or # 12 | # (at your option) any later version. # 13 | # # 14 | # Bibolamazi is distributed in the hope that it will be useful, # 15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of # 16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # 17 | # GNU General Public License for more details. # 18 | # # 19 | # You should have received a copy of the GNU General Public License # 20 | # along with Bibolamazi. If not, see . # 21 | # # 22 | ################################################################################ 23 | 24 | 25 | import bibolamazi.init 26 | 27 | 28 | if __name__ == "__main__": 29 | 30 | # run main program 31 | from bibolamazi.core import main 32 | main.main() 33 | -------------------------------------------------------------------------------- /bibolamazi/filters/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | ################################################################################ 3 | # # 4 | # This file is part of the Bibolamazi Project. # 5 | # Copyright (C) 2013 by Philippe Faist # 6 | # philippe.faist@bluewin.ch # 7 | # # 8 | # Bibolamazi is free software: you can redistribute it and/or modify # 9 | # it under the terms of the GNU General Public License as published by # 10 | # the Free Software Foundation, either version 3 of the License, or # 11 | # (at your option) any later version. # 12 | # # 13 | # Bibolamazi is distributed in the hope that it will be useful, # 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of # 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # 16 | # GNU General Public License for more details. # 17 | # # 18 | # You should have received a copy of the GNU General Public License # 19 | # along with Bibolamazi. If not, see . # 20 | # # 21 | ################################################################################ 22 | 23 | 24 | 25 | # don't allow the use of "from filters import *" -- it's time consuming to detect all filters; so 26 | # detect the filters only when needed, when calling `detect_filters()` 27 | __all__ = [] 28 | -------------------------------------------------------------------------------- /gui/bibolamazi_gui/searchwidget.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | SearchWidget 4 | 5 | 6 | 7 | 0 8 | 0 9 | 438 10 | 28 11 | 12 | 13 | 14 | 15 | 0 16 | 0 17 | 18 | 19 | 20 | Form 21 | 22 | 23 | 24 | 2 25 | 26 | 27 | 3 28 | 29 | 30 | 3 31 | 32 | 33 | 3 34 | 35 | 36 | 3 37 | 38 | 39 | 40 | 41 | find: 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | done 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /bibolamazi/core/version.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | ################################################################################ 3 | # # 4 | # This file is part of the Bibolamazi Project. # 5 | # Copyright (C) 2020 by Philippe Faist # 6 | # philippe.faist@bluewin.ch # 7 | # # 8 | # Bibolamazi is free software: you can redistribute it and/or modify # 9 | # it under the terms of the GNU General Public License as published by # 10 | # the Free Software Foundation, either version 3 of the License, or # 11 | # (at your option) any later version. # 12 | # # 13 | # Bibolamazi is distributed in the hope that it will be useful, # 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of # 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # 16 | # GNU General Public License for more details. # 17 | # # 18 | # You should have received a copy of the GNU General Public License # 19 | # along with Bibolamazi. If not, see . # 20 | # # 21 | ################################################################################ 22 | 23 | 24 | # This is the current BIBOLAMAZI version. 25 | # Bump the number here for different version numbers. 26 | 27 | version_str = "4.6b0" 28 | """ 29 | The version string. This is increased upon each release. 30 | """ 31 | 32 | 33 | copyright_year = "2023" 34 | """ 35 | Year of copyright. 36 | """ 37 | -------------------------------------------------------------------------------- /bibolamazi/core/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | ################################################################################ 3 | # # 4 | # This file is part of the Bibolamazi Project. # 5 | # Copyright (C) 2013 by Philippe Faist # 6 | # philippe.faist@bluewin.ch # 7 | # # 8 | # Bibolamazi is free software: you can redistribute it and/or modify # 9 | # it under the terms of the GNU General Public License as published by # 10 | # the Free Software Foundation, either version 3 of the License, or # 11 | # (at your option) any later version. # 12 | # # 13 | # Bibolamazi is distributed in the hope that it will be useful, # 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of # 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # 16 | # GNU General Public License for more details. # 17 | # # 18 | # You should have received a copy of the GNU General Public License # 19 | # along with Bibolamazi. If not, see . # 20 | # # 21 | ################################################################################ 22 | 23 | """ 24 | Core bibolamazi module. 25 | 26 | See :py:mod:`bibolamazi.core.bibfilter`, :py:mod:`bibolamazi.core.bibolamazifile`, 27 | :py:mod:`bibolamazi.core.bibusercache` for the main core modules. 28 | """ 29 | 30 | # ### Comment this out, so that we can import bibolamazi.core.version from 31 | # ### setup.py without e.g. crashing because pybtex isn't available... 32 | # 33 | #import bibolamazi.init 34 | -------------------------------------------------------------------------------- /gui/bibolamazi_gui/qtauto/ui_overlistbuttonwidget.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Form implementation generated from reading ui file 'overlistbuttonwidget.ui' 4 | # 5 | # Created by: PyQt5 UI code generator 5.7.1 6 | # 7 | # WARNING! All changes made in this file will be lost! 8 | 9 | from PyQt5 import QtCore, QtGui, QtWidgets 10 | 11 | class Ui_OverListButtonWidget(object): 12 | def setupUi(self, OverListButtonWidget): 13 | OverListButtonWidget.setObjectName("OverListButtonWidget") 14 | self.horizontalLayout = QtWidgets.QHBoxLayout(OverListButtonWidget) 15 | self.horizontalLayout.setContentsMargins(0, 0, 0, 0) 16 | self.horizontalLayout.setSpacing(0) 17 | self.horizontalLayout.setObjectName("horizontalLayout") 18 | self.btnAdd = QtWidgets.QToolButton(OverListButtonWidget) 19 | icon = QtGui.QIcon() 20 | icon.addPixmap(QtGui.QPixmap(":/pic/lstbtnadd.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) 21 | self.btnAdd.setIcon(icon) 22 | self.btnAdd.setIconSize(QtCore.QSize(10, 16)) 23 | self.btnAdd.setObjectName("btnAdd") 24 | self.horizontalLayout.addWidget(self.btnAdd) 25 | self.btnEdit = QtWidgets.QToolButton(OverListButtonWidget) 26 | icon1 = QtGui.QIcon() 27 | icon1.addPixmap(QtGui.QPixmap(":/pic/lstbtnedit.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) 28 | self.btnEdit.setIcon(icon1) 29 | self.btnEdit.setIconSize(QtCore.QSize(10, 16)) 30 | self.btnEdit.setObjectName("btnEdit") 31 | self.horizontalLayout.addWidget(self.btnEdit) 32 | self.btnRemove = QtWidgets.QToolButton(OverListButtonWidget) 33 | icon2 = QtGui.QIcon() 34 | icon2.addPixmap(QtGui.QPixmap(":/pic/lstbtnremove.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) 35 | self.btnRemove.setIcon(icon2) 36 | self.btnRemove.setIconSize(QtCore.QSize(10, 16)) 37 | self.btnRemove.setObjectName("btnRemove") 38 | self.horizontalLayout.addWidget(self.btnRemove) 39 | 40 | self.retranslateUi(OverListButtonWidget) 41 | QtCore.QMetaObject.connectSlotsByName(OverListButtonWidget) 42 | 43 | def retranslateUi(self, OverListButtonWidget): 44 | pass 45 | 46 | from . import bibolamazi_res_rc 47 | -------------------------------------------------------------------------------- /test/full_cases/test6.bibolamazi.bib: -------------------------------------------------------------------------------- 1 | 2 | 3 | .. Additionnal stuff here will not be managed by bibolamazi. It will also not be 4 | .. overwritten. You can e.g. temporarily add additional references here if you 5 | .. don't have bibolamazi installed. 6 | 7 | 8 | %%%-BIB-OLA-MAZI-BEGIN-%%% 9 | % 10 | % %% This bibliography database uses BIBOLAMAZI: 11 | % %% 12 | % %% https://github.com/phfaist/bibolamazi 13 | % %% 14 | % %% See comments below this configuration section if you're new to bibolamazi. 15 | % 16 | % %% This is the BIBOLAMAZI configuration section. Additional two leading 17 | % %% percent signs indicate comments within the configuration. 18 | % 19 | % %% **** SOURCES **** 20 | % 21 | % %% The _first_ accessible file in _each_ source list will be read 22 | % 23 | % src: srcbib/specialtests.bib 24 | % 25 | % %% Add additional sources here. Alternative files are useful, e.g., if the 26 | % %% same file is to be accessed with different paths on different machines. 27 | % 28 | % %% **** FILTERS **** 29 | % 30 | % %% Specify filters here. Specify as many filters as you want, each with a 31 | % %% `filter:' directive. See also `bibolamazi --list-filters' and 32 | % %% `bibolamazi --help ', or the "Help & Reference" page of the 33 | % %% graphical interface. 34 | % 35 | % filter: fixes -dFixSpaceAfterEscape 36 | % 37 | %%%-BIB-OLA-MAZI-END-%%% 38 | 39 | % 40 | % This file was generated by BIBOLAMAZI 4.0b5 on 2019-01-05T00:17:12.784492 41 | % 42 | % https://github.com/phfaist/bibolamazi 43 | % 44 | % 45 | % ALL CHANGES BEYOND THIS POINT WILL BE LOST NEXT TIME BIBOLAMAZI IS RUN. 46 | % 47 | 48 | @article{specialentries, 49 | author = "Dupont, Jean and Xyz, Jo\~ao and \AA{}serlund, \O{}vjsesen and Dvo\v{r}ak, Anotonin", 50 | abstract = "\c{c}edilla char is in name: Fran\c{c}ois P\'erusse. You Like \b{b}ars under \b{l}etters?", 51 | journal = "Nature", 52 | month = "June", 53 | number = "9000", 54 | pages = "161--163", 55 | publisher = "Nature Publishing Group, a division of Macmillan Publishers Limited. All Rights Reserved.", 56 | shorttitle = "Nature", 57 | title = "{The \o{}verfluctuatio\~n hyp\o{}thesis v\^erified foor qu\`antum pr\o{}cesses}", 58 | url = "http://dx.doi.org/10.1038/nature1234567", 59 | volume = "476", 60 | year = "2030" 61 | } 62 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![bibolamazi](bibolamazi.svg) 2 | 3 | Prepare consistent and uniform BibTeX files for your LaTeX documents 4 | 5 | Bibolamazi lets you prepare bibtex files for your LaTeX documents the way you 6 | want, by collecting entries from sources such as your master bibtex file, or 7 | bibtex files produced by your favorite reference manager, and applying specific 8 | rules. 9 | 10 | [![License](https://img.shields.io/github/license/phfaist/bibolamazi.svg?style=flat)](https://github.com/phfaist/bibolamazi/blob/master/LICENSE.txt) 11 | [![Build Status](https://img.shields.io/travis/phfaist/bibolamazi/master.svg?style=flat)](https://travis-ci.org/phfaist/bibolamazi) 12 | [![PyPI Version](https://img.shields.io/pypi/v/bibolamazi.svg?style=flat)](https://pypi.org/project/bibolamazi/) 13 | [![Language grade: Python](https://img.shields.io/lgtm/grade/python/g/phfaist/bibolamazi.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/phfaist/bibolamazi/context:python) 14 | 15 | 16 | Download & Install Bibolamazi 17 | ----------------------------- 18 | 19 | Download the application from our github releases page: 20 | 21 | [**Download Releases Page**](https://github.com/phfaist/bibolamazi/releases) 22 | 23 | Download the binary for your system, place it wherever you want, and run 24 | them. On Mac OS X, place the application bundle `Bibolamazi.app` into your 25 | `/Applications/` folder. 26 | 27 | If you prefer to use the command-line interface, you can install bibolamazi 28 | using `pip`; check out [the docs][thedocsdownloadandinstall]. 29 | 30 | [thedocsdownloadandinstall]: http://bibolamazi.readthedocs.org/en/latest/download-and-install/ 31 | 32 | 33 | Documentation 34 | ------------- 35 | 36 | Read the full Bibolamazi documentation on ReadTheDocs.org: 37 | 38 | [**Bibolamazi Documentation**](http://bibolamazi.readthedocs.org/en/latest/) 39 | 40 | You'll find there also information about creating your own filters, the 41 | bibolamzi python API, and more. 42 | 43 | 44 | Credits and Copyright 45 | --------------------- 46 | 47 | Copyright (c) 2019 Philippe Faist: ![phf-contact](phf.png) 48 | 49 | Bibolamazi is developed and maintained by Philippe Faist. It is distributed 50 | under the [GNU General Public License (GPL)][gpl], Version 3 or higher. 51 | 52 | [gpl]: http://www.gnu.org/copyleft/gpl.html 53 | 54 | -------------------------------------------------------------------------------- /gui/bin/bibolamazi_gui: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | ################################################################################ 4 | # # 5 | # This file is part of the Bibolamazi Project. # 6 | # Copyright (C) 2013 by Philippe Faist # 7 | # philippe.faist@bluewin.ch # 8 | # # 9 | # Bibolamazi is free software: you can redistribute it and/or modify # 10 | # it under the terms of the GNU General Public License as published by # 11 | # the Free Software Foundation, either version 3 of the License, or # 12 | # (at your option) any later version. # 13 | # # 14 | # Bibolamazi is distributed in the hope that it will be useful, # 15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of # 16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # 17 | # GNU General Public License for more details. # 18 | # # 19 | # You should have received a copy of the GNU General Public License # 20 | # along with Bibolamazi. If not, see . # 21 | # # 22 | ################################################################################ 23 | 24 | 25 | import os.path 26 | import sys 27 | 28 | 29 | try: 30 | import bibolamazi.init 31 | except ImportError: 32 | # realpath() needed for resolving executable symlink 33 | ourrootpath = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '..', '..')) 34 | sys.path.append(ourrootpath) 35 | sys.path.append(os.path.join(ourrootpath, 'gui')) 36 | import bibolamazi.init 37 | 38 | 39 | from bibolamazi_gui import bibolamazi_gui 40 | 41 | 42 | if __name__ == "__main__": 43 | 44 | # run main program 45 | 46 | bibolamazi_gui.main() 47 | 48 | -------------------------------------------------------------------------------- /test/full_cases/test5_job.aux: -------------------------------------------------------------------------------- 1 | \relax 2 | \providecommand\hyper@newdestlabel[2]{} 3 | \providecommand\HyperFirstAtBeginDocument{\AtBeginDocument} 4 | \HyperFirstAtBeginDocument{\ifx\hyper@anchor\@undefined 5 | \global\let\oldcontentsline\contentsline 6 | \gdef\contentsline#1#2#3#4{\oldcontentsline{#1}{#2}{#3}} 7 | \global\let\oldnewlabel\newlabel 8 | \gdef\newlabel#1#2{\newlabelxx{#1}#2} 9 | \gdef\newlabelxx#1#2#3#4#5#6{\oldnewlabel{#1}{{#2}{#3}}} 10 | \AtEndDocument{\ifx\hyper@anchor\@undefined 11 | \let\contentsline\oldcontentsline 12 | \let\newlabel\oldnewlabel 13 | \fi} 14 | \fi} 15 | \global\let\hyper@last\relax 16 | \gdef\HyperFirstAtBeginDocument#1{#1} 17 | \providecommand\HyField@AuxAddToFields[1]{} 18 | \providecommand\HyField@AuxAddToCoFields[2]{} 19 | \bgroup \renewcommand \citation [1]{}\citation {delRio2011Nature,Bell1964,Verlinde2011_entropic}\egroup 20 | \citation{delRio2011Nature} 21 | \citation{Bell1964} 22 | \citation{Verlinde2011_entropic} 23 | \bgroup \renewcommand \citation [1]{}\citation {aberg_2013_worklike}\egroup 24 | \citation{aberg_2013_worklike} 25 | \bgroup \renewcommand \citation [1]{}\citation {gour_measuring_2009_dupl}\egroup 26 | \citation{gour_measuring_2009_dupl} 27 | \bgroup \renewcommand \citation [1]{}\citation {aberg_2009_cumul}\egroup 28 | \citation{aberg_2009_cumul} 29 | \bgroup \renewcommand \citation [1]{}\citation {dahlsten2011inadequacy}\egroup 30 | \citation{dahlsten2011inadequacy} 31 | \bgroup \renewcommand \citation [1]{}\citation {Dahlsten2009arXiv0908.0424D,Dahlsten2011NJP_inadequacy}\egroup 32 | \citation{Dahlsten2009arXiv0908.0424D} 33 | \citation{dahlsten2011inadequacy} 34 | \bgroup \renewcommand \citation [1]{}\citation {specialentries}\egroup 35 | \citation{specialentries} 36 | \bgroup \renewcommand \citation [1]{}\citation {aberg_2009_cumul,dahlsten2011inadequacy,aberg_2013_worklike}\egroup 37 | \citation{aberg_2009_cumul} 38 | \citation{dahlsten2011inadequacy} 39 | \citation{aberg_2013_worklike} 40 | \bibstyle{unsrturl} 41 | \bibdata{test5.bibolamazi} 42 | \bibcite{delRio2011Nature}{1} 43 | \bibcite{Bell1964}{2} 44 | \bibcite{Verlinde2011_entropic}{3} 45 | \bibcite{aberg_2013_worklike}{4} 46 | \bibcite{gour_measuring_2009_dupl}{5} 47 | \bibcite{aberg_2009_cumul}{6} 48 | \bibcite{dahlsten2011inadequacy}{7} 49 | \bibcite{Dahlsten2009arXiv0908.0424D}{8} 50 | \bibcite{specialentries}{9} 51 | -------------------------------------------------------------------------------- /gui/bibolamazi_gui/qtauto/ui_searchwidget.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Form implementation generated from reading ui file 'searchwidget.ui' 4 | # 5 | # Created by: PyQt5 UI code generator 5.7.1 6 | # 7 | # WARNING! All changes made in this file will be lost! 8 | 9 | from PyQt5 import QtCore, QtGui, QtWidgets 10 | 11 | class Ui_SearchWidget(object): 12 | def setupUi(self, SearchWidget): 13 | SearchWidget.setObjectName("SearchWidget") 14 | SearchWidget.resize(438, 28) 15 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) 16 | sizePolicy.setHorizontalStretch(0) 17 | sizePolicy.setVerticalStretch(0) 18 | sizePolicy.setHeightForWidth(SearchWidget.sizePolicy().hasHeightForWidth()) 19 | SearchWidget.setSizePolicy(sizePolicy) 20 | self.horizontalLayout = QtWidgets.QHBoxLayout(SearchWidget) 21 | self.horizontalLayout.setContentsMargins(3, 3, 3, 3) 22 | self.horizontalLayout.setSpacing(2) 23 | self.horizontalLayout.setObjectName("horizontalLayout") 24 | self.lbl = QtWidgets.QLabel(SearchWidget) 25 | self.lbl.setObjectName("lbl") 26 | self.horizontalLayout.addWidget(self.lbl) 27 | self.txt = QtWidgets.QLineEdit(SearchWidget) 28 | self.txt.setObjectName("txt") 29 | self.horizontalLayout.addWidget(self.txt) 30 | self.btnNext = QtWidgets.QToolButton(SearchWidget) 31 | self.btnNext.setObjectName("btnNext") 32 | self.horizontalLayout.addWidget(self.btnNext) 33 | self.btnPrev = QtWidgets.QToolButton(SearchWidget) 34 | self.btnPrev.setObjectName("btnPrev") 35 | self.horizontalLayout.addWidget(self.btnPrev) 36 | self.btnDone = QtWidgets.QToolButton(SearchWidget) 37 | self.btnDone.setObjectName("btnDone") 38 | self.horizontalLayout.addWidget(self.btnDone) 39 | 40 | self.retranslateUi(SearchWidget) 41 | QtCore.QMetaObject.connectSlotsByName(SearchWidget) 42 | 43 | def retranslateUi(self, SearchWidget): 44 | _translate = QtCore.QCoreApplication.translate 45 | SearchWidget.setWindowTitle(_translate("SearchWidget", "Form")) 46 | self.lbl.setText(_translate("SearchWidget", "find: ")) 47 | self.btnNext.setText(_translate("SearchWidget", "▼")) 48 | self.btnPrev.setText(_translate("SearchWidget", "▲")) 49 | self.btnDone.setText(_translate("SearchWidget", "done")) 50 | 51 | -------------------------------------------------------------------------------- /test/showcache.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import sys 4 | import os.path 5 | import argparse 6 | import pickle 7 | import textwrap 8 | import pydoc 9 | from io import StringIO 10 | import locale 11 | 12 | sys.path += [os.path.realpath(os.path.join(os.path.dirname(__file__), '..'))] 13 | 14 | import bibolamazi.init 15 | 16 | from bibolamazi.core.bibusercache import BibUserCacheDic, BibUserCacheList 17 | 18 | 19 | parser = argparse.ArgumentParser('showcache') 20 | 21 | 22 | parser.add_argument('cachefile') 23 | 24 | 25 | args = parser.parse_args() 26 | 27 | cache = None 28 | with open(args.cachefile, 'rb') as f: 29 | cache = pickle.load(f) 30 | 31 | 32 | def dump_bibcacheobj(cacheobj, name=None, f=sys.stdout, indent=0, **kwargs): 33 | indent_step = kwargs.get('indent_step', 4) 34 | kwargs['f'] = f 35 | if isinstance(cacheobj, BibUserCacheDic): 36 | ncount = 0 37 | for (key, val) in cacheobj.dic.items(): 38 | if isinstance(key, str): 39 | skey = key 40 | else: 41 | skey = repr(key) 42 | f.write("\n" + " "*indent + skey + ": ") 43 | dump_bibcacheobj(val, name=key, indent=indent+indent_step, **kwargs) 44 | if key in cacheobj.tokens: 45 | f.write("\n" + " "*(indent+indent_step) + "{token: "+repr(cacheobj.tokens[key])+"}") 46 | ncount += 1 47 | if ncount > 10 and name: 48 | f.write("\n" + " "*indent + "[end of `%s' items]"%(name)) 49 | return 50 | if isinstance(cacheobj, BibUserCacheList): 51 | for val in cacheobj.lst: 52 | f.write("\n" + " "*indent + "* ") 53 | dump_bibcacheobj(val, name='', indent=indent+indent_step, **kwargs) 54 | return 55 | # display as string: 56 | s = str(cacheobj) 57 | if len(s) < 50: 58 | f.write(s) 59 | return 60 | 61 | #wrapper = textwrap.TextWrapper(width=90-indent, initial_indent=" "*indent, subsequent_indent=" "*indent) 62 | #f.write("\n" + wrapper.fill(s)) 63 | 64 | f.write("\n" + " "*indent + s.replace('\n', "\n"+" "*indent)) 65 | return 66 | 67 | 68 | f = StringIO() 69 | 70 | f.write("\n") 71 | f.write("Cache Dump\n") 72 | f.write("=" * 90 + "\n") 73 | f.write("Cache dump version: %s\n"%(cache['cachepickleversion'])) 74 | f.write("-" * 90 + "\n") 75 | 76 | dump_bibcacheobj(cache['cachedic'], f=f) 77 | 78 | f.write("\n" + "=" * 90 + "\n\n\n") 79 | 80 | encoding = locale.getdefaultlocale()[1]; 81 | pydoc.pager(f.getvalue()) 82 | 83 | sys.exit(0) 84 | -------------------------------------------------------------------------------- /test/full_cases/test9.bibolamazi.bib: -------------------------------------------------------------------------------- 1 | 2 | 3 | .. Additionnal stuff here will not be managed by bibolamazi. It will also not be 4 | .. overwritten. You can e.g. temporarily add additional references here if you 5 | .. don't have bibolamazi installed. 6 | 7 | 8 | %%%-BIB-OLA-MAZI-BEGIN-%%% 9 | % 10 | % %% This bibliography database uses BIBOLAMAZI: 11 | % %% 12 | % %% https://github.com/phfaist/bibolamazi 13 | % %% 14 | % %% See comments below this configuration section if you're new to bibolamazi. 15 | % 16 | % %% This is the BIBOLAMAZI configuration section. Additional two leading 17 | % %% percent signs indicate comments within the configuration. 18 | % 19 | % %% THIS TEST TESTS BOOL FILTER OPTIONS GIVEN AS --bool-option WITHOUT ARGS. 20 | % 21 | % %% **** SOURCES **** 22 | % 23 | % %% The _first_ accessible file in _each_ source list will be read 24 | % 25 | % src: srcbib/specialtests.bib 26 | % 27 | % %% Add additional sources here. Alternative files are useful, e.g., if the 28 | % %% same file is to be accessed with different paths on different machines. 29 | % 30 | % %% **** FILTERS **** 31 | % 32 | % %% Specify filters here. Specify as many filters as you want, each with a 33 | % %% `filter:' directive. See also `bibolamazi --list-filters' and 34 | % %% `bibolamazi --help ', or the "Help & Reference" page of the 35 | % %% graphical interface. 36 | % 37 | % filter: fixes --fix-space-after-escape --no-encode-utf8-to-latex --encode-latex-to-utf8=false 38 | % --no-remove-type-from-phd=false 39 | % 40 | % filter: nameinitials author editor -dOnlySingleLetterFirsts -dNamesToUtf8 41 | % 42 | %%%-BIB-OLA-MAZI-END-%%% 43 | 44 | % 45 | % This file was generated by BIBOLAMAZI 4.0b5 on 2019-01-05T00:21:08.439330 46 | % 47 | % https://github.com/phfaist/bibolamazi 48 | % 49 | % 50 | % ALL CHANGES BEYOND THIS POINT WILL BE LOST NEXT TIME BIBOLAMAZI IS RUN. 51 | % 52 | 53 | @article{specialentries, 54 | author = "Dupont, Jean and Xyz, João and Åserlund, Øvjsesen and Dvořak, Anotonin", 55 | abstract = "\c{c}edilla char is in name: Fran\c{c}ois P\'erusse. You Like \b{b}ars under \b{l}etters?", 56 | journal = "Nature", 57 | month = "June", 58 | number = "9000", 59 | pages = "161--163", 60 | publisher = "Nature Publishing Group, a division of Macmillan Publishers Limited. All Rights Reserved.", 61 | shorttitle = "Nature", 62 | title = "{The \o{}verfluctuatio\~n hyp\o{}thesis v\^erified foor qu\`antum pr\o{}cesses}", 63 | url = "http://dx.doi.org/10.1038/nature1234567", 64 | volume = "476", 65 | year = "2030" 66 | } 67 | -------------------------------------------------------------------------------- /gui/bibolamazi_gui/filterpackagepatheditor.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | FilterPackagePathEditor 4 | 5 | 6 | 7 | 0 8 | 0 9 | 309 10 | 390 11 | 12 | 13 | 14 | Form 15 | 16 | 17 | 18 | 19 | 20 | Qt::Vertical 21 | 22 | 23 | 24 | 20 25 | 40 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | Imported filter package 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 0 42 | 50 43 | 44 | 45 | 46 | background-color: rgba(0, 0, 120, 25); 47 | 48 | 49 | path 50 | 51 | 52 | Qt::RichText 53 | 54 | 55 | true 56 | 57 | 58 | 59 | 60 | 61 | 62 | set local python package ... 63 | 64 | 65 | 66 | 67 | 68 | 69 | set github repository ... 70 | 71 | 72 | 73 | 74 | 75 | 76 | Qt::Vertical 77 | 78 | 79 | 80 | 20 81 | 40 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /gui/bibolamazi_gui/pic/configlocalrepos.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 9 | 11 | 12 | 13 | 17 | 24 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /gui/bibolamazi_gui/qtauto/ui_filterpackagepatheditor.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Form implementation generated from reading ui file 'filterpackagepatheditor.ui' 4 | # 5 | # Created by: PyQt5 UI code generator 5.12.2 6 | # 7 | # WARNING! All changes made in this file will be lost! 8 | 9 | from PyQt5 import QtCore, QtGui, QtWidgets 10 | 11 | 12 | class Ui_FilterPackagePathEditor(object): 13 | def setupUi(self, FilterPackagePathEditor): 14 | FilterPackagePathEditor.setObjectName("FilterPackagePathEditor") 15 | FilterPackagePathEditor.resize(309, 390) 16 | self.verticalLayout = QtWidgets.QVBoxLayout(FilterPackagePathEditor) 17 | self.verticalLayout.setObjectName("verticalLayout") 18 | spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) 19 | self.verticalLayout.addItem(spacerItem) 20 | self.label = QtWidgets.QLabel(FilterPackagePathEditor) 21 | self.label.setObjectName("label") 22 | self.verticalLayout.addWidget(self.label) 23 | self.lblInfo = QtWidgets.QLabel(FilterPackagePathEditor) 24 | self.lblInfo.setMinimumSize(QtCore.QSize(0, 50)) 25 | self.lblInfo.setStyleSheet("background-color: rgba(0, 0, 120, 25);") 26 | self.lblInfo.setTextFormat(QtCore.Qt.RichText) 27 | self.lblInfo.setWordWrap(True) 28 | self.lblInfo.setObjectName("lblInfo") 29 | self.verticalLayout.addWidget(self.lblInfo) 30 | self.btnSetLocalPackage = QtWidgets.QPushButton(FilterPackagePathEditor) 31 | self.btnSetLocalPackage.setObjectName("btnSetLocalPackage") 32 | self.verticalLayout.addWidget(self.btnSetLocalPackage) 33 | self.btnSetGithubRepo = QtWidgets.QPushButton(FilterPackagePathEditor) 34 | self.btnSetGithubRepo.setObjectName("btnSetGithubRepo") 35 | self.verticalLayout.addWidget(self.btnSetGithubRepo) 36 | spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) 37 | self.verticalLayout.addItem(spacerItem1) 38 | 39 | self.retranslateUi(FilterPackagePathEditor) 40 | QtCore.QMetaObject.connectSlotsByName(FilterPackagePathEditor) 41 | 42 | def retranslateUi(self, FilterPackagePathEditor): 43 | _translate = QtCore.QCoreApplication.translate 44 | FilterPackagePathEditor.setWindowTitle(_translate("FilterPackagePathEditor", "Form")) 45 | self.label.setText(_translate("FilterPackagePathEditor", "Imported filter package")) 46 | self.lblInfo.setText(_translate("FilterPackagePathEditor", "path")) 47 | self.btnSetLocalPackage.setText(_translate("FilterPackagePathEditor", "set local python package ...")) 48 | self.btnSetGithubRepo.setText(_translate("FilterPackagePathEditor", "set github repository ...")) 49 | 50 | 51 | -------------------------------------------------------------------------------- /gui/bibolamazi_gui/qtauto/ui_githubauthenticationdialog.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Form implementation generated from reading ui file 'githubauthenticationdialog.ui' 4 | # 5 | # Created by: PyQt5 UI code generator 5.12.2 6 | # 7 | # WARNING! All changes made in this file will be lost! 8 | 9 | from PyQt5 import QtCore, QtGui, QtWidgets 10 | 11 | 12 | class Ui_GithubAuthenticationDialog(object): 13 | def setupUi(self, GithubAuthenticationDialog): 14 | GithubAuthenticationDialog.setObjectName("GithubAuthenticationDialog") 15 | GithubAuthenticationDialog.resize(511, 535) 16 | self.verticalLayout = QtWidgets.QVBoxLayout(GithubAuthenticationDialog) 17 | self.verticalLayout.setObjectName("verticalLayout") 18 | spacerItem = QtWidgets.QSpacerItem(20, 189, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) 19 | self.verticalLayout.addItem(spacerItem) 20 | self.lbl = QtWidgets.QLabel(GithubAuthenticationDialog) 21 | self.lbl.setTextFormat(QtCore.Qt.RichText) 22 | self.lbl.setWordWrap(True) 23 | self.lbl.setOpenExternalLinks(True) 24 | self.lbl.setTextInteractionFlags(QtCore.Qt.LinksAccessibleByMouse|QtCore.Qt.TextSelectableByMouse) 25 | self.lbl.setObjectName("lbl") 26 | self.verticalLayout.addWidget(self.lbl) 27 | spacerItem1 = QtWidgets.QSpacerItem(20, 10, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) 28 | self.verticalLayout.addItem(spacerItem1) 29 | self.txtToken = QtWidgets.QLineEdit(GithubAuthenticationDialog) 30 | self.txtToken.setObjectName("txtToken") 31 | self.verticalLayout.addWidget(self.txtToken) 32 | spacerItem2 = QtWidgets.QSpacerItem(20, 188, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) 33 | self.verticalLayout.addItem(spacerItem2) 34 | self.btns = QtWidgets.QDialogButtonBox(GithubAuthenticationDialog) 35 | self.btns.setOrientation(QtCore.Qt.Horizontal) 36 | self.btns.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) 37 | self.btns.setObjectName("btns") 38 | self.verticalLayout.addWidget(self.btns) 39 | 40 | self.retranslateUi(GithubAuthenticationDialog) 41 | self.btns.rejected.connect(GithubAuthenticationDialog.reject) 42 | self.btns.accepted.connect(GithubAuthenticationDialog.accept) 43 | QtCore.QMetaObject.connectSlotsByName(GithubAuthenticationDialog) 44 | 45 | def retranslateUi(self, GithubAuthenticationDialog): 46 | _translate = QtCore.QCoreApplication.translate 47 | GithubAuthenticationDialog.setWindowTitle(_translate("GithubAuthenticationDialog", "Github Authentication")) 48 | self.lbl.setText(_translate("GithubAuthenticationDialog", "Instructions to authenticate: .....")) 49 | 50 | 51 | -------------------------------------------------------------------------------- /doc/create-filter-package.rst: -------------------------------------------------------------------------------- 1 | .. _create-filter-package: 2 | 3 | Creating a new filter package 4 | ============================= 5 | 6 | Creating a filter package is as easy as creating a directory and putting an 7 | empty ``__init__.py`` file in there. That's it. That's your minimal Python 8 | package. 9 | 10 | For instance, let us create a filter package called `mypackage`. Create a 11 | folder called `mypackage`. Then create an empty file called ``__init__.py`` in 12 | that folder. Instead of `mypackage`, you may use the name that you like. Keep 13 | in mind, though, that filter package names must be valid Python identifiers, so 14 | you need to avoid hyphens, spaces, and accents; you should only use letters, 15 | underscores and digits, and the name can't start with a digit. 16 | 17 | Then you can put other python files in the package (say ``myfirstfilter.py`` and 18 | ``mysecondfilter.py``), which define filters. The Python file name without the 19 | `.py` extension is the name of the filter that you can use in the bibolamazi 20 | file. For instance, we sould have the following file structure:: 21 | 22 | mypackage/ 23 | - __init__.py (empty file) 24 | - myfirstfilter.py (definition of filter myfirstfilter) 25 | - mysecondfilter.py (definition of filter mysecondfilter) 26 | 27 | You can then import this filter package in your bibolamazi file using, for 28 | instance, the directive:: 29 | 30 | package: /path/to/mypackage 31 | 32 | You can then use `myfirstfilter` and `mysecondfilter` as normal filters in your 33 | bibolamazi file. In the following sections, we'll detail how to write custom 34 | filters so that they can do useful stuff, i.e., we'll see how we should go about 35 | to code the contents of ``myfirstfilter.py`` and ``mysecondfilter.py``. 36 | 37 | 38 | Distributing the filter package as a github repository 39 | ------------------------------------------------------ 40 | 41 | You can share your filters by creating a github repository to share your 42 | filters. The repository must be structured in one of two ways: 43 | 44 | * The repository itself contains a folder which is the python package, which 45 | itself contains the ``__init__.py`` file. The python package must have the 46 | same name as the repository, with hyphens converted to underscores. 47 | 48 | * The repository may be the python package itself, i.e., there is a 49 | ``__init__.py`` file at the root of the repository. 50 | 51 | Create the repository in this way, and then others can use your filters 52 | automatically by including the directive:: 53 | 54 | package: github:username/repo 55 | 56 | You can even keep the repository private, and allow access to your friends; if 57 | your friends configure github authentication within bibolamazi :ref:`as 58 | explained here `, then they can directly access your 59 | filters with the same directive. 60 | -------------------------------------------------------------------------------- /gui/bibolamazi_gui/qtauto/ui_sourcelisteditor.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Form implementation generated from reading ui file 'sourcelisteditor.ui' 4 | # 5 | # Created by: PyQt5 UI code generator 5.7.1 6 | # 7 | # WARNING! All changes made in this file will be lost! 8 | 9 | from PyQt5 import QtCore, QtGui, QtWidgets 10 | 11 | class Ui_SourceListEditor(object): 12 | def setupUi(self, SourceListEditor): 13 | SourceListEditor.setObjectName("SourceListEditor") 14 | SourceListEditor.resize(382, 462) 15 | self.gridLayout = QtWidgets.QGridLayout(SourceListEditor) 16 | self.gridLayout.setVerticalSpacing(20) 17 | self.gridLayout.setObjectName("gridLayout") 18 | self.btnAddSource = QtWidgets.QPushButton(SourceListEditor) 19 | self.btnAddSource.setObjectName("btnAddSource") 20 | self.gridLayout.addWidget(self.btnAddSource, 2, 0, 1, 2) 21 | self.btnAddFavorite = QtWidgets.QPushButton(SourceListEditor) 22 | icon = QtGui.QIcon() 23 | icon.addPixmap(QtGui.QPixmap(":/pic/bookmark.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) 24 | self.btnAddFavorite.setIcon(icon) 25 | self.btnAddFavorite.setObjectName("btnAddFavorite") 26 | self.gridLayout.addWidget(self.btnAddFavorite, 5, 0, 1, 2) 27 | self.lbl = QtWidgets.QLabel(SourceListEditor) 28 | self.lbl.setMinimumSize(QtCore.QSize(0, 100)) 29 | self.lbl.setText("") 30 | self.lbl.setTextFormat(QtCore.Qt.RichText) 31 | self.lbl.setWordWrap(True) 32 | self.lbl.setObjectName("lbl") 33 | self.gridLayout.addWidget(self.lbl, 0, 0, 1, 2) 34 | spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) 35 | self.gridLayout.addItem(spacerItem, 3, 0, 1, 1) 36 | self.lblLinkInfo = QtWidgets.QLabel(SourceListEditor) 37 | self.lblLinkInfo.setAutoFillBackground(False) 38 | self.lblLinkInfo.setStyleSheet("QLabel { font-style: italic; background-color: rgba(0,0,0,10%); }") 39 | self.lblLinkInfo.setText("") 40 | self.lblLinkInfo.setWordWrap(True) 41 | self.lblLinkInfo.setObjectName("lblLinkInfo") 42 | self.gridLayout.addWidget(self.lblLinkInfo, 1, 0, 1, 2) 43 | 44 | self.retranslateUi(SourceListEditor) 45 | QtCore.QMetaObject.connectSlotsByName(SourceListEditor) 46 | 47 | def retranslateUi(self, SourceListEditor): 48 | _translate = QtCore.QCoreApplication.translate 49 | SourceListEditor.setWindowTitle(_translate("SourceListEditor", "Form")) 50 | self.btnAddSource.setText(_translate("SourceListEditor", "Add Independent Source")) 51 | self.btnAddFavorite.setToolTip(_translate("SourceListEditor", "Add this source list to your favorites")) 52 | self.btnAddFavorite.setText(_translate("SourceListEditor", "add souce && alternatives to favorites")) 53 | 54 | from . import bibolamazi_res_rc 55 | -------------------------------------------------------------------------------- /gui/bibolamazi_gui/sourcelisteditor.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | SourceListEditor 4 | 5 | 6 | 7 | 0 8 | 0 9 | 382 10 | 462 11 | 12 | 13 | 14 | Form 15 | 16 | 17 | 18 | 20 19 | 20 | 21 | 22 | 23 | Add Independent Source 24 | 25 | 26 | 27 | 28 | 29 | 30 | Add this source list to your favorites 31 | 32 | 33 | add souce && alternatives to favorites 34 | 35 | 36 | 37 | :/pic/bookmark.png:/pic/bookmark.png 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 0 46 | 100 47 | 48 | 49 | 50 | 51 | 52 | 53 | Qt::RichText 54 | 55 | 56 | true 57 | 58 | 59 | 60 | 61 | 62 | 63 | Qt::Vertical 64 | 65 | 66 | 67 | 20 68 | 40 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | false 77 | 78 | 79 | QLabel { font-style: italic; background-color: rgba(0,0,0,10%); } 80 | 81 | 82 | 83 | 84 | 85 | true 86 | 87 | 88 | 15 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | 3 | import sys 4 | 5 | if sys.version_info < (3, 4): 6 | raise RuntimeError("Bibolamazi requires Python >= 3.4") 7 | 8 | #import bibolamazi.init # -- don't make the setup.py crash because some packages 9 | #e.g. pybtex aren't available 10 | from bibolamazi.core.version import version_str as bibolamaziversion_str 11 | 12 | sys.stderr.write(""" 13 | Welcome to the setup.py script for Bibolamazi. This setup.py script will only 14 | take care of compiling/installing the basic bibolamazi package and command-line 15 | utility. For the graphical interface, use the `setup.py` script located in the 16 | `gui/` directory, or download a precompiled version from 17 | `https://github.com/phfaist/bibolamazi/releases/`. 18 | 19 | """) 20 | 21 | 22 | # see http://stackoverflow.com/a/14399775/1694896 23 | def _parse_requires(fn): 24 | """ 25 | Parse PIP requirements given in that file. Nothing special, just splits lines and 26 | ignores those which start by '#'. 27 | """ 28 | with open(fn) as f: 29 | required = f.read().splitlines() 30 | return [ r 31 | for r in required 32 | if r.strip() and r.lstrip()[:1] != '#' 33 | ] 34 | 35 | 36 | install_requires = _parse_requires('pip_requirements.txt'), 37 | # 38 | sys.stderr.write("(Requirements: %s)\n\n\n" % (install_requires)) 39 | 40 | 41 | packages = find_packages(include=['bibolamazi', 'bibolamazi.*'], 42 | exclude=['bibolamazi_gui', 'bibolamazi_gui.*']) 43 | #print("packages = %r"%packages) 44 | 45 | setup( 46 | name = "bibolamazi", 47 | version = bibolamaziversion_str, 48 | 49 | # metadata for upload to PyPI 50 | author = "Philippe Faist", 51 | author_email = "philippe.faist@bluewin.ch", 52 | description = "Prepare consistent BibTeX files for your LaTeX documents", 53 | license = "GPL v3+", 54 | keywords = "bibtex latex bibliography consistent tidy formatting", 55 | url = "https://github.com/phfaist/bibolamazi/", 56 | classifiers=[ 57 | 'Development Status :: 5 - Production/Stable', 58 | 'License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)', 59 | 'Programming Language :: Python', 60 | 'Operating System :: OS Independent', 61 | 'Intended Audience :: Science/Research', 62 | 'Topic :: Scientific/Engineering', 63 | 'Topic :: Text Editors :: Text Processing', 64 | 'Topic :: Text Processing :: General', 65 | ], 66 | 67 | # could also include long_description, download_url, classifiers, etc. 68 | 69 | packages = packages, 70 | zip_safe = True, 71 | 72 | #scripts = ['bin/bibolamazi'], 73 | entry_points = { 74 | 'console_scripts': ['bibolamazi=bibolamazi.core.main:main'], 75 | }, 76 | 77 | install_requires = install_requires, 78 | 79 | package_data = { 80 | # If any package contains *.txt or *.rst files, include them: 81 | #'': ['*.txt', '*.rst'], 82 | # And include any *.msg files found in the 'hello' package, too: 83 | #'hello': ['*.msg'], 84 | }, 85 | 86 | 87 | ) 88 | -------------------------------------------------------------------------------- /test/test_filters_citeinspirehep.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import unittest 4 | import logging 5 | import tempfile 6 | import os.path 7 | import re 8 | import shutil 9 | 10 | from pybtex.database import Entry, Person, BibliographyData 11 | 12 | from bibolamazi.core import blogger 13 | from helpers import CustomAssertions 14 | from bibolamazi.filters.citeinspirehep import CiteInspireHEPFilter 15 | from bibolamazi.core.bibolamazifile import BibolamaziFile 16 | 17 | logger = logging.getLogger(__name__) 18 | 19 | 20 | class TestWorks(unittest.TestCase, CustomAssertions): 21 | 22 | def __init__(self, *args, **kwargs): 23 | super().__init__(*args, **kwargs) 24 | 25 | self.maxDiff = None 26 | 27 | @unittest.skip("Doesn't work for some reason") 28 | def test_fetch_basic(self): 29 | 30 | bf = BibolamaziFile(create=True) 31 | bf.setEntries([]) 32 | 33 | test_keys = [ 34 | "inspire:Phys.Rev.+47+777", 35 | "inspire:1305.1258--WWgg", 36 | "inspire:10.1103/PhysRev.47.777", 37 | "inspire:1408.4546,inspire:10.1103/PhysRev.47.777--EPR-paper", 38 | "inspire:hep-th/0001001", 39 | "inspire:1408.4546", 40 | "inspire:Phys.Rev.D.+66+010001", 41 | "inspire:Hagiwara:2002fs", 42 | "inspire:Nakamura:2010zzi", 43 | "inspire:RX-1037", 44 | "inspire:1302.0378", 45 | "inspire:'tHooft:1972fi", 46 | "inspire:Camb.Monogr.Part.Phys.Nucl.Phys.Cosmol.+8+1", 47 | ] 48 | 49 | tmpdir = tempfile.mkdtemp() 50 | try: 51 | # create fake aux file in that temp dir 52 | with open(os.path.join(tmpdir, 'testjobname.aux'), 'w') as auxf: 53 | auxf.write("\n".join([ 54 | r"""\citation{%s}"""%(inspirekey) 55 | for inspirekey in test_keys 56 | ])) 57 | 58 | filt = CiteInspireHEPFilter(jobname='testjobname', search_dirs=[tmpdir]) 59 | bf.registerFilterInstance(filt) 60 | 61 | filt.filter_bibolamazifile(bf) 62 | 63 | bibdata = bf.bibliographyData() 64 | 65 | logger.debug("bibdata = %r", bibdata) 66 | 67 | self.assertEqual(len(bibdata.entries), len(test_keys)) 68 | for keylist in test_keys: 69 | for key in keylist.split(','): 70 | self.assertIn(key, bibdata.entries) 71 | 72 | # see if the entries were populated correctly (probe these random parts:) 73 | EPR = bibdata.entries['inspire:Phys.Rev.+47+777'] 74 | self.assertTrue(len(EPR.persons['author']) == 3) 75 | self.assertEqual( [ " ".join(p.last_names) for p in EPR.persons['author'] ], 76 | ["Einstein", "Podolsky", "Rosen"] ) 77 | 78 | WWgg = bibdata.entries['inspire:1305.1258--WWgg'] 79 | self.assertTrue(WWgg.fields['doi'] == '10.1103/PhysRevD.88.012005') 80 | 81 | finally: 82 | shutil.rmtree(tmpdir) 83 | 84 | 85 | 86 | 87 | if __name__ == '__main__': 88 | blogger.setup_simple_console_logging(level=logging.DEBUG) 89 | unittest.main() 90 | -------------------------------------------------------------------------------- /gui/bibolamazi_gui/pic/remoterepos.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 10 | 13 | 17 | 18 | 19 | 23 | 30 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /doc/download-and-install.rst: -------------------------------------------------------------------------------- 1 | .. _download-and-install: 2 | 3 | Downloading and Installing Bibolamazi 4 | ------------------------------------- 5 | 6 | Bibolamazi comes in two flavors: 7 | 8 | - an Application that runs on Mac OS X, Linux and Windows (this is what most 9 | users probably want) 10 | 11 | - a command-line tool (for more advanced and automated usage) 12 | 13 | There are precompiled ready-for-use binaries for the Application (see below, 14 | :ref:`bibolamazi_application`). Alternatively, both flavors may be installed 15 | using ``pip``/``setuptools`` or from source (see 16 | :ref:`bibolamazi_installing_cmdl`). 17 | 18 | .. _bibolamazi_application: 19 | 20 | The Bibolamazi Application 21 | ~~~~~~~~~~~~~~~~~~~~~~~~~~ 22 | 23 | If you're unsure which flavor to get, this is the one you're looking for. It's 24 | straightfoward to download, there is no installation required, and the 25 | application is easy to use. 26 | 27 | Download the latest release from our releases page: 28 | 29 | **Download Release:** https://github.com/phfaist/bibolamazi/releases 30 | 31 | These binaries don't need any installation, you can just download them, place 32 | them wherever you want, and run them. 33 | 34 | You may now start using Bibolamazi normally. To read more on bibolamazi, skip to 35 | :ref:`using-bibolamazi-app`. 36 | 37 | 38 | .. _bibolamazi_installing_cmdl: 39 | 40 | Installing the Command-Line Interface 41 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 42 | 43 | Bibolamazi runs with Python 3 (this is there by default on most linux and Mac 44 | systems). 45 | 46 | Additionally, the graphical user interface requires PyQt5_. You can do this 47 | usually with ``pip install pyqt5``. If you're on a linux distribution, it's most 48 | probably in your distribution packages. Note you only need PyQt5 to run the 49 | graphical user interface: the command-line version will happily run without. 50 | 51 | **The easy way: via PIP** 52 | 53 | The recommended way to install Bibolamazi command line and gui interfaces is via 54 | ``pip``:: 55 | 56 | pip install bibolamazi # for the command-line interface 57 | pip install bibolamazigui # if you want the GUI interface 58 | 59 | After that, you'll find the ``bibolamazi`` (respectively ``bibolamazi_gui``) 60 | executables in your PATH:: 61 | 62 | > bibolamazi --help # command-line interface 63 | (...) 64 | > bibolamazi_gui # to launch the GUI 65 | (...) 66 | 67 | 68 | **The less easy way: From Source** 69 | 70 | You may, alternatively, download and compile the packages from source. 71 | 72 | - First, clone this repository on your computer:: 73 | 74 | > cd somewhere/where/I/want/to/keep/bibolamazi/ 75 | ...> git clone https://github.com/phfaist/bibolamazi 76 | 77 | - Then, run the setup script to install the package and script (see `Installing 78 | Python Modules `_):: 79 | 80 | > python setup.py install 81 | 82 | After that, you should find the ``bibolamazi`` executable in your PATH 83 | automatically:: 84 | 85 | > bibolamazi --help 86 | 87 | - If you want to install the GUI Application, you need to do that seperately. Go 88 | into the ``gui/`` directory of the source code, and run the python setup 89 | script there:: 90 | 91 | > cd gui/ 92 | gui> python setup.py install 93 | 94 | After that, you should find the ``bibolamazi_gui`` executable in your PATH 95 | automatically:: 96 | 97 | > bibolamazi_gui 98 | 99 | 100 | .. _PyQt5: https://www.riverbankcomputing.com/software/pyqt/download5 101 | .. _precompiled binary release: https://github.com/phfaist/bibolamazi/releases 102 | -------------------------------------------------------------------------------- /test/helpers.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import os 4 | import logging 5 | import unittest 6 | logger = logging.getLogger(__name__) 7 | 8 | from bibolamazi.core import butils 9 | 10 | from pybtex.database import Entry, Person, BibliographyData 11 | 12 | 13 | # some set-up 14 | def test_requires_github_access(): 15 | do_skip = butils.getbool(os.environ.get("BIBOLAMAZI_TESTS_SKIP_GITHUB_ACCESS", False)) 16 | return unittest.skipIf( 17 | do_skip, 18 | "Environment variable BIBOLAMAZI_TESTS_SKIP_GITHUB_ACCESS is set" 19 | ) 20 | 21 | 22 | 23 | 24 | # see https://stackoverflow.com/a/15868615/1694896 25 | 26 | def fmt_dbg_entry(e, linefmt=' {field}: "{value}"'): 27 | allfields = list(e.fields.items()) 28 | for role in ('editor', 'author'): 29 | if role in e.persons: 30 | alist = [str(a) for a in e.persons[role]] 31 | allfields = [ (role, "; ".join(alist)) ] + allfields 32 | 33 | return "\n".join([ linefmt.format(field=f,value=v) for f,v in allfields ]) 34 | 35 | 36 | class CustomAssertions: 37 | 38 | def assertEqual(self, a, b, msg=None): 39 | if isinstance(a, Entry) and isinstance(b, Entry): 40 | self.assert_entries_equal(a, b) 41 | 42 | if isinstance(a, BibliographyData) and isinstance(b, BibliographyData): 43 | self.assert_keyentrylists_equal(list(a.entries.items()), list(b.entries.items()), msg=msg) 44 | 45 | return super().assertEqual(a, b, msg=msg) 46 | 47 | 48 | def assert_entries_equal(self, e1, e2, **kwargs): 49 | 50 | self.assertEqual(e1.type, e2.type) 51 | 52 | for role in 'author', 'editor': 53 | self.assertEqual(role in e1.persons, role in e2.persons, 54 | msg="mismatch in presence of persons role '{}'".format(role)) 55 | if role in e1.persons: 56 | self.assertListEqual(e1.persons[role], e2.persons[role]) 57 | 58 | self.assertDictEqual(dict(e1.fields), dict(e2.fields), **kwargs) 59 | 60 | 61 | def assert_keyentrylists_equal(self, l1, l2, order=True, msg=None): 62 | 63 | #logger.debug("assert_keyentrylists_equal (%d,%d)"%(len(l1),len(l2))) 64 | 65 | def domsg(x, msg=msg): 66 | if msg: 67 | return x + '\n --- ' + msg 68 | return x 69 | 70 | if not order: 71 | # if order doesn't count, then sort both lists according to key 72 | l1 = sorted(l1, key=lambda x: x[0]) 73 | l2 = sorted(l2, key=lambda x: x[0]) 74 | 75 | if len(l1) != len(l2): 76 | # find which keys are not in each other's lists 77 | kl1 = set(dict(l1).keys()) 78 | kl2 = set(dict(l2).keys()) 79 | common = kl1 & kl2 80 | raise self.failureException(domsg(("List lengths differ, {} != {}.\n" 81 | "Keys in 1 not in 2 = {!r}\n" 82 | "Keys in 2 not in 1 = {!r}") 83 | .format(len(l1), len(l2), kl1 - common, kl2 - common))) 84 | 85 | for n in range(len(l1)): 86 | 87 | self.assertEqual(len(l1[n]), 2, msg=domsg("Entry #{} isn't 2-tuple".format(n))) 88 | self.assertEqual(len(l2[n]), 2, msg=domsg("Entry #{} isn't 2-tuple".format(n))) 89 | 90 | #logger.debug("Checking entry (%s,%s)"%(l1[n][0],l1[n][1])) 91 | 92 | self.assertEqual(l1[n][0], l2[n][0], 93 | msg=domsg("Entry keys differ {!r} != {!r}".format(l1[n][0],l2[n][0]))) 94 | self.assert_entries_equal(l1[n][1], l2[n][1], 95 | msg=domsg("Entry #{} '{}' differs".format(n, l1[n][0]))) 96 | -------------------------------------------------------------------------------- /gui/bibolamazi_gui/githubauthenticationdialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | GithubAuthenticationDialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 511 10 | 535 11 | 12 | 13 | 14 | Github Authentication 15 | 16 | 17 | 18 | 19 | 20 | Qt::Vertical 21 | 22 | 23 | 24 | 20 25 | 189 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | Instructions to authenticate: ..... 34 | 35 | 36 | Qt::RichText 37 | 38 | 39 | true 40 | 41 | 42 | true 43 | 44 | 45 | Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse 46 | 47 | 48 | 49 | 50 | 51 | 52 | Qt::Vertical 53 | 54 | 55 | QSizePolicy::Fixed 56 | 57 | 58 | 59 | 20 60 | 10 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | Qt::Vertical 72 | 73 | 74 | 75 | 20 76 | 188 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | Qt::Horizontal 85 | 86 | 87 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | btns 97 | rejected() 98 | GithubAuthenticationDialog 99 | reject() 100 | 101 | 102 | 292 103 | 387 104 | 105 | 106 | 286 107 | 274 108 | 109 | 110 | 111 | 112 | btns 113 | accepted() 114 | GithubAuthenticationDialog 115 | accept() 116 | 117 | 118 | 362 119 | 376 120 | 121 | 122 | 376 123 | 277 124 | 125 | 126 | 127 | 128 | 129 | -------------------------------------------------------------------------------- /test/test_filters_nameinitials.py: -------------------------------------------------------------------------------- 1 | 2 | from __future__ import print_function, unicode_literals 3 | from builtins import str as unicodestr 4 | 5 | import unittest 6 | 7 | from pybtex.database import Entry, Person 8 | from bibolamazi.filters.nameinitials import NameInitialsFilter 9 | 10 | 11 | class TestWorks(unittest.TestCase): 12 | 13 | def test_1(self): 14 | entry = Entry('article', fields={'url': 'https://example.com/doi/xfkdnsafldasknf'}, 15 | persons={'author': [Person('Albert Einstein'), 16 | Person('B. Podolsky'), 17 | Person('N Rosen')]}) 18 | n = NameInitialsFilter() 19 | n.filter_bibentry(entry) 20 | self.assertEqual(unicodestr(entry.persons['author'][0]), 'Einstein, A.') 21 | self.assertEqual(unicodestr(entry.persons['author'][1]), 'Podolsky, B.') 22 | self.assertEqual(unicodestr(entry.persons['author'][2]), 'Rosen, N.') 23 | 24 | def test_2(self): 25 | entry = Entry('article', fields={'url': 'https://example.com/doi/xfkdnsafldasknf'}, 26 | persons={'author': [Person('Albert Einstein'), 27 | Person('B. Podolsky'), 28 | Person('N Rosen')]}) 29 | n = NameInitialsFilter(only_single_letter_firsts='True') 30 | n.filter_bibentry(entry) 31 | self.assertEqual(unicodestr(entry.persons['author'][0]), 'Einstein, Albert') 32 | self.assertEqual(unicodestr(entry.persons['author'][1]), 'Podolsky, B.') 33 | self.assertEqual(unicodestr(entry.persons['author'][2]), 'Rosen, N.') 34 | 35 | def test_3(self): 36 | entry = Entry('article', fields={'url': 'https://example.com/doi/xfkdnsafldasknf'}, 37 | persons={'author': [Person("Dupont, Fran\\c cois"), 38 | Person('\\AA sm\\"ussen, Erik'), 39 | Person("Fr\\'ed\\'eric Dupond"), 40 | Person("{\\AA sm\\o ssen}, Erik"), 41 | Person("{Van \\AA sm\\o ssen}, Erik"), 42 | Person("Cr{\\'e}peau, Claude"), 43 | Person("Alhambra, {\\'A}lvaro"), 44 | Person("Dupuis, Fr\\'ed{\\'e}ric"), 45 | Person("Brand{\\~{a}}o, F."),]}) 46 | n = NameInitialsFilter(names_to_utf8=True) 47 | n.filter_bibentry(entry) 48 | self.assertEqual(unicodestr(entry.persons['author'][0]), 'Dupont, F.') 49 | self.assertEqual(unicodestr(entry.persons['author'][1]), u'\N{LATIN CAPITAL LETTER A WITH RING ABOVE}sm\N{LATIN SMALL LETTER U WITH DIAERESIS}ssen, E.') 50 | self.assertEqual(unicodestr(entry.persons['author'][2]), 'Dupond, F.') 51 | self.assertEqual(unicodestr(entry.persons['author'][3]), '{\N{LATIN CAPITAL LETTER A WITH RING ABOVE}sm\N{LATIN SMALL LETTER O WITH STROKE}ssen}, E.') 52 | self.assertEqual(unicodestr(entry.persons['author'][4]), '{Van \N{LATIN CAPITAL LETTER A WITH RING ABOVE}sm\N{LATIN SMALL LETTER O WITH STROKE}ssen}, E.') 53 | self.assertEqual(unicodestr(entry.persons['author'][5]), 'Cr\N{LATIN SMALL LETTER E WITH ACUTE}peau, C.') 54 | self.assertEqual(unicodestr(entry.persons['author'][6]), 'Alhambra, \N{LATIN CAPITAL LETTER A WITH ACUTE}.') 55 | self.assertEqual(unicodestr(entry.persons['author'][7]), 'Dupuis, F.') 56 | self.assertEqual(unicodestr(entry.persons['author'][8]), 'Brand\N{LATIN SMALL LETTER A WITH TILDE}o, F.') 57 | 58 | 59 | if __name__ == '__main__': 60 | from bibolamazi.core import blogger 61 | blogger.setup_simple_console_logging(level=1) 62 | unittest.main() 63 | -------------------------------------------------------------------------------- /doc/using-bibolamazi-app.rst: -------------------------------------------------------------------------------- 1 | 2 | .. _using-bibolamazi-app: 3 | 4 | Using the Bibolamazi Application 5 | ================================ 6 | 7 | Bibolamazi Operating Mode 8 | ------------------------- 9 | 10 | Bibolamazi works by reading your reference bibtex files---the 'sources', which might for 11 | example have been generated by your favorite bibliography manager or provided by your 12 | collaborators---and merging them all into a new file, applying specific rules, or 13 | 'filters', such as turning all the first names into initials or normalizing the way arxiv 14 | IDs are presented. 15 | 16 | The Bibolamazi file is this new file, in which all the required bibtex entries will be 17 | merged. When you prepare you LaTeX document, you should create a new bibolamazi file, and 18 | provide that bibolamazi file as the bibtex file for the bibliography. 19 | 20 | When you open a bibolamazi file, you will be prompted to edit its configuration. This is 21 | the set of rules which will tell bibolamazi where to look for your bibtex entries and how 22 | to handle them. You first need to specify all your sources, and then all the filters. 23 | 24 | The bibolamazi file is then a valid BibTeX file to include into your LaTeX document, so if 25 | your bibolamazi file is named ``main.bibolamazi.bib``, you would include the bibliography 26 | in your document with a LaTeX command similar to:: 27 | 28 | \bibliography{main.bibolamazi} 29 | 30 | 31 | Getting Started 32 | --------------- 33 | 34 | The easiest way to get started is to open the bibolamazi graphical application, 35 | and click on "Create new bibolamazi file". A sequence of prompts will allow you 36 | to specify where your source bibtex files are, and how you'd like to 37 | standardize/normalize/transform those entries. Finally, you will be asked where 38 | to save the new bibolamazi file. Then, the file will be opened for you. 39 | 40 | The code that is displayed is the bibolamazi configuration section. The 41 | Bibolamazi program reads this configuration section and parses the corresponding 42 | instructions in order fetch and perform the necessary tasks on your bibliography 43 | entries. The new file will already contain a valid configuration section. 44 | 45 | Try the "Run Bibolamazi" button at the top: This should run the given filters on 46 | the source files you have specified. In order to view the run-time messages, 47 | click on the "Messages" tab on the lower part of the window. 48 | 49 | You can view the resulting, processed bibtex entries in the "Preview Bibtex 50 | Entries" tab. The "Bibolamazi File Info" tab contains some general information 51 | about the parsed configuration section. 52 | 53 | You may edit the configuration section if you are not happy with the results. 54 | In the configuration section, lines that start with ``filter:`` instruct 55 | bibolamazi to apply a filter to all the bibliography entries. The word 56 | immediately after ``filter:`` (for instance, ``filter: arxiv``) specifies which 57 | filter to apply. The rest of the line are options which alter the filter's behavior. 58 | 59 | For instance, click on a line that starts with ``filter:``. The right part of 60 | the screen will change so that you can select different options for that filter. 61 | If you click on an option in the table, you will see a description of what that 62 | option does below the table. Double-click on the right part of the table to 63 | edit an option's value. 64 | 65 | Don't forget to include the bibolamazi file in place of your bibliography in 66 | your LaTeX document. So, if the bibolamazi file is named 67 | ``main.bibolamazi.bib``, include a line like so in your LaTeX document:: 68 | 69 | \bibliography{main.bibolamazi} 70 | 71 | 72 | Editing the configuration section 73 | --------------------------------- 74 | 75 | For precise instructions on the configuration section, see 76 | :ref:`bibolamazi-configuration-section`. 77 | -------------------------------------------------------------------------------- /gui/setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | 3 | import sys 4 | import os # os.listdir 5 | import os.path 6 | sys.path.insert(0, os.path.realpath(os.path.join(os.path.realpath(os.path.dirname(__file__)), '..'))) 7 | 8 | #import bibolamazi.init # -- don't make the setup.py crash because some packages 9 | #e.g. pybtex aren't available 10 | #from bibolamazi.core import version as bibolamaziversion 11 | from bibolamazi_gui import version as bibolamaziversion 12 | 13 | # sys.stderr.write(""" 14 | # NOTE: You'll have to make sure that `PyQt5` is installed in order to use 15 | # `bibolamazi_gui`. We unfortunately can't install this requirement automatically 16 | # when you run `pip install` because of technical issues. 17 | # 18 | # """) # "technical issues" == https://stackoverflow.com/a/4628806/1694896 19 | 20 | try: 21 | import PyQt5 22 | except ImportError: 23 | sys.stderr.write("Please install PyQt5, for instance by running:\n\n pip install pyqt5\n\n") 24 | raise RuntimeError("PyQt5 required") 25 | 26 | 27 | def gen_icon_data_files(): 28 | iconthmdir = 'hicolor' 29 | localbase = 'data/icons' 30 | destbase = 'share/icons' 31 | for res in os.listdir(os.path.join(localbase, iconthmdir)): 32 | resdir = os.path.join(iconthmdir, res) 33 | for cat in os.listdir(os.path.join(localbase, resdir)): 34 | catdir = os.path.join(resdir, cat) 35 | yield (os.path.join(destbase, catdir), 36 | [ os.path.join(localbase, catdir, x) 37 | for x in os.listdir(os.path.join(localbase, catdir)) ]) 38 | 39 | # https://stackoverflow.com/a/44462146/1694896 40 | if sys.platform.startswith('win') or sys.platform.startswith('darwin'): 41 | data_files = [] 42 | else: 43 | data_files = [ 44 | ('share/applications', ['data/bibolamazigui.desktop']), 45 | ] + list(gen_icon_data_files()) 46 | print("Data files = ", data_files) 47 | 48 | 49 | setup( 50 | name = "bibolamazigui", 51 | version = bibolamaziversion.version_str, 52 | 53 | # metadata for upload to PyPI 54 | author = "Philippe Faist", 55 | author_email = "philippe.faist@bluewin.ch", 56 | description = "Prepare consistent BibTeX files for your LaTeX documents", 57 | license = "GPL v3+", 58 | keywords = "bibtex latex bibliography consistent tidy formatting", 59 | url = "https://github.com/phfaist/bibolamazi", 60 | classifiers=[ 61 | 'Development Status :: 5 - Production/Stable', 62 | 'License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)', 63 | 'Programming Language :: Python', 64 | 'Operating System :: OS Independent', 65 | 'Intended Audience :: Science/Research', 66 | 'Topic :: Scientific/Engineering', 67 | 'Topic :: Text Editors :: Text Processing', 68 | 'Topic :: Text Processing :: General', 69 | ], 70 | 71 | # could also include long_description, download_url, classifiers, etc. 72 | 73 | packages = ['bibolamazi_gui', 'bibolamazi_gui.qtauto'], 74 | zip_safe = True, 75 | #scripts = ['bin/bibolamazi_gui'], 76 | entry_points = { 77 | 'console_scripts': ['bibolamazi_gui=bibolamazi_gui.bibolamazi_gui:main'], 78 | }, 79 | 80 | 81 | # make sure we have the same bibolamazi version. Since the GUI uses (some internals?) 82 | # of the bibolamazi library, make sure we have the same version. 83 | # 84 | # we should NOT list PyQt5 here, because of https://stackoverflow.com/a/4628806/1694896 . 85 | install_requires = [ 86 | 'bibolamazi=='+bibolamaziversion.version_str, 87 | 'markdown2', 88 | ], 89 | 90 | package_data = { 91 | # If any package contains *.txt or *.rst files, include them: 92 | #'': ['*.txt', '*.rst'], 93 | # And include any *.msg files found in the 'hello' package, too: 94 | #'hello': ['*.msg'], 95 | }, 96 | 97 | data_files = data_files, 98 | 99 | ) 100 | -------------------------------------------------------------------------------- /gui/bibolamazi_gui/filterpackagepatheditor.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | ################################################################################ 3 | # # 4 | # This file is part of the Bibolamazi Project. # 5 | # Copyright (C) 2018 by Philippe Faist # 6 | # philippe.faist@bluewin.ch # 7 | # # 8 | # Bibolamazi is free software: you can redistribute it and/or modify # 9 | # it under the terms of the GNU General Public License as published by # 10 | # the Free Software Foundation, either version 3 of the License, or # 11 | # (at your option) any later version. # 12 | # # 13 | # Bibolamazi is distributed in the hope that it will be useful, # 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of # 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # 16 | # GNU General Public License for more details. # 17 | # # 18 | # You should have received a copy of the GNU General Public License # 19 | # along with Bibolamazi. If not, see . # 20 | # # 21 | ################################################################################ 22 | 23 | 24 | import logging 25 | from html import escape as htmlescape 26 | 27 | import bibolamazi.init 28 | 29 | from bibolamazi.core.bibfilter import factory as filters_factory 30 | 31 | from PyQt5.QtCore import * 32 | from PyQt5.QtGui import * 33 | from PyQt5.QtWidgets import * 34 | 35 | from .qtauto.ui_filterpackagepatheditor import Ui_FilterPackagePathEditor 36 | from .sourcelisteditor import sanitize_bib_rel_path 37 | from . import githubreposelector 38 | 39 | logger = logging.getLogger(__name__) 40 | 41 | 42 | 43 | # ------------------------------------------------------------------------------ 44 | 45 | 46 | 47 | class FilterPackagePathEditor(QWidget): 48 | def __init__(self, parent): 49 | super().__init__(parent) 50 | 51 | self.ui = Ui_FilterPackagePathEditor() 52 | self.ui.setupUi(self) 53 | 54 | self.ref_dir = None 55 | 56 | filterPackagePathChanged = pyqtSignal(str) 57 | 58 | def setRefDir(self, ref_dir): 59 | self.ref_dir = ref_dir 60 | 61 | @pyqtSlot(str, str) 62 | def setFilterPackageInfo(self, arg): 63 | fpspec = filters_factory.FilterPackageSpec(arg) 64 | if fpspec.is_url: 65 | self.ui.lblInfo.setText("Location: {}".format(htmlescape(str(fpspec.url)))) 66 | else: 67 | self.ui.lblInfo.setText("{}: {}".format(htmlescape(str(fpspec.fpname)), 68 | htmlescape(str(fpspec.fpdir)))) 69 | 70 | @pyqtSlot(str) 71 | def setFilterPackageError(self, errmsg): 72 | self.ui.lblInfo.setText("{}".format(htmlescape(errmsg))) 73 | 74 | 75 | @pyqtSlot() 76 | def on_btnSetLocalPackage_clicked(self): 77 | 78 | fpath = QFileDialog.getExistingDirectory(self, "Locate Filter Package", str()) 79 | 80 | logger.debug("User selected fpath = %r", fpath) 81 | 82 | if not fpath: 83 | return 84 | 85 | fpath = sanitize_bib_rel_path(fpath, ref_dir=self.ref_dir) 86 | self.filterPackagePathChanged.emit(fpath) 87 | 88 | @pyqtSlot() 89 | def on_btnSetGithubRepo_clicked(self): 90 | 91 | gh = githubreposelector.GithubRepoSelector(self) 92 | 93 | r = gh.exec_() 94 | if r != QDialog.Accepted: 95 | return 96 | 97 | url = gh.getFilterPackageUrl() 98 | 99 | self.filterPackagePathChanged.emit(url) 100 | -------------------------------------------------------------------------------- /test/full_cases/test7.bibolamazi.bib: -------------------------------------------------------------------------------- 1 | 2 | 3 | .. Additionnal stuff here will not be managed by bibolamazi. It will also not be 4 | .. overwritten. You can e.g. temporarily add additional references here if you 5 | .. don't have bibolamazi installed. 6 | 7 | 8 | %%%-BIB-OLA-MAZI-BEGIN-%%% 9 | % 10 | % %% This bibliography database uses BIBOLAMAZI: 11 | % %% 12 | % %% https://github.com/phfaist/bibolamazi 13 | % %% 14 | % %% See comments below this configuration section if you're new to bibolamazi. 15 | % 16 | % %% This is the BIBOLAMAZI configuration section. Additional two leading 17 | % %% percent signs indicate comments within the configuration. 18 | % 19 | % %% **** SOURCES **** 20 | % 21 | % %% The _first_ accessible file in _each_ source list will be read 22 | % 23 | % src: srcbib/specialtests.bib 24 | % 25 | % %% Add additional sources here. Alternative files are useful, e.g., if the 26 | % %% same file is to be accessed with different paths on different machines. 27 | % 28 | % %% **** FILTERS **** 29 | % 30 | % %% Specify filters here. Specify as many filters as you want, each with a 31 | % %% `filter:' directive. See also `bibolamazi --list-filters' and 32 | % %% `bibolamazi --help ', or the "Help & Reference" page of the 33 | % %% graphical interface. 34 | % 35 | % filter: citearxiv --prefix="arXiv" -sJobname=test7_jobname 36 | % 37 | % filter: only_used -sJobname=test7_jobname 38 | % 39 | % 40 | %%%-BIB-OLA-MAZI-END-%%% 41 | 42 | % 43 | % This file was generated by BIBOLAMAZI 4.0b5 on 2019-01-05T00:17:21.525123 44 | % 45 | % https://github.com/phfaist/bibolamazi 46 | % 47 | % 48 | % ALL CHANGES BEYOND THIS POINT WILL BE LOST NEXT TIME BIBOLAMAZI IS RUN. 49 | % 50 | 51 | @article{arXiv:1211.1037, 52 | Author = "Faist, Philippe and Dupuis, Frédéric and Oppenheim, Jonathan and Renner, Renato", 53 | Title = "The Minimal Work Cost of Information Processing", 54 | Eprint = "1211.1037v2", 55 | DOI = "10.1038/ncomms8669", 56 | ArchivePrefix = "arXiv", 57 | PrimaryClass = "quant-ph", 58 | Abstract = "Irreversible information processing cannot be carried out without some inevitable thermodynamical work cost. This fundamental restriction, known as Landauer's principle, is increasingly relevant today, as the energy dissipation of computing devices impedes the development of their performance. Here we determine the minimal work required to carry out any logical process, for instance a computation. It is given by the entropy of the discarded information conditional to the output of the computation. Our formula takes precisely into account the statistically fluctuating work requirement of the logical process. It enables the explicit calculation of practical scenarios, such as computational circuits or quantum measurements. On the conceptual level, our result gives a precise and operationally justified connection between thermodynamic and information entropy, and explains the emergence of the entropy state function in macroscopic thermodynamics.", 59 | Year = "2012", 60 | Month = "Nov", 61 | Url = "http://arxiv.org/abs/1211.1037v2", 62 | File = "1211.1037v2.pdf" 63 | } 64 | 65 | @article{arXiv:1406.3618v1, 66 | Author = "Faist, Philippe and Oppenheim, Jonathan and Renner, Renato", 67 | Title = "Gibbs-Preserving Maps outperform Thermal Operations in the quantum regime", 68 | Eprint = "1406.3618v1", 69 | ArchivePrefix = "arXiv", 70 | PrimaryClass = "quant-ph", 71 | Abstract = "In this brief note, we compare two frameworks for characterizing possible operations in quantum thermodynamics. One framework considers Thermal Operations---unitaries which conserve energy. The other framework considers all maps which preserve the Gibbs state at a given temperature. Thermal Operations preserve the Gibbs state; hence a natural question which arises is whether the two frameworks are equivalent. Classically, this is true---Gibbs-Preserving Maps are no more powerful than Thermal Operations. Here, we show that this no longer holds in the quantum regime: a Gibbs-Preserving Map can generate coherent superpositions of energy levels while Thermal Operations cannot. This gap has an impact on clarifying a mathematical framework for quantum thermodynamics.", 72 | Year = "2014", 73 | Month = "Jun", 74 | Url = "http://arxiv.org/abs/1406.3618v1", 75 | File = "1406.3618v1.pdf" 76 | } 77 | -------------------------------------------------------------------------------- /gui/bibolamazi_gui/qtauto/ui_favoritesoverbtns.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Form implementation generated from reading ui file 'favoritesoverbtns.ui' 4 | # 5 | # Created by: PyQt5 UI code generator 5.7.1 6 | # 7 | # WARNING! All changes made in this file will be lost! 8 | 9 | from PyQt5 import QtCore, QtGui, QtWidgets 10 | 11 | class Ui_FavoritesOverBtns(object): 12 | def setupUi(self, FavoritesOverBtns): 13 | FavoritesOverBtns.setObjectName("FavoritesOverBtns") 14 | FavoritesOverBtns.resize(197, 32) 15 | FavoritesOverBtns.setWindowOpacity(0.8) 16 | self.horizontalLayout = QtWidgets.QHBoxLayout(FavoritesOverBtns) 17 | self.horizontalLayout.setContentsMargins(0, 0, 0, 0) 18 | self.horizontalLayout.setSpacing(0) 19 | self.horizontalLayout.setObjectName("horizontalLayout") 20 | spacerItem = QtWidgets.QSpacerItem(5, 10, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) 21 | self.horizontalLayout.addItem(spacerItem) 22 | self.btnEndEdit = QtWidgets.QToolButton(FavoritesOverBtns) 23 | icon = QtGui.QIcon() 24 | icon.addPixmap(QtGui.QPixmap(":/pic/ok.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) 25 | self.btnEndEdit.setIcon(icon) 26 | self.btnEndEdit.setIconSize(QtCore.QSize(10, 16)) 27 | self.btnEndEdit.setObjectName("btnEndEdit") 28 | self.horizontalLayout.addWidget(self.btnEndEdit) 29 | self.btnEdit = QtWidgets.QToolButton(FavoritesOverBtns) 30 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) 31 | sizePolicy.setHorizontalStretch(0) 32 | sizePolicy.setVerticalStretch(0) 33 | sizePolicy.setHeightForWidth(self.btnEdit.sizePolicy().hasHeightForWidth()) 34 | self.btnEdit.setSizePolicy(sizePolicy) 35 | icon1 = QtGui.QIcon() 36 | icon1.addPixmap(QtGui.QPixmap(":/pic/lstbtnedit.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) 37 | self.btnEdit.setIcon(icon1) 38 | self.btnEdit.setIconSize(QtCore.QSize(10, 16)) 39 | self.btnEdit.setObjectName("btnEdit") 40 | self.horizontalLayout.addWidget(self.btnEdit) 41 | self.btnDelete = QtWidgets.QToolButton(FavoritesOverBtns) 42 | icon2 = QtGui.QIcon() 43 | icon2.addPixmap(QtGui.QPixmap(":/pic/lstbtnremove.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) 44 | self.btnDelete.setIcon(icon2) 45 | self.btnDelete.setIconSize(QtCore.QSize(10, 16)) 46 | self.btnDelete.setObjectName("btnDelete") 47 | self.horizontalLayout.addWidget(self.btnDelete) 48 | spacerItem1 = QtWidgets.QSpacerItem(20, 5, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Minimum) 49 | self.horizontalLayout.addItem(spacerItem1) 50 | self.btnInsert = QtWidgets.QPushButton(FavoritesOverBtns) 51 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) 52 | sizePolicy.setHorizontalStretch(0) 53 | sizePolicy.setVerticalStretch(0) 54 | sizePolicy.setHeightForWidth(self.btnInsert.sizePolicy().hasHeightForWidth()) 55 | self.btnInsert.setSizePolicy(sizePolicy) 56 | self.btnInsert.setAutoFillBackground(True) 57 | icon3 = QtGui.QIcon() 58 | icon3.addPixmap(QtGui.QPixmap(":/pic/rightarrow.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) 59 | self.btnInsert.setIcon(icon3) 60 | self.btnInsert.setIconSize(QtCore.QSize(30, 16)) 61 | self.btnInsert.setFlat(True) 62 | self.btnInsert.setObjectName("btnInsert") 63 | self.horizontalLayout.addWidget(self.btnInsert) 64 | 65 | self.retranslateUi(FavoritesOverBtns) 66 | QtCore.QMetaObject.connectSlotsByName(FavoritesOverBtns) 67 | 68 | def retranslateUi(self, FavoritesOverBtns): 69 | _translate = QtCore.QCoreApplication.translate 70 | self.btnEndEdit.setToolTip(_translate("FavoritesOverBtns", "Finish editing")) 71 | self.btnEdit.setToolTip(_translate("FavoritesOverBtns", "Edit favorite commands")) 72 | self.btnDelete.setToolTip(_translate("FavoritesOverBtns", "Delete this favorite command")) 73 | self.btnInsert.setToolTip(_translate("FavoritesOverBtns", "Insert this favorite command at current position in config")) 74 | self.btnInsert.setText(_translate("FavoritesOverBtns", "insert")) 75 | 76 | from . import bibolamazi_res_rc 77 | -------------------------------------------------------------------------------- /gui/bibolamazi_gui/qtauto/ui_githubreposelector.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Form implementation generated from reading ui file 'githubreposelector.ui' 4 | # 5 | # Created by: PyQt5 UI code generator 5.12.2 6 | # 7 | # WARNING! All changes made in this file will be lost! 8 | 9 | from PyQt5 import QtCore, QtGui, QtWidgets 10 | 11 | 12 | class Ui_GithubRepoSelector(object): 13 | def setupUi(self, GithubRepoSelector): 14 | GithubRepoSelector.setObjectName("GithubRepoSelector") 15 | GithubRepoSelector.resize(430, 138) 16 | self.gridLayout = QtWidgets.QGridLayout(GithubRepoSelector) 17 | self.gridLayout.setObjectName("gridLayout") 18 | spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) 19 | self.gridLayout.addItem(spacerItem, 2, 0, 1, 1) 20 | self.stk = QtWidgets.QStackedWidget(GithubRepoSelector) 21 | self.stk.setObjectName("stk") 22 | self.pageUsername = QtWidgets.QWidget() 23 | self.pageUsername.setObjectName("pageUsername") 24 | self.gridLayout_2 = QtWidgets.QGridLayout(self.pageUsername) 25 | self.gridLayout_2.setContentsMargins(0, 0, 0, 0) 26 | self.gridLayout_2.setObjectName("gridLayout_2") 27 | self.txtUser = QtWidgets.QLineEdit(self.pageUsername) 28 | self.txtUser.setObjectName("txtUser") 29 | self.gridLayout_2.addWidget(self.txtUser, 1, 0, 1, 1) 30 | self.label = QtWidgets.QLabel(self.pageUsername) 31 | self.label.setObjectName("label") 32 | self.gridLayout_2.addWidget(self.label, 0, 0, 1, 1) 33 | self.stk.addWidget(self.pageUsername) 34 | self.pageRepo = QtWidgets.QWidget() 35 | self.pageRepo.setObjectName("pageRepo") 36 | self.gridLayout_3 = QtWidgets.QGridLayout(self.pageRepo) 37 | self.gridLayout_3.setContentsMargins(0, 0, 0, 0) 38 | self.gridLayout_3.setObjectName("gridLayout_3") 39 | self.lblPromptRepo = QtWidgets.QLabel(self.pageRepo) 40 | self.lblPromptRepo.setObjectName("lblPromptRepo") 41 | self.gridLayout_3.addWidget(self.lblPromptRepo, 0, 0, 1, 1) 42 | self.cbxRepos = QtWidgets.QComboBox(self.pageRepo) 43 | self.cbxRepos.setEditable(True) 44 | self.cbxRepos.setObjectName("cbxRepos") 45 | self.gridLayout_3.addWidget(self.cbxRepos, 1, 0, 1, 1) 46 | self.stk.addWidget(self.pageRepo) 47 | self.gridLayout.addWidget(self.stk, 1, 0, 1, 1) 48 | self.horizontalLayout = QtWidgets.QHBoxLayout() 49 | self.horizontalLayout.setObjectName("horizontalLayout") 50 | self.btnCancel = QtWidgets.QPushButton(GithubRepoSelector) 51 | self.btnCancel.setObjectName("btnCancel") 52 | self.horizontalLayout.addWidget(self.btnCancel) 53 | spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) 54 | self.horizontalLayout.addItem(spacerItem1) 55 | self.btnBack = QtWidgets.QPushButton(GithubRepoSelector) 56 | self.btnBack.setObjectName("btnBack") 57 | self.horizontalLayout.addWidget(self.btnBack) 58 | self.btnNext = QtWidgets.QPushButton(GithubRepoSelector) 59 | self.btnNext.setObjectName("btnNext") 60 | self.horizontalLayout.addWidget(self.btnNext) 61 | self.btnOk = QtWidgets.QPushButton(GithubRepoSelector) 62 | self.btnOk.setObjectName("btnOk") 63 | self.horizontalLayout.addWidget(self.btnOk) 64 | self.gridLayout.addLayout(self.horizontalLayout, 3, 0, 1, 1) 65 | 66 | self.retranslateUi(GithubRepoSelector) 67 | self.stk.setCurrentIndex(1) 68 | self.btnCancel.clicked.connect(GithubRepoSelector.reject) 69 | QtCore.QMetaObject.connectSlotsByName(GithubRepoSelector) 70 | 71 | def retranslateUi(self, GithubRepoSelector): 72 | _translate = QtCore.QCoreApplication.translate 73 | GithubRepoSelector.setWindowTitle(_translate("GithubRepoSelector", "Dialog")) 74 | self.label.setText(_translate("GithubRepoSelector", "Github user name / organization:")) 75 | self.lblPromptRepo.setText(_translate("GithubRepoSelector", "Repositories for user %s")) 76 | self.btnCancel.setText(_translate("GithubRepoSelector", "cancel")) 77 | self.btnBack.setText(_translate("GithubRepoSelector", "◀ back")) 78 | self.btnNext.setText(_translate("GithubRepoSelector", "next ▶")) 79 | self.btnOk.setText(_translate("GithubRepoSelector", "OK")) 80 | 81 | 82 | -------------------------------------------------------------------------------- /test/test_filters_citedoi.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import unittest 4 | import logging 5 | import tempfile 6 | import os.path 7 | import re 8 | import shutil 9 | 10 | from pybtex.database import Entry, Person, BibliographyData 11 | 12 | from bibolamazi.core import blogger 13 | from helpers import CustomAssertions 14 | from bibolamazi.filters.citedoi import (CiteDoiFilter, DoiOrgFetchedInfoCacheAccessor) 15 | from bibolamazi.core.bibolamazifile import BibolamaziFile 16 | 17 | logger = logging.getLogger(__name__) 18 | 19 | 20 | class TestWorks(unittest.TestCase, CustomAssertions): 21 | 22 | def __init__(self, *args, **kwargs): 23 | super().__init__(*args, **kwargs) 24 | 25 | self.maxDiff = None 26 | 27 | def test_fetch_basic_noprefix(self): 28 | 29 | bf = BibolamaziFile(create=True) 30 | bf.setEntries([]) 31 | 32 | tmpdir = tempfile.mkdtemp() 33 | try: 34 | # create fake aux file in that temp dir 35 | with open(os.path.join(tmpdir, 'testjobname.aux'), 'w') as auxf: 36 | auxf.write(r""" 37 | \citation{10.1103/PhysRev.76.749} 38 | \citation{SomeOtherCitation2013_stuff,MoreCitations} 39 | \citation{10.1147/rd.53.0183} 40 | \citation{10.1147/rd.53.0183,10.1103/RevModPhys.20.367} 41 | """) 42 | 43 | filt = CiteDoiFilter(jobname='testjobname', search_dirs=[tmpdir], prefix='') 44 | bf.registerFilterInstance(filt) 45 | 46 | filt.filter_bibolamazifile(bf) 47 | 48 | bibdata = bf.bibliographyData() 49 | self.assertTrue(len(bibdata.entries) == 3) 50 | self.assertTrue('10.1147/rd.53.0183' in bibdata.entries) 51 | self.assertTrue('10.1103/RevModPhys.20.367' in bibdata.entries) 52 | self.assertTrue('10.1103/PhysRev.76.749' in bibdata.entries) 53 | 54 | # see if the entries were populated correctly (probe these random parts:) 55 | Landauer = bibdata.entries['10.1147/rd.53.0183'] 56 | self.assertTrue(len(Landauer.persons['author']) == 1 and 57 | " ".join(Landauer.persons['author'][0].get_part('last')).strip().upper() 58 | == 'LANDAUER') 59 | self.assertTrue(re.match(r'\s*Rev(iews)?[. ]*(of)?[. ]*Mod(ern)?[. ]*Phys(ics)?[. ]*$', 60 | bibdata.entries['10.1103/RevModPhys.20.367'].fields['journal'])) 61 | 62 | finally: 63 | shutil.rmtree(tmpdir) 64 | 65 | def test_fetch_prefix(self): 66 | 67 | bf = BibolamaziFile(create=True) 68 | bf.setEntries([]) 69 | 70 | tmpdir = tempfile.mkdtemp() 71 | try: 72 | # create fake aux file in that temp dir 73 | with open(os.path.join(tmpdir, 'testjobname.aux'), 'w') as auxf: 74 | auxf.write(r""" 75 | \citation{doi:10.1103/PhysRev.76.749} 76 | \citation{10.1080/09500340008244031} 77 | \citation{SomeOtherCitation2013_stuff,And,MoreCitations} 78 | \citation{doi:10.1147/rd.53.0183,More,10.1080/09500340008244031,Citations} 79 | \citation{doi:10.1147/rd.53.0183,doi:10.1103/RevModPhys.20.367} 80 | """) # don't pick up the ones without the prefix 81 | 82 | filt = CiteDoiFilter(jobname='testjobname', search_dirs=[tmpdir]) 83 | bf.registerFilterInstance(filt) 84 | 85 | filt.filter_bibolamazifile(bf) 86 | 87 | bibdata = bf.bibliographyData() 88 | 89 | # logger.debug("All entries =\n%s", bibdata.to_string('bibtex')) 90 | 91 | self.assertTrue(len(bibdata.entries) == 3) 92 | self.assertTrue('doi:10.1147/rd.53.0183' in bibdata.entries) 93 | self.assertTrue('doi:10.1103/RevModPhys.20.367' in bibdata.entries) 94 | self.assertTrue('doi:10.1103/PhysRev.76.749' in bibdata.entries) 95 | 96 | # see if the entries were populated correctly (probe these random parts:) 97 | Landauer = bibdata.entries['doi:10.1147/rd.53.0183'] 98 | self.assertTrue(len(Landauer.persons['author']) == 1 and 99 | " ".join(Landauer.persons['author'][0].get_part('last')).strip().upper() 100 | == 'LANDAUER') 101 | self.assertTrue(re.match(r'\s*Rev(iews)?[. ]*(of)?[. ]*Mod(ern)?[. ]*Phys(ics)?[. ]*$', 102 | bibdata.entries['doi:10.1103/RevModPhys.20.367'].fields['journal'])) 103 | 104 | finally: 105 | shutil.rmtree(tmpdir) 106 | 107 | 108 | 109 | 110 | if __name__ == '__main__': 111 | blogger.setup_simple_console_logging(level=logging.DEBUG) 112 | unittest.main() 113 | -------------------------------------------------------------------------------- /gui/bibolamazi_gui/buttontabsmanager.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | ################################################################################ 3 | # # 4 | # This file is part of the Bibolamazi Project. # 5 | # Copyright (C) 2013 by Philippe Faist # 6 | # philippe.faist@bluewin.ch # 7 | # # 8 | # Bibolamazi is free software: you can redistribute it and/or modify # 9 | # it under the terms of the GNU General Public License as published by # 10 | # the Free Software Foundation, either version 3 of the License, or # 11 | # (at your option) any later version. # 12 | # # 13 | # Bibolamazi is distributed in the hope that it will be useful, # 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of # 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # 16 | # GNU General Public License for more details. # 17 | # # 18 | # You should have received a copy of the GNU General Public License # 19 | # along with Bibolamazi. If not, see . # 20 | # # 21 | ################################################################################ 22 | 23 | import logging 24 | logger = logging.getLogger(__name__) 25 | 26 | from PyQt5.QtCore import * 27 | from PyQt5.QtGui import * 28 | from PyQt5.QtWidgets import * 29 | 30 | from .uiutils import ContextAttributeSetter 31 | 32 | 33 | class ButtonTabsManager(QObject): 34 | def __init__(self, container, parent=None): 35 | super().__init__() 36 | 37 | self.container = container 38 | self.buttons = [] 39 | 40 | self._updating_buttons = False 41 | 42 | self.btngroup = QButtonGroup(self) 43 | self.btngroup.setExclusive(True) 44 | 45 | self.container.currentChanged.connect(self.containerCurrentChanged) 46 | 47 | 48 | def registerButton(self, btn, widgetInContainer): 49 | 50 | self.btngroup.addButton(btn) 51 | 52 | self.buttons.append( (btn, widgetInContainer) ) 53 | 54 | btn_id = len(self.buttons)-1 55 | btn.setProperty("_flatbuttontabsmanager_id", btn_id) 56 | widgetInContainer.setProperty("_flatbuttontabsmanager_id", btn_id) 57 | 58 | cur_btn_id = self._get_cur_btn_id() 59 | btn.setChecked(cur_btn_id is not None and cur_btn_id == btn_id) 60 | 61 | btn.toggled.connect(self.tabButtonToggled) 62 | 63 | 64 | def _get_cur_btn_id(self): 65 | cur_w = self.container.currentWidget() 66 | if cur_w is None: 67 | return None 68 | cur_btn_id = cur_w.property("_flatbuttontabsmanager_id") 69 | if cur_btn_id is None: 70 | return None 71 | return int(cur_btn_id) 72 | 73 | 74 | @pyqtSlot() 75 | def containerCurrentChanged(self): 76 | btn_id = self._get_cur_btn_id() 77 | # for j in range(len(self.buttons)): 78 | # b, w = self.buttons[j] 79 | # with ContextAttributeSetter( (b.signalsBlocked, 80 | # b.blockSignals, True) ): 81 | # b.setChecked(btn_id is not None and j == btn_id) 82 | if btn_id is not None: 83 | b = self.buttons[btn_id][0] 84 | with ContextAttributeSetter( (lambda: self._updating_buttons, 85 | self._set_updating_buttons, True) ): 86 | 87 | # the button group will make sure the others get unchecked 88 | b.setChecked(True) 89 | 90 | def _set_updating_buttons(self, yn): 91 | self._updating_buttons = yn 92 | 93 | @pyqtSlot(bool) 94 | def tabButtonToggled(self, on): 95 | if self._updating_buttons: 96 | return 97 | 98 | btn = self.sender() 99 | btn_id = int(btn.property("_flatbuttontabsmanager_id")) 100 | 101 | if btn_id < 0 or btn_id >= len(self.buttons): 102 | logger.warning("button id %d out of range (%d)", btn_id, len(self.buttons)) 103 | 104 | with ContextAttributeSetter( (self.container.signalsBlocked, 105 | self.container.blockSignals, True) ): 106 | self.container.setCurrentWidget(self.buttons[btn_id][1]) 107 | self.containerCurrentChanged() 108 | -------------------------------------------------------------------------------- /gui/bibolamazi_gui/filterinstanceeditor.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | FilterInstanceEditor 4 | 5 | 6 | 7 | 0 8 | 0 9 | 403 10 | 474 11 | 12 | 13 | 14 | Form 15 | 16 | 17 | 18 | 19 | 20 | 21 | 0 22 | 1 23 | 24 | 25 | 26 | QAbstractItemView::ScrollPerPixel 27 | 28 | 29 | QAbstractItemView::ScrollPerPixel 30 | 31 | 32 | 0 33 | 34 | 35 | false 36 | 37 | 38 | true 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 0 47 | 0 48 | 49 | 50 | 51 | 52 | 0 53 | 40 54 | 55 | 56 | 57 | 58 | 59 | 60 | Qt::RichText 61 | 62 | 63 | true 64 | 65 | 66 | 67 | 68 | 69 | 70 | color: rgb(198, 0, 0) 71 | 72 | 73 | Error: ... 74 | 75 | 76 | Qt::RichText 77 | 78 | 79 | true 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | Filter: 89 | 90 | 91 | 92 | 93 | 94 | 95 | QLabel { font-weight: bold } 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | Qt::Horizontal 106 | 107 | 108 | 109 | 40 110 | 20 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | info 119 | 120 | 121 | 122 | :/pic/question.png:/pic/question.png 123 | 124 | 125 | 126 | 127 | 128 | 129 | Add this full command line to your favorites 130 | 131 | 132 | add 133 | 134 | 135 | 136 | :/pic/bookmark.png:/pic/bookmark.png 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | -------------------------------------------------------------------------------- /gui/bibolamazi_gui/githubreposelector.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | GithubRepoSelector 4 | 5 | 6 | 7 | 0 8 | 0 9 | 430 10 | 138 11 | 12 | 13 | 14 | Dialog 15 | 16 | 17 | 18 | 19 | 20 | Qt::Vertical 21 | 22 | 23 | 24 | 20 25 | 40 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 1 34 | 35 | 36 | 37 | 38 | 0 39 | 40 | 41 | 0 42 | 43 | 44 | 0 45 | 46 | 47 | 0 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | Github user name / organization: 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 0 65 | 66 | 67 | 0 68 | 69 | 70 | 0 71 | 72 | 73 | 0 74 | 75 | 76 | 77 | 78 | Repositories for user %s 79 | 80 | 81 | 82 | 83 | 84 | 85 | true 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | cancel 99 | 100 | 101 | 102 | 103 | 104 | 105 | Qt::Horizontal 106 | 107 | 108 | 109 | 40 110 | 20 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | ◀ back 119 | 120 | 121 | 122 | 123 | 124 | 125 | next ▶ 126 | 127 | 128 | 129 | 130 | 131 | 132 | OK 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | btnCancel 144 | clicked() 145 | GithubRepoSelector 146 | reject() 147 | 148 | 149 | 56 150 | 107 151 | 152 | 153 | 5 154 | 62 155 | 156 | 157 | 158 | 159 | 160 | -------------------------------------------------------------------------------- /gui/bibolamazi_gui/favoritesoverbtns.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | FavoritesOverBtns 4 | 5 | 6 | 7 | 0 8 | 0 9 | 197 10 | 32 11 | 12 | 13 | 14 | 0.800000000000000 15 | 16 | 17 | 18 | 0 19 | 20 | 21 | 0 22 | 23 | 24 | 0 25 | 26 | 27 | 0 28 | 29 | 30 | 0 31 | 32 | 33 | 34 | 35 | Qt::Horizontal 36 | 37 | 38 | QSizePolicy::Expanding 39 | 40 | 41 | 42 | 5 43 | 10 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | Finish editing 52 | 53 | 54 | 55 | :/pic/ok.png:/pic/ok.png 56 | 57 | 58 | 59 | 10 60 | 16 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 0 70 | 0 71 | 72 | 73 | 74 | Edit favorite commands 75 | 76 | 77 | 78 | :/pic/lstbtnedit.png:/pic/lstbtnedit.png 79 | 80 | 81 | 82 | 10 83 | 16 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | Delete this favorite command 92 | 93 | 94 | 95 | :/pic/lstbtnremove.png:/pic/lstbtnremove.png 96 | 97 | 98 | 99 | 10 100 | 16 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | Qt::Horizontal 109 | 110 | 111 | QSizePolicy::Fixed 112 | 113 | 114 | 115 | 20 116 | 5 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 0 126 | 0 127 | 128 | 129 | 130 | Insert this favorite command at current position in config 131 | 132 | 133 | true 134 | 135 | 136 | insert 137 | 138 | 139 | 140 | :/pic/rightarrow.png:/pic/rightarrow.png 141 | 142 | 143 | 144 | 30 145 | 16 146 | 147 | 148 | 149 | true 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | -------------------------------------------------------------------------------- /gui/bibolamazi_gui/uiutils.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | ################################################################################ 3 | # # 4 | # This file is part of the Bibolamazi Project. # 5 | # Copyright (C) 2013 by Philippe Faist # 6 | # philippe.faist@bluewin.ch # 7 | # # 8 | # Bibolamazi is free software: you can redistribute it and/or modify # 9 | # it under the terms of the GNU General Public License as published by # 10 | # the Free Software Foundation, either version 3 of the License, or # 11 | # (at your option) any later version. # 12 | # # 13 | # Bibolamazi is distributed in the hope that it will be useful, # 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of # 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # 16 | # GNU General Public License for more details. # 17 | # # 18 | # You should have received a copy of the GNU General Public License # 19 | # along with Bibolamazi. If not, see . # 20 | # # 21 | ################################################################################ 22 | 23 | 24 | import logging 25 | logger = logging.getLogger(__name__) 26 | 27 | from PyQt5.QtCore import * 28 | from PyQt5.QtGui import * 29 | from PyQt5.QtWidgets import * 30 | 31 | 32 | 33 | class ContextAttributeSetter: 34 | """ 35 | Context manager that temporarily sets some attributes and restores them to 36 | their original value after the context is finished. 37 | 38 | Give a list of pairs of method and value to set. 39 | 40 | For example:: 41 | 42 | with ContextAttributeSetter( (object.isEnabled, object.setEnabled, False), ): 43 | ... 44 | 45 | will retreive the current state of if the object is enabled with 46 | `object.isEnabled()`, then will disable the object with 47 | `object.setEnabled(False)`. Upon exiting the with block, the state is 48 | restored to its original state with `object.setEnabled(..)`. 49 | """ 50 | 51 | def __init__(self, *args): 52 | """ 53 | Constructor. Does initializations. The \"enter\" statement is done with 54 | __enter__(). 55 | 56 | The arguments `*args` are one or more 3-tuples `(get_method, set_method, 57 | set_to_value)`. The current state of the property is queried with 58 | `get_method()`, the new state is set with `set_method()`, and 59 | `set_to_value` is the value that the property should be set to upon 60 | entering the execution context. 61 | """ 62 | super().__init__() 63 | self.attribpairs = args 64 | self.initvals = None 65 | 66 | def __enter__(self): 67 | self.initvals = [] 68 | for (getm, setm, v) in self.attribpairs: 69 | self.initvals.append(getm()) 70 | setm(v) 71 | 72 | return self 73 | 74 | def __exit__(self, type, value, traceback): 75 | # clean-up, go in reverse order 76 | N = len(self.attribpairs) 77 | for i in range(N): 78 | (getm, setm, v) = self.attribpairs[N-i-1] 79 | setm(self.initvals[N-i-1]) 80 | 81 | 82 | 83 | 84 | class BlockedSignals(ContextAttributeSetter): 85 | """ 86 | Context manager that temporarily block signals from Qt objects:: 87 | 88 | with BlockedSignals(object1, object2, ...): 89 | # The Qt objects object1, object2, ... have their signals 90 | # temporarily blocked within this "with" statement 91 | """ 92 | 93 | def __init__(self, *args): 94 | attrlist = [ 95 | (obj.signalsBlocked, obj.blockSignals, True) 96 | for obj in args 97 | ] 98 | super().__init__( *attrlist ) 99 | 100 | 101 | 102 | 103 | 104 | 105 | def is_dark_mode(widget): 106 | """ 107 | Return True if the given `widget` appears to be rendered in dark mode. 108 | 109 | Dark mode interface is determined by examining the brightness of the palette 110 | background color ("Base"). 111 | """ 112 | if widget is None: 113 | return False 114 | p = widget.palette() 115 | if p is None: 116 | return False 117 | if p.color(QPalette.Active, QPalette.Base).value() < 127: 118 | # dark Base color -> dark mode 119 | return True 120 | return False 121 | -------------------------------------------------------------------------------- /gui/bibolamazi_gui/bibolamazi_gui.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | ################################################################################ 5 | # # 6 | # This file is part of the Bibolamazi Project. # 7 | # Copyright (C) 2013 by Philippe Faist # 8 | # philippe.faist@bluewin.ch # 9 | # # 10 | # Bibolamazi is free software: you can redistribute it and/or modify # 11 | # it under the terms of the GNU General Public License as published by # 12 | # the Free Software Foundation, either version 3 of the License, or # 13 | # (at your option) any later version. # 14 | # # 15 | # Bibolamazi is distributed in the hope that it will be useful, # 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of # 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # 18 | # GNU General Public License for more details. # 19 | # # 20 | # You should have received a copy of the GNU General Public License # 21 | # along with Bibolamazi. If not, see . # 22 | # # 23 | ################################################################################ 24 | 25 | 26 | import sys 27 | import os 28 | import os.path 29 | import logging 30 | 31 | #if sys.platform.startswith("win"): 32 | # # why do we need this??!??!?! 33 | # logging.basicConfig(level=logging.DEBUG) 34 | 35 | import bibolamazi.init 36 | 37 | # set up basic logging 38 | from bibolamazi.core import blogger 39 | 40 | from bibolamazi.core.bibfilter import factory as filters_factory 41 | from bibolamazi.core.bibfilter import argtypes 42 | 43 | # Important: Do not import Qt5 yet 44 | # 45 | # We need to set some environment variables, etc., to make sure Qt can find all 46 | # its libraries and plugins well when using PyInstaller. 47 | 48 | 49 | 50 | #print("Bibolamazi: loading main script") 51 | 52 | logger = logging.getLogger(__name__) 53 | 54 | 55 | def setup_qt5_plugins_path(): 56 | try: 57 | basePath = sys._MEIPASS 58 | except Exception: 59 | return 60 | 61 | qt_platform_plugins_path = os.path.join(basePath, "PyQt5", "Qt", "plugins") 62 | 63 | logger.debug("Setting QT_QPA_PLATFORM_PLUGIN_PATH to %r", qt_platform_plugins_path) 64 | 65 | os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = qt_platform_plugins_path 66 | 67 | 68 | 69 | def exception_handler(etype, evalue, tb): 70 | if etype is KeyboardInterrupt: 71 | print("*** interrupt (ignoring)") 72 | return 73 | 74 | import traceback 75 | logger.warning("Internal Error: Uncaught Python Exception. Ignoring and hoping for the best.\n%s", 76 | "".join(traceback.format_exception(etype, evalue, tb))) 77 | 78 | # override Python's exception handler, 79 | sys.excepthook = exception_handler 80 | 81 | 82 | 83 | 84 | def main(): 85 | 86 | 87 | blogger.setup_simple_console_logging(level=logging.DEBUG) 88 | 89 | argv = list(sys.argv) 90 | 91 | # default level: set to root logger. May be set externally via environment variable 92 | # (e.g. for debugging) or with --verbose 93 | 94 | log_level = logging.INFO 95 | if '--verbose' in argv: 96 | argv.remove('--verbose') 97 | log_level = logging.DEBUG 98 | 99 | if 'BIBOLAMAZI_LOG_LEVEL' in os.environ and os.environ['BIBOLAMAZI_LOG_LEVEL']: 100 | logging.getLogger().setLevel(argtypes.LogLevel(os.environ['BIBOLAMAZI_LOG_LEVEL']).levelno) 101 | else: 102 | logging.getLogger().setLevel(log_level) 103 | 104 | logger.debug("main: log level set to %r", log_level) 105 | 106 | 107 | # setup Qt paths! 108 | setup_qt5_plugins_path() 109 | 110 | 111 | 112 | # ## Seems we still need this for pyinstaller, I'm not sure why.... 113 | # 114 | # load precompiled filters, if we've got any 115 | try: 116 | import bibolamazi_compiled_filter_list as pc 117 | filters_factory.load_precompiled_filters('bibolamazi.filters', dict([ 118 | (fname, pc.__dict__[fname]) for fname in pc.filter_list 119 | ])) 120 | except ImportError: 121 | pass 122 | 123 | 124 | # note: package providers will be loaded after loading the Qt application: 125 | 126 | from . import bibolamaziapp 127 | 128 | return bibolamaziapp.run_app(argv) 129 | 130 | 131 | if __name__ == '__main__': 132 | 133 | main() 134 | -------------------------------------------------------------------------------- /gui/bibolamazi_gui/githubauthenticationdialog.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | ################################################################################ 3 | # # 4 | # This file is part of the Bibolamazi Project. # 5 | # Copyright (C) 2018 by Philippe Faist # 6 | # philippe.faist@bluewin.ch # 7 | # # 8 | # Bibolamazi is free software: you can redistribute it and/or modify # 9 | # it under the terms of the GNU General Public License as published by # 10 | # the Free Software Foundation, either version 3 of the License, or # 11 | # (at your option) any later version. # 12 | # # 13 | # Bibolamazi is distributed in the hope that it will be useful, # 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of # 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # 16 | # GNU General Public License for more details. # 17 | # # 18 | # You should have received a copy of the GNU General Public License # 19 | # along with Bibolamazi. If not, see . # 20 | # # 21 | ################################################################################ 22 | 23 | import re 24 | import logging 25 | #from html import escape as htmlescape 26 | 27 | #import github 28 | 29 | import bibolamazi.init 30 | 31 | from PyQt5.QtCore import * 32 | from PyQt5.QtGui import * 33 | from PyQt5.QtWidgets import * 34 | 35 | from .uiutils import BlockedSignals #, ContextAttributeSetter 36 | from .qtauto.ui_githubauthenticationdialog import Ui_GithubAuthenticationDialog 37 | 38 | logger = logging.getLogger(__name__) 39 | 40 | 41 | # ------------------------------------------------------------------------------ 42 | 43 | 44 | class GithubAuthenticationDialog(QDialog): 45 | def __init__(self, parent): 46 | super().__init__(parent) 47 | 48 | self.ui = Ui_GithubAuthenticationDialog() 49 | self.ui.setupUi(self) 50 | 51 | # Button screenshots: take on hi dpi mac, scale image @ 80%, export to 52 | # png, note dimensions; specify 1/2 of the dimensions as image sizes 53 | # below so that pictures appear nice on retina displays 54 | 55 | self.ui.lbl.setText("""\ 56 | 57 | 64 | 65 |

Authenticate to Github

66 | 67 |

Please visit https://github.com/settings/tokens 69 | and follow the following instructions to generate a personal access token. This 70 | procedure ensures that bibolamazi never sees your github password.

71 | 72 |

1. Click on the button Generate new
 74 |     token

75 | 76 |

2. Give a name to the access token such as “bibolamazi access” and select the “repo” scope:

77 | 78 |

80 | 81 |

3. Scroll down and click Generate token

84 | 85 |

4. Paste the access token in the field below:

86 | 87 | 88 | """) 89 | 90 | self.ui.txtToken.textChanged.connect(self._update_gui_state) 91 | self._update_gui_state() 92 | 93 | self.adjustSize() 94 | self.resize(self.size() + QSize(150,80)) 95 | 96 | 97 | def getAuthToken(self): 98 | return self.ui.txtToken.text().strip() 99 | 100 | @pyqtSlot() 101 | def _update_gui_state(self): 102 | 103 | with BlockedSignals(self.ui.txtToken): 104 | self.ui.txtToken.setText( self.ui.txtToken.text().strip() ) 105 | 106 | self.ui.btns.button(QDialogButtonBox.Ok).setEnabled( 107 | self._is_valid_token(self.ui.txtToken.text()) 108 | ) 109 | 110 | 111 | def _is_valid_token(self, token): 112 | logger.debug("checking token = [...]%s", token[-4:]) 113 | return (re.match(r'^[a-zA-Z0-9.+_/!@*=-]{32,}$', token if token else '') is not None) 114 | -------------------------------------------------------------------------------- /gui/bibolamazi_gui/qtauto/ui_filterinstanceeditor.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Form implementation generated from reading ui file 'filterinstanceeditor.ui' 4 | # 5 | # Created by: PyQt5 UI code generator 5.12.1 6 | # 7 | # WARNING! All changes made in this file will be lost! 8 | 9 | from PyQt5 import QtCore, QtGui, QtWidgets 10 | 11 | 12 | class Ui_FilterInstanceEditor(object): 13 | def setupUi(self, FilterInstanceEditor): 14 | FilterInstanceEditor.setObjectName("FilterInstanceEditor") 15 | FilterInstanceEditor.resize(403, 474) 16 | self.gridLayout = QtWidgets.QGridLayout(FilterInstanceEditor) 17 | self.gridLayout.setObjectName("gridLayout") 18 | self.lstOptions = QtWidgets.QTreeView(FilterInstanceEditor) 19 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) 20 | sizePolicy.setHorizontalStretch(0) 21 | sizePolicy.setVerticalStretch(1) 22 | sizePolicy.setHeightForWidth(self.lstOptions.sizePolicy().hasHeightForWidth()) 23 | self.lstOptions.setSizePolicy(sizePolicy) 24 | self.lstOptions.setVerticalScrollMode(QtWidgets.QAbstractItemView.ScrollPerPixel) 25 | self.lstOptions.setHorizontalScrollMode(QtWidgets.QAbstractItemView.ScrollPerPixel) 26 | self.lstOptions.setIndentation(0) 27 | self.lstOptions.setItemsExpandable(False) 28 | self.lstOptions.setAllColumnsShowFocus(True) 29 | self.lstOptions.setObjectName("lstOptions") 30 | self.gridLayout.addWidget(self.lstOptions, 3, 0, 1, 2) 31 | self.lblOptionHelp = QtWidgets.QLabel(FilterInstanceEditor) 32 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Ignored, QtWidgets.QSizePolicy.Preferred) 33 | sizePolicy.setHorizontalStretch(0) 34 | sizePolicy.setVerticalStretch(0) 35 | sizePolicy.setHeightForWidth(self.lblOptionHelp.sizePolicy().hasHeightForWidth()) 36 | self.lblOptionHelp.setSizePolicy(sizePolicy) 37 | self.lblOptionHelp.setMinimumSize(QtCore.QSize(0, 40)) 38 | self.lblOptionHelp.setText("") 39 | self.lblOptionHelp.setTextFormat(QtCore.Qt.RichText) 40 | self.lblOptionHelp.setWordWrap(True) 41 | self.lblOptionHelp.setObjectName("lblOptionHelp") 42 | self.gridLayout.addWidget(self.lblOptionHelp, 4, 0, 1, 2) 43 | self.lblErrorMsg = QtWidgets.QLabel(FilterInstanceEditor) 44 | self.lblErrorMsg.setStyleSheet("color: rgb(198, 0, 0)") 45 | self.lblErrorMsg.setTextFormat(QtCore.Qt.RichText) 46 | self.lblErrorMsg.setWordWrap(True) 47 | self.lblErrorMsg.setObjectName("lblErrorMsg") 48 | self.gridLayout.addWidget(self.lblErrorMsg, 1, 0, 1, 2) 49 | self.horizontalLayout = QtWidgets.QHBoxLayout() 50 | self.horizontalLayout.setObjectName("horizontalLayout") 51 | self.label = QtWidgets.QLabel(FilterInstanceEditor) 52 | self.label.setObjectName("label") 53 | self.horizontalLayout.addWidget(self.label) 54 | self.lblFilterName = QtWidgets.QLabel(FilterInstanceEditor) 55 | self.lblFilterName.setStyleSheet("QLabel { font-weight: bold }") 56 | self.lblFilterName.setText("") 57 | self.lblFilterName.setObjectName("lblFilterName") 58 | self.horizontalLayout.addWidget(self.lblFilterName) 59 | spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) 60 | self.horizontalLayout.addItem(spacerItem) 61 | self.btnFilterHelp = QtWidgets.QPushButton(FilterInstanceEditor) 62 | icon = QtGui.QIcon() 63 | icon.addPixmap(QtGui.QPixmap(":/pic/question.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) 64 | self.btnFilterHelp.setIcon(icon) 65 | self.btnFilterHelp.setObjectName("btnFilterHelp") 66 | self.horizontalLayout.addWidget(self.btnFilterHelp) 67 | self.btnAddFavorite = QtWidgets.QPushButton(FilterInstanceEditor) 68 | icon1 = QtGui.QIcon() 69 | icon1.addPixmap(QtGui.QPixmap(":/pic/bookmark.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) 70 | self.btnAddFavorite.setIcon(icon1) 71 | self.btnAddFavorite.setObjectName("btnAddFavorite") 72 | self.horizontalLayout.addWidget(self.btnAddFavorite) 73 | self.gridLayout.addLayout(self.horizontalLayout, 2, 0, 1, 2) 74 | 75 | self.retranslateUi(FilterInstanceEditor) 76 | QtCore.QMetaObject.connectSlotsByName(FilterInstanceEditor) 77 | 78 | def retranslateUi(self, FilterInstanceEditor): 79 | _translate = QtCore.QCoreApplication.translate 80 | FilterInstanceEditor.setWindowTitle(_translate("FilterInstanceEditor", "Form")) 81 | self.lblErrorMsg.setText(_translate("FilterInstanceEditor", "Error: ...")) 82 | self.label.setText(_translate("FilterInstanceEditor", "Filter:")) 83 | self.btnFilterHelp.setText(_translate("FilterInstanceEditor", "info")) 84 | self.btnAddFavorite.setToolTip(_translate("FilterInstanceEditor", "Add this full command line to your favorites")) 85 | self.btnAddFavorite.setText(_translate("FilterInstanceEditor", "add")) 86 | 87 | 88 | from . import bibolamazi_res_rc 89 | -------------------------------------------------------------------------------- /bibolamazi/filters/echo.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | ################################################################################ 3 | # # 4 | # This file is part of the Bibolamazi Project. # 5 | # Copyright (C) 2015 by Philippe Faist # 6 | # philippe.faist@bluewin.ch # 7 | # # 8 | # Bibolamazi is free software: you can redistribute it and/or modify # 9 | # it under the terms of the GNU General Public License as published by # 10 | # the Free Software Foundation, either version 3 of the License, or # 11 | # (at your option) any later version. # 12 | # # 13 | # Bibolamazi is distributed in the hope that it will be useful, # 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of # 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # 16 | # GNU General Public License for more details. # 17 | # # 18 | # You should have received a copy of the GNU General Public License # 19 | # along with Bibolamazi. If not, see . # 20 | # # 21 | ################################################################################ 22 | 23 | 24 | #import re 25 | import logging 26 | logger = logging.getLogger(__name__) 27 | 28 | from bibolamazi.core.butils import getbool 29 | from bibolamazi.core.bibfilter import BibFilter, BibFilterError 30 | from bibolamazi.core.bibfilter.argtypes import enum_class 31 | #from bibolamazi.core.main import verbosity_logger_level 32 | 33 | from bibolamazi.core.bibfilter.argtypes import LogLevel 34 | 35 | 36 | 37 | HELP_AUTHOR = r""" 38 | Philippe Faist, (C) 2013, GPL 3+ 39 | """ 40 | 41 | HELP_DESC = r""" 42 | Echo a custom message in the bibolamazi log 43 | """ 44 | 45 | HELP_TEXT = r""" 46 | Echo a custom message in the bibolamazi log. This does not affect the database, 47 | but might provide someone running Bibolamazi with some important information. 48 | """ 49 | 50 | 51 | FMT_DEFAULT = 0 52 | FMT_SIMPLE = 1 53 | FMT_WARN = 2 54 | 55 | msgformats = { 56 | FMT_DEFAULT: ("-"*80 + "\n%s\n" + "-"*80), 57 | FMT_SIMPLE: "%s", 58 | FMT_WARN: ("\n" + "#"*80 + "\nWARNING: %s\n" + "#"*80 + "\n"), 59 | } 60 | 61 | EchoFormat = enum_class('EchoFormat', 62 | [('default', FMT_DEFAULT), 63 | ('simple', FMT_SIMPLE), 64 | ('warn', FMT_WARN) 65 | ], 66 | default_value='default', 67 | value_attr_name='msgformat') 68 | 69 | 70 | 71 | class EchoFilter(BibFilter): 72 | 73 | helpauthor = HELP_AUTHOR 74 | helpdescription = HELP_DESC 75 | helptext = HELP_TEXT 76 | 77 | def __init__(self, message=None, *args, **kwargs): 78 | """Echo a custom message into the bibolamazi logger. 79 | 80 | Arguments: 81 | - message: the message to echo 82 | - level(LogLevel): the logger level required to display the message (one of 'LONGDEBUG', 83 | 'DEBUG', 'WARNING', 'INFO', 'ERROR' or 'CRITICAL') 84 | - format(EchoFormat): how to display the message (one of 'default', 'simple' or 'warn') 85 | - warn(bool): short for '-sFormat=warn -sLevel=WARNING' 86 | """ 87 | super().__init__() 88 | 89 | self.message = message 90 | if len(args) > 0: 91 | if self.message is None: 92 | self.message = " ".join(args) 93 | else: 94 | raise BibFilterError(self.name(), "Got unexpected additional arguments: %s"%( 95 | ", ".join( ('"'+s+'"' for s in args) ) 96 | )) 97 | 98 | iswarn = kwargs.get('warn', None) 99 | if iswarn is not None and getbool(iswarn): 100 | if 'level' not in kwargs: 101 | kwargs['level'] = 'WARNING' 102 | if 'format' not in kwargs: 103 | kwargs['format'] = 'warn' 104 | 105 | self.loglevel = LogLevel(kwargs.get('level', logging.INFO)) 106 | 107 | f = EchoFormat(kwargs.get('format', FMT_DEFAULT)) 108 | self.fmt = msgformats[f.msgformat] 109 | 110 | 111 | def action(self): 112 | return BibFilter.BIB_FILTER_BIBOLAMAZIFILE 113 | 114 | def filter_bibolamazifile(self, bibolamazifile): 115 | 116 | logger.log(self.loglevel.levelno, 117 | self.fmt, 118 | self.message) 119 | 120 | return 121 | 122 | 123 | def bibolamazi_filter_class(): 124 | return EchoFilter 125 | 126 | -------------------------------------------------------------------------------- /bibolamazi/filters/shorten_authors_etal.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | ################################################################################ 3 | # # 4 | # This file is part of the Bibolamazi Project. # 5 | # Copyright (C) 2018 by Philippe Faist # 6 | # philippe.faist@bluewin.ch # 7 | # # 8 | # Bibolamazi is free software: you can redistribute it and/or modify # 9 | # it under the terms of the GNU General Public License as published by # 10 | # the Free Software Foundation, either version 3 of the License, or # 11 | # (at your option) any later version. # 12 | # # 13 | # Bibolamazi is distributed in the hope that it will be useful, # 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of # 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # 16 | # GNU General Public License for more details. # 17 | # # 18 | # You should have received a copy of the GNU General Public License # 19 | # along with Bibolamazi. If not, see . # 20 | # # 21 | ################################################################################ 22 | 23 | 24 | #import re 25 | import logging 26 | logger = logging.getLogger(__name__) 27 | 28 | #from bibolamazi.core.butils import getbool 29 | from bibolamazi.core.bibfilter import BibFilter #, BibFilterError 30 | from bibolamazi.core.bibfilter.argtypes import CommaStrList 31 | 32 | from pybtex.database import Person 33 | 34 | 35 | HELP_AUTHOR = r""" 36 | Shorten-authors-etal filter by Philippe Faist, (C) 2018, GPL 3+ 37 | """ 38 | 39 | HELP_DESC = r""" 40 | Shorten author list to a custom length and add "et al.", for standard BibTeX styles 41 | """ 42 | 43 | HELP_TEXT = r""" 44 | This filter shortens long author lists (you can specify max length with 45 | -sMaxNumAuthors=5) by instead "First author et al.". 46 | 47 | While normally this should be handled by the bibtex style, standard bibtex 48 | styles understand the author name "others" to be replaced by "et al.". This 49 | filter replaces long author lists (as determined by MaxNumAuthors) by "First 50 | Author and others", which is then formatted as "First Author et al.". 51 | """ 52 | 53 | 54 | class ShortenAuthorsEtalFilter(BibFilter): 55 | 56 | helpauthor = HELP_AUTHOR 57 | helpdescription = HELP_DESC 58 | helptext = HELP_TEXT 59 | 60 | def __init__(self, max_num_authors=5, num_keep_authors=1, apply_to_roles='author'): 61 | r""" 62 | 63 | Arguments: 64 | 65 | - max_num_authors(int): Maximum number of authors in list 66 | before "etal-ization". 67 | 68 | - num_keep_authors(int): If an author list is "etal-ized", 69 | then we keep this many authors before "et al.". For example, 70 | if num_keep_authors=2, then the result for long author lists is 71 | "First Author, Second Author, et al." (Note MaxNumAuthors 72 | still controls when the "etal-ization" occurs.) 73 | 74 | - apply_to_roles(CommaStrList): either "author", "editor" or 75 | "author,editor" to apply the "etal-ization" to author lists, 76 | editor lists, or to both. 77 | """ 78 | super().__init__() 79 | 80 | self.max_num_authors = int(max_num_authors) 81 | self.num_keep_authors = int(num_keep_authors) 82 | self.apply_to_roles = CommaStrList(apply_to_roles) 83 | 84 | logger.debug('shorten_authors_etal filter constructor done; ' 85 | 'max_num_authors=%d, num_keep_authors=%d, apply_to_roles=%r', 86 | self.max_num_authors, self.num_keep_authors, self.apply_to_roles) 87 | 88 | 89 | def action(self): 90 | return BibFilter.BIB_FILTER_SINGLE_ENTRY 91 | 92 | 93 | def filter_bibentry(self, entry): 94 | # 95 | # entry is a pybtex.database.Entry object 96 | # 97 | for role in self.apply_to_roles: 98 | if not role in entry.persons: 99 | continue # no author/editor list 100 | #logger.debug('Testing %s[%s] for author list truncation: %r ; %d %d', 101 | # entry.key, role, entry.persons[role], len(entry.persons[role]), 102 | # self.max_num_authors) 103 | if len(entry.persons[role]) > self.max_num_authors: 104 | # apply etal-ization 105 | entry.persons[role] = entry.persons[role][:self.num_keep_authors] + [Person('others')] 106 | 107 | #logger.debug('entry.persons[role] is now %r', entry.persons[role]) 108 | 109 | return 110 | 111 | 112 | 113 | def bibolamazi_filter_class(): 114 | return ShortenAuthorsEtalFilter 115 | 116 | -------------------------------------------------------------------------------- /test/test_full_cases.py: -------------------------------------------------------------------------------- 1 | 2 | import unittest 3 | 4 | import os.path 5 | import tempfile 6 | import shutil 7 | import logging 8 | import time 9 | 10 | from bibolamazi.core.bibolamazifile import BibolamaziFile 11 | import bibolamazi.core.main 12 | 13 | # import pybtex *after* bibolamazi (might need monkey-patching) 14 | import pybtex.database.input.bibtex 15 | 16 | import helpers 17 | 18 | from bibolamazi.core import blogger 19 | 20 | import bibolamazi.core.bibfilter.factory as filters_factory 21 | from bibolamazi.core.bibfilter import pkgprovider, pkgfetcher_github 22 | 23 | # 24 | # set up remote filter package fetching, usually this is done in main.py or bibolamaziapp.py 25 | # 26 | filters_factory.package_provider_manager = pkgprovider.PackageProviderManager() 27 | filters_factory.package_provider_manager.allow_remote = True 28 | filters_factory.package_provider_manager.registerPackageProvider( 29 | pkgfetcher_github.GithubPackageProvider(None) 30 | ) 31 | 32 | 33 | # 34 | # TO DEBUG: Create an empty subdir in this directory called '_tmpdir' and set 35 | # `use_mkdtemp=False` below. The processed bibolamazi file will be left there, 36 | # we can diff with the original to see what happened. Don't forget to clean up 37 | # the directory for each run. 38 | # 39 | use_mkdtemp = True #False 40 | localtmpdir = '_tmpdir' # used if use_mkdtemp=False 41 | 42 | 43 | 44 | 45 | class FullCaseTester: 46 | def __init__(self): 47 | super().__init__() 48 | 49 | 50 | def _run_full_case_test(self, name): 51 | 52 | logging.getLogger(__name__).info( 53 | "********** RUNNING \"FULL CASE\" TEST %s **********", 54 | name 55 | ) 56 | 57 | if use_mkdtemp: 58 | tmpdir = tempfile.mkdtemp() 59 | else: 60 | tmpdir = os.path.abspath(os.path.join(os.path.dirname(__file__), localtmpdir)) 61 | 62 | try: 63 | tmpbib = os.path.join(tmpdir, name+'.bibolamazi.bib') 64 | full_cases_dir = os.path.realpath( 65 | os.path.abspath(os.path.join(os.path.dirname(__file__), 'full_cases')) 66 | ) 67 | shutil.copyfile(os.path.join(full_cases_dir, name+'.bibolamazi.bib'), 68 | tmpbib) 69 | # symlink source files 70 | os.symlink(os.path.join(full_cases_dir, 'srcbib'), 71 | os.path.join(tmpdir, 'srcbib')) 72 | # symlink extra filter package source 73 | os.symlink(os.path.join(full_cases_dir, 'more_filters'), 74 | os.path.join(tmpdir, 'more_filters')) 75 | # ... and any necessary tex/aux files 76 | for auxfext in ('.tex', '.aux', '_jobname.tex', '_jobname.aux', '_job.tex', '_job.aux'): 77 | if os.path.exists(os.path.join(full_cases_dir, name + auxfext)): 78 | shutil.copyfile(os.path.join(full_cases_dir, name + auxfext), 79 | os.path.join(tmpdir, name + auxfext)) 80 | 81 | time.sleep(0.5) 82 | 83 | bfile = BibolamaziFile(tmpbib) 84 | 85 | parser = pybtex.database.input.bibtex.Parser() 86 | bf_orig_data = parser.parse_string(bfile.rawRest()) 87 | 88 | # run bibolamazi on the file -- run all filters 89 | for filtr in bfile.filters(): 90 | bfile.runFilter(filtr) 91 | 92 | bfile.saveToFile() # for debugging 93 | 94 | # compare the contents before and after the run 95 | self.assert_keyentrylists_equal(list(bf_orig_data.entries.items()), 96 | list(bfile.bibliographyData().entries.items())) 97 | 98 | finally: 99 | if use_mkdtemp: 100 | shutil.rmtree(tmpdir) 101 | 102 | 103 | 104 | class TestFullCases(unittest.TestCase, FullCaseTester, helpers.CustomAssertions): 105 | 106 | def __init__(self, *args, **kwargs): 107 | super().__init__(*args, **kwargs) 108 | 109 | self.maxDiff = None 110 | 111 | 112 | def test_0(self): 113 | self._run_full_case_test('test0') 114 | 115 | def test_1(self): 116 | self._run_full_case_test('test1') 117 | 118 | def test_2(self): 119 | self._run_full_case_test('test2') 120 | 121 | def test_3(self): 122 | self._run_full_case_test('test3') 123 | 124 | def test_5(self): 125 | self._run_full_case_test('test5') 126 | 127 | def test_5a(self): 128 | self._run_full_case_test('test5a') 129 | 130 | def test_6(self): 131 | self._run_full_case_test('test6') 132 | 133 | def test_7(self): 134 | self._run_full_case_test('test7') 135 | 136 | # test8 used to be inspirehep -- see now test_filters_citeinspirehep.py 137 | #def test_8(self): 138 | # self._run_full_case_test('test8') 139 | 140 | def test_9(self): 141 | self._run_full_case_test('test9') 142 | 143 | def zzztest(self): 144 | self._run_full_case_test('zzztest') 145 | 146 | @helpers.test_requires_github_access() 147 | def test_github_remote(self): 148 | self._run_full_case_test('test_github_remote') 149 | 150 | 151 | 152 | if __name__ == '__main__': 153 | blogger.setup_simple_console_logging(level=logging.INFO) 154 | unittest.main() 155 | -------------------------------------------------------------------------------- /gui/bibolamazi_gui/qtauto/ui_startupwidget.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Form implementation generated from reading ui file 'startupwidget.ui' 4 | # 5 | # Created by: PyQt5 UI code generator 5.12.1 6 | # 7 | # WARNING! All changes made in this file will be lost! 8 | 9 | from PyQt5 import QtCore, QtGui, QtWidgets 10 | 11 | 12 | class Ui_StartupWidget(object): 13 | def setupUi(self, StartupWidget): 14 | StartupWidget.setObjectName("StartupWidget") 15 | StartupWidget.resize(421, 441) 16 | self.verticalLayout_3 = QtWidgets.QVBoxLayout(StartupWidget) 17 | self.verticalLayout_3.setObjectName("verticalLayout_3") 18 | self.horizontalLayout = QtWidgets.QHBoxLayout() 19 | self.horizontalLayout.setObjectName("horizontalLayout") 20 | spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) 21 | self.horizontalLayout.addItem(spacerItem) 22 | self.lblMain = QtWidgets.QLabel(StartupWidget) 23 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) 24 | sizePolicy.setHorizontalStretch(0) 25 | sizePolicy.setVerticalStretch(0) 26 | sizePolicy.setHeightForWidth(self.lblMain.sizePolicy().hasHeightForWidth()) 27 | self.lblMain.setSizePolicy(sizePolicy) 28 | self.lblMain.setPixmap(QtGui.QPixmap(":/pic/bibolamazi.png")) 29 | self.lblMain.setObjectName("lblMain") 30 | self.horizontalLayout.addWidget(self.lblMain) 31 | spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) 32 | self.horizontalLayout.addItem(spacerItem1) 33 | self.verticalLayout_3.addLayout(self.horizontalLayout) 34 | spacerItem2 = QtWidgets.QSpacerItem(20, 5, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) 35 | self.verticalLayout_3.addItem(spacerItem2) 36 | self.frame = QtWidgets.QFrame(StartupWidget) 37 | self.frame.setObjectName("frame") 38 | self.gridLayout = QtWidgets.QGridLayout(self.frame) 39 | self.gridLayout.setHorizontalSpacing(5) 40 | self.gridLayout.setObjectName("gridLayout") 41 | self.btnOpenFile = QtWidgets.QPushButton(self.frame) 42 | self.btnOpenFile.setObjectName("btnOpenFile") 43 | self.gridLayout.addWidget(self.btnOpenFile, 0, 0, 1, 1) 44 | self.btnNewFile = QtWidgets.QPushButton(self.frame) 45 | self.btnNewFile.setObjectName("btnNewFile") 46 | self.gridLayout.addWidget(self.btnNewFile, 1, 0, 1, 2) 47 | self.btnOpenRecent = QtWidgets.QPushButton(self.frame) 48 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) 49 | sizePolicy.setHorizontalStretch(0) 50 | sizePolicy.setVerticalStretch(0) 51 | sizePolicy.setHeightForWidth(self.btnOpenRecent.sizePolicy().hasHeightForWidth()) 52 | self.btnOpenRecent.setSizePolicy(sizePolicy) 53 | self.btnOpenRecent.setObjectName("btnOpenRecent") 54 | self.gridLayout.addWidget(self.btnOpenRecent, 0, 1, 1, 1) 55 | self.verticalLayout_3.addWidget(self.frame) 56 | spacerItem3 = QtWidgets.QSpacerItem(20, 5, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) 57 | self.verticalLayout_3.addItem(spacerItem3) 58 | self.frame_2 = QtWidgets.QFrame(StartupWidget) 59 | self.frame_2.setObjectName("frame_2") 60 | self.gridLayout_2 = QtWidgets.QGridLayout(self.frame_2) 61 | self.gridLayout_2.setObjectName("gridLayout_2") 62 | self.btnSettings = QtWidgets.QPushButton(self.frame_2) 63 | self.btnSettings.setObjectName("btnSettings") 64 | self.gridLayout_2.addWidget(self.btnSettings, 0, 0, 1, 1) 65 | self.btnHelp = QtWidgets.QPushButton(self.frame_2) 66 | self.btnHelp.setObjectName("btnHelp") 67 | self.gridLayout_2.addWidget(self.btnHelp, 1, 0, 1, 1) 68 | self.verticalLayout_3.addWidget(self.frame_2) 69 | spacerItem4 = QtWidgets.QSpacerItem(20, 5, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) 70 | self.verticalLayout_3.addItem(spacerItem4) 71 | spacerItem5 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) 72 | self.verticalLayout_3.addItem(spacerItem5) 73 | self.btnQuit = QtWidgets.QPushButton(StartupWidget) 74 | icon = QtGui.QIcon() 75 | icon.addPixmap(QtGui.QPixmap(":/pic/closehide.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) 76 | self.btnQuit.setIcon(icon) 77 | self.btnQuit.setObjectName("btnQuit") 78 | self.verticalLayout_3.addWidget(self.btnQuit) 79 | 80 | self.retranslateUi(StartupWidget) 81 | QtCore.QMetaObject.connectSlotsByName(StartupWidget) 82 | 83 | def retranslateUi(self, StartupWidget): 84 | _translate = QtCore.QCoreApplication.translate 85 | StartupWidget.setWindowTitle(_translate("StartupWidget", "Bibolamazi")) 86 | self.btnOpenFile.setText(_translate("StartupWidget", "Open Bibolamazi File")) 87 | self.btnNewFile.setText(_translate("StartupWidget", "Create New Bibolamazi File ...")) 88 | self.btnOpenRecent.setText(_translate("StartupWidget", "...")) 89 | self.btnSettings.setText(_translate("StartupWidget", "Settings")) 90 | self.btnHelp.setText(_translate("StartupWidget", "Help && Reference Browser")) 91 | self.btnQuit.setText(_translate("StartupWidget", "Quit")) 92 | 93 | 94 | from . import bibolamazi_res_rc 95 | -------------------------------------------------------------------------------- /bibolamazi/init.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | ################################################################################ 3 | # # 4 | # This file is part of the Bibolamazi Project. # 5 | # Copyright (C) 2015 by Philippe Faist # 6 | # philippe.faist@bluewin.ch # 7 | # # 8 | # Bibolamazi is free software: you can redistribute it and/or modify # 9 | # it under the terms of the GNU General Public License as published by # 10 | # the Free Software Foundation, either version 3 of the License, or # 11 | # (at your option) any later version. # 12 | # # 13 | # Bibolamazi is distributed in the hope that it will be useful, # 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of # 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # 16 | # GNU General Public License for more details. # 17 | # # 18 | # You should have received a copy of the GNU General Public License # 19 | # along with Bibolamazi. If not, see . # 20 | # # 21 | ################################################################################ 22 | 23 | 24 | """ 25 | Initialization module 26 | 27 | This module is imported before any other bibolamazi module, just to make sure we have 28 | all the proper dependent modules set up, or to include our pre-packaged versions if need 29 | be. 30 | 31 | In fact, all bibolamazi modules import this module, so you don't even have to worry 32 | about importing it first. 33 | """ 34 | 35 | 36 | import sys 37 | import re 38 | 39 | 40 | if sys.version_info < (3, 4): 41 | raise RuntimeError("FATAL ERROR: Bibolamazi requires Python >= 3.4") 42 | 43 | 44 | # 45 | # add the LONGDEBUG level, and set our custom logger class 46 | # 47 | from .core import blogger as _blogger # lgtm 48 | 49 | 50 | 51 | # 52 | # Patch for pybtex. Bug in pybtex/bibtex/utils.py in split_tex_string 53 | # (https://sourceforge.net/p/pybtex/bugs/65/) 54 | # 55 | import pybtex.bibtex.utils as _pybtex_bibtex_utils 56 | def _split_tex_string(string, sep=None, strip=True, filter_empty=False): 57 | if sep is None: 58 | sep = r'(?:\s|(? 0: 72 | ### PhF: FIX TO NOT TRUNCATE THE STRING, TO ENABLE THE LOOKBEHIND ASSERTION IN REGEX. 73 | match = sep_re.match(string, pos=pos) 74 | if match: 75 | sep_len = len(match.group()) 76 | if pos + sep_len < string_len: 77 | result.append(string[name_start:pos]) 78 | name_start = pos + sep_len 79 | if name_start < string_len: 80 | result.append(string[name_start:]) 81 | if strip: 82 | result = [part.strip() for part in result] 83 | if filter_empty: 84 | result = [part for part in result if part] 85 | return result 86 | # 87 | _pybtex_bibtex_utils.split_tex_string = _split_tex_string 88 | 89 | 90 | 91 | # 92 | # Patch for pybtex. Bug in pybtex.database.output.bibtex: will insist on 93 | # escaping everything into latex, even latex commands themselves.... 94 | # so disable that. 95 | # 96 | import pybtex.database.output.bibtex as _pybtex_database_output_bibtex 97 | _pybtex_database_output_bibtex.Writer._encode = lambda self, text: text # do nothing please!! 98 | 99 | 100 | 101 | 102 | 103 | # 104 | # Patch for pybtex. Add __delitem__ to a OrderedCaseInsensitiveDict so that we 105 | # can erase fields in entry.fields 106 | # 107 | # import pybtex.utils as _pybtex_utils 108 | # def _OrderedCaseInsensitiveDict_delitem(self, key): 109 | # # find item 110 | # key_match = [k for k in self.order if k.lower() == key.lower()] 111 | # if len(key_match) == 0: 112 | # raise KeyError(key) 113 | # assert (len(key_match) == 1), "Multiple instances of same key in dictionary: %s"%(key) 114 | # # now we have the key with the right case 115 | # key_ok = key_match[0] 116 | # self.order.remove(key_ok) 117 | # super(_pybtex_utils.OrderedCaseInsensitiveDict, self).__delitem__(key_ok) 118 | 119 | # _pybtex_utils.OrderedCaseInsensitiveDict.__delitem__ = _OrderedCaseInsensitiveDict_delitem 120 | 121 | 122 | 123 | 124 | 125 | # 126 | # Patch for arxiv2bib (see https://github.com/nathangrigg/arxiv2bib/issues/8). 127 | # Recognize some really old arXiv IDs like 'atom-ph/XXXXXXX' instead of 128 | # 'physics/XXXXXXX' etc. 129 | # 130 | import arxiv2bib as _arxiv2bib 131 | _arxiv2bib.OLD_STYLE = re.compile(r"""^[a-zA-Z.-]+/\d{7}(v\d+)?$""") 132 | -------------------------------------------------------------------------------- /gui/bibolamazi_gui/bibconfigsynthigh.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | ################################################################################ 4 | # # 5 | # This file is part of the Bibolamazi Project. # 6 | # Copyright (C) 2013 by Philippe Faist # 7 | # philippe.faist@bluewin.ch # 8 | # # 9 | # Bibolamazi is free software: you can redistribute it and/or modify # 10 | # it under the terms of the GNU General Public License as published by # 11 | # the Free Software Foundation, either version 3 of the License, or # 12 | # (at your option) any later version. # 13 | # # 14 | # Bibolamazi is distributed in the hope that it will be useful, # 15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of # 16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # 17 | # GNU General Public License for more details. # 18 | # # 19 | # You should have received a copy of the GNU General Public License # 20 | # along with Bibolamazi. If not, see . # 21 | # # 22 | ################################################################################ 23 | 24 | 25 | import re 26 | 27 | import bibolamazi.init 28 | # bibolamazi filters 29 | from bibolamazi.core.bibfilter import factory as filters_factory 30 | from bibolamazi.core.bibolamazifile import BIBOLAMAZIFILE_COMMANDS 31 | 32 | from PyQt5.QtCore import * 33 | from PyQt5.QtGui import * 34 | 35 | 36 | 37 | rxsrc = re.compile(r'^\s*(?Psrc:)', re.MULTILINE) 38 | rxfilter = re.compile(r'^\s*(?Pfilter:)\s+(?P[-:\w]+)', re.MULTILINE) 39 | rxcmdother = re.compile(r'^\s*(?P(' 40 | + '|'.join([x for x in BIBOLAMAZIFILE_COMMANDS if x not in ['src', 'filter']]) 41 | + r'):)', re.MULTILINE) 42 | rxcomment = re.compile(r'^\s*%%.*$', re.MULTILINE) 43 | _rx_not_odd_num_backslashes = r'(((?<=[^\\])|^)(\\\\)*)'; 44 | rxstring1 = re.compile(_rx_not_odd_num_backslashes+r'(?P\"([^"\\]|\\\\|\\\")*\")', re.MULTILINE) 45 | rxstring2 = re.compile(_rx_not_odd_num_backslashes+r"(?P\'[^']*\')", re.MULTILINE) 46 | 47 | 48 | class BibolamaziConfigSyntaxHighlighter(QSyntaxHighlighter): 49 | def __init__(self, parent=None): 50 | super().__init__(parent) 51 | 52 | self.fmt_src = QTextCharFormat() 53 | self.fmt_src.setFontWeight(QFont.Bold) 54 | self.fmt_src.setForeground(QColor(0, 180, 180)) 55 | 56 | self.fmt_filter = QTextCharFormat() 57 | self.fmt_filter.setFontWeight(QFont.Bold) 58 | self.fmt_filter.setForeground(QColor(200,0,0)) 59 | 60 | self.fmt_cmdother = QTextCharFormat() 61 | self.fmt_cmdother.setFontWeight(QFont.Bold) 62 | 63 | self.fmt_filtername = QTextCharFormat() 64 | self.fmt_filtername.setForeground(QColor(100, 100, 200)) 65 | 66 | self.fmt_filtername_nonex = QTextCharFormat(self.fmt_filtername) 67 | self.fmt_filtername_nonex.setUnderlineStyle(QTextCharFormat.SpellCheckUnderline) 68 | 69 | self.fmt_comment = QTextCharFormat() 70 | self.fmt_comment.setForeground(QColor(120,140,120)) 71 | self.fmt_comment.setFontItalic(True) 72 | 73 | self.fmt_string = QTextCharFormat() 74 | self.fmt_string.setForeground(QColor(0,180,0)) 75 | 76 | 77 | def highlightBlock(self, text): 78 | 79 | #pcache = BibConfigParsingCache() 80 | 81 | #blockno = self.currentBlock().blockNumber() 82 | 83 | for m in rxsrc.finditer(text): 84 | self.setFormat(m.start('src'), len(m.group('src')), self.fmt_src) 85 | #pcache.add_sourcelist(line=blockno) 86 | 87 | for m in rxfilter.finditer(text): 88 | self.setFormat(m.start('filter'), len(m.group('filter')), self.fmt_filter) 89 | fmtname = self.fmt_filtername 90 | try: 91 | # try to load the filter module to see if it exists 92 | filtmodule = filters_factory.FilterInfo(m.group('filtername')) 93 | except Exception: 94 | fmtname = self.fmt_filtername_nonex 95 | 96 | #pcache.add_filter(line=blockno, filtername=m.group('filtername')) 97 | 98 | self.setFormat(m.start('filtername'), len(m.group('filtername')), fmtname) 99 | 100 | for m in rxcmdother.finditer(text): 101 | self.setFormat(m.start('cmd'), len(m.group('cmd')), self.fmt_cmdother) 102 | 103 | for m in rxstring1.finditer(text): 104 | self.setFormat(m.start('str'), len(m.group('str')), self.fmt_string) 105 | for m in rxstring2.finditer(text): 106 | self.setFormat(m.start('str'), len(m.group('str')), self.fmt_string) 107 | 108 | for m in rxcomment.finditer(text): 109 | self.setFormat(m.start(), len(m.group()), self.fmt_comment) 110 | 111 | #self.setCurrentBlockState(0) 112 | #self.setCurrentBlockUserData(pcache) 113 | -------------------------------------------------------------------------------- /gui/bibolamazi_gui/githubreposelector.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | ################################################################################ 3 | # # 4 | # This file is part of the Bibolamazi Project. # 5 | # Copyright (C) 2018 by Philippe Faist # 6 | # philippe.faist@bluewin.ch # 7 | # # 8 | # Bibolamazi is free software: you can redistribute it and/or modify # 9 | # it under the terms of the GNU General Public License as published by # 10 | # the Free Software Foundation, either version 3 of the License, or # 11 | # (at your option) any later version. # 12 | # # 13 | # Bibolamazi is distributed in the hope that it will be useful, # 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of # 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # 16 | # GNU General Public License for more details. # 17 | # # 18 | # You should have received a copy of the GNU General Public License # 19 | # along with Bibolamazi. If not, see . # 20 | # # 21 | ################################################################################ 22 | 23 | import logging 24 | from html import escape as htmlescape 25 | 26 | import github 27 | 28 | import bibolamazi.init 29 | 30 | from PyQt5.QtCore import * 31 | from PyQt5.QtGui import * 32 | from PyQt5.QtWidgets import * 33 | 34 | from .uiutils import BlockedSignals #, ContextAttributeSetter 35 | from .qtauto.ui_githubreposelector import Ui_GithubRepoSelector 36 | 37 | logger = logging.getLogger(__name__) 38 | 39 | 40 | # ------------------------------------------------------------------------------ 41 | 42 | 43 | class GithubRepoSelector(QDialog): 44 | def __init__(self, parent): 45 | super().__init__(parent) 46 | 47 | self.ui = Ui_GithubRepoSelector() 48 | self.ui.setupUi(self) 49 | 50 | self.ui.stk.setCurrentWidget(self.ui.pageUsername) 51 | 52 | self.ui.cbxRepos.repolist = [] 53 | 54 | self._update_gui_state() 55 | 56 | def getUsernameRepo(self): 57 | return (self.ui.txtUser.text(), self.ui.cbxRepos.currentText()) 58 | 59 | def getFilterPackageUrl(self): 60 | return 'github:' + self.ui.txtUser.text() + '/' + self.ui.cbxRepos.currentText() 61 | 62 | @pyqtSlot(str) 63 | def on_txtUser_textChanged(self, txt): 64 | self._update_gui_state() 65 | 66 | @pyqtSlot() 67 | def on_btnBack_clicked(self): 68 | self.ui.stk.setCurrentWidget(self.ui.pageUsername) 69 | self._update_gui_state() 70 | 71 | @pyqtSlot() 72 | def on_btnNext_clicked(self): 73 | self.ui.stk.setCurrentWidget(self.ui.pageRepo) 74 | self._update_gui_state() 75 | 76 | @pyqtSlot(str) 77 | def on_cbxRepos_editTextChanged(self, text): 78 | self._update_gui_state() 79 | 80 | @pyqtSlot() 81 | def on_btnOk_clicked(self): 82 | self.accept() 83 | 84 | def _update_gui_state(self): 85 | if self.ui.stk.currentWidget() == self.ui.pageUsername: 86 | self.ui.stk.setCurrentWidget(self.ui.pageUsername) 87 | self.ui.btnBack.setVisible(False) 88 | self.ui.btnNext.setVisible(True) 89 | self.ui.btnNext.setEnabled(True if self.ui.txtUser.text() else False) 90 | self.ui.btnOk.setVisible(False) 91 | elif self.ui.stk.currentWidget() == self.ui.pageRepo: 92 | username = self.ui.txtUser.text() 93 | self.ui.lblPromptRepo.setTextFormat(Qt.RichText) 94 | self.ui.lblPromptRepo.setText("Repositories for {}".format(htmlescape(username))) 95 | try: 96 | repolist = self._get_repolist_for_user(username) 97 | if self.ui.cbxRepos.repolist != repolist: 98 | with BlockedSignals(self.ui.cbxRepos): 99 | self.ui.cbxRepos.clear() 100 | for repo in repolist: 101 | self.ui.cbxRepos.addItem(repo) 102 | self.ui.cbxRepos.repolist = repolist 103 | except Exception as e: 104 | logger.debug("Ignoring exception ... %r", e) 105 | logger.exception("Ignoring exception") 106 | 107 | self.ui.btnBack.setVisible(True) 108 | self.ui.btnNext.setVisible(False) 109 | self.ui.btnOk.setVisible(True) 110 | self.ui.btnOk.setEnabled(True if self.ui.cbxRepos.currentText() else False) 111 | 112 | 113 | def _get_repolist_for_user(self, username): 114 | 115 | # use auth_token, if set 116 | from . import bibolamaziapp 117 | auth_token = bibolamaziapp.app_filterpackage_providers['github'].getAuthToken() 118 | 119 | if auth_token: 120 | G = github.Github(auth_token) 121 | else: 122 | G = github.Github() 123 | 124 | repo_list = [] 125 | for repo in G.get_user(username).get_repos(): 126 | repo_list.append(repo.name) 127 | 128 | logger.debug("Got repository list for user %r -> %r", username, repo_list) 129 | 130 | return repo_list 131 | 132 | 133 | --------------------------------------------------------------------------------