em as type SecretField in the configuration class.With the configuration defined, we can move on to the implementation class, which will use the S3 file system to implement the abstract methods of the BaseArtifactStore:

import s3fs

from zenml.artifact_stores import BaseArtifactStore

class MyS3ArtifactStore(BaseArtifactStore):

"""Custom artifact store implementation."""

_filesystem: Optional[s3fs.S3FileSystem] = None

@property

def filesystem(self) -> s3fs.S3FileSystem:

"""Get the underlying S3 file system."""

if self._filesystem:

return self._filesystem

self._filesystem = s3fs.S3FileSystem(

key=self.config.key,

secret=self.config.secret,

token=self.config.token,

client_kwargs=self.config.client_kwargs,

config_kwargs=self.config.config_kwargs,

s3_additional_kwargs=self.config.s3_additional_kwargs,

return self._filesystem

def open(self, path, mode: = "r"):

"""Custom logic goes here."""

return self.filesystem.open(path=path, mode=mode)

def exists(self, path):

"""Custom logic goes here."""

return self.filesystem.exists(path=path)

The configuration values defined in the corresponding configuration class are always available in the implementation class under self.config.

Finally, let's define a custom flavor that brings these two classes together. Make sure that you give your flavor a globally unique name here.

from zenml.artifact_stores import BaseArtifactStoreFlavor

class MyS3ArtifactStoreFlavor(BaseArtifactStoreFlavor):

"""Custom artifact store implementation."""

@property

def name(self):

"""The name of the flavor."""

return 'my_s3_artifact_store'

@property

def implementation_class(self):

"""Implementation class for this flavor."""

from ... import MyS3ArtifactStore

return MyS3ArtifactStore

@property

def config_class(self):

"""Configuration class for this flavor."""

from ... import MyS3ArtifactStoreConfig

return MyS3ArtifactStoreConfig