3434 CONDITIONS OF OSMC-PL.
3535"""
3636
37+ import abc
3738import io
3839import json
3940import logging
@@ -268,7 +269,54 @@ def getClassNames(self, className=None, recursive=False, qualified=False, sort=F
268269 return self ._ask (question = 'getClassNames' , opt = opt )
269270
270271
271- class OMCPathReal (pathlib .PurePosixPath ):
272+ class OMCPath (pathlib .PurePath , metaclass = abc .ABCMeta ):
273+ """
274+ Define the interface for OMCPath
275+ """
276+
277+ def __init__ (self , * path ):
278+ super ().__init__ (* path )
279+
280+ # functions from pathlib.Path
281+ def with_segments (self , * pathsegments ):
282+ raise NotImplementedError
283+
284+ def is_file (self , * , follow_symlinks = True ):
285+ raise NotImplementedError
286+
287+ def is_dir (self , * , follow_symlinks = True ):
288+ raise NotImplementedError
289+
290+ def read_text (self , encoding = None , errors = None , newline = None ):
291+ raise NotImplementedError
292+
293+ def write_text (self , data : str , encoding = None , errors = None , newline = None ):
294+ raise NotImplementedError
295+
296+ def mkdir (self , mode = 0o777 , parents = False , exist_ok = False ):
297+ raise NotImplementedError
298+
299+ def cwd (self ):
300+ raise NotImplementedError
301+
302+ def unlink (self , missing_ok : bool = False ):
303+ raise NotImplementedError
304+
305+ def resolve (self , strict : bool = False ):
306+ raise NotImplementedError
307+
308+ def absolute (self ):
309+ raise NotImplementedError
310+
311+ def exists (self , * , follow_symlinks = True ):
312+ raise NotImplementedError
313+
314+ # additional function specific for OMCPath
315+ def size (self ) -> int :
316+ raise NotImplementedError
317+
318+
319+ class OMCPathReal (OMCPath , pathlib .PurePosixPath ):
272320 """
273321 Implementation of a basic Path object which uses OMC as backend. The connection to OMC is provided via a
274322 OMCSessionZMQ session object.
@@ -286,27 +334,27 @@ def with_segments(self, *pathsegments):
286334 """
287335 return type (self )(* pathsegments , session = self ._session )
288336
289- def is_file (self ) -> bool :
337+ def is_file (self , * , follow_symlinks = True ) :
290338 """
291339 Check if the path is a regular file.
292340 """
293341 return self ._session .sendExpression (f'regularFileExists("{ self .as_posix ()} ")' )
294342
295- def is_dir (self ) -> bool :
343+ def is_dir (self , * , follow_symlinks = True ) :
296344 """
297345 Check if the path is a directory.
298346 """
299347 return self ._session .sendExpression (f'directoryExists("{ self .as_posix ()} ")' )
300348
301- def read_text (self , encoding = None , errors = None ) -> str :
349+ def read_text (self , encoding = None , errors = None , newline = None ) :
302350 """
303351 Read the content of the file represented by this path as text.
304352
305353 The additional arguments `encoding` and `errors` are only defined for compatibility with Path() definitions.
306354 """
307355 return self ._session .sendExpression (f'readFile("{ self .as_posix ()} ")' )
308356
309- def write_text (self , data : str , encoding = None , errors = None , newline = None ) -> bool :
357+ def write_text (self , data : str , encoding = None , errors = None , newline = None ):
310358 """
311359 Write text data to the file represented by this path.
312360
@@ -335,9 +383,9 @@ def cwd(self):
335383 Returns the current working directory as an OMCPath object.
336384 """
337385 cwd_str = self ._session .sendExpression ('cd()' )
338- return OMCPath (cwd_str , session = self ._session )
386+ return self . __class__ (cwd_str , session = self ._session )
339387
340- def unlink (self , missing_ok : bool = False ) -> bool :
388+ def unlink (self , missing_ok : bool = False ):
341389 """
342390 Unlink (delete) the file or directory represented by this path.
343391 """
@@ -346,7 +394,7 @@ def unlink(self, missing_ok: bool = False) -> bool:
346394 raise FileNotFoundError (f"Cannot delete file { self .as_posix ()} - it does not exists!" )
347395 return res
348396
349- def resolve (self , strict : bool = False ) -> OMCPath :
397+ def resolve (self , strict : bool = False ):
350398 """
351399 Resolve the path to an absolute path. This is done based on available OMC functions.
352400 """
@@ -386,14 +434,14 @@ def _omc_resolve(self, pathstr: str) -> OMCPath:
386434
387435 return omcpath_resolved
388436
389- def absolute (self ) -> OMCPath :
437+ def absolute (self ):
390438 """
391439 Resolve the path to an absolute path. This is done by calling resolve() as it is the best we can do
392440 using OMC functions.
393441 """
394442 return self .resolve (strict = True )
395443
396- def exists (self ) -> bool :
444+ def exists (self , * , follow_symlinks = True ) :
397445 """
398446 Semi replacement for pathlib.Path.exists().
399447 """
@@ -413,22 +461,39 @@ def size(self) -> int:
413461 raise OMCSessionException (f"Error reading file size for path { self .as_posix ()} !" )
414462
415463
416- if sys .version_info < (3 , 12 ):
417- warnings .warn (
418- message = "Python < 3.12 - using a limited compatibility class as OMCPath replacement." ,
419- category = DeprecationWarning ,
420- stacklevel = 1 ,
421- )
464+ class OMCPathLocal (OMCPath , pathlib .Path ):
465+ """
466+ Compatibility class for OMCPath in Python < 3.12. This allows to run all code which uses OMCPath (mainly
467+ ModelicaSystem) on these Python versions. There is one remaining limitation: only OMCProcessLocal will work as
468+ OMCPathCompatibility is based on the standard pathlib.Path implementation.
469+ """
470+
471+ # modified copy of pathlib.Path.__new__() definition
472+ def __new__ (cls , * args , ** kwargs ):
473+ logger .warning ("Python < 3.12 - using a limited version of class OMCPath." )
474+
475+ if cls is OMCPathLocal :
476+ cls = OMCPathLocalWindows if os .name == 'nt' else OMCPathLocalPosix
477+ # noinspection PyUnresolvedReferences
478+ self = cls ._from_parts (args )
479+ if not self ._flavour .is_supported :
480+ raise NotImplementedError ("cannot instantiate %r on your system"
481+ % (cls .__name__ ,))
482+ return self
483+
484+ def size (self ) -> int :
485+ """
486+ Needed compatibility function to have the same interface as OMCPathReal
487+ """
488+ return self .stat ().st_size
422489
423- class OMCPathCompatibility (pathlib .PosixPath ):
424490
425- def size ( self ) -> int :
426- return self . stat (). st_size
491+ class OMCPathLocalPosix ( pathlib . PosixPath , OMCPathLocal ) :
492+ pass
427493
428- OMCPath = OMCPathCompatibility # noqa: F811
429494
430- else :
431- OMCPath = OMCPathReal
495+ class OMCPathLocalWindows ( pathlib . WindowsPath , OMCPathLocal ) :
496+ pass
432497
433498
434499class OMCSessionZMQ :
@@ -490,21 +555,29 @@ def omcpath(self, *path) -> OMCPath:
490555 Create an OMCPath object based on the given path segments and the current OMC session.
491556 """
492557
493- # fallback solution for Python < 3.12; a modified pathlib.Path object is used as OMCPath replacement
558+ if isinstance (self .omc_process , OMCProcessLocal ):
559+ return OMCPathLocal (* path )
560+
494561 if sys .version_info < (3 , 12 ):
495- # noinspection PyArgumentList
496- return OMCPath (* path )
497- else :
498- return OMCPath (* path , session = self )
562+ raise OMCSessionException ("OMCPath for non-local usage is only supported for Python >= 3.12!" )
563+
564+ return OMCPathReal (* path , session = self )
499565
500- def omcpath_tempdir (self ) -> OMCPath :
566+ def omcpath_tempdir (self , tempdir_base : Optional [ OMCPath ] = None ) -> OMCPath :
501567 """
502- Get a temporary directory using OMC.
568+ Get a temporary directory using OMC. It is our own implementation as non-local usage relies on OMC to run all
569+ filesystem related access.
503570 """
504571 names = [str (uuid .uuid4 ()) for _ in range (100 )]
505572
506- tempdir_str = self .sendExpression ("getTempDirectoryPath()" )
507- tempdir_base = self .omcpath (tempdir_str )
573+ if tempdir_base is None :
574+ # shortcut for local usage
575+ if isinstance (self .omc_process , OMCProcessLocal ):
576+ tempdir_str = tempfile .gettempdir ()
577+ else :
578+ tempdir_str = self .sendExpression ("getTempDirectoryPath()" )
579+ tempdir_base = self .omcpath (tempdir_str )
580+
508581 tempdir : Optional [OMCPath ] = None
509582 for name in names :
510583 # create a unique temporary directory name
0 commit comments