Merge pull request #254452 from flyingcircusio/lib-attrsToList

lib.attrsets.attrsToList: add function
This commit is contained in:
Silvan Mosberger 2023-10-10 19:49:17 +02:00 committed by GitHub
commit 5323fbf703
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 56 additions and 2 deletions

@ -542,6 +542,36 @@ rec {
attrs:
map (name: f name attrs.${name}) (attrNames attrs);
/*
Deconstruct an attrset to a list of name-value pairs as expected by [`builtins.listToAttrs`](https://nixos.org/manual/nix/stable/language/builtins.html#builtins-listToAttrs).
Each element of the resulting list is an attribute set with these attributes:
- `name` (string): The name of the attribute
- `value` (any): The value of the attribute
The following is always true:
```nix
builtins.listToAttrs (attrsToList attrs) == attrs
```
:::{.warning}
The opposite is not always true. In general expect that
```nix
attrsToList (builtins.listToAttrs list) != list
```
This is because the `listToAttrs` removes duplicate names and doesn't preserve the order of the list.
:::
Example:
attrsToList { foo = 1; bar = "asdf"; }
=> [ { name = "bar"; value = "asdf"; } { name = "foo"; value = 1; } ]
Type:
attrsToList :: AttrSet -> [ { name :: String; value :: Any; } ]
*/
attrsToList = mapAttrsToList nameValuePair;
/* Like `mapAttrs`, except that it recursively applies itself to
the *leaf* attributes of a potentially-nested attribute set:

@ -81,8 +81,8 @@ let
inherit (self.attrsets) attrByPath hasAttrByPath setAttrByPath
getAttrFromPath attrVals attrValues getAttrs catAttrs filterAttrs
filterAttrsRecursive foldlAttrs foldAttrs collect nameValuePair mapAttrs
mapAttrs' mapAttrsToList concatMapAttrs mapAttrsRecursive mapAttrsRecursiveCond
genAttrs isDerivation toDerivation optionalAttrs
mapAttrs' mapAttrsToList attrsToList concatMapAttrs mapAttrsRecursive
mapAttrsRecursiveCond genAttrs isDerivation toDerivation optionalAttrs
zipAttrsWithNames zipAttrsWith zipAttrs recursiveUpdateUntil
recursiveUpdate matchAttrs overrideExisting showAttrPath getOutput getBin
getLib getDev getMan chooseDevOutputs zipWithNames zip

@ -20,6 +20,10 @@ let
expr = (builtins.tryEval (builtins.seq expr "didn't throw"));
expected = { success = false; value = false; };
};
testingEval = expr: {
expr = (builtins.tryEval expr).success;
expected = true;
};
testingDeepThrow = expr: testingThrow (builtins.deepSeq expr expr);
testSanitizeDerivationName = { name, expected }:
@ -816,6 +820,26 @@ runTests {
expected = { a = 1; b = 2; };
};
testListAttrsReverse = let
exampleAttrs = {foo=1; bar="asdf"; baz = [1 3 3 7]; fnord=null;};
exampleSingletonList = [{name="foo"; value=1;}];
in {
expr = {
isReverseToListToAttrs = builtins.listToAttrs (attrsToList exampleAttrs) == exampleAttrs;
isReverseToAttrsToList = attrsToList (builtins.listToAttrs exampleSingletonList) == exampleSingletonList;
testDuplicatePruningBehaviour = attrsToList (builtins.listToAttrs [{name="a"; value=2;} {name="a"; value=1;}]);
};
expected = {
isReverseToAttrsToList = true;
isReverseToListToAttrs = true;
testDuplicatePruningBehaviour = [{name="a"; value=2;}];
};
};
testAttrsToListsCanDealWithFunctions = testingEval (
attrsToList { someFunc= a: a + 1;}
);
# GENERATORS
# these tests assume attributes are converted to lists
# in alphabetical order