This is a package that allows you to create a key-value vault for storing variables in a global context

Overview

README

How to install?

pip3 install varvault

What is this?

This is a package that allows you to create a key-value vault for storing variables in a global context. It allows you to set up a keyring with pre-defined constants which act as keys for the vault. These constants are then what is stored inside the vault. A key is just a string, but the value that the key is mapped to can be assigned to any type of object in Python. If the object is serializable (like a list or a dict), it can also be writen to a JSON file
You can then use a decorator to annotate functions that you want to have use this vault to either store return variables in or to extract variables to be used as input for the function.

How does it work?

The way this works is that when you write a function, you annotate it with a special decorator (varvault.Vault.vaulter) that takes some arguments. This decorator will then handle any input arguments and return variables for you. The decorator takes some arguments that defines certain keys.

How about an example?

The best examples can be found in the test suites which can give a very good idea how it works and is guaranteed to be up-to-date.

import varvault


class Keyring(varvault.Keyring):
    arg1 = varvault.Key("arg1")
    arg2 = varvault.Key("arg2")


vault = varvault.create_vault(Keyring, "example-vault", "~/.vault/vault.json", varvault.VaultFlags.return_values_cannot_be_none()))


@vault.vaulter(return_keys=[Keyring.arg1, Keyring.arg2])
def create_args(arg1, arg2):
    return arg1, arg2


@vault.vaulter(input_keys=[Keyring.arg1, Keyring.arg2])
def use_args(**kwargs):
    arg1 = kwargs.get(Keyring.arg1)
    arg2 = kwargs.get(Keyring.arg2)

    print(f"{Keyring.arg1}: {arg1}, {Keyring.arg2}: {arg2}")


def run_create_args():
    create_args(1, 2)
    

def run_use_args():
    use_args()


if __name__ == "__main__":
    run_create_args()
    
    run_use_args()    
  1. In this example, we start by creating a class that defines a keyring. This keyring will be the keys used in the vault. Any key you use for storing variables or take variables out should be defined as a constant in this keyring (by default, this is the way to use it, but it is possible to be more flexible).

  2. Then we create the actual Vault-object. It's entirely possible to create a Vault without using the factory function, but the factory function will do some things for you to make it slightly easier. Creating the vault requires only two arguments and that is a class that inherits from the varvault.Keyring (a class based on the Keyring class here), and a name. Optionally, you can define some flags to further tweak the behavior of the vault. These tweaked behaviors include allowing for existing key-value pairs to be modified (this is not allowed by default), allowing return variables from functions defined with return keys to be None, and setting a flag to write some additional debug logs. You can also define a .JSON file to be used as a vault file to store all the arguments in.

  3. We create a function called create_args that takes some arguments (we have to insert variables into the vault somehow, right?) that we annotate with the vault decorator. We pass an argument to the decorator called return_keys. This argument tells the vault which keys this function will assign its return variables to. Note that the order of the return keys matter. In this case, the ingoing argument arg1 will be assigned to Keyring.arg1, and the ingoing argument arg2 will be assigned to Keyring.arg2. It's very possible to set return_var_key to a single string as well if you only have one variable to return. If you want more control over how return variables are handled, please see varvault.MiniVault and make use of that to ensure that return-variables are handled exactly as you want.

    Note: When this function is called and it finishes, the decorator here will capture the return variables and then store those return variables in the vault with the keys that were passed to the decorator. These variables can then be accessed by another function that uses the same vault-object as this one does.

  4. We then create a new function called use_args that we also annotate with the vault decorator. We pass a different argument to the decorator this time called input_keys. This argument tells the vault which keys in the vault we want passed to this function. The order of the keys doesn't really matter here, the order is mostly aesthetic.

    Note: What ends up happening when this function is called, is that the decorator will try to extract keys defined in input_keys from the vault and then pass those variables to the function as a dictionary (this is what **kwargs essentially is). It is possible to write arguments in the signature of the function itself (in this case the signature would be def use_args(arg1=None, arg2=None), but one of the purposes of the Keyring is that the constants defined in the keyring can be used to easily find where a key is being used. It's recommended to write the function like this but it is possible to write it with pre-defined arguments as well. Do note that the arguments have to have a default value, like None. Otherwise, when you call the function, you have to call the function with the arguments fulfilled as well.

  5. We create a very simple function called run_create_args which doesn't get annotated. This function is simply made to demonstrate what makes this vault so useful. When this function is called, it will obviously call create_args, which will create Keyring.arg1andKeyring.arg2` which will then be stored in the vault.

  6. A final function called run_use_args is then created which calls the use_args function. This function is able to use the arguments defined in create_args because with this vault, the context for where a function runs doesn't really matter as long as the input variables it needs exists in the vault-object already, and the function exists in that scope.

  7. Lastly, the variables that were involved in the execution of this code can be viewed by simply checking the contents of the file ~/.vault/vault.json. In this example the file would simply contain:

    {
      "arg1": 1,
      "arg2": 2
    }
    
  8. When a file such as this (see above) exists, it's very possible to re-create the same vault again from this file. In order to re-create the same vault again simply do this:

    vault = varvault.from_vault_file(Keyring,
                                     "example-vault",
                                     "~/.vault/vault.json",
                                     varvault.VaultFlags.permit_modifications()))
    

    When re-creating a vault from an existing file it's recommended to allow modifications (see varvault.VaultFlags.permit_modifications) in-case you are planning to write the same arguments to the vault again.

Conclusion. This flow demonstrates what this functionality can be used for. With this vault, the context for where a function executes doesn't matter as long as the keys the function needs have been assigned in the vault and the functions exists in the scope. The functions become building blocks that you can call regardless of context provided the above criteria have been met. You don't need to clutter your function calls with tons of input variables because all of that is handled for you by the vault and the decorator. If you use it correctly, you can end up with functions that on the surface appears to not use any arguments or pass any return variables at all. This makes the main body of your code clean and easy to follow. You can then use the Keyring to see where your keys are actually being used. By saving arguments to a file, it allows you to keep parts of the context the code ran in previously. This can be very useful when deploying something which then has to be un-deployed at a later time that isn't necessarily running in the same process as before. This adds an extra layer similar to environment variables that works slightly differently and exclusively in Python. Since the arguments are saved to a JSON file, anything that can parse JSON can obviously use the data as they see fit.

You might also like...
New time-based UUID formats which are suited for use as a database key

uuid6 New time-based UUID formats which are suited for use as a database key. This module extends immutable UUID objects (the UUID class) with the fun

Dynamic key remapper for Wayland Window System, especially for Sway

wayremap Dynamic keyboard remapper for Wayland. It works on both X Window Manager and Wayland, but focused on Wayland as it intercepts evdev input and

A fixture that allows runtime xfail

pytest-runtime-xfail pytest plugin, providing a runtime_xfail fixture, which is callable as runtime_xfail(), to allow runtime decisions to mark a test

Utility to play with ADCS, allows to request tickets and collect information about related objects.

certi Utility to play with ADCS, allows to request tickets and collect information about related objects. Basically, it's the impacket copy of Certify

Import the module and create an object of the class LocalVariable.
Import the module and create an object of the class LocalVariable.

LocalVariable Import the module and create an object of the class LocalVariable. Call the save method with the name and the value of a variable as arg

Create powerful passwords easily and with many options with this program
Create powerful passwords easily and with many options with this program

Password_Generator About the Program: You can create powerful passwords with this program with many options easily! Features: You can copy the generat

This project is a set of programs that I use to create a README.md file.
This project is a set of programs that I use to create a README.md file.

This project is a set of programs that I use to create a README.md file.

Create a Web Component (a Custom Element) from a python file

wyc Create a Web Component (a Custom Element) from a python file (transpile python code to javascript (es2015)). Features Use python to define your cu

🦩 A Python tool to create comment-free Jupyter notebooks.

Pelikan Pelikan lets you convert notebooks to comment-free notebooks. In other words, It removes Python block and inline comments from source cells in

Comments
  • 5.0.0: New major version

    5.0.0: New major version

    Made a ton of changes to the APIs and some new functionality:

    • Reworked how resources function. They now use the same mode as the builtin open function does. You can set modes like "r", "w", "a", "r+", "w+", and "a+". They will work as you expect, with the difference that those with a + indicates live-update is enabled, e.g. "r" is read mode, while "r+" is read with live-update enabled.
    • The standard JsonResource has been changed to create a backup file that is written to. After the backup file has been written to, the name of the file will be changed to the normal file. This way, there's always a file to read from. In very rare cases, if you kill the writing process, there will not be anything in the file since the file is opened in "w" mode, since append mode works really badly with JSON. We might lose a bit of data in such a case, but we retain most of it since we'll read from the standard file that still exists.
    • A Key can now take a set of modifier functions. These work just like validators (see validator.py) in that you create a method to annotate with varvault.modifier() which will allow you to modify the value of the object mapped to the key. This is useful if you want to strip a sequence of characters from a string, or expand vars/user in a path, or to always follow symlinks using os.path.realpath. This can reduce some boilerplate code.
    • The VaultFlags have been changed to just Flags and they have been changed to enums which is quite a bit more lightweight than creating new strings for every key.
    • The factory functions have been completely changed. There is now only create, and no from_vault. The resource object will handle the from_vault case by using append mode (mores "a", or "a+") instead.
    • There's no argument for resource_from or resource_to anymore; just resource. If you want to load a vault from one resource and write to another resource, you'll need to create a resource-object for the resource that you want to load from and load it into the vault manually after creating the vault.
    • A function has been added to utils called assert_and_raise. The function takes a condition as a bool and an exception object. It acts as an assert-function that can raise any exception you want (such as KeyError or ValueError) rather than AssertionError.
    • Internal logging has been changed to be more robust, though this sadly means it's a bit slower. It's not slow, just slower than it was. But the robustness improvements are worth it to get the logging you expect.
    • Added more type-annotations to exposed functions, such as for create under factory.py. This should help users to know how to use the functions better, provided they are using a proper IDE.
    opened by Evixy 0
  • 4.0.0: New major version

    4.0.0: New major version

    New features:

    • Added the possibility to define input keys through the name of the parameters in the signature of the function. It essentially comes down to calling a parameter the same as the name of a key in the keyring and making sure the flag VaultFlags.use_signature_for_input_keys is defined. This can reduce boilerplate, but does make it harder to track the usage of certain keys, which is why it will never be the default behavior of varvault.

    Other changes:

    • Updated the conclusion section of the README.md.
    • Reworked the filehandlers API and simplified the JsonFileHandler slightly.
      • The filehandler now holds the state and keeps track of it, rather than varvault itself keeping track of the state.
    • Made changes to the vaultstructs API to change the name of the abstract method to create which is a lot less cumbersome of a function name.
    • Made significant cleanup of code, mostly in vault.py to make it easier to work with, and to read and comprehend.
    opened by Evixy 0
  • 2.0.0: New major version

    2.0.0: New major version

    • Made changes to allow for the possibility to select a file-handler to write to the vault file, and to implement your own file-handler. If you want to use XML, you can create your own handler for doing that. You need to overload the read/write functions and make them read a dict from the file and write a dict to the file.
    • Removed deprecated vault-flags that were marked for deletion in 2.0.0.
    • Added some new vault-flags, such as a flag for disabling error logging.

    This version is mostly compatible with 1.x but there are some differences that are noteworthy:

    • The signature for vaultfactory.from_vault() has changed to become non-compatible with previous versions. The function enforces a positional argument for the file-handler class, which in most cases will be varvault.FileTypes.JSON. It could be defaulted, but that's not preferable as it becomes inconsistent.
    opened by Evixy 0
Releases(5.0.0)
  • 5.0.0(Dec 11, 2022)

    Made a ton of changes to the APIs and some new functionality:

    • Reworked how resources function. They now use the same mode as the builtin open function does. You can set modes like "r", "w", "a", "r+", "w+", and "a+". They will work as you expect, with the difference that those with a + indicates live-update is enabled, e.g. "r" is read mode, while "r+" is read with live-update enabled.
    • The standard JsonResource has been changed to create a backup file that is written to. After the backup file has been written to, the name of the file will be changed to the normal file. This way, there's always a file to read from. In very rare cases, if you kill the writing process, there will not be anything in the file since the file is opened in "w" mode, since append mode works really badly with JSON. We might lose a bit of data in such a case, but we retain most of it since we'll read from the standard file that still exists.
    • A Key can now take a set of modifier functions. These work just like validators (see validator.py) in that you create a method to annotate with varvault.modifier() which will allow you to modify the value of the object mapped to the key. This is useful if you want to strip a sequence of characters from a string, or expand vars/user in a path, or to always follow symlinks using os.path.realpath. This can reduce some boilerplate code.
    • The VaultFlags have been changed to just Flags and they have been changed to enums which is quite a bit more lightweight than creating new strings for every key.
    • The factory functions have been completely changed. There is now only create, and no from_vault. The resource object will handle the from_vault case by using append mode (mores "a", or "a+") instead.
    • There's no argument for resource_from or resource_to anymore; just resource. If you want to load a vault from one resource and write to another resource, you'll need to create a resource-object for the resource that you want to load from and load it into the vault manually after creating the vault.
    • A function has been added to utils called assert_and_raise. The function takes a condition as a bool and an exception object. It acts as an assert-function that can raise any exception you want (such as KeyError or ValueError) rather than AssertionError.
    • Internal logging has been changed to be more robust, though this sadly means it's a bit slower. It's not slow, just slower than it was. But the robustness improvements are worth it to get the logging you expect.
    • Added more type-annotations to exposed functions, such as for create under factory.py. This should help users to know how to use the functions better, provided they are using a proper IDE.
    Source code(tar.gz)
    Source code(zip)
  • 4.1.0(Sep 1, 2022)

    Made some bugfixes related to resources, where creating a resource that had a relative path to the same directory was not working. It was also not possible to create a vault without supplying a resource which it absolutely should be possible to do.

    Added new functionality to keys, where the usage of a certain key is logged in the key itself. It only logs usage in functions decorated with vaulter for now, but it can be quite helpful when you need to understand why a key is missing in the vault, or if you just want to know where a certain key is used if you are working on a big project.

    Source code(tar.gz)
    Source code(zip)
  • 4.0.1(Aug 26, 2022)

    Fixed a bug related to live-update and vault-structs which meant that specialized keys would not be reloaded as the correct key type. Added a test for this. Also made some fixes to how the state for a resource is handled. Simplified create_mv_from_resource to just take the expected keys as an argument.

    Source code(tar.gz)
    Source code(zip)
  • 4.0.0(Aug 26, 2022)

    New features:

    • Added the possibility to define input keys through the name of the parameters in the signature of the function. It essentially comes down to calling a parameter the same as the name of a key in the keyring and making sure the flag VaultFlags.use_signature_for_input_keys is defined. This can reduce boilerplate, but does make it harder to track the usage of certain keys, which is why it will never be the default behavior of varvault.

    Other changes:

    • Updated the conclusion section of the README.md.
    • Reworked the filehandlers API and simplified the JsonFileHandler slightly.
      • The filehandler now holds the state and keeps track of it, rather than varvault itself keeping track of the state.
    • Made changes to the vaultstructs API to change the name of the abstract method to create which is a lot less cumbersome of a function name.
    • Made significant cleanup of code, mostly in vault.py to make it easier to work with, and to read and comprehend.
    • Renamed filehandler.py to resource.py as that is more what it is than a filehandler, even if that will most likely be what it will be used for.
    Source code(tar.gz)
    Source code(zip)
  • 3.1.0(Aug 8, 2022)

    Made bugfixes for both live-update and filehandlers, which prompted some expansion to the API for the builtin JsonFileHandler: Added a new flag create_file_on_live_update to the JsonFileHandler which essentially creates the file when creating a filehandler that is meant to work with live-update because sometimes you want to create a new vault that is meant to fetch live-update changes later.

    Source code(tar.gz)
    Source code(zip)
  • 3.0.4(Aug 2, 2022)

  • 3.0.3(Aug 1, 2022)

    Made a fix to input_key_can_be_missing when using the vaulter decorator. Due to a recent change in get_multiple, this had to be changed as well so it works as expected. The user still has to make sure the input key that is missing is handled correctly in the decorated function.

    Source code(tar.gz)
    Source code(zip)
  • 3.0.2(Aug 1, 2022)

    Made a fix for the parameter default when using it with get. It had no effect, even when the flag input_key_can_be_missing was configured. Also added a test for this to make sure it works as expected.

    Source code(tar.gz)
    Source code(zip)
  • 3.0.1(Jul 31, 2022)

  • 3.0.0(Jul 31, 2022)

    3.0.0: New major version Significant changes:

    • Made some changes to how filehandlers are handled to make them more customizable to theoretically allow a user to run varvault towards a database.
      • This has caused some APIs to have to change since they didn't make any sense anymore, hence the new major version.
    • Moved validators to a separate new file validators.py since it didn't make much sense to have it in keyrings.py.
    • Scrapped the VaultInterface class. It makes no sense and we don't need it for a user to overload the class, which was its original intent.
    • Removed some functions under utils.py as they don't make sense to have there anymore.
    • Scrapped the constants in class VaultFlags (vaultflags.py) and instead we just use the name of the function as the constant that names the actual flag.
    • Made it so 'build_from_vault_key' in class VaultStructBase (vaultstructs.py) raises NotImplementedError if the function isn't implemented. Python handles abstract classes weirdly when the abstract class also inherits a bultin type (dict, list, float, etc) and allows you to create an instance of a class that doesn't implement all abstract methods, which causes some weird bugs.
    • The JsonFileHandler class has been moved to init.py instead of filehandlers.py.
    Source code(tar.gz)
    Source code(zip)
  • 1.3.0(Feb 15, 2022)

    Added a function called add to MiniVault which essentially wraps the __setitem__ function. This change aims to make it a little bit more easy to add variables to a MiniVault-object.

    Source code(tar.gz)
    Source code(zip)
  • 1.2.1(Dec 21, 2021)

    Made a fix for a bug where if a key was defined without a valid type (i.e. valid_type was set to None), the key could not be parsed from an existing vault file. Also added a test for it.

    Source code(tar.gz)
    Source code(zip)
  • 1.2.0(Dec 18, 2021)

    Added functionality for passing one or more validation functions to a key in a keyring to validate a key in much more detail than just checking that the type is correct.

    For example, it's possible to set up a key whose valid type is int and pass a validation function to the key to validate that the value is an even number. Alternatively, you could validate the length of a list to a certain number of elements, or make sure that a dict-object contains a specific set of keys.

    Source code(tar.gz)
    Source code(zip)
  • 1.1.4(Nov 26, 2021)

    There was a bug with the vaulter function, where returning the values in a minivault would bypass type-validation and you could essentially insert a value of any type for a given key into the vault. This has now been fixed and a test has been implemented for it.

    Source code(tar.gz)
    Source code(zip)
  • 1.1.3(Nov 20, 2021)

    Made a fix to log levels in the vaulter function to make sure that the log levels are always configured in post_call. If a vault was used in nested functions, the inner function would reset the log levels, and then the outer function would keep those log levels. This could cause unintended behavior when using debug flag for example.

    Source code(tar.gz)
    Source code(zip)
  • 1.1.2(Nov 20, 2021)

  • 1.1.1(Nov 20, 2021)

    Created new vault-flags input_key_can_be_missing and clean_return_keys which replaces input_var_can_be_missing and clean_return_var_keys respectively. The name of these new keys makes more sense and matches the rest of the code better.

    Source code(tar.gz)
    Source code(zip)
  • 1.1.0(Nov 20, 2021)

    Added a new vault flag called return_key_can_be_missing which will allow a vaulter-decorated function to not have to return all keys defined as return-keys. The object returned from the function must be a MiniVault

    Source code(tar.gz)
    Source code(zip)
  • 1.0.0(Nov 18, 2021)

Owner
Data Ductus
We turn any changes in IT into a competitive advantage for our clients
Data Ductus
Exports the local variables into a global dictionary for later debugging.

PyExfiltrator Julia’s @exfiltrate for Python; Exports the local variables into a global dictionary for later debugging. Installation pip install pyexf

null 6 Nov 7, 2022
Obsidian tools - a Python package for analysing an Obsidian.md vault

obsidiantools is a Python package for getting structured metadata about your Obsidian.md notes and analysing your vault.

Mark Farragher 153 Jan 4, 2023
A simple API that will return a key-value pair of randomly generated UUID

A simple API that will return a key-value pair of randomly generated UUID. Key will be a timestamp and value will be UUID. While the server is running, whenever the API is called, it should return all the previous UUIDs ever generated by the API alongside a new UUID.

Pius Lucky 2 Jan 18, 2022
A program will generate a eth key pair that has the public key that starts with a defined amount of 0

ETHAdressGenerator This short program will generate a eth key pair that has the public key that starts with a defined amount of 0 Requirements Python

null 3 Nov 19, 2021
A simple package for handling variables in string.

A simple package for handling string variables. Welcome! This is a simple package for handling variables in string, You can add or remove variables wi

null 1 Dec 31, 2021
Package that allows for validate and sanitize of string values.

py.validator A library of string validators and sanitizers Insipired by validator.js Strings only This library validates and sanitizes strings only. P

Sanel Hadzini 22 Nov 8, 2022
Compute the fair market value (FMV) of staking rewards at time of receipt.

tendermint-tax A tool to help calculate the tax liability of staking rewards on Tendermint chains. Specifically, this tool calculates the fair market

null 5 Jan 7, 2022
glip is a module for retrieve ip address like local-ip, global-ip, external-ip as string.

gle_ip_info glip is a module for retrieve ip address like local-ip, global-ip, external-ip as string.

Fatin Shadab 3 Nov 21, 2021
Keval allows you to call arbitrary Windows kernel-mode functions from user mode, even (and primarily) on another machine.

Keval Keval allows you to call arbitrary Windows kernel-mode functions from user mode, even (and primarily) on another machine. The user mode portion

null 42 Dec 17, 2022
Allows you to canibalize methods from classes effectively implementing trait-oriented programming

About This package enables code reuse in non-inheritance way from existing classes, effectively implementing traits-oriented programming pattern. Stor

null 1 Dec 13, 2021