Coverage for /home/pradyumna/Languages/python/packages/xdgpspconf/xdgpspconf/data.py : 17%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1#!/usr/bin/env python3
2# -*- coding: utf-8; mode: python; -*-
3# Copyright © 2020-2021 Pradyumna Paranjape
4#
5# This file is part of xdgpspconf.
6#
7# xdgpspconf is free software: you can redistribute it and/or modify
8# it under the terms of the GNU Lesser General Public License as published by
9# the Free Software Foundation, either version 3 of the License, or
10# (at your option) any later version.
11#
12# xdgpspconf is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU Lesser General Public License for more details.
16#
17# You should have received a copy of the GNU Lesser General Public License
18# along with xdgpspconf. If not, see <https://www.gnu.org/licenses/>. #
19"""
20Locate standard data.
22Read:
23 - standard xdg-base locations
24 - current directory and ancestors
25 - custom location
27"""
29import os
30import sys
31from pathlib import Path
32from typing import List
35def _is_mount(path: Path):
36 """
37 Check across platform if path is mountpoint or drive.
39 Args:
40 path: path to be checked
41 """
42 try:
43 if path.is_mount():
44 return True
45 return False
46 except NotImplementedError:
47 if path.resolve().drive + '\\' == str(path):
48 return True
49 return False
52def ancestral_data(child_dir: Path) -> List[Path]:
53 """
54 Walk up to nearest mountpoint or project root.
56 - collect all directories containing __init__.py
57 (assumed to be source directories)
58 - project root is directory that contains ``setup.cfg`` or ``setup.py``
59 - mountpoint is a unix mountpoint or windows drive root
60 - I am **NOT** my ancestor
62 Args:
63 child_dir: walk ancestry of `this` directory
65 Returns:
66 List of Paths to ancestral source directories:
67 First directory is most dominant
68 """
69 data_heir: List[Path] = []
71 while not _is_mount(child_dir):
72 if (child_dir / '__init__.py').is_file():
73 data_heir.append(child_dir)
74 if any((child_dir / setup).is_file()
75 for setup in ('setup.cfg', 'setup.py')):
76 # project directory
77 data_heir.append(child_dir)
78 break
79 child_dir = child_dir.parent
80 return data_heir
83def xdg_data() -> List[Path]:
84 """
85 Get XDG_DATA_HOME locations.
87 `specifications
88 <https://specifications.freedesktop.org/basedir-spec/latest/ar01s03.html>`__
90 Returns:
91 List of xdg-data Paths
92 First directory is most dominant
93 """
94 xdg_heir: List[Path] = []
95 # environment
96 if sys.platform.startswith('win'): # pragma: no cover
97 # windows
98 user_home = Path(os.environ['USERPROFILE'])
99 root_data = Path(os.environ['APPDATA'])
100 xdg_data_home = Path(
101 os.environ.get('LOCALAPPDATA', user_home / 'AppData/Local'))
102 xdg_heir.append(xdg_data_home)
103 xdg_heir.append(root_data)
104 else:
105 # assume POSIX
106 user_home = Path(os.environ['HOME'])
107 xdg_data_home = Path(
108 os.environ.get('XDG_DATA_HOME', user_home / '.data'))
109 xdg_heir.append(xdg_data_home)
110 xdg_data_dirs = os.environ.get('XDG_DATA_DIRS',
111 '/usr/local/share/:/usr/share/')
112 for xdg_dirs in xdg_data_dirs.split(':'):
113 xdg_heir.append(Path(xdg_dirs))
114 return xdg_heir
117def locate_data(project: str,
118 custom: os.PathLike = None,
119 ancestors: bool = False) -> List[Path]:
120 """
121 Locate data at standard locations.
123 Args:
124 project: name of project whose data is being fetched
125 custom: custom location for data
126 ancestors: inherit ancestor directories that contain __init__.py
127 dname: name of data file
129 Returns:
130 List of all possible data paths:
131 Existing and non-existing
132 First directory is most dominant
134 """
135 # Preference of data location *Most dominant first*
136 data_heir: List[Path] = []
138 # custom
139 if custom is not None:
140 if not Path(custom).is_dir():
141 raise FileNotFoundError(
142 f'Custom data directory: {custom} not found')
143 data_heir.append(Path(custom))
145 # environment variable
146 env_val = os.environ.get(project.upper() + '_DATA')
147 if env_val is not None:
148 if not Path(env_val).is_dir():
149 raise FileNotFoundError(f'RC data directory: {env_val} not found')
150 data_heir.append(Path(env_val))
152 # Current directory
153 current_dir = Path('.').resolve()
154 data_heir.append(current_dir)
156 if ancestors:
157 # ancestral directories
158 data_heir.extend(ancestral_data(current_dir))
160 # xdg locations
161 xdg_heir = xdg_data()
162 for heir in xdg_heir:
163 data_heir.append(heir / project)
165 # Shipped location
166 data_heir.append((Path(__file__).parent))
168 return data_heir