Skip to content

Commit e7534af

Browse files
authored
Merge pull request #37 from HECBioSim/dev
Charlie's doc string improvments
2 parents 7a8d164 + a866f55 commit e7534af

5 files changed

Lines changed: 112 additions & 8 deletions

File tree

crossflow/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@
55
together command-line driven tools.
66
"""
77

8-
__version__ = "0.1.4"
8+
__version__ = "0.1.5.dev0"

crossflow/filehandling.py

Lines changed: 64 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
filename_here = fh.save(filename_here)
1717
1818
they inherit from os.PathLike so can be used anywhere a conventional path can
19-
be used:
19+
be used e.g.
2020
2121
with open(fh) as f:
2222
...
@@ -44,6 +44,7 @@ def set_stage_point(stage_point):
4444
class FileHandler:
4545
"""
4646
Handle file operations
47+
4748
"""
4849

4950
def __init__(self, stage_point=None):
@@ -55,13 +56,27 @@ def __init__(self, stage_point=None):
5556
def load(self, path):
5657
"""
5758
Method to load file.
59+
60+
args:
61+
path (str): file path or URL
62+
63+
returns:
64+
FileHandle: a FileHandle object
65+
5866
"""
5967

6068
return FileHandle(path, self.stage_point, must_exist=True)
6169

6270
def create(self, path):
6371
"""
64-
Method to load file.
72+
Method to create a new file.
73+
74+
args:
75+
path (str): file path
76+
77+
returns:
78+
FileHandle: a FileHandle object
79+
6580
"""
6681

6782
return FileHandle(path, self.stage_point, must_exist=False)
@@ -70,14 +85,51 @@ def create(self, path):
7085
class FileHandle:
7186
"""
7287
A portable container for a file.
88+
89+
a FileHandle object is instantiated with the path of an existing file on
90+
an existing file system:
91+
92+
fh = FileHandle('/path/to/file')
93+
or:
94+
fh = FileHandle('http://example.com/file.txt')
95+
96+
and has a save() method that creates a local copy of that file:
97+
98+
filename_here = fh.save(filename_here)
99+
100+
FileHandle objects inherit from os.PathLike so can be used anywhere a
101+
conventional path can be used:
102+
103+
with open(fh) as f:
104+
...
105+
106+
They can also be used to read and write binary and text data directly:
107+
108+
data = fh.read_binary()
109+
text = fh.read_text()
110+
fh.write_binary(data)
111+
fh.write_text(text)
112+
73113
"""
74114

75115
def __init__(self, path, stage_point, must_exist=True):
76116
if not isinstance(path, (os.PathLike, str, bytes)):
77117
raise IOError(f"Error - illegal argument type {type(path)} for {path}")
78118
if must_exist:
79-
if not os.path.exists(path):
80-
raise IOError("Error - no such file")
119+
if isinstance(path, str) and (
120+
path.startswith("http://")
121+
or path.startswith("https://")
122+
or path.startswith("ftp://")
123+
):
124+
try:
125+
source = fsspec.open(path)
126+
with source as s:
127+
s.read(1)
128+
except Exception as e:
129+
raise IOError("Error - no such file") from e
130+
else:
131+
if not os.path.exists(path):
132+
raise IOError("Error - no such file")
81133
source = fsspec.open(path)
82134
ext = os.path.splitext(path)[1]
83135
self.path = path
@@ -180,6 +232,10 @@ def read_text(self):
180232
def write_binary(self, data):
181233
"""
182234
A method for writing binary file formats
235+
236+
args:
237+
data (bytes): binary data to write
238+
183239
"""
184240

185241
compressed_data = zlib.compress(data)
@@ -194,6 +250,10 @@ def write_binary(self, data):
194250
def write_text(self, text):
195251
"""
196252
A wrapper for writing binary formatted text.
253+
254+
args:
255+
text (str): text data to write
256+
197257
"""
198258

199259
self.write_binary(text.encode("utf-8"))

crossflow/tasks.py

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,19 @@ def _gen_filenames(pattern, n_files):
4242
class SubprocessTask:
4343
"""
4444
A task that runs a command-line executable
45+
46+
Methods:
47+
set_inputs: set the inputs the task requires
48+
set_outputs: set the outputs the task produces
49+
set_constant: set a constant for the task
50+
run: execute the task
51+
4552
"""
4653

4754
def __init__(self, template):
4855
"""
49-
Arguments:
56+
Initialize the SubprocessTask.
57+
args:
5058
template (str): a template for the command to be executed
5159
"""
5260
self.template = template
@@ -66,6 +74,10 @@ def __call__(self, *args):
6674
def set_inputs(self, inputs):
6775
"""
6876
Set the inputs the task requires
77+
78+
args:
79+
inputs (list): a list of input variable names
80+
6981
"""
7082
if not isinstance(inputs, list):
7183
raise TypeError(
@@ -76,6 +88,10 @@ def set_inputs(self, inputs):
7688
def set_outputs(self, outputs):
7789
"""
7890
Set the outputs the task produces
91+
92+
args:
93+
outputs (list): a list of output variable names
94+
7995
"""
8096
if not isinstance(outputs, list):
8197
raise TypeError(
@@ -88,6 +104,11 @@ def set_constant(self, key, value):
88104
Set a constant for the task
89105
If it was previously defined as an input variable, remove it from
90106
that list.
107+
108+
args:
109+
key (str): the name of the constant
110+
value (str): the value of the constant
111+
91112
"""
92113
d = {"name": key}
93114
try:
@@ -194,7 +215,8 @@ class FunctionTask:
194215

195216
def __init__(self, func):
196217
"""
197-
Arguments:
218+
Initialize the FunctionTask.
219+
args:
198220
func: the Python function to wrap
199221
"""
200222
self.func = func
@@ -210,18 +232,31 @@ def __call__(self, *args):
210232
def set_inputs(self, inputs):
211233
"""
212234
Set the inputs the task requires
235+
236+
args:
237+
inputs (list): a list of input variable names
238+
213239
"""
214240
self.inputs = inputs
215241

216242
def set_outputs(self, outputs):
217243
"""
218244
Set the outputs the task produces
245+
246+
args:
247+
outputs (list): a list of output variable names
248+
219249
"""
220250
self.outputs = outputs
221251

222252
def set_constant(self, key, value):
223253
"""
224-
Set a parameters for the task
254+
Set a constant for the task
255+
256+
args:
257+
key (str): the name of the constant
258+
value (str): the value of the constant
259+
225260
"""
226261
try:
227262
self.constants[key] = self.filehandler.load(value)

pyproject.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ dependencies = [
3232
"dask",
3333
"distributed",
3434
"fsspec",
35+
"requests",
36+
"aiohttp"
3537
]
3638

3739
[project.urls]

tests/test_filehandling.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,13 @@ def test_file_protocol(tmpdir):
5050
assert pf.read_text() == "content"
5151

5252

53+
def test_url_protocol():
54+
fh = filehandling.FileHandler()
55+
f = fh.load(
56+
"https://raw.githubusercontent.com/HECBioSim/crossflow/refs/heads/main/README.md"
57+
)
58+
59+
5360
"""
5461
def test_s3_protocol(tmpdir):
5562
d = tmpdir.mkdir('sub')

0 commit comments

Comments
 (0)