Skip to content

feat: pydantic settings#4081

Draft
flying-sheep wants to merge 3 commits intomainfrom
pa/settings
Draft

feat: pydantic settings#4081
flying-sheep wants to merge 3 commits intomainfrom
pa/settings

Conversation

@flying-sheep
Copy link
Copy Markdown
Member

@flying-sheep flying-sheep commented Apr 21, 2026

TODO: simplify logging stuff. settings.logpath can probably just be a deprecated alias to Path(settings..logfile.name), and all the side effects can happen in model validators

  • Closes #
  • Tests included or not required because:

flying-sheep and others added 3 commits April 21, 2026 17:05
Co-authored-by: Copilot <copilot@github.com>
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 23, 2026

❌ 8 Tests Failed:

Tests completed Failed Passed Skipped
1834 8 1826 908
View the top 3 failed test(s) by shortest run time
tests/test_logging.py::test_deep
Stack Traces | 0.003s run time
capsys = <_pytest.capture.CaptureFixture object at 0x7ff040ddc7c0>

    #x1B[0m#x1B[94mdef#x1B[39;49;00m#x1B[90m #x1B[39;49;00m#x1B[92mtest_deep#x1B[39;49;00m(capsys: pytest.CaptureFixture):#x1B[90m#x1B[39;49;00m
        s.logfile = sys.stderr#x1B[90m#x1B[39;49;00m
        s.verbosity = Verbosity.hint#x1B[90m#x1B[39;49;00m
        log.hint(#x1B[33m"#x1B[39;49;00m#x1B[33m0#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m)#x1B[90m#x1B[39;49;00m
>       #x1B[94massert#x1B[39;49;00m capsys.readouterr().err == #x1B[33m"#x1B[39;49;00m#x1B[33m--> 0#x1B[39;49;00m#x1B[33m\n#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m#x1B[90m#x1B[39;49;00m
#x1B[1m#x1B[31mE       AssertionError: assert '' == '--> 0\n'#x1B[0m
#x1B[1m#x1B[31mE         #x1B[0m
#x1B[1m#x1B[31mE         #x1B[0m#x1B[91m- --> 0#x1B[39;49;00m#x1B[90m#x1B[39;49;00m#x1B[0m

#x1B[1m#x1B[31mtests/test_logging.py#x1B[0m:73: AssertionError
tests/test_logging.py::test_defaults
Stack Traces | 0.003s run time
caplog = <_pytest.logging.LogCaptureFixture object at 0x7ff03e012e40>
original_settings = mappingproxy({'preset': <Preset.ScanpyV1: 'scanpy-v1'>, 'verbosity': <Verbosity.warning: 1>, 'logfile': <EncodedFile n...che_compression': 'lzf', 'max_memory': 15.0, 'n_jobs': 1, 'categories_to_ignore': ['N/A', 'dontknow', 'no_gate', '?']})

    #x1B[0m#x1B[94mdef#x1B[39;49;00m#x1B[90m #x1B[39;49;00m#x1B[92mtest_defaults#x1B[39;49;00m(#x1B[90m#x1B[39;49;00m
        caplog: pytest.LogCaptureFixture, original_settings: Mapping[#x1B[96mstr#x1B[39;49;00m, #x1B[96mobject#x1B[39;49;00m]#x1B[90m#x1B[39;49;00m
    ) -> #x1B[94mNone#x1B[39;49;00m:#x1B[90m#x1B[39;49;00m
>       #x1B[94massert#x1B[39;49;00m s.logpath #x1B[95mis#x1B[39;49;00m original_settings[#x1B[33m"#x1B[39;49;00m#x1B[33m_logpath#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m] #x1B[95mis#x1B[39;49;00m #x1B[94mNone#x1B[39;49;00m#x1B[90m#x1B[39;49;00m
                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#x1B[90m#x1B[39;49;00m
#x1B[1m#x1B[31mE       KeyError: '_logpath'#x1B[0m

#x1B[1m#x1B[31mtests/test_logging.py#x1B[0m:26: KeyError
tests/test_logging.py::test_timing
Stack Traces | 0.003s run time
monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7ff050f671d0>
capsys = <_pytest.capture.CaptureFixture object at 0x7ff0509a5ae0>

    #x1B[0m#x1B[94mdef#x1B[39;49;00m#x1B[90m #x1B[39;49;00m#x1B[92mtest_timing#x1B[39;49;00m(monkeypatch, capsys: pytest.CaptureFixture):#x1B[90m#x1B[39;49;00m
        counter = #x1B[94m0#x1B[39;49;00m#x1B[90m#x1B[39;49;00m
    #x1B[90m#x1B[39;49;00m
        #x1B[94mclass#x1B[39;49;00m#x1B[90m #x1B[39;49;00m#x1B[04m#x1B[92mIncTime#x1B[39;49;00m:#x1B[90m#x1B[39;49;00m
            #x1B[37m@staticmethod#x1B[39;49;00m#x1B[90m#x1B[39;49;00m
            #x1B[94mdef#x1B[39;49;00m#x1B[90m #x1B[39;49;00m#x1B[92mnow#x1B[39;49;00m(tz):#x1B[90m#x1B[39;49;00m
                #x1B[94mnonlocal#x1B[39;49;00m counter#x1B[90m#x1B[39;49;00m
                counter += #x1B[94m1#x1B[39;49;00m#x1B[90m#x1B[39;49;00m
                #x1B[94mreturn#x1B[39;49;00m datetime(#x1B[94m2000#x1B[39;49;00m, #x1B[94m1#x1B[39;49;00m, #x1B[94m1#x1B[39;49;00m, second=counter, microsecond=counter, tzinfo=tz)#x1B[90m#x1B[39;49;00m
    #x1B[90m#x1B[39;49;00m
        monkeypatch.setattr(log, #x1B[33m"#x1B[39;49;00m#x1B[33mdatetime#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m, IncTime)#x1B[90m#x1B[39;49;00m
        s.logfile = sys.stderr#x1B[90m#x1B[39;49;00m
        s.verbosity = Verbosity.debug#x1B[90m#x1B[39;49;00m
    #x1B[90m#x1B[39;49;00m
        log.hint(#x1B[33m"#x1B[39;49;00m#x1B[33m1#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m)#x1B[90m#x1B[39;49;00m
        #x1B[94massert#x1B[39;49;00m counter == #x1B[94m1#x1B[39;49;00m#x1B[90m#x1B[39;49;00m
>       #x1B[94massert#x1B[39;49;00m capsys.readouterr().err == #x1B[33m"#x1B[39;49;00m#x1B[33m--> 1#x1B[39;49;00m#x1B[33m\n#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m#x1B[90m#x1B[39;49;00m
#x1B[1m#x1B[31mE       AssertionError: assert '' == '--> 1\n'#x1B[0m
#x1B[1m#x1B[31mE         #x1B[0m
#x1B[1m#x1B[31mE         #x1B[0m#x1B[91m- --> 1#x1B[39;49;00m#x1B[90m#x1B[39;49;00m#x1B[0m

#x1B[1m#x1B[31mtests/test_logging.py#x1B[0m:127: AssertionError
tests/test_logging.py::test_formats
Stack Traces | 0.004s run time
capsys = <_pytest.capture.CaptureFixture object at 0x7ff0504ad250>

    #x1B[0m#x1B[94mdef#x1B[39;49;00m#x1B[90m #x1B[39;49;00m#x1B[92mtest_formats#x1B[39;49;00m(capsys: pytest.CaptureFixture):#x1B[90m#x1B[39;49;00m
        s.logfile = sys.stderr#x1B[90m#x1B[39;49;00m
        s.verbosity = Verbosity.debug#x1B[90m#x1B[39;49;00m
        log.error(#x1B[33m"#x1B[39;49;00m#x1B[33m0#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m)#x1B[90m#x1B[39;49;00m
>       #x1B[94massert#x1B[39;49;00m capsys.readouterr().err == #x1B[33m"#x1B[39;49;00m#x1B[33mERROR: 0#x1B[39;49;00m#x1B[33m\n#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m#x1B[90m#x1B[39;49;00m
#x1B[1m#x1B[31mE       AssertionError: assert '' == 'ERROR: 0\n'#x1B[0m
#x1B[1m#x1B[31mE         #x1B[0m
#x1B[1m#x1B[31mE         #x1B[0m#x1B[91m- ERROR: 0#x1B[39;49;00m#x1B[90m#x1B[39;49;00m#x1B[0m

#x1B[1m#x1B[31mtests/test_logging.py#x1B[0m:58: AssertionError
tests/test_logging.py::test_logfile
Stack Traces | 0.004s run time
tmp_path = PosixPath('.../pytest-0/popen-gw1/test_logfile0')
caplog = <_pytest.logging.LogCaptureFixture object at 0x7ff03dc81320>

    #x1B[0m#x1B[94mdef#x1B[39;49;00m#x1B[90m #x1B[39;49;00m#x1B[92mtest_logfile#x1B[39;49;00m(tmp_path: Path, caplog: pytest.LogCaptureFixture):#x1B[90m#x1B[39;49;00m
        s.verbosity = Verbosity.hint#x1B[90m#x1B[39;49;00m
    #x1B[90m#x1B[39;49;00m
        io = StringIO()#x1B[90m#x1B[39;49;00m
        s.logfile = io#x1B[90m#x1B[39;49;00m
        #x1B[94massert#x1B[39;49;00m s.logfile #x1B[95mis#x1B[39;49;00m io#x1B[90m#x1B[39;49;00m
        #x1B[94massert#x1B[39;49;00m s.logpath #x1B[95mis#x1B[39;49;00m #x1B[94mNone#x1B[39;49;00m#x1B[90m#x1B[39;49;00m
        log.error(#x1B[33m"#x1B[39;49;00m#x1B[33mtest!#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m)#x1B[90m#x1B[39;49;00m
>       #x1B[94massert#x1B[39;49;00m io.getvalue() == #x1B[33m"#x1B[39;49;00m#x1B[33mERROR: test!#x1B[39;49;00m#x1B[33m\n#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m#x1B[90m#x1B[39;49;00m
#x1B[1m#x1B[31mE       AssertionError: assert '' == 'ERROR: test!\n'#x1B[0m
#x1B[1m#x1B[31mE         #x1B[0m
#x1B[1m#x1B[31mE         #x1B[0m#x1B[91m- ERROR: test!#x1B[39;49;00m#x1B[90m#x1B[39;49;00m#x1B[0m

#x1B[1m#x1B[31mtests/test_logging.py#x1B[0m:91: AssertionError
tests/test_readwrite.py::test_write[default-csv]
Stack Traces | 0.004s run time
monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7ff0519239b0>
tmp_path = PosixPath('.../pytest-0/popen-gw1/test_write_default_csv_0')
ext = 'csv', style = 'default'

    #x1B[0m#x1B[37m@pytest#x1B[39;49;00m.mark.parametrize(#x1B[33m"#x1B[39;49;00m#x1B[33mext#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m, [#x1B[33m"#x1B[39;49;00m#x1B[33mh5ad#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m, pytest.param(#x1B[33m"#x1B[39;49;00m#x1B[33mzarr#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m, marks=needs.zarr), #x1B[33m"#x1B[39;49;00m#x1B[33mcsv#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m])#x1B[90m#x1B[39;49;00m
    #x1B[37m@pytest#x1B[39;49;00m.mark.parametrize(#x1B[33m"#x1B[39;49;00m#x1B[33mstyle#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m, [#x1B[33m"#x1B[39;49;00m#x1B[33mpath#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m, #x1B[33m"#x1B[39;49;00m#x1B[33mext#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m, #x1B[33m"#x1B[39;49;00m#x1B[33mdefault#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m])#x1B[90m#x1B[39;49;00m
    #x1B[94mdef#x1B[39;49;00m#x1B[90m #x1B[39;49;00m#x1B[92mtest_write#x1B[39;49;00m(#x1B[90m#x1B[39;49;00m
        monkeypatch: pytest.MonkeyPatch,#x1B[90m#x1B[39;49;00m
        tmp_path: Path,#x1B[90m#x1B[39;49;00m
        ext: Literal[#x1B[33m"#x1B[39;49;00m#x1B[33mh5ad#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m, #x1B[33m"#x1B[39;49;00m#x1B[33mzarr#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m, #x1B[33m"#x1B[39;49;00m#x1B[33mcsv#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m],#x1B[90m#x1B[39;49;00m
        style: Literal[#x1B[33m"#x1B[39;49;00m#x1B[33mpath#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m, #x1B[33m"#x1B[39;49;00m#x1B[33mext#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m, #x1B[33m"#x1B[39;49;00m#x1B[33mdefault#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m],#x1B[90m#x1B[39;49;00m
    ) -> #x1B[94mNone#x1B[39;49;00m:#x1B[90m#x1B[39;49;00m
        monkeypatch.chdir(tmp_path)#x1B[90m#x1B[39;49;00m
        adata = AnnData(np.array([[#x1B[94m1#x1B[39;49;00m, #x1B[94m2#x1B[39;49;00m], [#x1B[94m3#x1B[39;49;00m, #x1B[94m4#x1B[39;49;00m]]))#x1B[90m#x1B[39;49;00m
    #x1B[90m#x1B[39;49;00m
        #x1B[90m# test that writing works (except style="default" and ext="csv")#x1B[39;49;00m#x1B[90m#x1B[39;49;00m
        ctx = (#x1B[90m#x1B[39;49;00m
            pytest.warns(#x1B[96mFutureWarning#x1B[39;49;00m, match=#x1B[33mr#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m#x1B[33mremoved from this function#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m)#x1B[90m#x1B[39;49;00m
            #x1B[94mif#x1B[39;49;00m ext == #x1B[33m"#x1B[39;49;00m#x1B[33mcsv#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m#x1B[90m#x1B[39;49;00m
            #x1B[94melse#x1B[39;49;00m nullcontext()#x1B[90m#x1B[39;49;00m
        )#x1B[90m#x1B[39;49;00m
        #x1B[94mmatch#x1B[39;49;00m style, ext:#x1B[90m#x1B[39;49;00m
            #x1B[94mcase#x1B[39;49;00m#x1B[90m #x1B[39;49;00m#x1B[33m"#x1B[39;49;00m#x1B[33mpath#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m, #x1B[94m_#x1B[39;49;00m:#x1B[90m#x1B[39;49;00m
                #x1B[94mwith#x1B[39;49;00m ctx:#x1B[90m#x1B[39;49;00m
                    sc.write(#x1B[33mf#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m#x1B[33mtest.#x1B[39;49;00m#x1B[33m{#x1B[39;49;00mext#x1B[33m}#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m, adata)#x1B[90m#x1B[39;49;00m
                d = tmp_path#x1B[90m#x1B[39;49;00m
            #x1B[94mcase#x1B[39;49;00m#x1B[90m #x1B[39;49;00m#x1B[33m"#x1B[39;49;00m#x1B[33mext#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m, #x1B[94m_#x1B[39;49;00m:#x1B[90m#x1B[39;49;00m
                #x1B[94mwith#x1B[39;49;00m ctx:#x1B[90m#x1B[39;49;00m
                    sc.write(#x1B[33m"#x1B[39;49;00m#x1B[33mtest#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m, adata, ext=ext)#x1B[90m#x1B[39;49;00m
                d = sc.settings.writedir#x1B[90m#x1B[39;49;00m
            #x1B[94mcase#x1B[39;49;00m #x1B[33m"#x1B[39;49;00m#x1B[33mdefault#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m, #x1B[33m"#x1B[39;49;00m#x1B[33mcsv#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m:#x1B[90m#x1B[39;49;00m
                #x1B[90m# check that it throws an error instead#x1B[39;49;00m#x1B[90m#x1B[39;49;00m
                ff = sc.settings.file_format_data#x1B[90m#x1B[39;49;00m
                #x1B[94mwith#x1B[39;49;00m pytest.raises(#x1B[96mValueError#x1B[39;49;00m, match=#x1B[33mr#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m#x1B[33mCannot set file_format_data to csv#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m):#x1B[90m#x1B[39;49;00m
>                   sc.settings.file_format_data = ext  #x1B[90m# type: ignore[assignment]#x1B[39;49;00m#x1B[90m#x1B[39;49;00m
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^#x1B[90m#x1B[39;49;00m

#x1B[1m#x1B[.../scanpy/tests/test_readwrite.py#x1B[0m:77: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
#x1B[1m#x1B[.../home/runner/.local.../scanpy/B9PcT7QG/hatch-test.few-extras/lib/python3.14....../site-packages/pydantic/main.py#x1B[0m:1046: in __setattr__
    #x1B[0msetattr_handler(#x1B[96mself#x1B[39;49;00m, name, value)#x1B[90m#x1B[39;49;00m
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

model = Settings(preset=<Preset.ScanpyV1: 'scanpy-v1'>, verbosity=<Verbosity.hint: 3>, logfile=<EncodedFile name="<_io.FileIO ...ories_to_ignore=['N/A', 'dontknow', 'no_gate', '?'], logpath=PosixPath("<_io.FileIO name=12 mode='rb+' closefd=True>"))
name = 'file_format_data', val = 'csv'

>   #x1B[0m    #x1B[33m'#x1B[39;49;00m#x1B[33mvalidate_assignment#x1B[39;49;00m#x1B[33m'#x1B[39;49;00m: #x1B[94mlambda#x1B[39;49;00m model, name, val: model.__pydantic_validator__.validate_assignment(model, name, val),  #x1B[90m# pyright: ignore[reportAssignmentType]#x1B[39;49;00m#x1B[90m#x1B[39;49;00m
                                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#x1B[90m#x1B[39;49;00m
        #x1B[33m'#x1B[39;49;00m#x1B[33mprivate#x1B[39;49;00m#x1B[33m'#x1B[39;49;00m: _private_setattr_handler,#x1B[90m#x1B[39;49;00m
        #x1B[33m'#x1B[39;49;00m#x1B[33mcached_property#x1B[39;49;00m#x1B[33m'#x1B[39;49;00m: #x1B[94mlambda#x1B[39;49;00m model, name, val: model.#x1B[91m__dict__#x1B[39;49;00m.#x1B[92m__setitem__#x1B[39;49;00m(name, val),#x1B[90m#x1B[39;49;00m
        #x1B[33m'#x1B[39;49;00m#x1B[33mextra_known#x1B[39;49;00m#x1B[33m'#x1B[39;49;00m: #x1B[94mlambda#x1B[39;49;00m model, name, val: _object_setattr(model, name, val),#x1B[90m#x1B[39;49;00m
    }#x1B[90m#x1B[39;49;00m
#x1B[1m#x1B[31mE   pydantic_core._pydantic_core.ValidationError: 1 validation error for Settings#x1B[0m
#x1B[1m#x1B[31mE   file_format_data#x1B[0m
#x1B[1m#x1B[31mE     Input should be 'h5ad' or 'zarr' [type=literal_error, input_value='csv', input_type=str]#x1B[0m
#x1B[1m#x1B[31mE       For further information visit https://errors.pydantic.dev/2.13/v/literal_error#x1B[0m

#x1B[1m#x1B[.../home/runner/.local.../scanpy/B9PcT7QG/hatch-test.few-extras/lib/python3.14....../site-packages/pydantic/main.py#x1B[0m:112: ValidationError

#x1B[33mDuring handling of the above exception, another exception occurred:#x1B[0m

monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7ff0519239b0>
tmp_path = PosixPath('.../pytest-0/popen-gw1/test_write_default_csv_0')
ext = 'csv', style = 'default'

    #x1B[0m#x1B[37m@pytest#x1B[39;49;00m.mark.parametrize(#x1B[33m"#x1B[39;49;00m#x1B[33mext#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m, [#x1B[33m"#x1B[39;49;00m#x1B[33mh5ad#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m, pytest.param(#x1B[33m"#x1B[39;49;00m#x1B[33mzarr#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m, marks=needs.zarr), #x1B[33m"#x1B[39;49;00m#x1B[33mcsv#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m])#x1B[90m#x1B[39;49;00m
    #x1B[37m@pytest#x1B[39;49;00m.mark.parametrize(#x1B[33m"#x1B[39;49;00m#x1B[33mstyle#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m, [#x1B[33m"#x1B[39;49;00m#x1B[33mpath#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m, #x1B[33m"#x1B[39;49;00m#x1B[33mext#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m, #x1B[33m"#x1B[39;49;00m#x1B[33mdefault#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m])#x1B[90m#x1B[39;49;00m
    #x1B[94mdef#x1B[39;49;00m#x1B[90m #x1B[39;49;00m#x1B[92mtest_write#x1B[39;49;00m(#x1B[90m#x1B[39;49;00m
        monkeypatch: pytest.MonkeyPatch,#x1B[90m#x1B[39;49;00m
        tmp_path: Path,#x1B[90m#x1B[39;49;00m
        ext: Literal[#x1B[33m"#x1B[39;49;00m#x1B[33mh5ad#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m, #x1B[33m"#x1B[39;49;00m#x1B[33mzarr#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m, #x1B[33m"#x1B[39;49;00m#x1B[33mcsv#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m],#x1B[90m#x1B[39;49;00m
        style: Literal[#x1B[33m"#x1B[39;49;00m#x1B[33mpath#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m, #x1B[33m"#x1B[39;49;00m#x1B[33mext#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m, #x1B[33m"#x1B[39;49;00m#x1B[33mdefault#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m],#x1B[90m#x1B[39;49;00m
    ) -> #x1B[94mNone#x1B[39;49;00m:#x1B[90m#x1B[39;49;00m
        monkeypatch.chdir(tmp_path)#x1B[90m#x1B[39;49;00m
        adata = AnnData(np.array([[#x1B[94m1#x1B[39;49;00m, #x1B[94m2#x1B[39;49;00m], [#x1B[94m3#x1B[39;49;00m, #x1B[94m4#x1B[39;49;00m]]))#x1B[90m#x1B[39;49;00m
    #x1B[90m#x1B[39;49;00m
        #x1B[90m# test that writing works (except style="default" and ext="csv")#x1B[39;49;00m#x1B[90m#x1B[39;49;00m
        ctx = (#x1B[90m#x1B[39;49;00m
            pytest.warns(#x1B[96mFutureWarning#x1B[39;49;00m, match=#x1B[33mr#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m#x1B[33mremoved from this function#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m)#x1B[90m#x1B[39;49;00m
            #x1B[94mif#x1B[39;49;00m ext == #x1B[33m"#x1B[39;49;00m#x1B[33mcsv#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m#x1B[90m#x1B[39;49;00m
            #x1B[94melse#x1B[39;49;00m nullcontext()#x1B[90m#x1B[39;49;00m
        )#x1B[90m#x1B[39;49;00m
        #x1B[94mmatch#x1B[39;49;00m style, ext:#x1B[90m#x1B[39;49;00m
            #x1B[94mcase#x1B[39;49;00m#x1B[90m #x1B[39;49;00m#x1B[33m"#x1B[39;49;00m#x1B[33mpath#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m, #x1B[94m_#x1B[39;49;00m:#x1B[90m#x1B[39;49;00m
                #x1B[94mwith#x1B[39;49;00m ctx:#x1B[90m#x1B[39;49;00m
                    sc.write(#x1B[33mf#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m#x1B[33mtest.#x1B[39;49;00m#x1B[33m{#x1B[39;49;00mext#x1B[33m}#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m, adata)#x1B[90m#x1B[39;49;00m
                d = tmp_path#x1B[90m#x1B[39;49;00m
            #x1B[94mcase#x1B[39;49;00m#x1B[90m #x1B[39;49;00m#x1B[33m"#x1B[39;49;00m#x1B[33mext#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m, #x1B[94m_#x1B[39;49;00m:#x1B[90m#x1B[39;49;00m
                #x1B[94mwith#x1B[39;49;00m ctx:#x1B[90m#x1B[39;49;00m
                    sc.write(#x1B[33m"#x1B[39;49;00m#x1B[33mtest#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m, adata, ext=ext)#x1B[90m#x1B[39;49;00m
                d = sc.settings.writedir#x1B[90m#x1B[39;49;00m
            #x1B[94mcase#x1B[39;49;00m #x1B[33m"#x1B[39;49;00m#x1B[33mdefault#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m, #x1B[33m"#x1B[39;49;00m#x1B[33mcsv#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m:#x1B[90m#x1B[39;49;00m
                #x1B[90m# check that it throws an error instead#x1B[39;49;00m#x1B[90m#x1B[39;49;00m
                ff = sc.settings.file_format_data#x1B[90m#x1B[39;49;00m
>               #x1B[94mwith#x1B[39;49;00m pytest.raises(#x1B[96mValueError#x1B[39;49;00m, match=#x1B[33mr#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m#x1B[33mCannot set file_format_data to csv#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m):#x1B[90m#x1B[39;49;00m
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#x1B[90m#x1B[39;49;00m
#x1B[1m#x1B[31mE               AssertionError: Regex pattern did not match.#x1B[0m
#x1B[1m#x1B[31mE                 Expected regex: 'Cannot set file_format_data to csv'#x1B[0m
#x1B[1m#x1B[31mE                 Actual message: "1 validation error for Settings\nfile_format_data\n  Input should be 'h5ad' or 'zarr' [type=literal_error, input_value='csv', input_type=str]\n    For further information visit https://errors.pydantic.dev/2.13/v/literal_error"#x1B[0m

#x1B[1m#x1B[.../scanpy/tests/test_readwrite.py#x1B[0m:76: AssertionError
src/scanpy/preprocessing/_normalization.py::scanpy.preprocessing._normalization.normalize_total
Stack Traces | 0.005s run time
212 ...             [1, 22, 1, 2, 2],
213 ...         ],
214 ...         dtype="float32",
215 ...     )
216 ... )
217 >>> adata.X
218 array([[ 3.,  3.,  3.,  6.,  6.],
219        [ 1.,  1.,  1.,  2.,  2.],
220        [ 1., 22.,  1.,  2.,  2.]], dtype=float32)
221 >>> X_norm = sc.pp.normalize_total(adata, target_sum=1, inplace=False)["X"]
Expected:
    normalizing counts per cell
        finished (0:00:00)
Got nothing

#x1B[1m#x1B[.../scanpy/preprocessing/_normalization.py#x1B[0m:221: DocTestFailure
tests/test_logging.py::test_records
Stack Traces | 0.022s run time
caplog = <_pytest.logging.LogCaptureFixture object at 0x7ff03dc80750>

    #x1B[0m#x1B[94mdef#x1B[39;49;00m#x1B[90m #x1B[39;49;00m#x1B[92mtest_records#x1B[39;49;00m(caplog: pytest.LogCaptureFixture) -> #x1B[94mNone#x1B[39;49;00m:#x1B[90m#x1B[39;49;00m
        s.verbosity = Verbosity.debug#x1B[90m#x1B[39;49;00m
        log.error(#x1B[33m"#x1B[39;49;00m#x1B[33m0#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m)#x1B[90m#x1B[39;49;00m
        log.warning(#x1B[33m"#x1B[39;49;00m#x1B[33m1#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m)#x1B[90m#x1B[39;49;00m
        log.info(#x1B[33m"#x1B[39;49;00m#x1B[33m2#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m)#x1B[90m#x1B[39;49;00m
        log.hint(#x1B[33m"#x1B[39;49;00m#x1B[33m3#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m)#x1B[90m#x1B[39;49;00m
        log.debug(#x1B[33m"#x1B[39;49;00m#x1B[33m4#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m)#x1B[90m#x1B[39;49;00m
>       #x1B[94massert#x1B[39;49;00m caplog.record_tuples == [#x1B[90m#x1B[39;49;00m
            (#x1B[33m"#x1B[39;49;00m#x1B[33mroot#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m, #x1B[94m40#x1B[39;49;00m, #x1B[33m"#x1B[39;49;00m#x1B[33m0#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m),#x1B[90m#x1B[39;49;00m
            (#x1B[33m"#x1B[39;49;00m#x1B[33mroot#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m, #x1B[94m30#x1B[39;49;00m, #x1B[33m"#x1B[39;49;00m#x1B[33m1#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m),#x1B[90m#x1B[39;49;00m
            (#x1B[33m"#x1B[39;49;00m#x1B[33mroot#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m, #x1B[94m20#x1B[39;49;00m, #x1B[33m"#x1B[39;49;00m#x1B[33m2#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m),#x1B[90m#x1B[39;49;00m
            (#x1B[33m"#x1B[39;49;00m#x1B[33mroot#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m, #x1B[94m15#x1B[39;49;00m, #x1B[33m"#x1B[39;49;00m#x1B[33m3#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m),#x1B[90m#x1B[39;49;00m
            (#x1B[33m"#x1B[39;49;00m#x1B[33mroot#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m, #x1B[94m10#x1B[39;49;00m, #x1B[33m"#x1B[39;49;00m#x1B[33m4#x1B[39;49;00m#x1B[33m"#x1B[39;49;00m),#x1B[90m#x1B[39;49;00m
        ]#x1B[90m#x1B[39;49;00m
#x1B[1m#x1B[31mE       AssertionError: assert [('root', 40,...ot', 30, '1')] == [('root', 40,...ot', 10, '4')]#x1B[0m
#x1B[1m#x1B[31mE         #x1B[0m
#x1B[1m#x1B[31mE         Right contains 3 more items, first extra item: #x1B[0m(#x1B[33m'#x1B[39;49;00m#x1B[33mroot#x1B[39;49;00m#x1B[33m'#x1B[39;49;00m, #x1B[94m20#x1B[39;49;00m, #x1B[33m'#x1B[39;49;00m#x1B[33m2#x1B[39;49;00m#x1B[33m'#x1B[39;49;00m)#x1B[90m#x1B[39;49;00m#x1B[0m
#x1B[1m#x1B[31mE         #x1B[0m
#x1B[1m#x1B[31mE         Full diff:#x1B[0m
#x1B[1m#x1B[31mE         #x1B[0m#x1B[90m #x1B[39;49;00m [#x1B[90m#x1B[39;49;00m#x1B[0m
#x1B[1m#x1B[31mE         #x1B[90m #x1B[39;49;00m     (#x1B[90m#x1B[39;49;00m#x1B[0m
#x1B[1m#x1B[31mE         #x1B[90m #x1B[39;49;00m         'root',#x1B[90m#x1B[39;49;00m#x1B[0m
#x1B[1m#x1B[31mE         #x1B[90m #x1B[39;49;00m         40,#x1B[90m#x1B[39;49;00m#x1B[0m
#x1B[1m#x1B[31mE         #x1B[90m #x1B[39;49;00m         '0',#x1B[90m#x1B[39;49;00m#x1B[0m
#x1B[1m#x1B[31mE         #x1B[90m #x1B[39;49;00m     ),#x1B[90m#x1B[39;49;00m#x1B[0m
#x1B[1m#x1B[31mE         #x1B[90m #x1B[39;49;00m     (#x1B[90m#x1B[39;49;00m#x1B[0m
#x1B[1m#x1B[31mE         #x1B[90m #x1B[39;49;00m         'root',#x1B[90m#x1B[39;49;00m#x1B[0m
#x1B[1m#x1B[31mE         #x1B[90m #x1B[39;49;00m         30,#x1B[90m#x1B[39;49;00m#x1B[0m
#x1B[1m#x1B[31mE         #x1B[90m #x1B[39;49;00m         '1',#x1B[90m#x1B[39;49;00m#x1B[0m
#x1B[1m#x1B[31mE         #x1B[90m #x1B[39;49;00m     ),#x1B[90m#x1B[39;49;00m#x1B[0m
#x1B[1m#x1B[31mE         #x1B[91m-     (#x1B[39;49;00m#x1B[90m#x1B[39;49;00m#x1B[0m
#x1B[1m#x1B[31mE         #x1B[91m-         'root',#x1B[39;49;00m#x1B[90m#x1B[39;49;00m#x1B[0m
#x1B[1m#x1B[31mE         #x1B[91m-         20,#x1B[39;49;00m#x1B[90m#x1B[39;49;00m#x1B[0m
#x1B[1m#x1B[31mE         #x1B[91m-         '2',#x1B[39;49;00m#x1B[90m#x1B[39;49;00m#x1B[0m
#x1B[1m#x1B[31mE         #x1B[91m-     ),#x1B[39;49;00m#x1B[90m#x1B[39;49;00m#x1B[0m
#x1B[1m#x1B[31mE         #x1B[91m-     (#x1B[39;49;00m#x1B[90m#x1B[39;49;00m#x1B[0m
#x1B[1m#x1B[31mE         #x1B[91m-         'root',#x1B[39;49;00m#x1B[90m#x1B[39;49;00m#x1B[0m
#x1B[1m#x1B[31mE         #x1B[91m-         15,#x1B[39;49;00m#x1B[90m#x1B[39;49;00m#x1B[0m
#x1B[1m#x1B[31mE         #x1B[91m-         '3',#x1B[39;49;00m#x1B[90m#x1B[39;49;00m#x1B[0m
#x1B[1m#x1B[31mE         #x1B[91m-     ),#x1B[39;49;00m#x1B[90m#x1B[39;49;00m#x1B[0m
#x1B[1m#x1B[31mE         #x1B[91m-     (#x1B[39;49;00m#x1B[90m#x1B[39;49;00m#x1B[0m
#x1B[1m#x1B[31mE         #x1B[91m-         'root',#x1B[39;49;00m#x1B[90m#x1B[39;49;00m#x1B[0m
#x1B[1m#x1B[31mE         #x1B[91m-         10,#x1B[39;49;00m#x1B[90m#x1B[39;49;00m#x1B[0m
#x1B[1m#x1B[31mE         #x1B[91m-         '4',#x1B[39;49;00m#x1B[90m#x1B[39;49;00m#x1B[0m
#x1B[1m#x1B[31mE         #x1B[91m-     ),#x1B[39;49;00m#x1B[90m#x1B[39;49;00m#x1B[0m
#x1B[1m#x1B[31mE         #x1B[90m #x1B[39;49;00m ]#x1B[90m#x1B[39;49;00m#x1B[0m

#x1B[1m#x1B[31mtests/test_logging.py#x1B[0m:45: AssertionError

To view more test analytics, go to the Test Analytics Dashboard
📋 Got 3 mins? Take this short survey to help us improve Test Analytics.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant