Skip to content

Commit

Permalink
Merge pull request #11 from hechth/session_inject
Browse files Browse the repository at this point in the history
Switched to session as parameter for the fs
  • Loading branch information
hechth committed Nov 29, 2023
2 parents 7b0a71d + 45f88b3 commit cf10722
Show file tree
Hide file tree
Showing 4 changed files with 140 additions and 87 deletions.
119 changes: 62 additions & 57 deletions fs_irods/iRODSFS.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
from io import BufferedIOBase, BufferedRandom, IOBase
import datetime
from io import BufferedRandom
import io
import os

from multiprocessing import RLock
Expand All @@ -10,36 +12,29 @@
from irods.session import iRODSSession
from irods.collection import iRODSCollection
from irods.path import iRODSPath
from irods.data_object import iRODSDataObject



from contextlib import contextmanager

from fs_irods.utils import can_create

_utc=datetime.timezone(datetime.timedelta(0))

class iRODSFS(FS):
def __init__(self, host: str, port:int, user:str, password: str, zone: str) -> None:
def __init__(self, session: iRODSSession) -> None:
super().__init__()
self._lock = RLock()
self._host = host
self._port = port
self._user = user
self._password = password
self._zone = zone
self._host = session.host
self._port = session.port
self._zone = session.zone

self._session = session

def wrap(self, path: str) -> str:
if path.startswith(f"/{self._zone}"):
return path
return str(iRODSPath(self._zone, path))


@contextmanager
def _session(self) -> iRODSSession:
with self._lock:
with iRODSSession(host=self._host, port=self._port, user=self._user, password=self._password, zone=self._zone) as session:
yield session


def getinfo(self, path: str, namespaces: list|None = None) -> Info:
"""Get information about a resource on the filesystem.
Args:
Expand All @@ -55,14 +50,26 @@ def getinfo(self, path: str, namespaces: list|None = None) -> Info:
"""
self._check_exists(path)

with self._session() as session:
raw_info = {"basic": {"name": path}}
if session.data_objects.exists(self.wrap(path)):
with self._lock:
raw_info: dict = {"basic": {}, "details": {}, "access": {}}
path = self.wrap(path)
data_object: iRODSDataObject|iRODSCollection = None

if self._session.data_objects.exists(path):
data_object = self._session.data_objects.get(path)
raw_info["basic"]["is_dir"] = False
raw_info["details"] = {"type": "file"}
elif session.collections.exists(self.wrap(path)):
raw_info["details"] = {"type": data_object.type}
raw_info["details"]["size"] = data_object.size
elif self._session.collections.exists(path):
data_object = self._session.collections.get(path)
raw_info["basic"]["is_dir"] = True
raw_info["details"] = {"type": "directory"}

raw_info["basic"]["name"] = data_object.name
raw_info["access"]["user"] = data_object.owner_name

raw_info["details"]["modified"] = data_object.modify_time.replace(tzinfo=_utc).timestamp()
raw_info["details"]["created"] = data_object.create_time.replace(tzinfo=_utc).timestamp()

return Info(raw_info)

Expand All @@ -77,8 +84,8 @@ def listdir(self, path: str) -> list:
DirectoryExpected: If the path is not a directory.
"""
self._check_exists(path)
with self._session() as session:
coll: iRODSCollection = session.collections.get(self.wrap(path))
with self._lock:
coll: iRODSCollection = self._session.collections.get(self.wrap(path))
return [item.path for item in coll.data_objects + coll.subcollections]

def makedir(self, path: str, permissions: Permissions|None = None, recreate: bool = False):
Expand All @@ -101,10 +108,9 @@ def makedir(self, path: str, permissions: Permissions|None = None, recreate: boo
if not self.isdir(os.path.dirname(path)):
raise ResourceNotFound(path)

with self._session() as session:
session.collections.create(self.wrap(path), recurse=False)
with self._lock:
self._session.collections.create(self.wrap(path), recurse=False)

@contextmanager
def openbin(self, path: str, mode:str = "r", buffering: int = -1, **options) -> BufferedRandom:
"""Open a binary file-like object on the filesystem.
Args:
Expand Down Expand Up @@ -133,20 +139,19 @@ def openbin(self, path: str, mode:str = "r", buffering: int = -1, **options) ->

self._check_isfile(path)

with self._session() as session:
with self._lock:
mode = mode.replace("b", "")
file = session.data_objects.open(
self.wrap(path),
mode,
create,
allow_redirect=False,
auto_close=False,
**options
)
try:
yield file
finally:
file.close()
file = self._session.data_objects.open(
self.wrap(path),
mode,
create,
allow_redirect=False,
auto_close=False,
**options
)
if 'a' in mode:
file.seek(0, io.SEEK_END)
return file

def remove(self, path: str):
"""Remove a file from the filesystem.
Expand All @@ -159,8 +164,8 @@ def remove(self, path: str):
self._check_exists(path)
self._check_isfile(path)

with self._session() as session:
session.data_objects.unlink(self.wrap(path))
with self._lock:
self._session.data_objects.unlink(self.wrap(path))

def _check_isfile(self, path: str):
"""Check if a path points to a file and raise an FileExpected error if not.
Expand Down Expand Up @@ -191,8 +196,8 @@ def removedir(self, path: str):
if not self.isempty(path):
raise DirectoryNotEmpty(path)

with self._session() as session:
session.collections.remove(self.wrap(path), recurse=False)
with self._lock:
self._session.collections.remove(self.wrap(path), recurse=False)

def _is_root(self, path: str) -> bool:
"""Check if path points to root of the filesystem.
Expand All @@ -218,9 +223,9 @@ def removetree(self, path: str):
self._check_exists(path)
self._check_isdir(path)

with self._session() as session:
with self._lock:
if self._is_root(path):
root: iRODSCollection = session.collections.get(self.wrap(path))
root: iRODSCollection = self._session.collections.get(self.wrap(path))
for item in root.data_objects:
item.unlink()
for item in root.subcollections:
Expand All @@ -229,7 +234,7 @@ def removetree(self, path: str):
item.remove()
item.unregister()
else:
session.collections.remove(self.wrap(path), recurse=True)
self._session.collections.remove(self.wrap(path), recurse=True)

def _check_isdir(self, path: str):
"""Check if a path is a directory.
Expand Down Expand Up @@ -259,9 +264,9 @@ def _check_exists(self, path:str):
Raises:
ResourceNotFound: If the path does not exist.
"""
with self._session() as session:
with self._lock:
path = self.wrap(path)
if not session.data_objects.exists(path) and not session.collections.exists(path):
if not self._session.data_objects.exists(path) and not self._session.collections.exists(path):
raise ResourceNotFound(path)

def isfile(self, path: str) -> bool:
Expand All @@ -271,8 +276,8 @@ def isfile(self, path: str) -> bool:
Returns:
bool: True if the path is a file, False otherwise.
"""
with self._session() as session:
return session.data_objects.exists(self.wrap(path))
with self._lock:
return self._session.data_objects.exists(self.wrap(path))

def isdir(self, path: str) -> bool:
"""Check if a path is a directory.
Expand All @@ -281,8 +286,8 @@ def isdir(self, path: str) -> bool:
Returns:
bool: True if the path is a directory, False otherwise.
"""
with self._session() as session:
return session.collections.exists(self.wrap(path))
with self._lock:
return self._session.collections.exists(self.wrap(path))

def create(self, path:str):
"""Create a file on the filesystem.
Expand All @@ -298,8 +303,8 @@ def create(self, path:str):
if self.isfile(path):
raise FileExists(path)

with self._session() as session:
session.data_objects.create(self.wrap(path))
with self._lock:
self._session.data_objects.create(self.wrap(path))

def exists(self, path: str) -> bool:
"""Check if a resource exists.
Expand All @@ -308,6 +313,6 @@ def exists(self, path: str) -> bool:
Returns:
bool: True if the path exists, False otherwise.
"""
with self._session() as session:
with self._lock:
path = self.wrap(path)
return session.data_objects.exists(path) or session.collections.exists(path)
return self._session.data_objects.exists(path) or self._session.collections.exists(path)
8 changes: 7 additions & 1 deletion tests/iRODSFSBuilder.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from fs_irods import iRODSFS

from irods.session import iRODSSession

class iRODSFSBuilder:
def __init__(self):
Expand All @@ -8,6 +9,7 @@ def __init__(self):
self._user = 'rods'
self._password = 'rods'
self._zone = 'tempZone'
self._session = iRODSSession(host=self._host, port=self._port, user=self._user, password=self._password, zone=self._zone)

def with_host(self, host):
self._host = host
Expand All @@ -29,5 +31,9 @@ def with_zone(self, zone):
self._zone = zone
return self

def with_session(self, session):
self._session = session
return self

def build(self):
return iRODSFS(host=self._host, port=self._port, user=self._user, password=self._password, zone=self._zone)
return iRODSFS(self._session)
8 changes: 5 additions & 3 deletions tests/test_fs_extension.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
import time
import unittest
import pytest
from fs.test import FSTestCases
from fs_irods import iRODSFS

from tests.iRODSFSBuilder import iRODSFSBuilder


@pytest.mark.skip
class TestMyFS(FSTestCases, unittest.TestCase):

def make_fs(self):
sut = iRODSFSBuilder().build()
return sut

def destroy_fs(self, fs):
fs.removetree("")
def destroy_fs(self, fs: iRODSFS):
fs.removetree("/")
time.sleep(0.1)
Loading

0 comments on commit cf10722

Please sign in to comment.