here's what I do. I have one module for each project that lays out all of the directories, URL's and common file locations in a relative structure, using pathlib.
Here's a sample for a geocoding project:
the module is named GeoPaths.py and is imported by just about every other module in the project.
A neat feature of using something like this, is that you can run it on it's own in a copy of the project to
immediately set up your directory structure (it will create missing directories, but will leave already existing
directories alone):
GeoPaths.py
import os
from pathlib import Path
class GeoPaths:
def __init__(self, depth=0):
dir_depth = abs(depth)
os.chdir(os.path.abspath(os.path.dirname(__file__)))
self.homepath = Path('.')
while dir_depth:
self.homepath = self.homepath / '..'
dir_depth -= 1
rootpath = self.homepath / '..'
self.docspath = rootpath / 'docs'
self.docspath.mkdir(exist_ok=True)
self.testspath = rootpath / 'tests'
self.testspath.mkdir(exist_ok=True)
self.datapath = rootpath / 'data'
self.datapath.mkdir(exist_ok=True)
self.csvpath = self.datapath / 'csv'
self.csvpath.mkdir(exist_ok=True)
self.htmlpath = self.datapath / 'html'
self.htmlpath.mkdir(exist_ok=True)
self.jsonpath = self.datapath / 'json'
self.jsonpath.mkdir(exist_ok=True)
self.MasterAddressPath = self.datapath / 'MasterAddressDatabase'
self.MasterAddressPath.mkdir(exist_ok=True)
self.prettypath = self.datapath / 'pretty'
self.prettypath.mkdir(exist_ok=True)
self.tmppath = self.datapath / 'tmp'
self.tmppath.mkdir(exist_ok=True)
# Osm data is arranged by state and file type.
# A rather longdirectory tree, but laid out here for ease of use in software
self.osmpath = self.datapath / 'osm'
self.osmpath.mkdir(exist_ok=True)
self.geofabrik_datapath = self.osmpath / 'GeofabrikAndCensus'
self.geofabrik_datapath.mkdir(exist_ok=True)
# URL's
self.TigerLineGeoDatabase: 'https://www.census.gov/geographies/mapping-files/time-series/geo/tiger-geodatabase-file.html'
self.qgis_plugins = 'https://plugins.qgis.org/plugins/?page=1&&'
self.osmfilelink = 'https://ftp.osuosl.org/pub/openstreetmap/planet/'
self.geofabrikserver = 'https://download.geofabrik.de/north-america.html'
# Common files:
self.geofabrikjson = self.jsonpath / 'GeofabrikLinks.json'
if __name__ == '__main__':
GeoPaths()
Before running the script, my directory structure for a new project looks like this:
Output:
├── src
│ └── GeoPaths.py
└── venv
...
After running GeoPaths.py directory structure looks like this:
$ . ./venv/bin/activate
(venv)$ python src/GeoPaths.py
Output:
.
├── data
│ ├── csv
│ ├── html
│ ├── json
│ ├── MasterAddressDatabase
│ ├── osm
│ │ └── GeofabrikAndCensus
│ ├── pretty
│ └── tmp
├── docs
├── src
│ └── GeoPaths.py
├── tests
└── venv
...
Now, assume you have a module named MyModule.py in the src diretory, and you want to open a json file named sillyfile.json.
here's the code that would do that:
MyModule.py
from GeoPaths import GeoPaths
import json
class MySillyClass:
def __init__(self):
self.gpaths = GeoPaths()
self.jsonfile = self.gpaths.jsonpath / 'sillyfile.json'
def create_dict(self):
sillydict = {
'Cowboys': '21',
'GreenBayPackers': '7'
}
with self.jsonfile.open('w') as fp:
json.dump(sillydict, fp)
def read_it_back(self):
with self.jsonfile.open() as fp:
read_sillydict = json.load(fp)
for key, value in read_sillydict.items():
print(f"{key}: {value}")
def main():
mcc = MySillyClass()
mcc.create_dict()
mcc.read_it_back()
if __name__ == '__main__':
main()
you can actually run this
results:
Output:
Cowboys: 21
GreenBayPackers: 7
The depth attribute in GeoPaths.py can be used when code in in a subdirectory of src.
Increment by on for each sublevel, and paths will automatically be adjusted for all source code in that subdirectory.