diff --git a/_unittests/ut_pycode/test_check_pep8_sample.py b/_unittests/ut_pycode/test_check_pep8_sample.py index 3ccaf116..9bdcee15 100644 --- a/_unittests/ut_pycode/test_check_pep8_sample.py +++ b/_unittests/ut_pycode/test_check_pep8_sample.py @@ -3,8 +3,7 @@ """ import os import unittest - -from pyquickhelper.loghelper import fLOG +import sys from pyquickhelper.pycode import check_pep8, ExtTestCase from pyquickhelper.pycode.utils_tests_helper import PEP8Exception @@ -23,21 +22,18 @@ def unused_var(self): def undeclared_var(self): aa + 5 # pylint: disable=E0602, W0104 + @unittest.skipIf(sys.version_info[:2] <= (3, 6), + reason="pylint not available in the last version") def test_unused_variable(self): - fLOG( - __file__, - self._testMethodName, - OutputPrint=__name__ == "__main__") - this = os.path.abspath(os.path.dirname(__file__)) def check_pep8_one_file(): - check_pep8(this, fLOG=fLOG, max_line_length=150, recursive=False, + check_pep8(this, max_line_length=150, recursive=False, neg_pattern="##", pattern="test_check_pep8_sample.py") def check_pep8_error_file(): - check_pep8(this, fLOG=fLOG, recursive=False, + check_pep8(this, recursive=False, pylint_ignore=('C0111', 'R0201', 'C0103'), pattern="test_check_pep8_sample.py", neg_pattern="##", @@ -49,12 +45,12 @@ def check_pep8_error_file(): self.assertRaise(check_pep8_one_file, PEP8Exception, "F[ECL1] line too long (link) 169 > 150") - check_pep8(this, fLOG=fLOG, max_line_length=170, recursive=False, - pylint_ignore=('C0111', 'R0201', 'C0103'), + check_pep8(this, max_line_length=170, recursive=False, + pylint_ignore=('C0111', 'C0103'), pattern="test_check_pep8_sample.py", neg_pattern="##", skip=["test_check_pep8_sample.py:373: [E731]", - "test_check_pep8_sample.py:36", + "test_check_pep8_sample.py:35", "test_check_pep8_sample.py:39", "test_check_pep8_sample.py:11", "test_check_pep8_sample.py:40: E0602", diff --git a/_unittests/ut_sphinxext/test_builders_missing.py b/_unittests/ut_sphinxext/test_builders_missing.py index 5c742b96..6d1913f5 100644 --- a/_unittests/ut_sphinxext/test_builders_missing.py +++ b/_unittests/ut_sphinxext/test_builders_missing.py @@ -16,6 +16,7 @@ class TestBuildersMissing(ExtTestCase): def test_builders_missing(self): from docutils import nodes as skip_ from sphinx.builders.latex.util import ExtBabel + from sphinx.builders.latex.theming import Theme context = {'sphinxpkgoptions': '', 'latex_engine': 'pdflatex', 'fontenc': [], 'babel': [], @@ -68,7 +69,11 @@ def get(self, name): # pylint: disable=R1711 document = dummy() for cl in cls: - inst = cl(document, builder) + if cl == EnhancedLaTeXTranslator: + theme = Theme('manual') + inst = cl(document, builder, theme) + else: + inst = cl(document, builder) inst._footnote = 'nofootnote' inst.rst_image_dest = '' if hasattr(inst, 'visit_table'): diff --git a/_unittests/ut_sphinxext/test_simpleimage_extension.py b/_unittests/ut_sphinxext/test_simpleimage_extension.py index 67928e75..5305536b 100644 --- a/_unittests/ut_sphinxext/test_simpleimage_extension.py +++ b/_unittests/ut_sphinxext/test_simpleimage_extension.py @@ -1,5 +1,5 @@ """ -@brief test log(time=4s) +@brief test log(time=6s) @author Xavier Dupre """ import sys @@ -10,8 +10,6 @@ import shutil from io import StringIO from docutils.parsers.rst import directives - -from pyquickhelper.loghelper.flog import fLOG from pyquickhelper.pycode import get_temp_folder, ExtTestCase, is_travis_or_appveyor from pyquickhelper.helpgen import rst2html from pyquickhelper.sphinxext import SimpleImageDirective @@ -23,19 +21,9 @@ class TestSimpleImageExtension(ExtTestCase): def test_post_parse_sn(self): - fLOG( - __file__, - self._testMethodName, - OutputPrint=__name__ == "__main__") - directives.register_directive("video", SimpleImageDirective) def test_simpleimage(self): - fLOG( - __file__, - self._testMethodName, - OutputPrint=__name__ == "__main__") - from docutils import nodes as skip_ this = os.path.abspath(os.path.dirname(__file__)) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 9ca250df..85500b0a 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -6,8 +6,16 @@ jobs: matrix: Python310: python.version: '3.10' + sphinx.version: '' + require.version: '' + Python310-4: + python.version: '3.10' + sphinx.version: '==4.5.0' + require.version: '' Python36: python.version: '3.6' + sphinx.version: '' + require.version: '-3.6' maxParallel: 3 steps: @@ -29,7 +37,7 @@ jobs: displayName: 'Install Graphviz' - script: python -m pip install --upgrade pip setuptools wheel displayName: 'Install tools' - - script: pip install -r requirements.txt + - script: pip install -r requirements$(require.version).txt displayName: 'Install Requirements' - script: python -m pip install scikit-learn displayName: 'Install scipy scikit-learn' @@ -37,6 +45,8 @@ jobs: displayName: 'Install tkinterquickhelper' - script: pip uninstall -y pyquickhelper displayName: 'uninstall pyquickhelper' + - script: python -m pip install "sphinx$(sphinx.version)" + displayName: 'Install Sphinx' - script: export PYTHONPATH=src displayName: 'PYTHONPATH=src' - script: | @@ -50,6 +60,7 @@ jobs: # - script: python -u setup.py build_sphinx # displayName: 'Builds Documentation' - task: PublishPipelineArtifact@0 + condition: eq('$(sphinx.version)', '') inputs: artifactName: 'wheel-linux-$(python.version)' targetPath: 'dist' diff --git a/requirements-3.6.txt b/requirements-3.6.txt new file mode 100644 index 00000000..80a18c5f --- /dev/null +++ b/requirements-3.6.txt @@ -0,0 +1,59 @@ +autopep8 +bokeh +cairosvg>=2.5.0 +cffi +codecov +coverage>=5.0 +cryptography +docformatter +fastapi +fire +git-pandas +gitdb +img2pdf +ipython>=7.0.0 +jinja2==3.0.3 +js2py +jupyter +jupyter-client +jupyter-sphinx>=0.2.0 +jyquickhelper>=0.3.128 +keyring +keyrings.alt +keyrings.cryptfile +Mako +matplotlib +mistune +nbconvert>=6.0.7,!=6.3.0,!=6.4.0,!=6.4.1,!=6.4.2,!=6.5.0 +nbformat +notebook>=6.0.0 +numpy>=1.19 +numpydoc +openpyxl +pandas>=1.0 +pandocfilters +pillow +psutil +pycodestyle>=2.0.0 +pycryptodomex +pydocstyle +pyinstrument +pylint +pylzma +pyquicksetup +pysftp +python-jenkins>=1.0.0 +PyYAML +scipy +semantic_version +setuptools +Sphinx>=3.0 +sphinx-gallery +sphinxcontrib-imagesvg +sphinx_rtd_theme +tabulate +tqdm +traitlets +unify +virtualenv +wheel diff --git a/requirements.txt b/requirements.txt index 80a18c5f..c88660a2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -38,7 +38,7 @@ pycodestyle>=2.0.0 pycryptodomex pydocstyle pyinstrument -pylint +pylint>=2.14.0 pylzma pyquicksetup pysftp diff --git a/src/pyquickhelper/helpgen/sphinxm_convert_doc_sphinx_helper.py b/src/pyquickhelper/helpgen/sphinxm_convert_doc_sphinx_helper.py index ce8a7184..758898fa 100644 --- a/src/pyquickhelper/helpgen/sphinxm_convert_doc_sphinx_helper.py +++ b/src/pyquickhelper/helpgen/sphinxm_convert_doc_sphinx_helper.py @@ -443,7 +443,12 @@ def translate(self): # visitor = self.builder.create_translator(self.document, self.builder) # automatically adds methods visit_ and depart_ for translator # based on the list of registered extensions. Might be worth using it. - visitor = self.translator_class(self.document, self.builder) + theme = self.builder.themes.get('manual') + if theme is None: + raise RuntimeError( # pragma: no cover + "theme cannot be None.") + visitor = self.translator_class( + self.document, self.builder, theme=theme) self.document.walkabout(visitor) self.output = visitor.body @@ -1043,13 +1048,7 @@ def __init__(self, srcdir, confdir, outdir, doctreedir, buildername="memoryhtml" # delayed import to speed up time from sphinx.application import builtin_extensions - try: - from sphinx.application import CONFIG_FILENAME, Config, Tags - sphinx_version = 2 # pragma: no cover - except ImportError: - # Sphinx 3.0.0 - from sphinx.config import CONFIG_FILENAME, Config, Tags - sphinx_version = 3 + from sphinx.config import CONFIG_FILENAME, Config, Tags # read config self.tags = Tags(tags) @@ -1076,11 +1075,6 @@ def __init__(self, srcdir, confdir, outdir, doctreedir, buildername="memoryhtml" self.sphinx__display_version__ = __display_version__ # create the environment - if sphinx_version == 2: # pragma: no cover - with warnings.catch_warnings(): - warnings.simplefilter( - "ignore", (DeprecationWarning, PendingDeprecationWarning, ImportWarning)) - self.config.check_unicode() self.config.pre_init_values() # set up translation infrastructure @@ -1356,12 +1350,7 @@ def add_builder(self, builder, override=False): self._added_objects.append(('builder', builder)) if builder.name not in self.registry.builders: self.debug('[_CustomSphinx] adding builder: %r', builder) - try: - # Sphinx >= 1.8 - self.registry.add_builder(builder, override=override) - except TypeError: # pragma: no cover - # Sphinx < 1.8 - self.registry.add_builder(builder) + self.registry.add_builder(builder, override=override) else: self.debug('[_CustomSphinx] already added builder: %r', builder) @@ -1409,27 +1398,11 @@ def run(self): obj.run = run - try: - # Sphinx >= 1.8 - Sphinx.add_directive(self, name, obj, content=content, # pylint: disable=E1123 - arguments=arguments, - override=override, **options) - except TypeError: - # Sphinx >= 3.0.0 - Sphinx.add_directive(self, name, obj, override=override, **options) - except ExtensionError: # pragma: no cover - # Sphinx < 1.8 - Sphinx.add_directive(self, name, obj, content=content, # pylint: disable=E1123 - arguments=arguments, **options) + Sphinx.add_directive(self, name, obj, override=override, **options) def add_domain(self, domain, override=True): self._added_objects.append(('domain', domain)) - try: - # Sphinx >= 1.8 - Sphinx.add_domain(self, domain, override=override) - except TypeError: # pragma: no cover - # Sphinx < 1.8 - Sphinx.add_domain(self, domain) + Sphinx.add_domain(self, domain, override=override) # For some reason, the directives are missing from the main catalog # in docutils. for k, v in domain.directives.items(): @@ -1443,15 +1416,6 @@ def add_domain(self, domain, override=True): # We add the role without the domain name as a prefix. self.add_role(k, v) - def override_domain(self, domain): - self._added_objects.append(('domain-over', domain)) - try: - Sphinx.override_domain(self, domain) - except AttributeError: # pragma: no cover - # Sphinx==3.0.0 - raise AttributeError( - "override_domain not available in sphinx==3.0.0") - def add_role(self, name, role, override=True): self._added_objects.append(('role', name)) self.debug('[_CustomSphinx] adding role: %r', (name, role)) @@ -1514,14 +1478,8 @@ def add_config_value(self, name, default, rebuild, types_=()): # pylint: disabl def add_directive_to_domain(self, domain, name, obj, has_content=None, # pylint: disable=W0221,W0237 argument_spec=None, override=False, **option_spec): self._added_objects.append(('directive_to_domain', domain, name)) - try: - Sphinx.add_directive_to_domain(self, domain, name, obj, # pylint: disable=E1123 - has_content=has_content, argument_spec=argument_spec, - override=override, **option_spec) - except TypeError: # pragma: no cover - # Sphinx==3.0.0 - Sphinx.add_directive_to_domain(self, domain, name, obj, - override=override, **option_spec) + Sphinx.add_directive_to_domain(self, domain, name, obj, + override=override, **option_spec) def add_role_to_domain(self, domain, name, role, override=False): self._added_objects.append(('roles_to_domain', domain, name)) diff --git a/src/pyquickhelper/server/filestore_sqlite.py b/src/pyquickhelper/server/filestore_sqlite.py index 27038163..2308de80 100644 --- a/src/pyquickhelper/server/filestore_sqlite.py +++ b/src/pyquickhelper/server/filestore_sqlite.py @@ -27,23 +27,31 @@ def __init__(self, path="_file_store_.db3"): self.path_ = path self._create() - def _get_column_table(self, table): - cur = self.con_.cursor() + def _get_column_table(self, table, con=None): + close = con is None + if con is None: + con = self._get_connexion() + cur = con.cursor() res = cur.execute("PRAGMA table_info(%s);" % table) res = cur.fetchall() + if close: + con.close() return res - def _check_same_column(self, table, columns): - cols = self._get_column_table(table) + def _check_same_column(self, table, columns, con=None): + cols = self._get_column_table(table, con=con) names = [_[1] for _ in cols] return names == columns + def _get_connexion(self): + return sqlite3.connect(self.path_) + def _create(self): """ Creates the database if it does not exists. """ - self.con_ = sqlite3.connect(self.path_) - cur = self.con_.cursor() + con = self._get_connexion() + cur = con.cursor() cur.execute("SELECT name FROM sqlite_master WHERE type='table';") res = cur.fetchall() commit = False @@ -56,9 +64,10 @@ def _create(self): commit = True if (('data',) in res and not self._check_same_column( - "data", ["id", "idfile", "name", "value", "date", "comment"])): + "data", ["id", "idfile", "name", "value", "date", "comment"], + con=con)): cur.execute("DROP TABLE data;") - self.con_.commit() + con.commit() cur.execute("SELECT name FROM sqlite_master WHERE type='table';") res = cur.fetchall() @@ -69,7 +78,8 @@ def _create(self): name TEXT, value REAL, date TEXT, comment TEXT)''') commit = True if commit: - self.con_.commit() + con.commit() + con.close() def submit(self, name, content, format=None, date=None, metadata=None, team=None, project=None, version=None): @@ -118,9 +128,11 @@ def submit(self, name, content, format=None, date=None, metadata=None, sqlite_insert_blob_query = """ INSERT INTO files (%s) VALUES (%s)""" % ( ",".join(fields), ",".join(map(SqlLite3FileStore.v2s, values))) - cur = self.con_.cursor() + con = self._get_connexion() + cur = con.cursor() cur.execute(sqlite_insert_blob_query) - self.con_.commit() + con.commit() + con.close() output = dict(name=name, format=format, metadata=metadata, team=team, project=project, version=version, date=date) @@ -148,12 +160,15 @@ def submit_data(self, idfile, name, value, date=None, comment=None): sqlite_insert_blob_query = """ INSERT INTO data (%s) VALUES (%s)""" % ( ",".join(fields), ",".join("%r" % v for v in values)) - cur = self.con_.cursor() + con = self._get_connexion() + cur = con.cursor() cur.execute(sqlite_insert_blob_query) - self.con_.commit() + con.commit() + con.close() def _enumerate(self, condition, fields): - cur = self.con_.cursor() + con = self._get_connexion() + cur = con.cursor() query = '''SELECT %s FROM files %s %s''' % ( ",".join(fields), "WHERE" if len(condition) > 0 else "", @@ -169,6 +184,7 @@ def _enumerate(self, condition, fields): if 'metadata' in res and res['metadata']: res['metadata'] = json.loads(res['metadata']) yield res + con.close() def enumerate_content(self, name=None, format=None, date=None, metadata=None, team=None, project=None, version=None): @@ -255,7 +271,8 @@ def enumerate_data(self, idfile=None, name=None, join=False, else: cond.append('%s=%s' % (k, SqlLite3FileStore.v2s(v, '"'))) - cur = self.con_.cursor() + con = self._get_connexion() + cur = con.cursor() if join: fields = ["data.id", "idfile", "data.name", "data.date", "data.value", "data.comment"] @@ -281,3 +298,4 @@ def enumerate_data(self, idfile=None, name=None, join=False, res = {k: v for k, v in zip(fields, line) # pylint: disable=R1721 if v is not None} yield res + con.close() diff --git a/src/pyquickhelper/sphinxext/sphinx_latex_builder.py b/src/pyquickhelper/sphinxext/sphinx_latex_builder.py index a5ea88dd..c061153a 100644 --- a/src/pyquickhelper/sphinxext/sphinx_latex_builder.py +++ b/src/pyquickhelper/sphinxext/sphinx_latex_builder.py @@ -35,11 +35,16 @@ class EnhancedLaTeXTranslator(LaTeXTranslator): and modifies a few functions. """ - def __init__(self, document, builder): + def __init__(self, document, builder, theme=None): if not hasattr(builder, 'config'): raise TypeError( "Unexpected type for builder {0}".format(type(builder))) - LaTeXTranslator.__init__(self, document, builder) + try: + # Sphinx>=5 + LaTeXTranslator.__init__(self, document, builder, theme=theme) + except TypeError: + # Sphinx<5 + LaTeXTranslator.__init__(self, document, builder) newlines = builder.config.text_newlines if newlines == 'windows': @@ -192,7 +197,12 @@ def __init__(self, builder): LaTeXWriter.__init__(self, builder) def translate(self): - visitor = self.builder.create_translator(self.document, self.builder) + theme = self.builder.themes.get('manual') + if theme is None: + raise RuntimeError( # pragma: no cover + "theme cannot be None.") + visitor = self.builder.create_translator( + self.document, self.builder, theme) self.document.walkabout(visitor) self.output = visitor.astext()