{"id":19045792,"url":"https://github.com/soldni/springs","last_synced_at":"2025-07-13T20:38:18.838Z","repository":{"id":39029763,"uuid":"506813038","full_name":"soldni/springs","owner":"soldni","description":"A set of utilities to turn Dataclasses into useful configuration managers.","archived":false,"fork":false,"pushed_at":"2024-03-27T07:27:35.000Z","size":3493,"stargazers_count":11,"open_issues_count":5,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-06-29T08:15:44.191Z","etag":null,"topics":["experiments","machine-learning","python","yaml"],"latest_commit_sha":null,"homepage":"https://springs.soldaini.net","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/soldni.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-06-23T22:50:50.000Z","updated_at":"2024-04-08T23:53:05.000Z","dependencies_parsed_at":"2024-11-08T22:51:45.679Z","dependency_job_id":null,"html_url":"https://github.com/soldni/springs","commit_stats":null,"previous_names":[],"tags_count":28,"template":false,"template_full_name":null,"purl":"pkg:github/soldni/springs","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/soldni%2Fsprings","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/soldni%2Fsprings/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/soldni%2Fsprings/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/soldni%2Fsprings/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/soldni","download_url":"https://codeload.github.com/soldni/springs/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/soldni%2Fsprings/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265201561,"owners_count":23727009,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["experiments","machine-learning","python","yaml"],"created_at":"2024-11-08T22:51:40.740Z","updated_at":"2025-07-13T20:38:18.816Z","avatar_url":"https://github.com/soldni.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Springs\n\n\u003cimg style=\"  margin-left: auto; margin-right:auto; margin-bottom: 2em; display: block\" id=\"hero\" src=\"https://github.com/soldni/springs/raw/main/assets/img/logo.png\" alt=\"Logo for Springs\" width=\"200px\" height=\"auto\"\u003e\n\nA set of utilities to turn [OmegaConf][1] into a fully fledge configuration utils.\nJust like the springs inside an Omega watch, the Springs library helps you move on with your experiments.\n\nSprings overlaps in functionality with [Hydra][2], but without all the unnecessary boilerplate.\n\nThe current logo for Springs was generated using [DALL·E 2][5].\n\nTo install Springs from [PyPI][6], simply run:\n\n```bash\npip install springs\n```\n\n**Table of Contents**:\n\n- [Philosophy](#philosophy)\n- [A Note About Unstructured Configs](#a-note-about-unstructured-configs)\n- [Initializing Objects from Configurations](#initializing-objects-from-configurations)\n- [Static and Dynamic Type Checking](#static-and-dynamic-type-checking)\n- [Flexible Configurations](#flexible-configurations)\n- [Adding Help Messages to Configurations](#adding-help-messages-to-configurations)\n- [Command Line Options](#command-line-options)\n- [Tips and Tricks](#tips-and-tricks)\n\n\n## Philosophy\n\nOmegaConf supports creating configurations in all sorts of manners, but we believe that there are benefits into defining configuration from structured objects, namely dataclass.\nSprings is built around that notion: write one or more dataclass to compose a configuration (with appropriate defaults), then parse the remainder of options or missing values from command line/a yaml file.\n\nLet's look at an example. Imagine we are building a configuration for a machine learning (ML) experiment, and we want to provide information about model and data to use.\nWe start by writing the following structure configuration\n\n```python\nimport springs as sp\nfrom dataclasses import dataclass\n\n# Data config\n# sp.dataclass is an alias for\n# dataclasses.dataclass\n@sp.dataclass\nclass DataConfig:\n    # sp.MISSING is an alias to\n    # omegaconf.MISSING\n    path: str = sp.MISSING\n    split: str = 'train'\n\n# Model config\n@sp.dataclass\nclass ModelConfig:\n    name: str = sp.MISSING\n    num_labels: int = 2\n\n\n# Experiment config\n@sp.dataclass\nclass ExperimentConfig:\n    batch_size: int = 16\n    seed: int = 42\n\n\n# Overall config\n# for our program\n@sp.dataclass\nclass Config:\n    data: DataConfig = DataConfig()\n    model: ModelConfig = ModelConfig()\n    exp: ExperimentConfig = ExperimentConfig()\n```\n\nNote how, in matching with OmegaConf syntax, we use `MISSING` to indicate any value that has no default and should be provided at runtime.\n\nIf we want to use this configuration with a function that actually runs this experiment, we can use `sp.cli` as follows:\n\n```python\n@sp.cli(Config)\ndef main(config: Config)\n    # this will print the configuration\n    # like a dict\n    print(config)\n    # you can use dot notation to\n    # access attributes...\n    config.exp.seed\n    # ...or treat it like a dictionary!\n    config['exp']['seed']\n\n\nif __name__ == '__main__':\n    main()\n\n```\n\nNotice how, in the configuration `Config` above, some parameters are missing.\nWe can specify them from command line...\n\n```bash\npython main.py \\\n    data.path=/path/to/data \\\n    model.name=bert-base-uncased\n```\n\n...or from one or more YAML config files (if multiple, *e.g.,* `-c /path/to/cfg1.yaml -c /path/to/cfg2.yaml` the latter ones override the former ones).\n\n\n```YAML\ndata:\n    path: /path/to/data\n\nmodel:\n    name: bert-base-uncased\n\n# you can override any part of\n# the config via YAML or CLI\n# CLI takes precedence over YAML.\nexp:\n    seed: 1337\n\n```\n\nTo run with from YAML, do:\n\n```bash\npython main.py -c config.yaml\n```\n\nEasy, right?\n\n\n## A Note About Unstructured Configs\n\nYou are not required to used a structured config with Springs.\nTo use our CLI with a bunch of yaml files and/or command line arguments, simply decorate your main function with no arguments.\n\n```python\n@sp.cli()\ndef main(config)\n    # do stuff\n    ...\n```\n\n## Initializing Objects from Configurations\n\nSometimes a configuration contains all the necessary information to instantiate an object from it.\nSprings supports this use case, and it is as easy as providing a `_target_` node in a configuration:\n\n```python\n@sp.dataclass\nclass ModelConfig:\n    _target_: str = (\n        'transformers.'\n        'AutoModelForSequenceClassification.'\n        'from_pretrained'\n    )\n    pretrained_model_name_or_path: str = \\\n        'bert-base-uncased'\n    num_classes: int = 2\n```\n\nIn your experiment code, run:\n\n```python\ndef run_model(model_config: ModelConfig):\n    ...\n    model = sp.init.now(\n        model_config, ModelConfig\n    )\n```\n\n**Note:** While previous versions of Springs merely supported specifying the return type, now it is actively and strongly encouraged.\nRunning `sp.init.now(model_config)` will raise a warning if the type is not provided. To prevent this warning, use `sp.toggle_warnings(False)` before calling `sp.init.now`/ `sp.init.later`.\n\n### `init.now` vs `init.later`\n\n`init.now` is used to immediately initialize a class or run a method.\nBut what if the function you are not ready to run the `_target_` you want to initialize?\nThis is common for example if you receive a configuration in the init method of a class, but you don't have all parameters to run it until later in the object lifetime. In that case, you might want to use `init.later`.\nExample:\n\n```python\nconfig = sp.from_dict({'_target_': 'str.lower'})\nfn = sp.init.later(config, Callable[..., str])\n\n... # much computation occurs\n\n# returns `this to lowercase`\nfn('THIS TO LOWERCASE')\n```\n\nNote that, for convenience `sp.init.now` is aliased to `sp.init`.\n\n### Providing Class Paths as `_target_`\n\nIf, for some reason, cannot specify the path to a class as a string, you can use `sp.Target.to_string` to resolve a function, class, or method to its path:\n\n```python\nimport transformers\n\n@sp.dataclass\nclass ModelConfig:\n    _target_: str = sp.Target.to_string(\n        transformers.\n        AutoModelForSequenceClassification.\n        from_pretrained\n    )\n    pretrained_model_name_or_path: str = \\\n        'bert-base-uncased'\n    num_classes: int = 2\n```\n\n## Static and Dynamic Type Checking\n\nSprings supports both static and dynamic (at runtime) type checking when initializing objects.\nTo enable it, pass the expected return type when initializing an object:\n\n```python\n@sp.cli(TokenizerConfig)\ndef main(config: TokenizerConfig):\n    tokenizer = sp.init(\n        config, PreTrainedTokenizerBase\n    )\n    print(tokenizer)\n```\n\nThis will raise an error when the tokenizer is not a subclass of `PreTrainedTokenizerBase`. Further, if you use a static type checker in your workflow (e.g., [Pylance][3] in [Visual Studio Code][4]), `springs.init` will also annotate its return type accordingly.\n\n## Flexible Configurations\n\nSometimes a configuration has some default parameters, but others are optional and depend on other factors, such as the `_target_` class.  In these cases, it is convenient to set up a flexible dataclass, using `make_flexy` after the `dataclass` decorator.\n\n```python\n@sp.flexyclass\nclass MetricConfig:\n    _target_: str = sp.MISSING\n    average: str = 'macro'\n\nconfig = sp.from_dataclass(MetricConfig)\noverrides = {\n    # we override the _target_\n    '_target_': 'torchmetrics.F1Score',\n    # this attribute does not exist in the\n    # structured config\n    'num_classes': 2\n}\n\nconfig = sp.merge(config,\n                  sp.from_dict(overrides))\nprint(config)\n# this will print the following:\n# {\n#    '_target_': 'torchmetrics.F1Score',\n#    'average': 'macro',\n#    'num_classes': 2\n# }\n```\n\n## Adding Help Messages to Configurations\n\nSprings supports adding help messages to your configurations; this is useful to provide a description of parameters to users of your application.\n\nTo add a help for a parameter, simply pass `help=...` to a field constructor:\n\n```python\n@sp.dataclass\nclass ModelConfig:\n    _target_: str = sp.field(\n        default='transformers.'\\\n            'AutoModelForSequenceClassification.'\\\n            'from_pretrained',\n        help='The class for the model'\n    )\n    pretrained_model_name_or_path: str = sp.field(\n        default='bert-base-uncased',\n        help='The name of the model to use'\n    )\n    num_classes: int = sp.field(\n        default=2,\n        help='The number of classes for classification'\n    )\n\n@sp.dataclass\nclass ExperimentConfig:\n    model: ModelConfig = sp.field(\n        default_factory=ModelConfig,\n        help='The model configuration'\n    )\n\n@sp.cli(ExperimentConfig)\ndef main(config: ExperimentConfig):\n    ...\n\nif __name__ == '__main__':\n    main()\n```\n\nAs you can see, you can also add help messages to nested configurations. Help messages are printed when you call `python my_script.py --options` or `python my_script.py --o`.\n\n## Command Line Options\n\nYou can print all command line options by calling `python my_script.py -h` or `python my_script.py --help`. Currently, a Springs application supports the following:\n\n|Flag | Default | Action | Description|\n|----:|:-------:|:------:|:-----------|\n|`-h/--help` | `False` | toggle | show the help message and exit|\n|`-c/--config` | `[]` | append | either a path to a YAML file containing a configuration, or a nickname for a configuration in the registry; multiple configurations can be specified with additional `-c/--config` flags, and they will be merged in the order they are provided|\n|`-o/--options` | `False` | toggle | print all default options and CLI flags|\n|`-i/--inputs` | `False` | toggle | print the input configuration|\n|`-p/--parsed` | `False` | toggle | print the parsed configuration|\n|`-l/--log-level` | `WARNING` | set | logging level to use for this program; can be one of `CRITICAL`, `ERROR`, `WARNING`, `INFO`, or `DEBUG`; defaults to `WARNING`.|\n|`-d/--debug` | `False` |toggle| enable debug mode; equivalent to `--log-level DEBUG`|\n|`-q/--quiet` | `False` |toggle| if provided, it does not print the configuration when running|\n|`-r/--resolvers` | `False` |toggle| print all registered resolvers in OmegaConf, Springs, and current codebase|\n|`-n/--nicknames` | `False` |toggle| print all registered nicknames in Springs|\n|`-s/--save` | `None` | set | save the configuration to a YAML file and exit|\n\n## Tips and Tricks\n\nThis section includes a bunch of tips and tricks for working with OmegaConf and YAML.\n\n### Tip 1: Repeating nodes in YAML input\n\nIn setting up YAML configuration files for ML experiments, it is common to\nhave almost-repeated sections.\nIn these cases, you can take advantage of YAML's built in variable mechanism and dictionary merging to remove duplicated imports:\n\n```yaml\n# \u0026tc assigns an alias to this node\ntrain_config: \u0026tc\n  path: /path/to/data\n  src_field: full_text\n  tgt_field: summary\n  split_name: train\n\ntest_config:\n  # \u003c\u003c operator indicates merging,\n  # *tc is a reference to the alias above\n  \u003c\u003c : *tc\n  split_name: test\n```\n\nThis will resolve to:\n\n```yaml\ntrain_config:\n  path: /path/to/data\n  split_name: train\n  src_field: full_text\n  tgt_field: summary\n\ntest_config:\n  path: /path/to/data\n  split_name: test\n  src_field: full_text\n  tgt_field: summary\n```\n\n\n[1]: https://omegaconf.readthedocs.io/\n[2]: https://hydra.cc/\n[3]: https://devblogs.microsoft.com/python/announcing-pylance-fast-feature-rich-language-support-for-python-in-visual-studio-code/\n[4]: https://code.visualstudio.com\n[5]: https://openai.com/dall-e-2/\n[6]: https://pypi.org/project/springs/\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsoldni%2Fsprings","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsoldni%2Fsprings","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsoldni%2Fsprings/lists"}