From 071d6057741650bc6741aafab8dbef4f77e6d344 Mon Sep 17 00:00:00 2001 From: Wouter Vanden Hove Date: Mon, 13 Mar 2023 13:45:51 +0100 Subject: [PATCH 1/4] add ipython-profile support (#1) * add ipython-profile support * add tests to fetch ipytohn_profiler from config --------- Co-authored-by: Wouter Vanden Hove --- HISTORY.txt | 4 ++ README.rst | 21 ++++++++ ipdb/__main__.py | 38 +++++++++++++-- tests/test_config.py | 113 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 171 insertions(+), 5 deletions(-) diff --git a/HISTORY.txt b/HISTORY.txt index 62b0a1f..b0a35be 100644 --- a/HISTORY.txt +++ b/HISTORY.txt @@ -4,6 +4,10 @@ Changelog 0.13.14 (unreleased) -------------------- +- Add ipython_profile support. We can now run ipdb with a non-default + ipython-profile by setting an environment-variable ``IPDB_IPYTHON_PROFILE`` + or by setting ``ipython_profile`` in the config. [WouterVH] + - Run ``black`` on ipdb-codebase with line-length 88. [WouterVH] diff --git a/README.rst b/README.rst index e43e581..0143114 100644 --- a/README.rst +++ b/README.rst @@ -120,6 +120,27 @@ Or you can use ``iex`` as a function decorator to launch ipdb if an exception is Using ``from future import print_function`` for Python 3 compat implies dropping Python 2.5 support. Use ``ipdb<=0.8`` with 2.5. + +Using a non-default ipython-profile +----------------------------------- +By default ``ipdb`` will instantiate an ipython-session loaded with the default profile called ``default``. +You can set a non-default profile by setting the environment variable ``IPDB_IPYTON_PROFILE``: + +.. code-block:: bash + + export IPDB_IPYTON_PROFILE="ipdb" + +Or by setting in ``pyproject.toml``: + +.. code-block:: toml + + [tool.ipdb] + ipython_profile = "ipdb" + +This should correspond with a profile-directory ``profile_ipdb```in your ``IPYTHON_HOME``. +If this profile-directory does not exist, we fall back to the default profile. + + Issues with ``stdout`` ---------------------- diff --git a/ipdb/__main__.py b/ipdb/__main__.py index c4b649a..56376f9 100644 --- a/ipdb/__main__.py +++ b/ipdb/__main__.py @@ -13,7 +13,10 @@ __version__ = "0.13.14.dev0" from IPython import get_ipython +from IPython.core.application import ProfileDir from IPython.core.debugger import BdbQuit_excepthook +from IPython.core.profiledir import ProfileDirError +from IPython.paths import get_ipython_dir from IPython.terminal.ipapp import TerminalIPythonApp from IPython.terminal.embed import InteractiveShellEmbed @@ -23,20 +26,30 @@ import ConfigParser as configparser -def _get_debugger_cls(): +def _get_debugger_cls(ipython_profile="default"): shell = get_ipython() if shell is None: # Not inside IPython # Build a terminal app in order to force ipython to load the # configuration - ipapp = TerminalIPythonApp() + ipython_dir = get_ipython_dir() + try: + profile_dir = ProfileDir.find_profile_dir_by_name( + ipython_dir=ipython_dir, + name=ipython_profile, + ) + except ProfileDirError: # fallback to default-profile + profile_dir = ProfileDir.find_profile_dir_by_name( + ipython_dir=ipython_dir, + ) + ipapp = TerminalIPythonApp(profile_dir=profile_dir) + # Avoid output (banner, prints) ipapp.interact = False ipapp.initialize(["--no-term-title"]) shell = ipapp.shell else: # Running inside IPython - # Detect if embed shell or not and display a message if isinstance(shell, InteractiveShellEmbed): sys.stderr.write( @@ -49,10 +62,17 @@ def _get_debugger_cls(): return shell.debugger_cls -def _init_pdb(context=None, commands=[]): +def _init_pdb(context=None, ipython_profile=None, commands=[]): if context is None: context = os.getenv("IPDB_CONTEXT_SIZE", get_context_from_config()) - debugger_cls = _get_debugger_cls() + + if ipython_profile is None: + ipython_profile = os.getenv( + "IPDB_IPYTHON_PROFILE", get_ipython_profile_from_config() + ) + + debugger_cls = _get_debugger_cls(ipython_profile=ipython_profile) + try: p = debugger_cls(context=context) except TypeError: @@ -94,6 +114,14 @@ def get_context_from_config(): ) +def get_ipython_profile_from_config(): + parser = get_config() + try: + return parser.get("ipdb", "ipython_profile") + except (configparser.NoSectionError, configparser.NoOptionError): + return "default" + + class ConfigFile(object): """ Filehandle wrapper that adds a "[ipdb]" section to the start of a config diff --git a/tests/test_config.py b/tests/test_config.py index e4fc7e7..2d5ff4a 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -16,6 +16,7 @@ from ipdb.__main__ import ( get_config, get_context_from_config, + get_ipython_profile_from_config, ) @@ -137,6 +138,22 @@ def test_noenv_nodef_nosetup_pyproject(self): self.assertEqual(self.pyproject_context, cfg.getint("ipdb", "context")) self.assertRaises(configparser.NoOptionError, cfg.get, "ipdb", "version") + def test_noenv_nodef_nosetup_pyproject(self): + """ + Setup: $IPDB_CONFIG unset, $HOME/.ipdb does not exist, + setup.cfg does not exist, pyproject.toml exists + Result: load pyproject.toml + """ + os.unlink(self.env_filename) + os.unlink(self.default_filename) + os.remove(self.setup_filename) + with ModifiedEnvironment(IPDB_CONFIG=None, HOME=self.tmpd): + cfg = get_config() + # breakpoint() + self.assertEqual(["ipdb"], cfg.sections()) + self.assertEqual(self.pyproject_context, cfg.getint("ipdb", "context")) + self.assertRaises(configparser.NoOptionError, cfg.get, "ipdb", "version") + def test_env_nodef_setup_pyproject(self): """ Setup: $IPDB_CONFIG is set, $HOME/.ipdb does not exist, @@ -382,3 +399,99 @@ def test_noenv_nodef_invalid_setup(self): pass else: self.fail("Expected TomlDecodeError from invalid config file") + + +class get_ipython_profile_from_config_TestCase(unittest.TestCase): + """ + Test cases for function `get_ipython_profile_from_config`. + """ + + def setUp(self): + """ + Set fixtures for this test case. + """ + set_config_files_fixture(self) + + def test_missing_key_setup(self): + """ + Setup: $IPDB_CONFIG unset, $HOME/.ipdb does not exist, + setup.cfg does not exist, pyproject.toml content is invalid. + Result: Propagate exception from `get_config`. + """ + os.unlink(self.env_filename) + os.unlink(self.default_filename) + os.unlink(self.setup_filename) + write_lines_to_file( + self.pyproject_filename, + ["[tool.ipdb]"], + ) + + try: + from tomllib import TOMLDecodeError + except ImportError: + try: + from tomli import TOMLDecodeError + except ImportError: + from toml.decoder import TomlDecodeError as TOMLDecodeError + + with ModifiedEnvironment(IPDB_CONFIG=None, HOME=self.tmpd): + profile_name = get_ipython_profile_from_config() + assert profile_name == "default" + + def test_default_profile_setup(self): + """ + Setup: $IPDB_CONFIG unset, $HOME/.ipdb does not exist, + setup.cfg does not exist, pyproject.toml content is invalid. + Result: Propagate exception from `get_config`. + """ + os.unlink(self.env_filename) + os.unlink(self.default_filename) + os.unlink(self.setup_filename) + write_lines_to_file( + self.pyproject_filename, + [ + "[tool.ipdb]", + "ipython_profile = 'default'", + ], + ) + + try: + from tomllib import TOMLDecodeError + except ImportError: + try: + from tomli import TOMLDecodeError + except ImportError: + from toml.decoder import TomlDecodeError as TOMLDecodeError + + with ModifiedEnvironment(IPDB_CONFIG=None, HOME=self.tmpd): + profile_name = get_ipython_profile_from_config() + assert profile_name == "default" + + def test_non_existing_profile_setup(self): + """ + Setup: $IPDB_CONFIG unset, $HOME/.ipdb does not exist, + setup.cfg does not exist, pyproject.toml content is invalid. + Result: Propagate exception from `get_config`. + """ + os.unlink(self.env_filename) + os.unlink(self.default_filename) + os.unlink(self.setup_filename) + write_lines_to_file( + self.pyproject_filename, + [ + "[tool.ipdb]", + "ipython_profile = 'foo'", + ], + ) + + try: + from tomllib import TOMLDecodeError + except ImportError: + try: + from tomli import TOMLDecodeError + except ImportError: + from toml.decoder import TomlDecodeError as TOMLDecodeError + + with ModifiedEnvironment(IPDB_CONFIG=None, HOME=self.tmpd): + profile_name = get_ipython_profile_from_config() + assert profile_name == "foo" From a8927fc967febfa9df0012329261970f4a2d7cea Mon Sep 17 00:00:00 2001 From: Wouter Vanden Hove Date: Fri, 31 Mar 2023 10:05:26 +0200 Subject: [PATCH 2/4] add ipython-profile support (#2) * add ipython-profile support * add tests to fetch ipytohn_profiler from config * cleanup profile-tests --------- Co-authored-by: Wouter Vanden Hove --- README.rst | 6 ++-- ipdb/__main__.py | 61 ++++++++++++++++++++++++++++++++-------- tests/test_config.py | 67 ++++++++------------------------------------ 3 files changed, 65 insertions(+), 69 deletions(-) diff --git a/README.rst b/README.rst index 0143114..fe7016e 100644 --- a/README.rst +++ b/README.rst @@ -124,11 +124,11 @@ Or you can use ``iex`` as a function decorator to launch ipdb if an exception is Using a non-default ipython-profile ----------------------------------- By default ``ipdb`` will instantiate an ipython-session loaded with the default profile called ``default``. -You can set a non-default profile by setting the environment variable ``IPDB_IPYTON_PROFILE``: +You can set a non-default profile by setting the environment variable ``IPDB_IPYTHON_PROFILE``: .. code-block:: bash - export IPDB_IPYTON_PROFILE="ipdb" + export IPDB_IPYTHON_PROFILE="ipdb" Or by setting in ``pyproject.toml``: @@ -137,7 +137,7 @@ Or by setting in ``pyproject.toml``: [tool.ipdb] ipython_profile = "ipdb" -This should correspond with a profile-directory ``profile_ipdb```in your ``IPYTHON_HOME``. +This should correspond with a profile-directory ``profile_ipdb`` in your ``IPYTHON_HOME``. If this profile-directory does not exist, we fall back to the default profile. diff --git a/ipdb/__main__.py b/ipdb/__main__.py index 56376f9..e3aebad 100644 --- a/ipdb/__main__.py +++ b/ipdb/__main__.py @@ -13,9 +13,8 @@ __version__ = "0.13.14.dev0" from IPython import get_ipython -from IPython.core.application import ProfileDir from IPython.core.debugger import BdbQuit_excepthook -from IPython.core.profiledir import ProfileDirError +from IPython.core.profiledir import ProfileDir, ProfileDirError from IPython.paths import get_ipython_dir from IPython.terminal.ipapp import TerminalIPythonApp from IPython.terminal.embed import InteractiveShellEmbed @@ -33,15 +32,50 @@ def _get_debugger_cls(ipython_profile="default"): # Build a terminal app in order to force ipython to load the # configuration ipython_dir = get_ipython_dir() + profile_dir = None + + # First, try to find the requested profile try: profile_dir = ProfileDir.find_profile_dir_by_name( ipython_dir=ipython_dir, name=ipython_profile, ) - except ProfileDirError: # fallback to default-profile - profile_dir = ProfileDir.find_profile_dir_by_name( - ipython_dir=ipython_dir, - ) + except ProfileDirError: + # Profile doesn't exist, try to create it + try: + profile_dir = ProfileDir.create_profile_dir_by_name( + ipython_dir=ipython_dir, + name=ipython_profile, + ) + except (ProfileDirError, Exception): + # Creation failed, fallback to default profile + profile_dir = None + + # If we still don't have a profile_dir, try the default profile + if profile_dir is None: + try: + # Try to find default profile + profile_dir = ProfileDir.find_profile_dir_by_name( + ipython_dir=ipython_dir, + name='default', + ) + except ProfileDirError: + # Default doesn't exist either, create it + try: + profile_dir = ProfileDir.create_profile_dir_by_name( + ipython_dir=ipython_dir, + name='default', + ) + except (ProfileDirError, Exception): + # Last resort: create profile without name + profile_dir = ProfileDir.create_profile_dir_by_name( + ipython_dir=ipython_dir, + ) + + # Ensure we have a profile_dir before creating TerminalIPythonApp + if profile_dir is None: + raise RuntimeError("Unable to create or find any IPython profile directory") + ipapp = TerminalIPythonApp(profile_dir=profile_dir) # Avoid output (banner, prints) @@ -62,14 +96,19 @@ def _get_debugger_cls(ipython_profile="default"): return shell.debugger_cls -def _init_pdb(context=None, ipython_profile=None, commands=[]): +def _init_pdb(context=None, ipython_profile=None, commands=None): + if commands is None: + commands = [] + if context is None: - context = os.getenv("IPDB_CONTEXT_SIZE", get_context_from_config()) + context = os.getenv("IPDB_CONTEXT_SIZE", None) + if context is None: + context = get_context_from_config() if ipython_profile is None: - ipython_profile = os.getenv( - "IPDB_IPYTHON_PROFILE", get_ipython_profile_from_config() - ) + ipython_profile = os.getenv("IPDB_IPYTHON_PROFILE", None) + if ipython_profile is None: + ipython_profile = get_ipython_profile_from_config() debugger_cls = _get_debugger_cls(ipython_profile=ipython_profile) diff --git a/tests/test_config.py b/tests/test_config.py index 2d5ff4a..e976d59 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -138,22 +138,6 @@ def test_noenv_nodef_nosetup_pyproject(self): self.assertEqual(self.pyproject_context, cfg.getint("ipdb", "context")) self.assertRaises(configparser.NoOptionError, cfg.get, "ipdb", "version") - def test_noenv_nodef_nosetup_pyproject(self): - """ - Setup: $IPDB_CONFIG unset, $HOME/.ipdb does not exist, - setup.cfg does not exist, pyproject.toml exists - Result: load pyproject.toml - """ - os.unlink(self.env_filename) - os.unlink(self.default_filename) - os.remove(self.setup_filename) - with ModifiedEnvironment(IPDB_CONFIG=None, HOME=self.tmpd): - cfg = get_config() - # breakpoint() - self.assertEqual(["ipdb"], cfg.sections()) - self.assertEqual(self.pyproject_context, cfg.getint("ipdb", "context")) - self.assertRaises(configparser.NoOptionError, cfg.get, "ipdb", "version") - def test_env_nodef_setup_pyproject(self): """ Setup: $IPDB_CONFIG is set, $HOME/.ipdb does not exist, @@ -412,37 +396,27 @@ def setUp(self): """ set_config_files_fixture(self) - def test_missing_key_setup(self): + def test_missing_profile_setup(self): """ - Setup: $IPDB_CONFIG unset, $HOME/.ipdb does not exist, - setup.cfg does not exist, pyproject.toml content is invalid. - Result: Propagate exception from `get_config`. + Setup: pyproject.toml has no [tool.ipdb]-section. """ os.unlink(self.env_filename) os.unlink(self.default_filename) os.unlink(self.setup_filename) write_lines_to_file( self.pyproject_filename, - ["[tool.ipdb]"], + [] ) - try: - from tomllib import TOMLDecodeError - except ImportError: - try: - from tomli import TOMLDecodeError - except ImportError: - from toml.decoder import TomlDecodeError as TOMLDecodeError - with ModifiedEnvironment(IPDB_CONFIG=None, HOME=self.tmpd): profile_name = get_ipython_profile_from_config() - assert profile_name == "default" + self.assertEqual(profile_name, "default") def test_default_profile_setup(self): """ - Setup: $IPDB_CONFIG unset, $HOME/.ipdb does not exist, - setup.cfg does not exist, pyproject.toml content is invalid. - Result: Propagate exception from `get_config`. + Setup: pyproject.toml has a [tool.ipdb]-section + with the ipython_profile explicitly set to 'default'. + """ os.unlink(self.env_filename) os.unlink(self.default_filename) @@ -455,23 +429,14 @@ def test_default_profile_setup(self): ], ) - try: - from tomllib import TOMLDecodeError - except ImportError: - try: - from tomli import TOMLDecodeError - except ImportError: - from toml.decoder import TomlDecodeError as TOMLDecodeError - with ModifiedEnvironment(IPDB_CONFIG=None, HOME=self.tmpd): profile_name = get_ipython_profile_from_config() - assert profile_name == "default" + self.assertEqual(profile_name, "default") - def test_non_existing_profile_setup(self): + def test_non_default_profile_setup(self): """ - Setup: $IPDB_CONFIG unset, $HOME/.ipdb does not exist, - setup.cfg does not exist, pyproject.toml content is invalid. - Result: Propagate exception from `get_config`. + Setup: pyproject.toml has a [tool.ipdb]-section + with the ipython_profile explicitly set to a non-default. """ os.unlink(self.env_filename) os.unlink(self.default_filename) @@ -484,14 +449,6 @@ def test_non_existing_profile_setup(self): ], ) - try: - from tomllib import TOMLDecodeError - except ImportError: - try: - from tomli import TOMLDecodeError - except ImportError: - from toml.decoder import TomlDecodeError as TOMLDecodeError - with ModifiedEnvironment(IPDB_CONFIG=None, HOME=self.tmpd): profile_name = get_ipython_profile_from_config() - assert profile_name == "foo" + self.assertEqual(profile_name, "foo") From 13a608d6e3218dd3bd2714f38ef75d0d2bb86813 Mon Sep 17 00:00:00 2001 From: Godefroid Chapelle Date: Fri, 27 Feb 2026 03:46:44 +0100 Subject: [PATCH 3/4] add devenv --- .envrc | 12 ++++ .gitignore | 11 +++ devenv.lock | 200 ++++++++++++++++++++++++++++++++++++++++++++++++++++ devenv.nix | 49 +++++++++++++ devenv.yaml | 8 +++ 5 files changed, 280 insertions(+) create mode 100644 .envrc create mode 100644 devenv.lock create mode 100644 devenv.nix create mode 100644 devenv.yaml diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..cc5c18b --- /dev/null +++ b/.envrc @@ -0,0 +1,12 @@ +#!/usr/bin/env bash + +export DIRENV_WARN_TIMEOUT=20s + +eval "$(devenv direnvrc)" + +# `use devenv` supports the same options as the `devenv shell` command. +# +# To silence all output, use `--quiet`. +# +# Example usage: use devenv --quiet --impure --option services.postgres.enable:bool true +use devenv diff --git a/.gitignore b/.gitignore index 088871b..38bbaee 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,14 @@ include # pip pip-selfcheck.json + +# Devenv +.devenv* +devenv.local.nix +devenv.local.yaml + +# direnv +.direnv + +# pre-commit +.pre-commit-config.yaml diff --git a/devenv.lock b/devenv.lock new file mode 100644 index 0000000..fc42d62 --- /dev/null +++ b/devenv.lock @@ -0,0 +1,200 @@ +{ + "nodes": { + "blueprint": { + "inputs": { + "nixpkgs": [ + "llm-agents", + "nixpkgs" + ], + "systems": "systems" + }, + "locked": { + "lastModified": 1771437256, + "owner": "numtide", + "repo": "blueprint", + "rev": "06ee7190dc2620ea98af9eb225aa9627b68b0e33", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "blueprint", + "type": "github" + } + }, + "devenv": { + "locked": { + "dir": "src/modules", + "lastModified": 1772143911, + "owner": "cachix", + "repo": "devenv", + "rev": "83c4b5682b84fe04c049970792f38d5879d3c0f1", + "type": "github" + }, + "original": { + "dir": "src/modules", + "owner": "cachix", + "repo": "devenv", + "type": "github" + } + }, + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1767039857, + "owner": "NixOS", + "repo": "flake-compat", + "rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "flake-compat", + "type": "github" + } + }, + "git-hooks": { + "inputs": { + "flake-compat": "flake-compat", + "gitignore": "gitignore", + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1772024342, + "owner": "cachix", + "repo": "git-hooks.nix", + "rev": "6e34e97ed9788b17796ee43ccdbaf871a5c2b476", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "git-hooks.nix", + "type": "github" + } + }, + "gitignore": { + "inputs": { + "nixpkgs": [ + "git-hooks", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1762808025, + "owner": "hercules-ci", + "repo": "gitignore.nix", + "rev": "cb5e3fdca1de58ccbc3ef53de65bd372b48f567c", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "gitignore.nix", + "type": "github" + } + }, + "llm-agents": { + "inputs": { + "blueprint": "blueprint", + "nixpkgs": [ + "nixpkgs" + ], + "treefmt-nix": "treefmt-nix" + }, + "locked": { + "lastModified": 1772119213, + "owner": "numtide", + "repo": "llm-agents.nix", + "rev": "1586a18853ab948e9a2f6805a78cefa263cf5223", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "llm-agents.nix", + "type": "github" + } + }, + "nixpkgs": { + "inputs": { + "nixpkgs-src": "nixpkgs-src" + }, + "locked": { + "lastModified": 1770434727, + "owner": "cachix", + "repo": "devenv-nixpkgs", + "rev": "8430f16a39c27bdeef236f1eeb56f0b51b33d348", + "type": "github" + }, + "original": { + "owner": "cachix", + "ref": "rolling", + "repo": "devenv-nixpkgs", + "type": "github" + } + }, + "nixpkgs-src": { + "flake": false, + "locked": { + "lastModified": 1769922788, + "narHash": "sha256-H3AfG4ObMDTkTJYkd8cz1/RbY9LatN5Mk4UF48VuSXc=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "207d15f1a6603226e1e223dc79ac29c7846da32e", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "devenv": "devenv", + "git-hooks": "git-hooks", + "llm-agents": "llm-agents", + "nixpkgs": "nixpkgs", + "pre-commit-hooks": [ + "git-hooks" + ] + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "treefmt-nix": { + "inputs": { + "nixpkgs": [ + "llm-agents", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1770228511, + "owner": "numtide", + "repo": "treefmt-nix", + "rev": "337a4fe074be1042a35086f15481d763b8ddc0e7", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "treefmt-nix", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/devenv.nix b/devenv.nix new file mode 100644 index 0000000..a6304ed --- /dev/null +++ b/devenv.nix @@ -0,0 +1,49 @@ +{ pkgs, lib, config, inputs, ... }: + +{ + # https://devenv.sh/basics/ + env.GREET = "devenv"; + + # https://devenv.sh/packages/ + packages = [ + pkgs.git + inputs.llm-agents.packages.${pkgs.stdenv.system}.goose-cli + ]; + + # https://devenv.sh/languages/ + # languages.rust.enable = true; + + # https://devenv.sh/processes/ + # processes.dev.exec = "${lib.getExe pkgs.watchexec} -n -- ls -la"; + + # https://devenv.sh/services/ + # services.postgres.enable = true; + + # https://devenv.sh/scripts/ + scripts.hello.exec = '' + echo hello from $GREET + ''; + + # https://devenv.sh/basics/ + enterShell = '' + hello # Run scripts directly + git --version # Use packages + ''; + + # https://devenv.sh/tasks/ + # tasks = { + # "myproj:setup".exec = "mytool build"; + # "devenv:enterShell".after = [ "myproj:setup" ]; + # }; + + # https://devenv.sh/tests/ + enterTest = '' + echo "Running tests" + git --version | grep --color=auto "${pkgs.git.version}" + ''; + + # https://devenv.sh/git-hooks/ + # git-hooks.hooks.shellcheck.enable = true; + + # See full reference at https://devenv.sh/reference/options/ +} diff --git a/devenv.yaml b/devenv.yaml new file mode 100644 index 0000000..c79d7a6 --- /dev/null +++ b/devenv.yaml @@ -0,0 +1,8 @@ +inputs: + llm-agents: + url: github:numtide/llm-agents.nix + inputs: + nixpkgs: + follows: nixpkgs + nixpkgs: + url: github:cachix/devenv-nixpkgs/rolling From ccc4bc229b0d5ceda795bcb4bec03ec428633b82 Mon Sep 17 00:00:00 2001 From: Godefroid Chapelle Date: Fri, 27 Feb 2026 04:24:36 +0100 Subject: [PATCH 4/4] update to supported versions # Conflicts: # .github/workflows/tests.yml --- .github/workflows/tests.yml | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 3a96dab..0b69b6c 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -15,25 +15,12 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, macos-latest, windows-latest] - python-version: ["2.7", "3.5", "3.6", "3.7", "3.8", "3.9", "3.10", "3.11", "3.12"] - exclude: - # excludes 2.7 on windows as chocolatey does not support it anymore - - os: windows-latest - python-version: 2.7 - - os: ubuntu-latest - python-version: 3.5 - - os: ubuntu-latest - python-version: 3.6 - include: - - os: ubuntu-20.04 - python-version: 3.5 - - os: ubuntu-20.04 - python-version: 3.6 + python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} @@ -47,5 +34,5 @@ jobs: pip install -e . - name: run tests run: | - coverage run setup.py test + coverage run -m unittest discover tests codecov