-
Notifications
You must be signed in to change notification settings - Fork 10
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added common install state primitives with strong typing #27
Merged
Conversation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Codecov ReportAttention:
Additional details and impacted files@@ Coverage Diff @@
## main #27 +/- ##
==========================================
+ Coverage 74.90% 77.64% +2.74%
==========================================
Files 12 13 +1
Lines 753 1163 +410
Branches 127 218 +91
==========================================
+ Hits 564 903 +339
- Misses 134 172 +38
- Partials 55 88 +33 ☔ View full report in Codecov by Sentry. |
This was
linked to
issues
Jan 20, 2024
nfx
added a commit
that referenced
this pull request
Jan 29, 2024
Merged
nfx
added a commit
that referenced
this pull request
Jan 29, 2024
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There always needs to be a location, where you put application code, artifacts, and configuration.
The
Installation
class is used to manage the~/.{product}
folder on WorkspaceFS to track typed files.It provides methods for serializing and deserializing objects of a specific type, as well as managing the storage location
for those objects. The class includes methods for loading and saving objects, uploading and downloading
files, and managing the installation folder.
The
Installation
class can be helpful for unit testing by allowing you to mock the file system and controlthe behavior of the
load
andsave
methods.See unit testing for more details.
[back to top]
Install Folder
The
install_folder
method returns the path to the installation folder on WorkspaceFS. The installation folderis used to store typed files that are managed by the
Installation
class. Publishing wheelsupdate the
version.json
file in the install folder.If an
install_folder
argument is provided to the constructor of theInstallation
class, it will be usedas the installation folder. Otherwise, the installation folder will be determined based on the current user's
username. Specifically, the installation folder will be
/Users/{user_name}/.{product}
, where{user_name}
is the username of the current user and
{product}
is the name of the productassociated with the installation. Here is an example of how you can use the
install_folder
method:In this example, the
Installation
object is created for the "blueprint" product. Theinstall_folder
methodis then called to print the path to the installation folder. The output will be
/Users/{user_name}/.blueprint
,where
{user_name}
is the username of the current user.You can also provide an
install_folder
argument to the constructor to specify a custom installation folder.Here is an example of how you can do this:
In this example, the
Installation
object is created for the "blueprint" product with a custom installationfolder of
/my/custom/folder
. Theinstall_folder
method is then called to print the path to the installationfolder. The output will be
/my/custom/folder
.[back to top]
Detecting Current Installation
Installation.current(ws, product)
returns theInstallation
object for the given product in the current workspace.If the installation is not found, a
NotFound
error is raised. Ifassume_user
argument is True, the methodwill assume that the installation is in the user's home directory and return it if found. If False, the method
will only return an installation that is in the
/Applications
directory.[back to top]
Detecting Installations From All Users
Installation.existing(ws, product)
Returns a collection of all existing installations for the given product in the current workspace.This method searches for installations in the root /Applications directory and home directories of all users in the workspace.
Let's say, users
foo@example.com
andbar@example.com
installedblueprint
product in their home folders. The followingcode will print
/Workspace/bar@example.com/.blueprint
and/Workspace/foo@example.com/.blueprint
:[back to top]
Saving
@dataclass
configurationThe
save(obj)
method saves a dataclass instance of typeT
to a file on WorkspaceFS. If nofilename
is provided,the name of the
type_ref
class will be used as the filename. Any missing parent directories are created automatically.If the object has a
__version__
attribute, the method will add a$version
field to the serialized objectwith the value of the
__version__
attribute. See configuration format evolutionfor more details.
save(obj)
works with JSON and YAML configurations without the need to supplyfilename
keywordattribute. When you need to save CSV files, the
filename
attribute is required. If you need toupload arbitrary and untyped files, use the
upload()
method.Here is an example of how you can use the
save
method:In this example, the
Installation
object is created for the "blueprint" product. A dataclass object of typeMyClass
is then created and saved to a file using thesave
method. The object is then loaded from the fileusing the
load
method and compared to the original object to verify thatit was saved correctly.
[back to top]
Saving CSV files
You may need to upload a CSV file to Databricks Workspace, so that it's easier editable from a Databricks Workspace UI
or tools like Google Sheets or Microsoft Excel. If non-technical humands don't need to edit application state,
use dataclasses for configuration. CSV files currently don't support
format evolution.
The following example will save
workspaces.csv
file with two records and a header:[back to top]
Loading
@dataclass
configurationThe
load(type_ref[, filename])
method loads an object of typetype_ref
from a file on WorkspaceFS. If nofilename
isprovided, the
__file__
attribute oftype_ref
will be used as the filename, otherwise the library will figure out the namebased on a class name.
[back to top]
Configuration Format Evolution
As time progresses, your application evolves. So does the configuration file format with it. This library provides
a common utility to seamlessly evolve configuration file format across versions, providing callbacks to convert
from older versions to newer.
If the type has a
__version__
attribute, the method will check that the version of the object in the filematches the expected version. If the versions do not match, the method will attempt to migrate the object to
the expected version using a method named
v{actual_version}_migrate
on thetype_ref
class. If the migrationis successful, the method will return the migrated object. If the migration is not successful, the method will
raise an
IllegalState
exception. Let's say, we have/Users/foo@example.com/.blueprint/config.yml
file withonly the
initial: 999
as content, which is from older installations of theblueprint
product:[back to top]
Uploading Untyped Files
The
upload(filename, raw_bytes)
andupload_dbfs(filename, raw_bytes)
methods upload raw bytes to a file onWorkspaceFS (or DBFS) with the given
filename
, creating any missing directories where required. This methodis used to upload files that are not typed, i.e., they do not use the
@dataclass
decorator.The most common example is a wheel, which we already integrate with
Installation
framework.[back to top]
Listing All Files in the Install Folder
You can use
files()
method to recursively list all files in the install folder.[back to top]
Unit Testing Installation State
You can create a
MockInstallation
object and use it to override the default installation folder and the contentsof the files in that folder. This allows you to test the of your code in different scenarios, such as when a file
is not found or when the contents of a file do not match the expected format.
For example, you have the following
WorkspaceConfig
class that is serialized intoconfig.yml
on your workspace:Here's the only code necessary to verify that specific content got written:
This method is far superior than directly comparing raw bytes content via mock:
And it's even better if you use PyTest, where we have even deeper integration.
[back to top]
Assert Rewriting with PyTest
If you are using PyTest, then add this to your
conftest.py
, so thatthe assertions are more readable:
[back to top]