44import functools
55import hashlib
66import inspect
7- import math # noqa
7+ import math # noqa: F401
88import os
9- import random # noqa
9+ import random # noqa: F401
10+ import shutil
1011import sys
1112import textwrap
1213import types
1718
1819import numpy as np
1920import numpy .ctypeslib as npct
20- from numpy import ndarray
2121
22- import parcels .rng as ParcelsRandom # noqa
23- from parcels import rng # noqa
22+ import parcels .rng as ParcelsRandom # noqa: F401
23+ from parcels import rng # noqa: F401
2424from parcels ._compat import MPI
2525from parcels .application_kernels .advection import (
2626 AdvectionAnalytical ,
@@ -76,19 +76,14 @@ def __init__(
7676 self .funcvars = funcvars
7777 self .funccode = funccode
7878 self .py_ast = py_ast
79- self .dyn_srcs = []
80- self .src_file = None
81- self .lib_file = None
82- self .log_file = None
79+ self .src_file : str | None = None
80+ self .lib_file : str | None = None
81+ self .log_file : str | None = None
8382 self .scipy_positionupdate_kernels_added = False
8483
8584 # Generate the kernel function and add the outer loop
8685 if self ._ptype .uses_jit :
87- src_file_or_files , self .lib_file , self .log_file = self .get_kernel_compile_files ()
88- if type (src_file_or_files ) in (list , dict , tuple , ndarray ):
89- self .dyn_srcs = src_file_or_files
90- else :
91- self .src_file = src_file_or_files
86+ self .src_file , self .lib_file , self .log_file = self .get_kernel_compile_files ()
9287
9388 def __del__ (self ):
9489 # Clean-up the in-memory dynamic linked libraries.
@@ -139,7 +134,10 @@ def remove_deleted(self, pset):
139134 pset .remove_indices (indices )
140135
141136 @abc .abstractmethod
142- def get_kernel_compile_files (self ): ...
137+ def get_kernel_compile_files (self ) -> tuple [str , str , str ]: ...
138+
139+ @abc .abstractmethod
140+ def remove_lib (self ) -> None : ...
143141
144142
145143class Kernel (BaseKernel ):
@@ -272,25 +270,7 @@ def __init__(
272270 c_include_str = self ._c_include
273271 self .ccode = loopgen .generate (self .funcname , self .field_args , self .const_args , kernel_ccode , c_include_str )
274272
275- src_file_or_files , self .lib_file , self .log_file = self .get_kernel_compile_files ()
276- if type (src_file_or_files ) in (list , dict , tuple , np .ndarray ):
277- self .dyn_srcs = src_file_or_files
278- else :
279- self .src_file = src_file_or_files
280-
281- def __del__ (self ):
282- # Clean-up the in-memory dynamic linked libraries.
283- # This is not really necessary, as these programs are not that large, but with the new random
284- # naming scheme which is required on Windows OS'es to deal with updates to a Parcels' kernel.
285- try :
286- self .remove_lib ()
287- except :
288- pass
289- self ._fieldset = None
290- self .field_args = None
291- self .const_args = None
292- self .funcvars = None
293- self .funccode = None
273+ self .src_file , self .lib_file , self .log_file = self .get_kernel_compile_files ()
294274
295275 @property
296276 def ptype (self ):
@@ -330,9 +310,9 @@ def Setcoords(particle, fieldset, time):
330310 particle .time = particle .time_nextloop
331311
332312 def Updatecoords (particle , fieldset , time ):
333- particle .lon_nextloop = particle .lon + particle_dlon # noqa
334- particle .lat_nextloop = particle .lat + particle_dlat # noqa
335- particle .depth_nextloop = particle .depth + particle_ddepth # noqa
313+ particle .lon_nextloop = particle .lon + particle_dlon # type: ignore[name-defined] # noqa
314+ particle .lat_nextloop = particle .lat + particle_dlat # type: ignore[name-defined] # noqa
315+ particle .depth_nextloop = particle .depth + particle_ddepth # type: ignore[name-defined] # noqa
336316 particle .time_nextloop = particle .time + particle .dt
337317
338318 self ._pyfunc = (Setcoords + self + Updatecoords )._pyfunc
@@ -412,29 +392,22 @@ def remove_lib(self):
412392 del self ._lib
413393 self ._lib = None
414394
415- all_files_array = []
416- if self .src_file is None :
417- if self .dyn_srcs is not None :
418- [all_files_array .append (fpath ) for fpath in self .dyn_srcs ]
419- else :
420- if self .src_file is not None :
421- all_files_array .append (self .src_file )
395+ all_files : list [str ] = []
396+ if self .src_file is not None :
397+ all_files .append (self .src_file )
422398 if self .log_file is not None :
423- all_files_array .append (self .log_file )
424- if self .lib_file is not None and all_files_array is not None and self . delete_cfiles is not None :
425- self .cleanup_remove_files (self .lib_file , all_files_array , self .delete_cfiles )
399+ all_files .append (self .log_file )
400+ if self .lib_file is not None :
401+ self .cleanup_remove_files (self .lib_file , all_files , self .delete_cfiles )
426402
427403 # If file already exists, pull new names. This is necessary on a Windows machine, because
428404 # Python's ctype does not deal in any sort of manner well with dynamic linked libraries on this OS.
429405 if self ._ptype .uses_jit :
430- src_file_or_files , self .lib_file , self .log_file = self .get_kernel_compile_files ()
431- if type (src_file_or_files ) in (list , dict , tuple , ndarray ):
432- self .dyn_srcs = src_file_or_files
433- else :
434- self .src_file = src_file_or_files
406+ self .src_file , self .lib_file , self .log_file = self .get_kernel_compile_files ()
435407
436408 def get_kernel_compile_files (self ):
437409 """Returns the correct src_file, lib_file, log_file for this kernel."""
410+ basename : str
438411 if MPI :
439412 mpi_comm = MPI .COMM_WORLD
440413 mpi_rank = mpi_comm .Get_rank ()
@@ -453,39 +426,26 @@ def get_kernel_compile_files(self):
453426 dyn_dir = get_cache_dir ()
454427 basename = f"{ cache_name } _0"
455428 lib_path = "lib" + basename
456- src_file_or_files = None
457- if type (basename ) in (list , dict , tuple , ndarray ):
458- src_file_or_files = ["" ] * len (basename )
459- for i , src_file in enumerate (basename ):
460- src_file_or_files [i ] = f"{ os .path .join (dyn_dir , src_file )} .c"
461- else :
462- src_file_or_files = f"{ os .path .join (dyn_dir , basename )} .c"
429+
430+ assert isinstance (basename , str )
431+
432+ src_file = f"{ os .path .join (dyn_dir , basename )} .c"
463433 lib_file = f"{ os .path .join (dyn_dir , lib_path )} .{ 'dll' if sys .platform == 'win32' else 'so' } "
464434 log_file = f"{ os .path .join (dyn_dir , basename )} .log"
465- return src_file_or_files , lib_file , log_file
435+ return src_file , lib_file , log_file
466436
467437 def compile (self , compiler ):
468438 """Writes kernel code to file and compiles it."""
469- all_files_array = []
470439 if self .src_file is None :
471- if self .dyn_srcs is not None :
472- for dyn_src in self .dyn_srcs :
473- with open (dyn_src , "w" ) as f :
474- f .write (self .ccode )
475- all_files_array .append (dyn_src )
476- compiler .compile (self .dyn_srcs , self .lib_file , self .log_file )
477- else :
478- if self .src_file is not None :
479- with open (self .src_file , "w" ) as f :
480- f .write (self .ccode )
481- if self .src_file is not None :
482- all_files_array .append (self .src_file )
483- compiler .compile (self .src_file , self .lib_file , self .log_file )
484- if len (all_files_array ) > 0 :
485- if self .delete_cfiles is False :
486- logger .info (f"Compiled { self .name } ==> { self .src_file } " )
487- if self .log_file is not None :
488- all_files_array .append (self .log_file )
440+ return
441+
442+ with open (self .src_file , "w" ) as f :
443+ f .write (self .ccode )
444+
445+ compiler .compile (self .src_file , self .lib_file , self .log_file )
446+
447+ if self .delete_cfiles is False :
448+ logger .info (f"Compiled { self .name } ==> { self .src_file } " )
489449
490450 def load_lib (self ):
491451 self ._lib = npct .load_library (self .lib_file , "." )
@@ -558,14 +518,22 @@ def from_list(cls, fieldset, ptype, pyfunc_list, *args, **kwargs):
558518 return functools .reduce (lambda x , y : x + y , pyfunc_list )
559519
560520 @staticmethod
561- def cleanup_remove_files (lib_file , all_files_array , delete_cfiles ):
562- if lib_file is not None :
563- if os .path .isfile (lib_file ): # and delete_cfiles
564- os .remove (lib_file )
565- if delete_cfiles :
566- for s in all_files_array :
567- if os .path .exists (s ):
568- os .remove (s )
521+ def cleanup_remove_files (lib_file : str | None , all_files : list [str ], delete_cfiles : bool ) -> None :
522+ if lib_file is None :
523+ return
524+
525+ # Remove compiled files
526+ if os .path .isfile (lib_file ):
527+ os .remove (lib_file )
528+
529+ macos_debugging_files = f"{ lib_file } .dSYM"
530+ if os .path .isdir (macos_debugging_files ):
531+ shutil .rmtree (macos_debugging_files )
532+
533+ if delete_cfiles :
534+ for s in all_files :
535+ if os .path .exists (s ):
536+ os .remove (s )
569537
570538 @staticmethod
571539 def cleanup_unload_lib (lib ):
0 commit comments