In the last post, I set up owncloud with WebDAV server. Now it's time to use it.
Table of Contents:
Python WebDAV client - easywebdav
I was searching for good python library to work with WebDAV for a long time. I finally found it- easywebdav. It works nicely but the problem is that doesn't have support for python 3. Let's jump quickly to my simple project for cli tool- webdav editor.
WebDAV editor
I decided to create cli tool to work with WebDAV server- webdav editor. Right now it supports only basic commands like login, listing the content of directories, uploading and downloading files.
I started from creating file webdav_utility.py:
fromurlparseimporturlparseimporteasywebdavclassClient(object):deflogin(self,*args):argparse_namespace=args[0]url_components=urlparse(argparse_namespace.server)host,port=url_components.netloc.split(':')webdav_client=easywebdav.connect(host=host,port=port,path=url_components.path,username=argparse_namespace.user,password=argparse_namespace.password)pickle.dump(webdav_client,open('webdav_login','wb'))deflist_content(self,*args):argparse_namespace=args[0]print[i.nameforiinwebdav_client.ls(argparse_namespace.path)]defupload_file(self,*args):argparse_namespace=args[0]webdav_client.upload(argparse_namespace.from_path,argparse_namespace.to_path)defdownload_file(self,*args):argparse_namespace=args[0]webdav_client.download(argparse_namespace.from_path,argparse_namespace.to_path)
In class Client, I write simple functions that are wrappers around easywebdav API. In login I parse provided URL in form like localhost:8888/owncloud/remote.php/webdav to get host, port and path for easywebdav.connect to establish a proper connection.
Another method that is worth mentioning is list_content where I retrieve names of files under a directory on WebDAV server. In every method I provide *args argument and argparse_namespace which leads to another component of application- module cli.py:
importargparsefromwebdav_utilityimportClientclient=Client()parser=argparse.ArgumentParser(description='Simple command line utility for WebDAV')subparsers=parser.add_subparsers(help='Commands')login_parser=subparsers.add_parser('login',help='Authenticate with WebDAV')login_parser.add_argument('-s','--server',required=True)login_parser.add_argument('-u','--user',required=True)login_parser.add_argument('-p','--password',required=True)login_parser.set_defaults(func=client.login)ls_parser=subparsers.add_parser('ls',help='List content of directory under WebDAV')ls_parser.add_argument('-p','--path',required=True)ls_parser.set_defaults(func=client.list_content)upload_parser=subparsers.add_parser('upload',help='Upload files to WebDAV')upload_parser.add_argument('-f','--from',metavar='PATH')upload_parser.add_argument('-t','--to',metavar='PATH')upload_parser.set_defaults(func=client.upload_file)download_parser=subparsers.add_parser('download',help='Download files from WebDAV')download_parser.add_argument('-f','--from',metavar='PATH')download_parser.add_argument('-t','--to',metavar='PATH')download_parser.set_defaults(func=client.download_file)if__name__=='__main__':args=parser.parse_args()args.func(args)
There I use argparse. I create the main parser with four additionals subparsers for login, ls, upload and download. Thanks to that I have different namespace for every one of previously mentioned subparsers.
Problem is that this solution is not generic enough because after running my command with login parameter I can get: Namespace(server='localhost:8888',user='admin',password='admin') and running the same command but with ls I will receive: Namespace(path='path_to_file'). To handle that I used set_defaults for every subparser. I tell argparse to invoke function specified by func keyword (which is different for every command). Thanks to that I only need to call this code once:
if__name__=='__main__':args=parser.parse_args()args.func(args)
That's the reason I introduce argparse_namespaces in Client.
OK, tool right now works nicely, but there is no place to store information if I am logged or not. So calling python cli.py login -s localhost -u admin -p admin works but python cli.py ls -p / not. To overcome that I came up with an idea to pickle webdav_client like this:
classClient(object):deflogin(self,*args):# login user etcpickle.dump(webdav_client,open('webdav_login','wb'))deflist_content(self,*args):webdav_client=pickle.load(open('webdav_login','rb'))# rest of the code
Then I can easily run:
$ python cli.py login --server example.org/owncloud/remote.php/webdav --user admin --password admin
$ python cli.py ls --path '/'['/owncloud/remote.php/webdav/', '/owncloud/remote.php/webdav/Documents/', '/owncloud/remote.php/webdav/Photos/', '/owncloud/remote.php/webdav/ownCloud%20Manual.pdf']
Conclusion
In this series, I setup an owncloud server and write simple tool just to show capabilities of WebDAV. I believe that some work, especially for webdav editor cli can still be done: the better way to handle user auth than pickle, separate Client class from argparse dependencies. If you have additional comments or thoughts please write a comment! Thank you for reading.
Other blog posts in this series:
Github repo for this blog post: link.
Special thanks to Kasia for being editor for this post. Thank you.
Cover image by kleuske under CC BY-SA 2.0.