coveragepy icon indicating copy to clipboard operation
coveragepy copied to clipboard

`--omit` command line flag and config values are not merged

Open lukasjuhrich opened this issue 3 years ago • 4 comments

Describe the bug I hope this is not a duplicate, I've looked for a while

I am in a situation where I do not have control over the --omit flag under which the coverage process is ran (pycharm does that for me and it is not configurable). However, I have control over the coveragerc.

Unfortunately, the --omit flag seems to overwrite both the [run] and the [report] sections' omit= keys.

Environment

`coverage debug sys`
-- sys -------------------------------------------------------                                       
               coverage_version: 6.6.0b1                                                                               
                coverage_module: /opt/pycroft/venv/lib/python3.10/site-packages/coverage/__init__.py
                         tracer: -none-                                                                                
                        CTracer: available
           plugins.file_tracers: -none-
            plugins.configurers: -none-
      plugins.context_switchers: -none-
              configs_attempted: .coveragerc
                   configs_read: /opt/pycroft/app/.coveragerc
                    config_file: /opt/pycroft/app/.coveragerc
                config_contents: b'[run]\ndebug = trace\nsource =\n    pycroft\n    ldap_sync\n    hades_logs\n    web\nomit =\n    tests\n    **/alembic/**\n    .pycharm_helpers\n\n[report]\nomit =\n    **/alembic/**\n'
                      data_file: -none-
                         python: 3.10.1 (main, Dec  8 2021, 03:30:49) [GCC 10.2.1 20210110]
                       platform: Linux-6.0.6-arch1-1-x86_64-with-glibc2.31
                 implementation: CPython
                     executable: /opt/pycroft/venv/bin/python3
                   def_encoding: utf-8
                    fs_encoding: utf-8
                            pid: 27
                            cwd: /opt/pycroft/app
                           path: /opt/pycroft/venv/bin
                                 /usr/local/lib/python310.zip
                                 /usr/local/lib/python3.10
                                 /usr/local/lib/python3.10/lib-dynload
                                 /opt/pycroft/venv/lib/python3.10/site-packages
                                 /opt/pycroft/app
                    environment: HOME = /opt/pycroft
                                 PYTHONDEVMODE = 1
                                 PYTHON_GET_PIP_SHA256 = c518250e91a70d7b20cceb15272209a4ded2a0c263ae5776f129e0d9b5674309
                                 PYTHON_GET_PIP_URL = https://github.com/pypa/get-pip/raw/3cb8888cc2869620f57d5d2da64da38f516078c7/public/get-pip.py
                                 PYTHON_PIP_VERSION = 21.2.4
                                 PYTHON_SETUPTOOLS_VERSION = 57.5.0
                                 PYTHON_VERSION = 3.10.1
                   command_line: /opt/pycroft/venv/bin/coverage debug sys
         sqlite3_sqlite_version: 3.34.1
             sqlite3_temp_store: 0
        sqlite3_compile_options: COMPILER=gcc-10.2.1 20210110, ENABLE_COLUMN_METADATA, ENABLE_DBSTAT_VTAB,
                                 ENABLE_FTS3, ENABLE_FTS3_PARENTHESIS, ENABLE_FTS3_TOKENIZER, ENABLE_FTS4,
                                 ENABLE_FTS5, ENABLE_JSON1, ENABLE_LOAD_EXTENSION, ENABLE_PREUPDATE_HOOK,
                                 ENABLE_RTREE, ENABLE_SESSION, ENABLE_STMTVTAB, ENABLE_UNLOCK_NOTIFY,
                                 ENABLE_UPDATE_DELETE_LIMIT, HAVE_ISNAN, LIKE_DOESNT_MATCH_BLOBS,
                                 MAX_SCHEMA_RETRY=25, MAX_VARIABLE_NUMBER=250000, OMIT_LOOKASIDE,
                                 SECURE_DELETE, SOUNDEX, TEMP_STORE=1, THREADSAFE=1, USE_URI
`pip freeze` (shouldn't be relevant)
aiofiles==0.8.0
aiohttp==3.8.1
aiosignal==1.2.0
alabaster==0.7.12
alembic==1.6.5
amqp==5.0.7
aniso8601==9.0.1
async-timeout==4.0.1
attrs==21.2.0
Babel==2.9.1
backcall==0.2.0
billiard==3.6.4.0
black==22.3.0
bleach==4.1.0
blinker==1.4
boltons==21.0.0
celery==5.2.1
celery-types==0.9.3
certifi==2021.10.8
charset-normalizer==2.0.9
click==8.0.3
click-didyoumean==0.3.0
click-plugins==1.1.1
click-repl==0.2.0
cloudpickle==2.2.0
colorama==0.4.4
colored==1.4.3
commonmark==0.9.1
coverage==6.6.0b1
decorator==5.1.0
dnspython==2.1.0
docutils==0.17.1
elementpath==2.4.0
eliot==1.14.0
eliot-tree==21.0.0
email-validator==1.1.3
factory-boy==3.2.1
Faker==10.0.0
fints==3.0.1
Flask==1.1.2
Flask-Babel==2.0.0
Flask-Login==0.5.0
Flask-RESTful==0.3.9
Flask-Testing==0.8.1
Flask-WTF==1.0.0
frozenlist==1.2.0
gitdb2==2.0.6
GitPython==2.1.15
gprof2dot==2021.2.21
greenlet==1.1.2
guzzle-sphinx-theme==0.7.11
idna==3.3
imagesize==1.3.0
inflection==0.5.1
iniconfig==1.1.1
ipaddr==2.2.0
ipython==7.30.1
iso8601==1.0.2
itsdangerous==1.1.0
jedi==0.18.1
Jinja2==2.11.3
jmespath==0.10.0
jsonschema==3.2.0
kombu==5.2.2
ldap3==2.5.2
livereload==2.6.3
mac-vendor-lookup==0.1.11
Mako==1.1.6
MarkupSafe==1.1.1
marshmallow==3.18.0
matplotlib-inline==0.1.3
mt-940==4.19.0
multidict==5.2.0
mypy==0.961
mypy-extensions==0.4.3
packaging==21.3
parso==0.8.3
passlib==1.7.4
pathspec==0.9.0
pexpect==4.8.0
pickleshare==0.7.5
Pillow==8.4.0
platformdirs==2.5.2
pluggy==1.0.0
prompt-toolkit==3.0.24
psycopg2==2.8.6
psycopg2-binary==2.9.2
ptyprocess==0.7.0
py==1.11.0
py-healthcheck==1.10.1
pyasn1==0.4.8
-e git+ssh://gh/agdsn/pycroft@f9f28339668c09d4b97a455aeb8af16d9a18c333#egg=pycroft
pydot==1.4.2
Pygments==2.10.0
pyinstrument==4.1.1
pynvml==11.4.1
pyparsing==3.0.6
pyrsistent==0.18.0
pytest==7.0.0
pytest-fixture-tools==1.1.0
pytest-profiling==1.7.0
pytest-timeout==2.1.0
python-dateutil==2.8.2
python-editor==1.0.4
pytz==2021.3
reportlab==3.6.3
requests==2.26.0
rich==12.6.0
scalene==1.5.13
sentry-sdk==1.0.0
sepaxml==2.5.0
simplejson==3.11.1
six==1.16.0
smmap==5.0.0
smmap2==3.0.1
snowballstemmer==2.2.0
Sphinx==5.1.1
sphinx-autobuild==2021.3.14
sphinx-paramlinks==0.5.4
sphinxcontrib-applehelp==1.0.2
sphinxcontrib-devhelp==1.0.2
sphinxcontrib-htmlhelp==2.0.0
sphinxcontrib-jsmath==1.0.1
sphinxcontrib-qthelp==1.0.3
sphinxcontrib-serializinghtml==1.1.5
SQLAlchemy==1.4.37
sqlalchemy-schemadisplay==1.4.dev0
sqlalchemy2-stubs==0.0.2a23
text-unidecode==1.3
toml==0.10.2
tomli==2.0.0
toolz==0.11.2
tornado==6.1
traitlets==5.1.1
types-babel==2.9.2
types-backports==0.1.3
types-ipaddress==1.0.8
types-Jinja2==2.11.9
types-jsonschema==4.3.0
types-MarkupSafe==1.1.10
typing_extensions==4.0.1
urllib3==1.26.7
uWSGI==2.0.20
uwsgitop==0.11
vine==5.0.0
wcwidth==0.2.5
webencodings==0.5.1
Werkzeug==1.0.1
wrapt==1.12.1
WTForms==2.2.1
WTForms-SQLAlchemy==0.3
wtforms-widgets @ file:///opt/pycroft/app/deps/wtforms-widgets
xmlschema==1.9.1
yarl==1.7.2
zope.interface==5.4.0

To Reproduce Compare the output of coverage run --debug=config test.py

Output 1
-- config ----------------------------------------------------
         attempted_config_files: .coveragerc 
                   command_line: None
                    concurrency: None
                    config_file: /opt/pycroft/app/.coveragerc
              config_files_read: /opt/pycroft/app/.coveragerc
                        context: None
                    cover_pylib: False
                      data_file: .coverage
                          debug: config
               disable_warnings: -none-
                dynamic_context: None
                   exclude_list: #\s*(pragma|PRAGMA)[:\s]?\s*(no|NO)\s*(cover|COVER)
                      extra_css: None
                     fail_under: 0.0
                       html_dir: htmlcov
              html_skip_covered: None
                html_skip_empty: None
                     html_title: Coverage report
                  ignore_errors: False
                    json_output: coverage.json
              json_pretty_print: False
             json_show_contexts: False
                    lcov_output: coverage.lcov
                           note: None
                       parallel: False
            partial_always_list: while (True|1|False|0):
                                 if (True|1|False|0):
                   partial_list: #\s*(pragma|PRAGMA)[:\s]?\s*(no|NO)\s*(branch|BRANCH)
                          paths: OrderedDict()
                 plugin_options: {}
                        plugins: -none-
                      precision: 0
                 relative_files: False
                report_contexts: None
                 report_include: None
                    report_omit: **/alembic/**
                    run_include: None
                       run_omit: tests
                                 **/alembic/**
                                 .pycharm_helpers
                  show_contexts: False
                   show_missing: False
                        sigterm: False
                   skip_covered: False
                     skip_empty: False
                           sort: None
                         source: pycroft
                                 ldap_sync
                                 hades_logs
                                 web
                    source_pkgs: -none-
                          timid: False
                     xml_output: coverage.xml
              xml_package_depth: 99
-- end -------------------------------------------------------
/opt/pycroft/venv/lib/python3.10/site-packages/coverage/control.py:799: CoverageWarning: No data was collected. (no-data-collected)
  self._warn("No data was collected.", slug="no-data-collected")

to the output of `coverage run --debug=config --omit=FOOOO test.py`
Output 2
-- config ----------------------------------------------------
         attempted_config_files: .coveragerc
                         branch: False
                   command_line: None
                    concurrency: None
                    config_file: /opt/pycroft/app/.coveragerc
              config_files_read: /opt/pycroft/app/.coveragerc
                        context: None
                    cover_pylib: False
                      data_file: .coverage
                          debug: config
               disable_warnings: -none-
                dynamic_context: None
                   exclude_list: #\s*(pragma|PRAGMA)[:\s]?\s*(no|NO)\s*(cover|COVER)
                      extra_css: None
                     fail_under: 0.0
                       html_dir: htmlcov
              html_skip_covered: None
                html_skip_empty: None
                     html_title: Coverage report
                  ignore_errors: False
                    json_output: coverage.json
              json_pretty_print: False
             json_show_contexts: False
                    lcov_output: coverage.lcov
                           note: None
                       parallel: False
            partial_always_list: while (True|1|False|0):
                                 if (True|1|False|0):
                   partial_list: #\s*(pragma|PRAGMA)[:\s]?\s*(no|NO)\s*(branch|BRANCH)
                          paths: OrderedDict()
                 plugin_options: {}
                        plugins: -none-
                      precision: 0
                 relative_files: False
                report_contexts: None
                 report_include: None
                    report_omit: FOOOO
                    run_include: None
                       run_omit: FOOOO
                  show_contexts: False
                   show_missing: False
                        sigterm: False
                   skip_covered: False
                     skip_empty: False
                           sort: None
                         source: pycroft
                                 ldap_sync
                                 hades_logs
                                 web
                    source_pkgs: -none-
                          timid: False
                     xml_output: coverage.xml
              xml_package_depth: 99
-- end -------------------------------------------------------

Expected behavior In the second command,

  • run_omit should have multiple values, ending with FOOOO
  • report_omit should have multiple values, ending with FOOOO

lukasjuhrich avatar Nov 10 '22 14:11 lukasjuhrich

This would be a change in how the command line arguments are used. Can you tell me more about how PyCharm is setting the omit option, and how you are trying to set it? I haven't heard of it doing this before.

nedbat avatar Nov 11 '22 10:11 nedbat

@nedbat I'm running „$FOO with coverage“ with a docker-compose based python interpreter.

Inside the container, a command like the following is run:

/opt/pycroft/venv/bin/python \
  /opt/.pycharm_helpers/coverage_runner/run_coverage.py \
  run --branch --omit="/opt/pycharm-professional/plugins/python/helpers*" \
  /opt/.pycharm_helpers/pycharm/_jb_pytest_runner.py \
    --target tests/ldap_sync/test_ldap_sync.py::TestMultipleUsersFilter 

The run_coverage.py is a wrapper around coverage.py, which passes argv as is. You see that it passes the pycharm helpers folder to the --omit-flag.

In my coveragerc however, I want to omit migrations; the entries are

[run]
source_pkgs = […]
omit =
    **/alembic/**
    .pycharm_helpers

[report]
omit =
    **/alembic/**

since I don't have any control about the run_coverage.py wrapper and I can't configure any flags passed to it I'm stuck with the config.

lukasjuhrich avatar Nov 12 '22 09:11 lukasjuhrich

I think I have this exact problem with the current version of PyCharm.

On Windows, the command line it builds when executing a run configuration 'with Coverage' looks like this:

python.exe "C:/Program Files (x86)/JetBrains/PyCharm 2025.1/plugins/python-ce/helpers/coverage_runner/run_coverage.py"
    run "--omit=\"C:\Program Files (x86)\JetBrains\PyCharm 2025.1\plugins\python-ce\helpers*\""
    "C:/Program Files (x86)/JetBrains/PyCharm 2025.1/plugins/python-ce/helpers/pycharm/_jb_pytest_runner.py"
    --path E:/Code/pyprojects/<my project here>

It respects other fields set in my .coveragerc file, such as cover_pylib, but its attempt to exclude some of its own files seems to be interfering with my [omit] settings.

Technically I suppose this is a bug in Pycharm, and I'll report it there as well.

Kylotan avatar Apr 22 '25 21:04 Kylotan

Actually, I just found that this has been logged as a PyCharm bug for years: https://youtrack.jetbrains.com/issue/PY-41334/omit-directive-from-.coveragerc-is-not-working

Kylotan avatar Apr 22 '25 21:04 Kylotan