Как рекурсивно объединить папки с отдельными вложенными папками и пропустить пустые папки?

#python #python-3.x #recursion

Вопрос:

Я написал эту простую функцию, которая рекурсивно перечисляет содержимое каталога и его подкаталогов, она возвращает словарь только с одним ключом, корневым ключом, который является введенным путем, значение ключа представляет собой список содержимого, если содержимое представляет собой файл, соответствующий элемент str содержит имя файла с расширением;

В противном случае, если содержимое представляет собой папку, соответствующий элемент dict структурирован с использованием формата, аналогичного указанному выше, разница в том, что ключом является путь относительно введенного пути, а не абсолютный путь.

Код:

 from pathlib import Path  def recur_dir(path, first=True, root=''):   if first:   root = str(path).replace('\', '/')   if not root.endswith('/'):   root  = '/'   result = {root: []}   entries = result[root]   else:   entries = []   result = entries   for entry in Path(path).glob('*'):   if entry.is_dir():   entry = {str(entry).replace('\', '/').replace(root, ''): recur_dir(entry, False, root)}  else:   entry = entry.name   entries.append(entry)   return result  

Пример:

 In [45]: import json; print(json.dumps(recur_dir('C:/Program Files (x86)/ExpressVPN'), indent=4)) {  "C:/Program Files (x86)/ExpressVPN/": [  {  "bootstrap": [  {  "bootstrap/amd64": [  "nssm.exe"  ]  }  ]  },  {  "expressvpn-ui": [  {  "expressvpn-ui/Assets": [  {  "expressvpn-ui/Assets/en-US": [  "150x150Logo.scale-100.png",  "150x150Logo.scale-125.png",  "150x150Logo.scale-150.png",  "150x150Logo.scale-200.png",  "150x150Logo.scale-400.png",  "44x44Logo.scale-100.png",  "44x44Logo.scale-125.png",  "44x44Logo.scale-150.png",  "44x44Logo.scale-200.png",  "44x44Logo.scale-400.png",  "70x70Logo.scale-100.png",  "70x70Logo.scale-125.png",  "70x70Logo.scale-150.png",  "70x70Logo.scale-200.png",  "70x70Logo.scale-400.png"  ]  }  ]  },  "AustinHarris.JsonRpc.dll",  "Caliburn.Micro.dll",  "Caliburn.Micro.Platform.dll",  "CommandLine.dll",  "Common.Logging.Core.dll",  "Common.Logging.dll",  "Common.Logging.Log4Net1213.dll",  "ExpressVPN-Installer.exe",  "ExpressVPN-Installer.exe.config",  "ExpressVPN.Client.Engine.dll",  "ExpressVPN.Client.EngineProxy.dll",  "ExpressVPN.Client.Installer.dll",  "ExpressVPN.Client.Utils.dll",  "ExpressVpn.Client.Utils.NamedPipes.dll",  "ExpressVPN.Client.Windows.dll",  "ExpressVPN.exe",  "ExpressVPN.exe.config",  "ExpressVPN.Utils.dll",  "ExpressVpn.Utils.Wmi.dll",  "ExpressVPN.VisualElementsManifest.xml",  "ExpressVPNNotificationService.exe",  "ExpressVPNNotificationService.exe.config",  "ExpressVPNNotificationServiceStarter.exe",  "Hardcodet.Wpf.TaskbarNotification.dll",  "HtmlAgilityPack.dll",  "IconLib.dll",  "log4net.dll",  "ManagedWifi.dll",  "Microsoft.Toolkit.Uwp.Notifications.dll",  "MissingLinq.Linq2Management.dll",  "Newtonsoft.Json.dll",  "Resources.pri",  "RestSharp.dll",  "Sentry.dll",  "Sentry.PlatformAbstractions.dll",  "Sentry.Protocol.dll",  "System.Management.Automation.dll",  "System.Reactive.Core.dll",  "System.Reactive.Interfaces.dll",  "System.Reactive.Linq.dll",  "System.Reactive.Windows.Threading.dll",  "System.Runtime.InteropServices.RuntimeInformation.dll",  "System.ValueTuple.dll",  "System.Windows.Interactivity.dll"  ]  },  {  "expressvpnd": [  {  "expressvpnd/.config": [  {  "expressvpnd/.config/expressvpn": [  "browser_helper"  ]  }  ]  },  "com.expressvpn.helper.firefox.json",  "com.expressvpn.helper.json",  "expressvpn-browser-helper.exe",  "expressvpnd.exe",  "libxvclient.dll",  "lightway.exe",  {  "expressvpnd/windows": [  "ExpressVPN.FilterManager.dll",  "ExpressVPN.NetworkUtils.dll",  "ExpressVPN.SplitTunnel.dll",  "libcrypto-1_1-x64.dll",  "liblzo2-2.dll",  "libpkcs11-helper-1.dll",  "libssl-1_1-x64.dll",  "notices.rtf",  "openvpn.exe",  {  "expressvpnd/windows/rasutility": [  "Common.Logging.Core.dll",  "Common.Logging.dll",  "Common.Logging.Log4Net1213.dll",  "DotRas.dll",  "ExpressVPN.Utils.dll",  "log4net.dll",  "ManagedWifi.dll",  "Newtonsoft.Json.dll",  "RasUtility.exe",  "RasUtility.exe.config",  "Sentry.dll",  "Sentry.PlatformAbstractions.dll",  "Sentry.Protocol.dll",  "System.Management.Automation.dll",  "System.Reactive.Core.dll",  "System.Reactive.Interfaces.dll",  "System.Reactive.Linq.dll",  "System.Runtime.InteropServices.RuntimeInformation.dll",  "System.ValueTuple.dll"  ]  },  {  "expressvpnd/windows/xvutil": [  "CommandLine.dll",  "Common.Logging.Core.dll",  "Common.Logging.dll",  "Common.Logging.Log4Net1213.dll",  "ExpressVPN.EngineUtils.dll",  "ExpressVPN.Utils.dll",  "ExpressVpn.Utils.Wmi.dll",  "log4net.dll",  "ManagedWifi.dll",  "MissingLinq.Linq2Management.dll",  "Newtonsoft.Json.dll",  "Sentry.dll",  "Sentry.PlatformAbstractions.dll",  "Sentry.Protocol.dll",  "System.Management.Automation.dll",  "System.Reactive.Core.dll",  "System.Reactive.Interfaces.dll",  "System.Reactive.Linq.dll",  "System.Runtime.InteropServices.RuntimeInformation.dll",  "System.ValueTuple.dll",  "XvUtil.exe",  "XvUtil.exe.config"  ]  }  ]  }  ]  },  {  "splittunnel": [  "expressvpndriverinstaller.exe",  "expressvpnsplittunnel.cat",  "expressvpnsplittunnel.inf",  "expressvpnsplittunnel.sys"  ]  },  {  "tap": [  {  "tap/driver": [  {  "tap/driver/amd64": [  "HWCertReport_1152921505690468143.html",  "OemVista.inf",  "tapexpressvpn.cat",  "tapexpressvpn.sys"  ]  }  ]  },  {  "tap/tapinstall": [  {  "tap/tapinstall/amd64": [  "tapinstall.exe"  ]  }  ]  }  ]  },  {  "wintun": [  {  "wintun/driver": [  {  "wintun/driver/amd64": [  "expressvpn-wintun.cat",  "expressvpn-wintun.inf",  "expressvpn-wintun.sys",  "HWCertReport_1152921505692733217.html"  ]  }  ]  }  ]  }  ] }  

I would like to how to recursively pop elements that represent empty folders and flatten directories that contain only one subdirectory.

As you can see, if the content is a folder it is represented as a dict , with its path as key and the list of its contents as the value, and if the folder is empty the value is an empty list .

And if the content is a folder the value is a list of only one dict element …

In short I want it to become this:

 {  "C:/Program Files (x86)/ExpressVPN/": [  {  "bootstrap/amd64": [  "nssm.exe"  ]  },  {  "expressvpn-ui": [  {  "expressvpn-ui/Assets/en-US": [  "150x150Logo.scale-100.png",  "150x150Logo.scale-125.png",  "150x150Logo.scale-150.png",  "150x150Logo.scale-200.png",  "150x150Logo.scale-400.png",  "44x44Logo.scale-100.png",  "44x44Logo.scale-125.png",  "44x44Logo.scale-150.png",  "44x44Logo.scale-200.png",  "44x44Logo.scale-400.png",  "70x70Logo.scale-100.png",  "70x70Logo.scale-125.png",  "70x70Logo.scale-150.png",  "70x70Logo.scale-200.png",  "70x70Logo.scale-400.png"  ]  },  "AustinHarris.JsonRpc.dll",  "Caliburn.Micro.dll",  "Caliburn.Micro.Platform.dll",  "CommandLine.dll",  "Common.Logging.Core.dll",  "Common.Logging.dll",  "Common.Logging.Log4Net1213.dll",  "ExpressVPN-Installer.exe",  "ExpressVPN-Installer.exe.config",  "ExpressVPN.Client.Engine.dll",  "ExpressVPN.Client.EngineProxy.dll",  "ExpressVPN.Client.Installer.dll",  "ExpressVPN.Client.Utils.dll",  "ExpressVpn.Client.Utils.NamedPipes.dll",  "ExpressVPN.Client.Windows.dll",  "ExpressVPN.exe",  "ExpressVPN.exe.config",  "ExpressVPN.Utils.dll",  "ExpressVpn.Utils.Wmi.dll",  "ExpressVPN.VisualElementsManifest.xml",  "ExpressVPNNotificationService.exe",  "ExpressVPNNotificationService.exe.config",  "ExpressVPNNotificationServiceStarter.exe",  "Hardcodet.Wpf.TaskbarNotification.dll",  "HtmlAgilityPack.dll",  "IconLib.dll",  "log4net.dll",  "ManagedWifi.dll",  "Microsoft.Toolkit.Uwp.Notifications.dll",  "MissingLinq.Linq2Management.dll",  "Newtonsoft.Json.dll",  "Resources.pri",  "RestSharp.dll",  "Sentry.dll",  "Sentry.PlatformAbstractions.dll",  "Sentry.Protocol.dll",  "System.Management.Automation.dll",  "System.Reactive.Core.dll",  "System.Reactive.Interfaces.dll",  "System.Reactive.Linq.dll",  "System.Reactive.Windows.Threading.dll",  "System.Runtime.InteropServices.RuntimeInformation.dll",  "System.ValueTuple.dll",  "System.Windows.Interactivity.dll"  ]  },  {  "expressvpnd": [  {  "expressvpnd/.config/expressvpn": [  "browser_helper"  ]  },  "com.expressvpn.helper.firefox.json",  "com.expressvpn.helper.json",  "expressvpn-browser-helper.exe",  "expressvpnd.exe",  "libxvclient.dll",  "lightway.exe",  {  "expressvpnd/windows": [  "ExpressVPN.FilterManager.dll",  "ExpressVPN.NetworkUtils.dll",  "ExpressVPN.SplitTunnel.dll",  "libcrypto-1_1-x64.dll",  "liblzo2-2.dll",  "libpkcs11-helper-1.dll",  "libssl-1_1-x64.dll",  "notices.rtf",  "openvpn.exe",  {  "expressvpnd/windows/rasutility": [  "Common.Logging.Core.dll",  "Common.Logging.dll",  "Common.Logging.Log4Net1213.dll",  "DotRas.dll",  "ExpressVPN.Utils.dll",  "log4net.dll",  "ManagedWifi.dll",  "Newtonsoft.Json.dll",  "RasUtility.exe",  "RasUtility.exe.config",  "Sentry.dll",  "Sentry.PlatformAbstractions.dll",  "Sentry.Protocol.dll",  "System.Management.Automation.dll",  "System.Reactive.Core.dll",  "System.Reactive.Interfaces.dll",  "System.Reactive.Linq.dll",  "System.Runtime.InteropServices.RuntimeInformation.dll",  "System.ValueTuple.dll"  ]  },  {  "expressvpnd/windows/xvutil": [  "CommandLine.dll",  "Common.Logging.Core.dll",  "Common.Logging.dll",  "Common.Logging.Log4Net1213.dll",  "ExpressVPN.EngineUtils.dll",  "ExpressVPN.Utils.dll",  "ExpressVpn.Utils.Wmi.dll",  "log4net.dll",  "ManagedWifi.dll",  "MissingLinq.Linq2Management.dll",  "Newtonsoft.Json.dll",  "Sentry.dll",  "Sentry.PlatformAbstractions.dll",  "Sentry.Protocol.dll",  "System.Management.Automation.dll",  "System.Reactive.Core.dll",  "System.Reactive.Interfaces.dll",  "System.Reactive.Linq.dll",  "System.Runtime.InteropServices.RuntimeInformation.dll",  "System.ValueTuple.dll",  "XvUtil.exe",  "XvUtil.exe.config"  ]  }  ]  }  ]  },  {  "splittunnel": [  "expressvpndriverinstaller.exe",  "expressvpnsplittunnel.cat",  "expressvpnsplittunnel.inf",  "expressvpnsplittunnel.sys"  ]  },  {  "tap": [  {  "tap/driver/amd64": [  "HWCertReport_1152921505690468143.html",  "OemVista.inf",  "tapexpressvpn.cat",  "tapexpressvpn.sys"  ]  },  {  "tap/tapinstall/amd64": [  "tapinstall.exe"  ]  }  ]  },  {  "wintun/driver/amd64": [  "expressvpn-wintun.cat",  "expressvpn-wintun.inf",  "expressvpn-wintun.sys",  "HWCertReport_1152921505692733217.html"  ]  }  ] }  

Как это сделать?