pathpilot 0.2.2__tar.gz → 0.3.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pathpilot-0.2.2 → pathpilot-0.3.1}/PKG-INFO +11 -10
- {pathpilot-0.2.2 → pathpilot-0.3.1}/README.md +5 -5
- {pathpilot-0.2.2 → pathpilot-0.3.1}/pathpilot/__init__.py +1 -1
- {pathpilot-0.2.2 → pathpilot-0.3.1}/pathpilot/_file/_excel.py +60 -37
- {pathpilot-0.2.2 → pathpilot-0.3.1}/pathpilot/_file/base.py +13 -73
- {pathpilot-0.2.2 → pathpilot-0.3.1}/pathpilot/_folder/base.py +5 -25
- {pathpilot-0.2.2 → pathpilot-0.3.1}/pathpilot/core.py +4 -4
- {pathpilot-0.2.2 → pathpilot-0.3.1}/pathpilot/utils.py +18 -9
- {pathpilot-0.2.2 → pathpilot-0.3.1}/pyproject.toml +3 -3
- {pathpilot-0.2.2 → pathpilot-0.3.1}/LICENSE +0 -0
- {pathpilot-0.2.2 → pathpilot-0.3.1}/pathpilot/_file/__init__.py +0 -0
- {pathpilot-0.2.2 → pathpilot-0.3.1}/pathpilot/_file/_csv.py +0 -0
- {pathpilot-0.2.2 → pathpilot-0.3.1}/pathpilot/_file/_pickle.py +0 -0
- {pathpilot-0.2.2 → pathpilot-0.3.1}/pathpilot/_file/_sqlite.py +0 -0
- {pathpilot-0.2.2 → pathpilot-0.3.1}/pathpilot/_file/_text.py +0 -0
- {pathpilot-0.2.2 → pathpilot-0.3.1}/pathpilot/_file/_zip.py +0 -0
- {pathpilot-0.2.2 → pathpilot-0.3.1}/pathpilot/_file/utils.py +0 -0
- {pathpilot-0.2.2 → pathpilot-0.3.1}/pathpilot/_folder/__init__.py +0 -0
- {pathpilot-0.2.2 → pathpilot-0.3.1}/pathpilot/_folder/backup.py +0 -0
- {pathpilot-0.2.2 → pathpilot-0.3.1}/pathpilot/_folder/utils.py +0 -0
- {pathpilot-0.2.2 → pathpilot-0.3.1}/pathpilot/decorators.py +0 -0
- {pathpilot-0.2.2 → pathpilot-0.3.1}/pathpilot/exceptions.py +0 -0
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
2
|
Name: pathpilot
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.1
|
|
4
4
|
Summary: Library that facilitates file and folder manipulation in Python.
|
|
5
|
-
Home-page: https://github.com/zteinck/pathpilot
|
|
6
5
|
License: MIT
|
|
7
6
|
Author: Zachary Einck
|
|
8
7
|
Author-email: zacharyeinck@gmail.com
|
|
@@ -14,12 +13,14 @@ Classifier: Programming Language :: Python :: 3.9
|
|
|
14
13
|
Classifier: Programming Language :: Python :: 3.10
|
|
15
14
|
Classifier: Programming Language :: Python :: 3.11
|
|
16
15
|
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
17
|
Requires-Dist: XlsxWriter
|
|
18
18
|
Requires-Dist: cachegrab (>=0.2.2)
|
|
19
|
-
Requires-Dist: clockwork (>=0.
|
|
19
|
+
Requires-Dist: clockwork (>=0.3.4)
|
|
20
20
|
Requires-Dist: numpy
|
|
21
|
-
Requires-Dist: oddments (>=0.
|
|
21
|
+
Requires-Dist: oddments (>=0.3.1)
|
|
22
22
|
Requires-Dist: pandas
|
|
23
|
+
Project-URL: Homepage, https://github.com/zteinck/pathpilot
|
|
23
24
|
Project-URL: Repository, https://github.com/zteinck/pathpilot
|
|
24
25
|
Description-Content-Type: text/markdown
|
|
25
26
|
|
|
@@ -42,7 +43,7 @@ pip install pathpilot
|
|
|
42
43
|
|
|
43
44
|
|
|
44
45
|
## Main Features
|
|
45
|
-
- `
|
|
46
|
+
- `file_factory` ➔ Function that assigns new file instances to the correct child class. Many file types are supported natively including: *.xlsx*, *.csv*, *.txt*, *.pickle*, etc. The mapping of file extensions to their respective classes is managed using the `extension_mapping` global dictionary. Unmapped extensions are assigned to the `FileBase` class.
|
|
46
47
|
- `Folder` ➔ Class for interacting with folders. It is important to be mindful of the `read_only` parameter which, if set to `True`, allows folders to be created or deleted programically.
|
|
47
48
|
|
|
48
49
|
|
|
@@ -51,7 +52,7 @@ Please note the examples below represent a small fraction of the functionality o
|
|
|
51
52
|
|
|
52
53
|
### Imports
|
|
53
54
|
```python
|
|
54
|
-
from pathpilot import Folder,
|
|
55
|
+
from pathpilot import Folder, file_factory
|
|
55
56
|
```
|
|
56
57
|
|
|
57
58
|
### Folders
|
|
@@ -79,10 +80,10 @@ new_years_file = january_folder.join('Happy New Year.txt')
|
|
|
79
80
|
```
|
|
80
81
|
|
|
81
82
|
### Files
|
|
82
|
-
First, we create an instance of the `ExcelFile` class using the `
|
|
83
|
+
First, we create an instance of the `ExcelFile` class using the `file_factory` function. This occurs automatically by virtue of the `.xlsx` file extension.
|
|
83
84
|
```python
|
|
84
85
|
# create ExcelFile instance
|
|
85
|
-
file =
|
|
86
|
+
file = file_factory(r'C:\Users\MyID\Documents\MyFolder\MyFile.xlsx')
|
|
86
87
|
```
|
|
87
88
|
|
|
88
89
|
Next, let's check if the file exists. If not, let's save a `pandas` `DataFrame` as an Excel file.
|
|
@@ -100,7 +101,7 @@ Creating MyFile.xlsx
|
|
|
100
101
|
|
|
101
102
|
Now let's read the file we created as a `DataFrame`.
|
|
102
103
|
```python
|
|
103
|
-
# read the file we created as a pd.DataFrame
|
|
104
|
+
# read the file we created as a pd.DataFrame
|
|
104
105
|
df = file.read()
|
|
105
106
|
```
|
|
106
107
|
|
|
@@ -17,7 +17,7 @@ pip install pathpilot
|
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
## Main Features
|
|
20
|
-
- `
|
|
20
|
+
- `file_factory` ➔ Function that assigns new file instances to the correct child class. Many file types are supported natively including: *.xlsx*, *.csv*, *.txt*, *.pickle*, etc. The mapping of file extensions to their respective classes is managed using the `extension_mapping` global dictionary. Unmapped extensions are assigned to the `FileBase` class.
|
|
21
21
|
- `Folder` ➔ Class for interacting with folders. It is important to be mindful of the `read_only` parameter which, if set to `True`, allows folders to be created or deleted programically.
|
|
22
22
|
|
|
23
23
|
|
|
@@ -26,7 +26,7 @@ Please note the examples below represent a small fraction of the functionality o
|
|
|
26
26
|
|
|
27
27
|
### Imports
|
|
28
28
|
```python
|
|
29
|
-
from pathpilot import Folder,
|
|
29
|
+
from pathpilot import Folder, file_factory
|
|
30
30
|
```
|
|
31
31
|
|
|
32
32
|
### Folders
|
|
@@ -54,10 +54,10 @@ new_years_file = january_folder.join('Happy New Year.txt')
|
|
|
54
54
|
```
|
|
55
55
|
|
|
56
56
|
### Files
|
|
57
|
-
First, we create an instance of the `ExcelFile` class using the `
|
|
57
|
+
First, we create an instance of the `ExcelFile` class using the `file_factory` function. This occurs automatically by virtue of the `.xlsx` file extension.
|
|
58
58
|
```python
|
|
59
59
|
# create ExcelFile instance
|
|
60
|
-
file =
|
|
60
|
+
file = file_factory(r'C:\Users\MyID\Documents\MyFolder\MyFile.xlsx')
|
|
61
61
|
```
|
|
62
62
|
|
|
63
63
|
Next, let's check if the file exists. If not, let's save a `pandas` `DataFrame` as an Excel file.
|
|
@@ -75,7 +75,7 @@ Creating MyFile.xlsx
|
|
|
75
75
|
|
|
76
76
|
Now let's read the file we created as a `DataFrame`.
|
|
77
77
|
```python
|
|
78
|
-
# read the file we created as a pd.DataFrame
|
|
78
|
+
# read the file we created as a pd.DataFrame
|
|
79
79
|
df = file.read()
|
|
80
80
|
```
|
|
81
81
|
|
|
@@ -54,8 +54,6 @@ class ExcelFile(FileBase):
|
|
|
54
54
|
keeps track of the current tab number
|
|
55
55
|
verbose : bool
|
|
56
56
|
if True, information is printed when a worksheet is created or written to.
|
|
57
|
-
troubleshoot : bool
|
|
58
|
-
if True, additional information is printed for troubleshooting purposes.
|
|
59
57
|
|
|
60
58
|
Note:
|
|
61
59
|
--------------------
|
|
@@ -73,16 +71,14 @@ class ExcelFile(FileBase):
|
|
|
73
71
|
f,
|
|
74
72
|
number_tabs=False,
|
|
75
73
|
verbose=True,
|
|
76
|
-
troubleshoot=False,
|
|
77
74
|
**kwargs
|
|
78
75
|
):
|
|
79
76
|
super().__init__(f, **kwargs)
|
|
80
77
|
self.format_cache = dict()
|
|
81
78
|
self.sheet_cache = dict()
|
|
82
79
|
self.number_tabs = number_tabs
|
|
83
|
-
self.page = 0
|
|
84
80
|
self.verbose = verbose
|
|
85
|
-
self.
|
|
81
|
+
self.page = 0
|
|
86
82
|
|
|
87
83
|
|
|
88
84
|
#╭-------------------------------------------------------------------------╮
|
|
@@ -204,7 +200,8 @@ class ExcelFile(FileBase):
|
|
|
204
200
|
@property
|
|
205
201
|
def active_sheet(self):
|
|
206
202
|
''' current active worksheet '''
|
|
207
|
-
# used __dict__ because hasattr calls __getattr__
|
|
203
|
+
# used __dict__ because hasattr calls __getattr__
|
|
204
|
+
# when attr not found in __dict__
|
|
208
205
|
if '_active_sheet' not in self.__dict__:
|
|
209
206
|
self.create_worksheet('Sheet1')
|
|
210
207
|
return self._active_sheet
|
|
@@ -332,10 +329,6 @@ class ExcelFile(FileBase):
|
|
|
332
329
|
out : *
|
|
333
330
|
xlsxwriter.worksheet.Worksheet attribute
|
|
334
331
|
'''
|
|
335
|
-
|
|
336
|
-
if self.troubleshoot:
|
|
337
|
-
print(f"self.__getattr__(name='{name}')")
|
|
338
|
-
|
|
339
332
|
return getattr(self.active_sheet, name)
|
|
340
333
|
|
|
341
334
|
|
|
@@ -586,10 +579,15 @@ class ExcelFile(FileBase):
|
|
|
586
579
|
|
|
587
580
|
if self.verbose:
|
|
588
581
|
size_label = get_size_label(sys.getsizeof(data))
|
|
589
|
-
print(
|
|
582
|
+
print(
|
|
583
|
+
f'\twriting {size_label} to '
|
|
584
|
+
f'{self.active_sheet.name!r} tab',
|
|
585
|
+
end='... '
|
|
586
|
+
)
|
|
590
587
|
|
|
591
588
|
if not data:
|
|
592
|
-
if self.verbose:
|
|
589
|
+
if self.verbose:
|
|
590
|
+
print('SKIPPED')
|
|
593
591
|
return
|
|
594
592
|
|
|
595
593
|
start_col, start_row = self.parse_start_cell(start_cell)
|
|
@@ -648,10 +646,10 @@ class ExcelFile(FileBase):
|
|
|
648
646
|
'''
|
|
649
647
|
Description
|
|
650
648
|
------------
|
|
651
|
-
Writes a DataFrame to an Excel worksheet. This is an alternative to
|
|
652
|
-
that addresses some of its limitations such as not being
|
|
653
|
-
already have a format including the index,
|
|
654
|
-
or datetimes.
|
|
649
|
+
Writes a DataFrame to an Excel worksheet. This is an alternative to
|
|
650
|
+
df.to_excel() that addresses some of its limitations such as not being
|
|
651
|
+
able format cells that already have a format including the index,
|
|
652
|
+
headers, and cells that contain dates or datetimes.
|
|
655
653
|
|
|
656
654
|
Parameters
|
|
657
655
|
------------
|
|
@@ -748,10 +746,16 @@ class ExcelFile(FileBase):
|
|
|
748
746
|
# Check if empty
|
|
749
747
|
if df.empty:
|
|
750
748
|
if raise_on_empty:
|
|
751
|
-
raise ValueError(
|
|
749
|
+
raise ValueError(
|
|
750
|
+
"'df' argument cannot be empty."
|
|
751
|
+
)
|
|
752
752
|
if len(df.columns) == 0:
|
|
753
|
-
raise ValueError(
|
|
754
|
-
|
|
753
|
+
raise ValueError(
|
|
754
|
+
"'df' argument must have "
|
|
755
|
+
"an index or columns."
|
|
756
|
+
)
|
|
757
|
+
total_row = False
|
|
758
|
+
total_column = False
|
|
755
759
|
|
|
756
760
|
# Check for duplicate column names
|
|
757
761
|
odd.verify_no_duplicates(df=df, attr='columns')
|
|
@@ -761,7 +765,8 @@ class ExcelFile(FileBase):
|
|
|
761
765
|
total_column_name = 'Total'
|
|
762
766
|
if total_column_name in df.columns:
|
|
763
767
|
raise ValueError(
|
|
764
|
-
|
|
768
|
+
"'df' already has a column "
|
|
769
|
+
f"named {total_column_name!r}"
|
|
765
770
|
)
|
|
766
771
|
df[total_column_name] = df.sum(axis=1, numeric_only=True)
|
|
767
772
|
|
|
@@ -776,13 +781,14 @@ class ExcelFile(FileBase):
|
|
|
776
781
|
numeric_columns -= percent_columns
|
|
777
782
|
|
|
778
783
|
datelike_columns = set(
|
|
779
|
-
df.select_dtypes(include=[np.datetime64])
|
|
784
|
+
df.select_dtypes(include=[np.datetime64])\
|
|
785
|
+
.columns.tolist()
|
|
780
786
|
)
|
|
781
787
|
|
|
782
788
|
for k in df.columns:
|
|
783
|
-
if isinstance(k, str)
|
|
784
|
-
odd.column_name_is_datelike(k)
|
|
785
|
-
|
|
789
|
+
if isinstance(k, str) \
|
|
790
|
+
and odd.column_name_is_datelike(k) \
|
|
791
|
+
and not np.issubdtype(df[k].dtype, np.timedelta64):
|
|
786
792
|
datelike_columns.add(k)
|
|
787
793
|
|
|
788
794
|
# Parse start cell
|
|
@@ -799,6 +805,7 @@ class ExcelFile(FileBase):
|
|
|
799
805
|
|
|
800
806
|
# Force data_format to comply with the standard {column name : format}
|
|
801
807
|
if isinstance(data_format, dict):
|
|
808
|
+
# check if diciontary keys are index/column names
|
|
802
809
|
if not all(k in df.columns for k in data_format):
|
|
803
810
|
if any(isinstance(v, (list, tuple, dict))
|
|
804
811
|
for v in data_format.values()):
|
|
@@ -807,14 +814,15 @@ class ExcelFile(FileBase):
|
|
|
807
814
|
|
|
808
815
|
# Auto-detects the best format for each DataFrame column
|
|
809
816
|
if data_format == 'auto':
|
|
810
|
-
data_format = dict()
|
|
811
817
|
|
|
812
818
|
# cascade auto formatting
|
|
813
819
|
if total_row_format is None:
|
|
814
|
-
total_row_format =
|
|
820
|
+
total_row_format = data_format[:]
|
|
815
821
|
|
|
816
822
|
if total_column_format is None:
|
|
817
|
-
total_column_format =
|
|
823
|
+
total_column_format = data_format[:]
|
|
824
|
+
|
|
825
|
+
data_format = {}
|
|
818
826
|
|
|
819
827
|
infer_format = lambda fmt, s: \
|
|
820
828
|
fmt if s.sum() - s.round().sum() == 0 \
|
|
@@ -848,18 +856,33 @@ class ExcelFile(FileBase):
|
|
|
848
856
|
datetime_columns = set()
|
|
849
857
|
|
|
850
858
|
for k in list(datelike_columns):
|
|
851
|
-
if np.issubdtype(df[k].dtype, np.datetime64)
|
|
859
|
+
if np.issubdtype(df[k].dtype, np.datetime64) \
|
|
860
|
+
or df[k].isna().all():
|
|
861
|
+
continue
|
|
862
|
+
|
|
852
863
|
fmt = date_formats.get(k)
|
|
864
|
+
to_dt = lambda x: pd.to_datetime(x, format=fmt)
|
|
865
|
+
|
|
853
866
|
try:
|
|
854
|
-
df[k] =
|
|
867
|
+
df[k] = to_dt(df[k])
|
|
855
868
|
except:
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
869
|
+
try:
|
|
870
|
+
# handles mixed dtypes that will convert individually
|
|
871
|
+
df[k] = df[k].apply(odd.ignore_nan(to_dt))
|
|
872
|
+
except:
|
|
873
|
+
types = set(type(x) for x in df[k].dropna())
|
|
874
|
+
if types == {str}:
|
|
875
|
+
if fmt is None:
|
|
876
|
+
datelike_columns.remove(k)
|
|
877
|
+
else:
|
|
878
|
+
df[k] = df[k].apply(odd.ignore_nan(lambda x: \
|
|
879
|
+
datetime.datetime.strptime(x, fmt)
|
|
880
|
+
))
|
|
881
|
+
datetime_columns.add(k)
|
|
882
|
+
elif all(issubclass(x, datetime.datetime) for x in types):
|
|
883
|
+
datetime_columns.add(k)
|
|
884
|
+
else:
|
|
885
|
+
datelike_columns.remove(k)
|
|
863
886
|
|
|
864
887
|
for k in datelike_columns:
|
|
865
888
|
data_format[k] = 'datetime'
|
|
@@ -867,7 +890,7 @@ class ExcelFile(FileBase):
|
|
|
867
890
|
s = df[k].dropna()
|
|
868
891
|
if s.empty: continue
|
|
869
892
|
if k in datetime_columns:
|
|
870
|
-
if all(x.time() == datetime.time
|
|
893
|
+
if all(x.time() == datetime.time.min for x in s.values):
|
|
871
894
|
df[k] = df[k].apply(odd.ignore_nan(lambda x: x.date()))
|
|
872
895
|
data_format[k] = 'date'
|
|
873
896
|
else:
|
|
@@ -5,7 +5,6 @@ import os
|
|
|
5
5
|
import pandas as pd
|
|
6
6
|
import numpy as np
|
|
7
7
|
import oddments as odd
|
|
8
|
-
import clockwork as cw
|
|
9
8
|
from cachegrab import sha256
|
|
10
9
|
|
|
11
10
|
from .._folder import Folder
|
|
@@ -135,34 +134,6 @@ class FileBase(object):
|
|
|
135
134
|
return wrapper
|
|
136
135
|
|
|
137
136
|
|
|
138
|
-
@staticmethod
|
|
139
|
-
def add_timestamp(func):
|
|
140
|
-
'''
|
|
141
|
-
Parameters
|
|
142
|
-
------------
|
|
143
|
-
args : tuple
|
|
144
|
-
arguments are only passed to the respective clockwork function
|
|
145
|
-
kwargs : dict
|
|
146
|
-
keyword arguments are passed to the respective clockwork function
|
|
147
|
-
with the exception of 'loc' and 'encase':
|
|
148
|
-
|
|
149
|
-
loc : str
|
|
150
|
-
the location where you want the timestamp.
|
|
151
|
-
Supported values are 'prefix' and 'suffix'
|
|
152
|
-
encase : bool
|
|
153
|
-
if True, the timestamp is encased in paranthesis
|
|
154
|
-
'''
|
|
155
|
-
|
|
156
|
-
def wrapper(self, *args, **kwargs):
|
|
157
|
-
loc = kwargs.pop('loc', 'prefix')
|
|
158
|
-
encase = kwargs.pop('encase', False)
|
|
159
|
-
timestamp = func(self, *args, **kwargs)
|
|
160
|
-
if encase: timestamp = f'({timestamp})'
|
|
161
|
-
return getattr(self, loc)(timestamp)
|
|
162
|
-
|
|
163
|
-
return wrapper
|
|
164
|
-
|
|
165
|
-
|
|
166
137
|
@staticmethod
|
|
167
138
|
def add_affix(func):
|
|
168
139
|
'''
|
|
@@ -195,16 +166,16 @@ class FileBase(object):
|
|
|
195
166
|
'''
|
|
196
167
|
Description
|
|
197
168
|
------------
|
|
198
|
-
This method ensures that functions returning new instances create
|
|
199
|
-
of the correct subclass. For instance, if a CSVFile instance is
|
|
200
|
-
to an Excel file, this method guarantees that the returned
|
|
201
|
-
an ExcelFile object. If subclass typing must be preserved
|
|
202
|
-
changes, the subclass can set the factory to None. For
|
|
203
|
-
CryptoFile should always create instances of CryptoFile even
|
|
204
|
-
file extension is changed.
|
|
169
|
+
This method ensures that functions returning new instances create
|
|
170
|
+
objects of the correct subclass. For instance, if a CSVFile instance is
|
|
171
|
+
converted to an Excel file, this method guarantees that the returned
|
|
172
|
+
instance is an ExcelFile object. If subclass typing must be preserved
|
|
173
|
+
regardless of changes, the subclass can set the factory to None. For
|
|
174
|
+
example, a CryptoFile should always create instances of CryptoFile even
|
|
175
|
+
if the file extension is changed.
|
|
205
176
|
|
|
206
|
-
Note: This must be at the class level since calling self.
|
|
207
|
-
the instance level passes self as the first argument.
|
|
177
|
+
Note: This must be at the class level since calling self.file_factory()
|
|
178
|
+
at the instance level passes self as the first argument.
|
|
208
179
|
|
|
209
180
|
Parameters
|
|
210
181
|
------------
|
|
@@ -218,7 +189,8 @@ class FileBase(object):
|
|
|
218
189
|
file : FileBase subclass instance
|
|
219
190
|
spawned file instance
|
|
220
191
|
'''
|
|
221
|
-
|
|
192
|
+
ff = cls.file_factory
|
|
193
|
+
return (cls if ff is None else ff)(*args, **kwargs)
|
|
222
194
|
|
|
223
195
|
|
|
224
196
|
#╭-------------------------------------------------------------------------╮
|
|
@@ -489,7 +461,7 @@ class FileBase(object):
|
|
|
489
461
|
|
|
490
462
|
|
|
491
463
|
def deep_copy(self):
|
|
492
|
-
''' create a copy of the
|
|
464
|
+
''' create a copy of the file object '''
|
|
493
465
|
return self.spawn(self.path)
|
|
494
466
|
|
|
495
467
|
|
|
@@ -500,36 +472,4 @@ class FileBase(object):
|
|
|
500
472
|
|
|
501
473
|
@Decorators.add_affix
|
|
502
474
|
def suffix():
|
|
503
|
-
''' add suffix to file name '''
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
# helper functions adding timestamps to files
|
|
507
|
-
@Decorators.add_timestamp
|
|
508
|
-
def quarter(self, delta=0):
|
|
509
|
-
return cw.quarter_end(delta=delta).label
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
def qtr(self, *args, **kwargs):
|
|
513
|
-
return self.quarter(*args, **kwargs)
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
@Decorators.add_timestamp
|
|
517
|
-
def month(self, delta=0):
|
|
518
|
-
return cw.month_end(delta=delta).ymd
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
@Decorators.add_timestamp
|
|
522
|
-
def day(self, weekday, delta=0):
|
|
523
|
-
return cw.day_of_week(weekday=weekday, delta=delta).ymd
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
@Decorators.add_timestamp
|
|
527
|
-
def year(self, delta=0):
|
|
528
|
-
return str(cw.year_end(delta=delta).year)
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
@Decorators.add_timestamp
|
|
532
|
-
def timestamp(self, normalize=False, week_offset=0, fmt=None):
|
|
533
|
-
now = cw.Date(normalize=normalize, week_offset=week_offset)
|
|
534
|
-
now = str(now).replace(':','.') if fmt is None else now.str(fmt)
|
|
535
|
-
return now
|
|
475
|
+
''' add suffix to file name '''
|
|
@@ -3,11 +3,8 @@ import shutil
|
|
|
3
3
|
import os
|
|
4
4
|
import pandas as pd
|
|
5
5
|
import oddments as odd
|
|
6
|
-
from cachegrab import sha256
|
|
7
|
-
|
|
8
6
|
import clockwork as cw
|
|
9
|
-
from
|
|
10
|
-
convert_date_format_to_regex
|
|
7
|
+
from cachegrab import sha256
|
|
11
8
|
|
|
12
9
|
from ..decorators import check_read_only
|
|
13
10
|
from ..exceptions import ReadOnlyError
|
|
@@ -36,7 +33,7 @@ class Folder(object):
|
|
|
36
33
|
|
|
37
34
|
Class Attributes
|
|
38
35
|
--------------------
|
|
39
|
-
|
|
36
|
+
file_factory : object
|
|
40
37
|
Function or class that determines which subclass is returned when
|
|
41
38
|
a new file object is initialized.
|
|
42
39
|
sorter : func
|
|
@@ -319,7 +316,7 @@ class Folder(object):
|
|
|
319
316
|
raise ValueError(' '.join(message + ['found.']))
|
|
320
317
|
|
|
321
318
|
if date_format is not None and date_pattern is None:
|
|
322
|
-
date_pattern =
|
|
319
|
+
date_pattern = cw.date_format_to_regex(date_format)
|
|
323
320
|
|
|
324
321
|
if date_pattern is not None:
|
|
325
322
|
date_pattern = format_date_pattern(date_pattern)
|
|
@@ -454,7 +451,7 @@ class Folder(object):
|
|
|
454
451
|
|
|
455
452
|
@classmethod
|
|
456
453
|
def _spawn_file(cls, *args, **kwargs):
|
|
457
|
-
return cls.
|
|
454
|
+
return cls.file_factory(*args, **kwargs)
|
|
458
455
|
|
|
459
456
|
|
|
460
457
|
@classmethod
|
|
@@ -784,7 +781,7 @@ class Folder(object):
|
|
|
784
781
|
|
|
785
782
|
Returns
|
|
786
783
|
----------
|
|
787
|
-
out :
|
|
784
|
+
out : object
|
|
788
785
|
folder or file object
|
|
789
786
|
'''
|
|
790
787
|
self.validate_join_args(args)
|
|
@@ -841,23 +838,6 @@ class Folder(object):
|
|
|
841
838
|
shutil.copytree(self.path, destination.path)
|
|
842
839
|
|
|
843
840
|
|
|
844
|
-
# helper functions adding timestamps to folders
|
|
845
|
-
def quarter(self, delta=0, **kwargs):
|
|
846
|
-
return self.join(cw.quarter_end(delta=delta).label, **kwargs)
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
def month(self, delta=0, **kwargs):
|
|
850
|
-
return self.join(cw.month_end(delta=delta).ymd, **kwargs)
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
def day(self, weekday, delta=0, **kwargs):
|
|
854
|
-
return self.join(cw.day_of_week(weekday=weekday, delta=delta).ymd, **kwargs)
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
def year(self, delta=0, **kwargs):
|
|
858
|
-
return self.join(str(cw.year_end(delta=delta).year), **kwargs)
|
|
859
|
-
|
|
860
|
-
|
|
861
841
|
#╭-------------------------------------------------------------------------╮
|
|
862
842
|
#| Static Methods |
|
|
863
843
|
#╰-------------------------------------------------------------------------╯
|
|
@@ -27,7 +27,7 @@ extension_mapping = {
|
|
|
27
27
|
#| Functions |
|
|
28
28
|
#╰-------------------------------------------------------------------------╯
|
|
29
29
|
|
|
30
|
-
def
|
|
30
|
+
def file_factory(f, **kwargs):
|
|
31
31
|
''' assigns new file instances to the correct subclass '''
|
|
32
32
|
extension = trifurcate(f)[-1]
|
|
33
33
|
out = extension_mapping.get(extension, FileBase)(f, **kwargs)
|
|
@@ -44,8 +44,8 @@ def get_data_path():
|
|
|
44
44
|
|
|
45
45
|
|
|
46
46
|
#╭-------------------------------------------------------------------------╮
|
|
47
|
-
#| Assign Class
|
|
47
|
+
#| Assign Class Attributes |
|
|
48
48
|
#╰-------------------------------------------------------------------------╯
|
|
49
49
|
|
|
50
|
-
FileBase.
|
|
51
|
-
Folder.
|
|
50
|
+
FileBase.file_factory = file_factory
|
|
51
|
+
Folder.file_factory = file_factory
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import datetime
|
|
3
|
-
|
|
3
|
+
import clockwork as cw
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
def split_extension(x):
|
|
@@ -53,19 +53,28 @@ def get_cwd():
|
|
|
53
53
|
return f
|
|
54
54
|
|
|
55
55
|
|
|
56
|
-
def
|
|
56
|
+
def _to_timestamp(func):
|
|
57
57
|
|
|
58
58
|
def wrapper(path):
|
|
59
|
-
|
|
59
|
+
letter = func.__name__.split('_')[1][0]
|
|
60
|
+
ts = getattr(os.path, f'get{letter}time')(path)
|
|
61
|
+
|
|
62
|
+
# Conversion to datetime is redundant since cw.Timestamp
|
|
63
|
+
# constructor accepts timestamps, but explicitly using
|
|
64
|
+
# datetime library ensures time zone information is
|
|
65
|
+
# respected in case constructor behavior ever changes.
|
|
66
|
+
dt = datetime.datetime.fromtimestamp(ts)
|
|
67
|
+
|
|
68
|
+
return cw.Timestamp(dt)
|
|
60
69
|
|
|
61
70
|
return wrapper
|
|
62
71
|
|
|
63
72
|
|
|
64
|
-
@
|
|
65
|
-
def get_created_date(
|
|
66
|
-
|
|
73
|
+
@_to_timestamp
|
|
74
|
+
def get_created_date():
|
|
75
|
+
pass
|
|
67
76
|
|
|
68
77
|
|
|
69
|
-
@
|
|
70
|
-
def get_modified_date(
|
|
71
|
-
|
|
78
|
+
@_to_timestamp
|
|
79
|
+
def get_modified_date():
|
|
80
|
+
pass
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "pathpilot"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.3.1"
|
|
4
4
|
description = "Library that facilitates file and folder manipulation in Python."
|
|
5
5
|
authors = ["Zachary Einck <zacharyeinck@gmail.com>"]
|
|
6
6
|
license = "MIT"
|
|
@@ -10,9 +10,9 @@ homepage = "https://github.com/zteinck/pathpilot"
|
|
|
10
10
|
|
|
11
11
|
[tool.poetry.dependencies]
|
|
12
12
|
python = "^3.8"
|
|
13
|
-
clockwork = ">=0.
|
|
13
|
+
clockwork = ">=0.3.4"
|
|
14
14
|
cachegrab = ">=0.2.2"
|
|
15
|
-
oddments = ">=0.
|
|
15
|
+
oddments = ">=0.3.1"
|
|
16
16
|
pandas = "*"
|
|
17
17
|
numpy = "*"
|
|
18
18
|
XlsxWriter = "*"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|