Stefanus A Haryono
email: stefanusah@smu.edu.sg

Ferdian Thung
email: ferdianthung@smu.edu.sg

David Lo
email: davidlo@smu.edu.sg

Julia Lawall
email: julia.lawall@inria.fr

Lingxiao Jiang
email: lxjiang@smu.edu.sg

MLCatchUp: Automated Update of Deprecated Machine-Learning APIs in Python

Keywords: Python, Program Transformation, Automatic Update, Deprecated API

Machine learning (ML) libraries are gaining vast popularity, especially in the Python programming language. Using the latest version of such libraries is recommended to ensure the best performance and security. When migrating to the latest version of a machine learning library, usages of deprecated APIs need to be updated, which is a time-consuming process. In this paper, we propose MLCatchUp, an automated API usage update tool for deprecated APIs of popular ML libraries written in Python. MLCatchUp automatically infers the required transformation to migrate usages of deprecated API through the differences between the deprecated and updated API signatures. MLCatchUp offers a readable transformation rule in the form of a domain specific language (DSL). We evaluate MLCatchUp using a dataset of 267 real-world Python code containing 551 usages of 68 distinct deprecated APIs, where MLCatchUp achieves 90.7% accuracy. A video demonstration of MLCatchUp is available at https://youtu.be/5NjOPNt5iaA.

I. INTRODUCTION

One factor behind the recent surge in popularity of machine learning (ML) is the availability of easy to use ML libraries, typically implemented in Python. However, similar to other libraries, Python ML libraries are also affected by API deprecations. The problem may even be more significant for Python ML libraries, as more popular libraries tend to see more evolution and thus have many deprecated APIs [START_REF] Xavier | Historical and impact analysis of API breaking changes: A large-scale study[END_REF], [START_REF] Li | Characterising deprecated Android APIs[END_REF]. Deprecation of APIs may occur with each update of the library. To use a new release of a library, updating usages of deprecated APIs is often required. However, the update can be cumbersome and time-consuming, and thus users may prefer to continue using the older version [START_REF] Wang | Exploring how deprecated Python library APIs are (not) handled[END_REF]- [START_REF] Sawant | On the reaction to deprecation of 25,357 clients of 4+1 popular Java APIs[END_REF]. The use of the older version, however, may expose the program to lower performance and to security issues [START_REF] Wang | Exploring how deprecated Python library APIs are (not) handled[END_REF], [START_REF] Kula | Do developers update their library dependencies?[END_REF]. Thus, a tool that supports the update of deprecated API usages is beneficial.

Several studies have attempted to automate updates process of deprecated API usages [START_REF] Lamothe | A4: Automatically assisting Android API migrations using code examples[END_REF]- [START_REF] Thung | Towards generating transformation rules without examples for Android API replacement[END_REF]. However, prior works mainly target Java programs, and no study has attempted to automate the update for Python deprecated API usages. Python has several unique features compared to Java: [START_REF] Xavier | Historical and impact analysis of API breaking changes: A large-scale study[END_REF] Python is dynamically-typed, compared to Java which is staticallytyped. In Python, variable types may change during code execution, and information regarding variable and function return types are typically unavailable. [START_REF] Li | Characterising deprecated Android APIs[END_REF] Python has two types of parameters, i.e., positional and keyword parameters, while Java only supports positional parameter. Python also supports parameter default values.

In this paper, we present MLCatchUp, an automated update tool for usages of deprecated APIs of popular Python ML libraries. MLCatchUp performs type inference by leveraging static analysis and deep learning tools [START_REF] Mir | Type4py: Deep similarity learning-based type inference for python[END_REF], [START_REF] Lehtosalo | Mypy -optional static typing for python[END_REF]. MLCatchUp also supports both positional and keyword parameters. Moreover, MLCatchUp does not require any update example for its update, only requiring the deprecated and updated API signatures to infer the required migration. This is a demonstration paper accompanying our full research paper [START_REF] Haryono | Characterization and automatic update of deprecated machine-learning API usages[END_REF].

MLCatchUp takes as input a pair of deprecated and updated API signatures, and a file containing deprecated API usages to be updated. The deprecated and updated API signatures are used to infer the transformation operations needed to migrate the usage of the deprecated API. The transformation operations obtained from this inference process are expressed in a DSL to facilitate understanding the transformation performed. ML-CatchUp automatically detects the specified deprecated API usages and applies the inferred transformation operations, updating the deprecated API usages within the code. MLCatchUp also leverages type inference, allowing it to determine variable types and function return types. To the best of our knowledge, we are the first to create an automated API usage update tool without update examples for Python.

We evaluated MLCatchUp using a test dataset of 267 realworld Python code files collected from Github public repositories. Each file contains one to five deprecated API usages, amounting to a total of 551 deprecated API usages. In this evaluation, MLCatchUp can detect 93.7% of the deprecated API usages without type inference. The addition of type inference improves MLCatchUp's deprecated API usage detection rate to 100%. MLCatchUp achieves an accuracy of 80.6% (i.e., it correctly updates 80.6% of the deprecated API usages). We conducted a qualitative analysis on the update result and found that there are context-dependent API migrations whose updates depend on the value of one or more arguments in the API. Thus, we enhance the capability of MLCatchUp to accept some constraints expressed using the DSL as additional user input. Using this additional input, MLCatchUp achieves an accuracy of 90.7%.

A. MLCatchUp Architecture

The architecture of MLCatchUp is shown in Fig. 1. ML-CatchUp has two main inputs: the input file to be updated (O-1) and the input API signatures for both a deprecated API and its replacement (O-2). The input file is parsed into an Abstract Syntax Tree (AST) using the built-in Python module. 1 Type inference is applied to the AST to determine the types of variables and method call return values. Then, MLCatchUp locates the deprecated API usages by comparing the fully qualified name of the method calls within the code to the deprecated API signature (S-1), resulting in the deprecated API usage locations (O-3).

MLCatchUp uses the input API signatures in the transformation inference process (S-2). The inferred transformations are in the form of DSL commands (O-4) which contain a series of operations that will be performed sequentially for the update (e.g., rename a method, rename a parameter, etc.). The DSL is then parsed into a list of operations to be executed by MLCatchUp. These operations are applied to the deprecated API usage locations (S-3), producing the updated AST (O-5).

The updated AST is then compared with the input file AST to check for code differences between the two. Any found code differences are then applied to the input Python file (S-4) by making only the necessary changes to the API usages without any modification to the original code comments and spacing. This results in the updated input file (O-6). We next further describe the main components of MLCatchUp.

B. MLCatchUp Transformation Operations

The transformation operations provided by MLCatchUp are based on an empirical study of 112 deprecated APIs and their replacements from the last two years of releases of Scikit-learn, PyTorch, and Tensorflow [START_REF] Haryono | Characterization and automatic update of deprecated machine-learning API usages[END_REF]. The transformation operations that are supported by MLCatchUp are: (1) rename a method; (2) rename a parameter; (3) remove a parameter; (4) convert a positional to a keyword parameter;

(5) add a parameter; (6) change a parameter type; [START_REF] Sawant | On the reaction to deprecation of 25,357 clients of 4+1 popular Java APIs[END_REF] add a constraint to a parameter value; and (8) remove API. Further details about the transformation operations are found in our full research paper [START_REF] Haryono | Characterization and automatic update of deprecated machine-learning API usages[END_REF].

1 https://docs.python.org/3/library/ast.html

C. MLCatchUp Transformation Inference

MLCatchUp automatically infers the required transformations for API usage update based on the difference between the deprecated and updated API signatures. We define an API signature as the fully qualified name of the API (i.e. the API's module and function name) and the list of parameters available for the API, where each parameter consists of the parameter name and an optional default value. Given a pair of deprecated and updated API signatures, MLCatchUp performs a sequence of comparisons, including a comparison of the API names, and comparisons of their parameter names, positions, types, and default values. These comparisons will produce the required transformation operations for the API update.

D. Additional Input Constraint

While MLCatchUp can automatically infer the required transformation from the deprecated and updated API signatures, it cannot infer the transformation constraints that are needed in context-dependent deprecated API updates (i.e., the update may differ according to the values of the deprecated API arguments), as such constraints are not provided in the API signature. To mitigate this problem, MLCatchUp accepts an additional input in the form of transformation constraints expressed in the DSL. This can be done by manually editing the inferred update DSL script (O-4) created by the transformation inference process, and adding the required constraints (See Section IV-B for a usage example).

E. Type Inference

MLCatchUp uses type inference to determine variable types and the return types of method calls. This type information is used to replace the variable or the method name used in an API invocation to determine the API's fully qualified name. The type inference is implemented using PEP (Python Enhancement Proposal) 484,2 that provides type hints and annotations for Python code. For this purpose, MLCatchUp use Mypy [START_REF] Lehtosalo | Mypy -optional static typing for python[END_REF], a static type checker for Python that uses the PEP 484 type hints. Mypy's APIs are used to analyze MLCatchUp's input code, collecting variable and method types by searching for type annotations from the imported library. The collected types are used to replace the variables and method calls during the deprecated API usage detection.

To further enhance MLCatchUp's type inference functionality for libraries that do not provide type annotations, we also use deep learning-based type inference [START_REF] Mir | Type4py: Deep similarity learning-based type inference for python[END_REF]. A neural model is trained using hierarchical neural network (HNN) with a dataset of 4,910 Python projects. From the Python source code files, type hints (i.e., information helpful in predicting types) are extracted. These type hints consist of information taken from the function (function name, function arguments) and the code context (return statement, function argument usages). To enable the model to learn from the type hints, the Word2Vec [START_REF] Mikolov | Distributed representations of words and phrases and their compositionality[END_REF] word embedding is used. After the neural model is trained, the Triplet Loss function is used to create type clusters, where each cluster represents a similar type. These type clusters are used for type prediction. Given a method signature as an input, the model will extract the type hints and create the feature embedding. Then, KNN (k-nearest neighbor) search is used to determine which type is the closest to the given embedding. The predicted type is then used by MLCatchUp in the same way as the types inferred using Mypy.

III. EVALUATION

A. Dataset and Experiment Settings

We evaluated MLCatchUp on a dataset of 267 files containing 551 deprecated ML API usages in Python from GitHub repositories. They are comprised of 68 different deprecated APIs from Scikit-learn, PyTorch, Tensorflow, Numpy, and Spacy. For each deprecated API, we randomly collected at most five files. We consider two metrics in this evaluation: (1) detection rate (i.e., the number of detected deprecated API usages divided by the ground truth number of deprecated API usages) and (2) update accuracy (i.e., the number of correct updates produced by MLCatchUp compared to the ground truth number of deprecated API usages). We use automated and manual analysis to determine the correctness of the updated code. In the automated analysis, we check the validity of the updated code syntax by compiling it using the Python built-in py compile module. 3 In the manual analysis, we employed the help of three Python programmers with four years of experience to label if the updated code is correct. These programmers are not authors of this paper and were given instructions and training prior to the labelling process. If labelling disagreement occurred, a discussion was conducted.

B. Evaluation Result

The detection rate experiment results are shown in Table I

IV. USAGE EXAMPLE

MLCatchUp can be used by both library users and developers via a command line interface (CLI). To update usages of a deprecated API, a user needs to provide the deprecated and updated API signatures, along with the code that needs to be updated. MLCatchUp's update process consists of two steps: The command instructs MLCatchUp to infer the required transformation for migrating a deprecated tensorflow. compat.v1.to_float() API usage. MLCatchUp detects that the two API signatures have different method names and an addition of API parameter in the updated API signature, thus a rename_method and an add_parameter operations are added. The added parameter value for the 3 We use the DSL file to instruct MLCatchUp to transform the code shown in Fig. 2; we use the following command: This command instructs MLCatchUp to apply the transformation specified in the DSL. The DSL script is parsed into its corresponding operations, comprising a rename_method operation and an add_parameter operation. Both operations are applied to each instance of a tensorflow.compat.v1.to_float API invocation, migrating them to use the tensorflow.cast API with the addition of a dtype=tensorflow.float32 parameter. Fig. 3 highlights the code differences between the input and updated code. In line 2, an import statement is added for the tensorflow.cast updated API. In lines 9-10 and 11-15, the deprecated API usages are updated to use the newly imported tensorflow.cast API invocation with the addition of the dtype=tensorflow.float32 parameter.

B. Scenario II -Context-dependent API Migration

As MLCatchUp is unable to automatically infer the required transformation constraints for context-dependent deprecated API migration, the user needs to manually add this information into the inferred DSL script. Consider the migration of usages of the deprecated API sklearn.model_selection.K-Fold that needs to be updated with an add_parameter operation only if the value of random_state argument is not None. The input for the transformation inference process is as follows: V. RELATED WORK Several works have attempted to automate the update of deprecated API usages. Diff-CatchUp [START_REF] Xing | API-evolution support with Diff-CatchUp[END_REF] is a classic work that automatically detects API changes in the library, infers possible replacements, and identifies possible examples on how to migrate the changed APIs from the library's code base. Diff-CatchUp however does not produce a transformation script or come with a transformation engine that can automatically update occurrences of broken API usages in a client code base. Rather, developers need to manually perform the transformations based on the examples and information produced by Diff-CatchUp. A4 [START_REF] Lamothe | A4: Automatically assisting Android API migrations using code examples[END_REF] automatically assists Android API migrations by learning API migration patterns from code examples. AppEvolve [START_REF] Fazzini | Automated API-usage update for Android apps[END_REF] automates API-usage update for Android, creating patches from before-and after-update code examples. CocciEvolve [START_REF] Haryono | Automatic Android deprecated-API usage update by learning from single updated example[END_REF] infers a readable transformation in the form of the semantic patch language (SmPL) [START_REF] Padioleau | SmPL: A domain-specific language for specifying collateral evolutions in Linux device drivers[END_REF] using only a single after-update code example. NEAT [START_REF] Thung | Towards generating transformation rules without examples for Android API replacement[END_REF] generates transformation rules for deprecated Android API usage migrations without any update example. REFAZER [START_REF] Rolim | Learning syntactic program transformations from examples[END_REF] synthesizes program transformations for Python code by inductive programming using input-output examples. T2R [START_REF] Ketkar | Type migration in ultra-large-scale codebases[END_REF] performs automatic type migration for Java code to help fix API-breaking changes in evolving codebases. No work has been done on the automated migration of Python deprecated APIs. MLCatchUp offers automated migration of Python deprecated API usages without any update example. MLCatchUp does not require the source code of the APIs' library, as it only needs the deprecated and updated API signatures to infer the required update. MLCatchUp also addresses Python's unique features such as dynamic-typing through type-inference using a combination of static analysis and deep learning.

VI. CONCLUSION AND FUTURE WORK

In this paper, we present MLCatchUp, a tool that automates the update of usages of deprecated APIs of popular Python ML libraries. MLCatchUp automatically infers the required transformation from the differences between the deprecated and updated API signatures, and presents the operations in the form of a DSL. MLCatchUp is built with type inference, allowing it to determine variables and function return types. We have evaluated the performance of MLCatchUp and demonstrated that it achieves 100% deprecated API usages detection rate with type inference. We have also evaluated the update accuracy of MLCatchUp, where it achieves an accuracy of 80.6% without user-provided transformation constraints, and an accuracy of 90.7% with the addition of such constraints. We promote MLCatchUp as a tool that can be used by both library users and developers to automate the process of updating deprecated API usages. The implementation of MLCatchUp is available at https://github.com/soarsmu/MLCatchUp.

Fig. 1 .

 1 Fig. 1. MLCatchUp Architecture II. DESIGN AND IMPLEMENTATION

1 )-output <output_filepath> 2 )

 12 Transformation inference is used to infer and output the required DSL script from the API signatures. MLCatchUp's CLI takes the command line argument --infer to specify the transformation inference mode, and --output to indicate the path for the output file to contain the produced DSL script. The format of this command is as follows: python MLCatchUp.py --infer <deprecated_api_signature> <updated_api_signature> -Transformation application is used to parse the DSL script and apply the transformation to an input file. MLCatchUp's CLI takes the command line arguments --transform to specify the transformation application mode, --dsl to indicate the path to the file containing the DSL script, --input to indicate the file to be updated, and --output to indicate the output file where the updated code is written. The format of this command is: python MLCatchUp.py --transform --dsl <dsl_script_filepath> --input <deprecated_filepath> --output <output_filepath> A. Scenario I -Basic Transformation Consider the tensorflow.compat.v1.to_float deprecated API usages given in lines 6 and 7 of Fig. 2. The deprecated API needs to be updated into an invocation of tensorflow.cast with an addition of a dtype=tensor flow.float32 parameter. The command used for the transformation inference process is: python MLCatchUp.py --infer tensorflow.compat.v1.to_float() tensorflow.cast(dtype=tensorflow.float32) --output out.dsl

  python MLCatchUp.py --transform --dsl out.dsl --input main.py --output updated.py

  While the above script provides the desired transformation operation, the required transformation constraint is not present. We can fix it by adding a constraint to the inferred DSL script:

	python MLCatchUp.py --infer sklearn.model_selection.KFold()
	sklearn.model_selection.KFold(shuffle=True)
	--output out.dsl
	This transformation inference results in this DSL script:
	add_parameter shuffle with_value True for
	sklearn.model_selection.KFold

add_parameter shuffle with_value True for sklearn. model_selection.KFold if random_state has_value != None

https://www.python.org/dev/peps/pep-0484/

Acknowledgement. This research is supported by the Singapore National Research Foundation (award number: NRF2016-NRF-ANR003) and the ANR ITrans project.


Stefanus A Haryono
email: stefanusah@smu.edu.sg

Ferdian Thung
email: ferdianthung@smu.edu.sg

David Lo
email: davidlo@smu.edu.sg

Julia Lawall
email: julia.lawall@inria.fr

Lingxiao Jiang
email: lxjiang@smu.edu.sg

Characterization and Automatic Updates of Deprecated Machine-Learning API Usages

Keywords: Python, Program Transformation, Automatic Update, Deprecated API

Due to the rise of AI applications, machine learning (ML) libraries, often written in Python, have become far more accessible. ML libraries tend to be updated periodically, which may deprecate existing APIs, making it necessary for application developers to update their usages. In this paper, we build a tool to automate deprecated API usage updates. We first present an empirical study to better understand how updates of deprecated ML API usages in Python can be done. The study involves a dataset of 112 deprecated APIs from Scikit-Learn, TensorFlow, and PyTorch. Guided by the findings of our empirical study, we propose MLCatchUp, a tool to automate the updates of Python deprecated API usages, that automatically infers the API migration transformation through comparison of the deprecated and updated API signatures. These transformations are expressed in a Domain Specific Language (DSL). We evaluate MLCatchUp using a dataset containing 267 files with 551 API usages that we collected from public GitHub repositories. In our dataset, MLCatchUp can detect deprecated API usages with perfect accuracy, and update them correctly for 80.6% of the cases. We further improve the accuracy of MLCatchUp in performing updates by adding a feature that allows it to accept an additional user input that specifies the transformation constraints in the DSL for context-dependent API migration. Using this addition, MLCatchUp can make correct updates for 90.7% of the cases.

I. INTRODUCTION

The popularity of machine learning (ML) has surged in recent years. Currently, the most popular programming language for ML is Python, due to the many Python libraries that support and provide ML capabilities via a set of Application Programming Interface methods (simply referred to as APIs). Applications (a.k.a. client code of the libraries) can then access the library functionality via these APIs. Libraries are typically updated to add new features, fix bugs, or improve performance. With each new update, changes in the library's API are inevitable, which may include API deprecation. API deprecation typically affects API methods, rendering them obsolete and requiring client code to be modified to invoke the updated API methods to ensure that the code works with the new version of the library (hereafter, we refer to a deprecated API method as a deprecated API).

Using the latest version of the ML library is important for the performance and security of the library client [START_REF] Han | An empirical study of the dependency networks of deep learning libraries[END_REF], [START_REF] Wang | Exploring how deprecated Python library APIs are (not) handled[END_REF]. Yet, updating usages of deprecated APIs can be cumbersome, causing many developers to stick to an older version despite the performance issue and security risk [START_REF] Han | An empirical study of the dependency networks of deep learning libraries[END_REF]- [START_REF] Kula | Do developers update their library dependencies?[END_REF]. Hence, providing a better alternative to manually updating the usages of Python deprecated ML library APIs can benefit many developers.

In this work, we first conduct an empirical study to ascertain the level of innovation needed in the automatic update of ML libraries deprecated API usages and then design a solution to address the problem. We conduct our empirical study on three popular Python ML libraries, namely Scikit-Learn, Ten-sorFlow, and PyTorch, by analyzing their API deprecations. Through this empirical study, we aim to discover deprecated API migration characteristics of popular Python ML libraries in multiple dimensions, i.e., the update operation in the API migration, the API migration mapping, and the API migration context dependency. For each dimension, we define some categories of deprecated API migrations. While the result of our study may also be applicable to other non-ML Python libraries, we purposely focus on the ML domain due to the rise of ML systems [START_REF] Amershi | Software engineering for machine learning: A case study[END_REF], [START_REF] Khomh | Software engineering for machine-learning applications: The road ahead[END_REF] and ML libraries popularity.

Based on the findings in the empirical study, we propose a tool to automate the update of Python deprecated API usages called MLCatchUp. MLCatchUp takes as input the deprecated API signature, the updated API signature, and the file to be updated. It then automatically infers the required transformation by comparing the deprecated and updated APIs' signatures. The inferred transformations are expressed in the form of a Domain Specific Language (DSL) that can be easily understandable by MLCatchUp's users. We design this DSL based on the results of our empirical study.

Prior to this study, several attempts have been made to automate the update of deprecated API usages in other programming languages [START_REF] Lamothe | A4: Automatically assisting Android API migrations using code examples[END_REF]- [START_REF] Thung | Towards generating transformation rules without examples for Android API replacement[END_REF]. However, prior works primarily target Java programs, and none has targeted API deprecation in Python. Python has several unique features as compared to Java: it is a dynamically-typed language, it has two types of parameters (positional and keyword parameters), it offers parameter default values, etc. In particular, being a dynamically-typed language poses the following problems:

(1) Variable types may change during code execution; [START_REF] Wang | Exploring how deprecated Python library APIs are (not) handled[END_REF] Information regarding variable types and function return types are typically unavailable. These problems render analysis and Consider the Python code snippet shown in Figure 1. In this code snippet, the variable data is first initialized as a list in line 2. In line 5, this data variable is used as a parameter to the torch.tensor API, which returns a torch.Tensor object. This torch.Tensor object is assigned into the data variable, changing the variable type. This data variable is then used to invoke the torch.Tensor.mul in line 7. If a tool cannot correctly determine that the type of the data variable in line 7 is torch.Tensor object, it would also not be able to determine that the data.mul method call used in line 7 is a torch.Tensor.mul API invocation. To address this problem, MLCatchUp is built with type inference functionality, leveraging state-of-the-art static analysis and deep learning tools [START_REF] Mir | Type4py: Deep similarity learning-based type inference for python[END_REF], [START_REF] Lehtosalo | Mypy -optional static typing for python[END_REF].

We have evaluated MLCatchUp on a dataset of 267 files containing 551 deprecated API usages involving 68 Python ML library APIs. Based on this evaluation, MLCatchUp can detect 93.7% of deprecated API usages without type inference. With the addition of type inference, it can detect deprecated API usages in all the cases, while it can perform correct updates 80.6% of all cases (accuracy of 80.6%). We have also conducted a qualitative study on the failed update results, where we found that one of the limitations of MLCatchUp is its inability to infer transformation constraints for contextdependent migrations, i.e., API migrations that depend on the value and type of the arguments used. To address this problem, we add a feature into MLCatchUp to accept such transformation constraints as an additional user input. With this feature, MLCatchUp achieved 90.7% accuracy.

In summary, the main contributions of this work are:

• We perform an empirical study on deprecated API usage migrations for popular Python ML libraries (Scikit-Learn, TensorFlow, and PyTorch), and characterize them in several dimensions. • We create MLCatchUp, an automated Python API usage update tool with type inference that can infer the required API transformation automatically. To the best of our knowledge, this is the first such tool for Python. We design our tool to support the main migration characteristics of ML libraries that we identified in our empirical study.

II. EMPIRICAL STUDY

Through this study, we seek to get a better understanding of the characteristics of deprecated API migrations of Python ML libraries. Using findings of this study, we aim to create a tool to automate the update deprecated Python ML API usages. As highlighted in Section I, our goal is not to create a tool that supports all kinds of Python API migrations, but rather those that frequently appear for popular Python ML libraries.

A. Research Questions

Our empirical study analyzes the API migration characteristics of Python ML libraries, answering the following questions:

B. Data Collection

For our study, we picked a subset of the available Python ML libraries based on the number of GitHub repositories that depend on the libraries (obtained through GitHub dependency graph 1 ). As of August 2020, more than 120,000 repositories utilize Scikit-Learn, while more than 82,000 repositories use Tensorflow. Keras and Pytorch are used by at least 52,000 and 34,000 repositories, respectively. However, since Keras is included in TensorFlow since January 2017, 2 we picked Scikit-Learn, TensorFlow, and PyTorch as the subjects of our study.

Currently, there is no standard for deprecating ML library APIs. Thus, we collected the API deprecations by manually reading the change log of each library. We focused on looking for text or API methods that are marked with the word "deprecat-" and "replace-" in the change log, which indicates API deprecation or replacement. For Scikit-Learn, the change log is available in their official documentation page. 3 For PyTorch 4 and TensorFlow,5 the change log can be found in their GitHub release note. We limit our manual collection to the change logs of major and minor release versions between July 2018 and August 2020. From the documentation, we found a total of 112 pairs of deprecated APIs and their updated APIs, distributed across the libraries as shown in Table I.

C. RQ1: Deprecated API Migration Characteristics

In this research question, we aim to identify different categories (types) of API migrations considering different dimensions. We utilized thematic analysis, which is a qualitative data analysis method for systematically identifying, organizing, and offering insight into patterns or themes across a dataset [START_REF] Braun | Using thematic analysis in psychology[END_REF], [START_REF] Cruzes | Recommended steps for thematic synthesis in software engineering[END_REF]. In this process, we first familiarize ourselves with the data by thoroughly reading and analyzing the deprecated and updated signatures of the 112 deprecated APIs, as well as additional information from various documentation. We also investigate how the migrations from the deprecated to the updated APIs can be done. Next, in multiple iterations, we identify categories of migrations, across multiple dimensions.

Our thematic analysis identifies many categories (types) of API migrations that can be put in three dimensions. The first dimension (D1) is related to the update operation required to perform the migration. The second one (D2) relates to the degree of relationship (e.g., 1-to-1, etc.) between the deprecated and updated APIs. And the last one (D3) relates to the context dependence of the migration. The definitions of these dimensions and their categories are: D1: Update Operation. We observe common patterns in the updates required to migrate a deprecated API to its updated APIs by looking at the differences between the signatures of the two APIs. We find the following categories:

• Remove a parameter: This operation removes the deprecated API usage function parameter(s). If the deprecated parameter is not removed, it will result in a TypeError, as the parameter no longer exists. 3 provides an example of this operation for a usage of the sklearn.utils.estimator_checks.check_estimator deprecated API. In this example, the allowed parameter type in the updated API is changed to only the Estimator type. To ensure that the argument type match the type requirement of the updated API, a type check is added for the function invocation argument (lines 5-8). • Add a constraint to a parameter value: This operation adds a constraint to the value of the API parameter due to a change in the permitted values of the parameter. The API argument's value is checked to ensure that the value fits the newly permitted range of values. If the argument's value does not fit, we need to modify its value accordingly. An example of this update operation is shown in Figure 4 for the torch.normal deprecated API. In this example, the value of the out argument must have the same size as the mean and std arguments. To update the usage of this deprecated API, we add an if statement that checks the sizes of these objects (line 4-5). without replacing its usage with any updated API. This is typically used when the deprecated API is no longer needed or no longer has any effect when invoked.

D2: API Mapping. This dimension represents the ratio between the number of the deprecated and updated APIs involved in the migration. We found three types of mappings:

• 1:1 API mapping: A deprecated API is modified or replaced by a single updated API. • 1:N API mapping: A deprecated API is modified or replaced by at least two updated APIs. • 1:0 API mapping: A deprecated API is removed without any suggested replacement.

D3: Context Dependency. This dimension indicates whether the deprecated API migration depends on the context of the deprecated API usage. This context refers to the value and type of the arguments in the deprecated API usage. We found two categories of context dependency.

• A context-dependent update: An API migration that depends on the value of one or more arguments of the API invocation. For example, the sklearn.model_selection.KFold API is only deprecated if the random_state argument is not None, in which case the shuffle argument must be set to True. Otherwise, there is no change to the API. For example, in Figure 5, the update is done by adding an if statement that checks the value of the contextual variable seed used as the random_state argument. • A context-independent update: An API migration that is not affected by the value of the API invocation arguments.

D. RQ2: Distribution of Migration Categories (Types)

In the second research question, we are interested in the distribution of deprecated API migration categories within the dimensions defined in Section II-C: update operation, API mapping, and context dependency. We labeled each of the 112 APIs based on the categories, across the 3 dimensions.

First, we label the APIs based on the update operation. Table II shows the result of this labeling. We found that most deprecated API migrations in Scikit-Learn involve removing a parameter. PyTorch and TensorFlow deprecated API migrations mainly rename methods. TensorFlow API migrations often rename parameters. Among the operations, change parameter type, add constraint to parameter value, and remove API are the least commonly used, amounting to 5 or fewer APIs for each update operation. Note that some API From these distributions within the three dimensions, we found that simpler updates are prevalent among different Python ML libraries. Rename method, rename parameter, add parameter, and remove parameter are the most commonly used, each being observed in the migrations of at least 10 APIs deprecated APIs. 107 out of 112 APIs follow the 1:1 update mapping. Finally, the majority of API updates are contextindependent, which accounts for 103 out of 112 APIs. We leverage these findings to guide our priorities in creating an automated update tool for Python ML deprecated API usage.

III. AUTOMATED UPDATE FOR PYTHON DEPRECATED API USAGES

We incorporate the findings of our empirical study in creating an automated update tool for Python deprecated APIs, mainly to direct the types of transformations that the tool should support. We create MLCatchUp, a tool that provides automated updates for Python deprecated API usages. ML-CatchUp infers the required transformations for the update by comparing the difference between the deprecated API Fig. 6: MLCatchUp Architecture signature and the updated API signature. Using these API signatures and the code containing the usage of deprecated API as an input, MLCatchUp will automatically provide a new version of the code where all usages of the specified deprecated APIs are replaced with their corresponding updated APIs. During the transformation process, MLCatchUp utilizes a domain specific language to make its transformation more readable for users. MLCatchUp also utilizes type inference to mitigate the problem of dynamic typing that we highlighted in Section In we discuss in detail the architecture and features of MLCatchUp.

A. MLCatchUp Architecture

The architecture and pipeline of MLCatchUp are shown in Figure 6. There are two main inputs to MLCatchUp, namely the input Python file (O-1), and the input API signatures (O-3). The input Python file is the file that is going to be updated, while the input API signatures are the deprecated API signature and the updated API signature. The input Python file is transformed into its AST using the abstract syntax tree module provided by Python 6 for easier transformation. From the AST, MLCatchUp uses type inference to determine the types of variables, and the types of method call return values. Then, the deprecated API usages are located by comparing the fully qualified name of the method calls within the code to the deprecated API signature (S-1). This process results in the deprecated API usage locations (O-2).

Input API signatures are used in the transformation inference process (S-2). The transformations are in the form of DSL commands (O-4), containing a series of atomic operations required for the update (e.g. rename method, rename parameter, etc.) which are to be performed sequentially. The DSL is then parsed into a list of operations that can be executed by MLCatchUp. These operations are applied to the deprecated API usage locations (S-3), producing the updated AST (O-5).

The updated AST is then compared with the input file AST to check for code differences between the two ASTs. The code differences are then applied to the input Python file (S-4) by making only the necessary changes to the API usages without any modification to the original code comments and spacing. This results in the updated input file (O-6).

In the following subsections, we present the main components of the MLCatchUp automated update process. 6 https://docs.python.org/3/library/ast.html

B. Transformation Operations and DSL

MLCatchUp supports the 8 update operations identified in our empirical study. Each operation is paired with its corresponding construct in the DSL to describe the transformation. The required transformation operations for each API migration are inferred automatically, as we will discuss in Section III-C. The inference process produces a DSL script that specifies all the required transformations between a pair of deprecated and updated APIs. The grammar of the DSL can be accessed from our (anonymous) online appendix: https://doi.org/10.6084/m9.figshare.14525136.v3.

Each transformation listed in the DSL grammar corresponds to a basic transformation operation provided by MLCatchUp. The mapping between each basic transformation operation and its DSL grammar is shown in Table V.

C. Transformation Inference

MLCatchUp automatically infers the required change to update the usage of the deprecated API using the deprecated and updated API signatures as its inputs. Based on these signatures, MLCatchUp produces DSL commands representing the steps to update code containing deprecated API usages.

We define an API signature as the fully qualified name of the API and the list of parameters available for the API, where each parameter consists of the parameter name and an optional default value. A fully qualified API name consists of the API module name and the API function name. This information is sufficient as Python does not provide method overloading. The API parameter definition is declared in a comma separated list of positional and keyword parameters.

The difference between the deprecated and the updated API signature is used to automatically infer the required transformation for the API usage update. The pseudocode of the transformation inference is shown in Algorithm 1. Using these deprecated and updated API signatures, several steps are done to produce the DSL commands to update the deprecated API usage. First, if the updated API signature is an empty string, we add a remove_api operation (lines 2-3). If the updated API signature is not empty, we compare the fully qualified name (line 5) of the deprecated and updated API signature, then add a rename_method operation if the names differ (line 6). Then, we eliminate identical API parameters from both API signatures (line 8), as the same parameters between the two APIs will not affect the API update. Two API parameters are considered identical if they have the same name and position. After removing identical parameters, we compare the remaining API parameters from the two API signatures. Two possible actions are taken during this comparison. First, if two API parameters have the same position but different keyword names, we add a rename_parameter operation into the DSL (lines 11-14). Second, if two API parameters have the same name, but one is a positional parameter in the deprecated API signature and the other is a keyword parameter in the updated API signature, we add a positi-onal_to_keyword_parameter operation (lines [START_REF] Zhou | API deprecation: a retrospective analysis and detection method for code examples on the web[END_REF][START_REF] Brito | On the use of replacement messages in API deprecation: An empirical study[END_REF][START_REF] Sawant | Why are features deprecated? an investigation into the motivation behind deprecation[END_REF][START_REF] Sawant | On the reaction to deprecation of 25,357 clients of 4+1 popular Java APIs[END_REF]. Then, we check whether there are any remaining API parameters in the deprecated and the updated API signatures. Each of the remaining API parameters in the deprecated API signature is added as a remove_parameter operation into the DSL commands (lines 19-21). Finally, for each remaining API parameter in the updated API signature, we add an add_parameter operation (lines 22-24).

To illustrate, consider the tensorflow.compat.v1.to _float() deprecated API. This API usage needs to be updated to use the tensorflow.cast(dtype=tensorflow.float32) API. MLCatchUp infers the transformation as follows. First, MLCatchUp finds a difference between the fully qualified name of the deprecated API and the fully qualified name of the updated API, and thus a rename_method operation is added. Then, MLCatchUp finds that there are no identical parameters between the two API signatures, leaving only a single API parameter in the updated API signature. This parameter is added as These DSL commands can be applied to files using the deprecated tensorflow.compat.v1.to_float() API. First, the file is parsed into its AST. Then, each DSL command is parsed and translated into the corresponding transformation that is applied to the AST. After the transformations are applied, the AST is changed back into code, which is then compared with the deprecated code. Based on the code differences, MLCatchUp applies the transformation to the original code, making only the necessary changes towards the deprecated API usages, retaining the comments and spacing of the original code. An example result of the update is shown in the code diff in Figure 8.

While MLCatchUp can infer the required transformation operations, MLCatchUp is unable to infer the required information regarding any added constraints for the transformation itself. Indeed the API signatures do not provide such information. To mitigate this problem, we allow MLCatchUp to be run with an optional argument in which the user can specify the transformation constraint as an input. This input constraint must be written using the MLCatchUp DSL. An example of the inferred DSL script and the provided input constraint for the sklearn.model_selection.KFold API update is shown in Figure 9.

In Figure 9, we see that from the API signatures, ML-CatchUp is able to infer that the uses of the sklearn.mo-del_selection.KFold deprecated API need to be updated with the addition of the shuffle=True parameter. However, MLCatchUp is unable to obtain the transformation constraint from the API signatures, providing an incomplete inferred series of transformation commands. In reality, the add parameter update operation should only be done if the value of random_state parameter is not None. This constraint can be expressed through a user input constraint.

D. Type Inference

In MLCatchUp, we incorporate type inference to determine the types of variables and the return types of method calls within the code. This type information can then be used to substitute the variable or the method invocation used in an API invocation to determine the API's fully qualified name. As an example, given the code shown in Figure 10, MLCatchUp will produce the variable and method call type information shown in Table VI. By using the inferred type information in the x1.add(x2) API invocation in line 4, we replace the variable x1 by the inferred type torch.Tensor, which results in the API invocation of torch.Tensor.add(x2) with the fully qualified API name torch.Tensor.add. This replacement is only done as an internal process of MLCatchUp to determine the fully qualified name of API invocations in the processed code.

We implement this type inference by utilizing the PEP (Python Enhancement Proposal) 484, 7 which focuses on the usage of type hints and type annotations for Python code. Following this PEP, third-party libraries have started to provide type annotations in their library code, providing hints on the return type of the library's API methods. In MLCatchUp, we make use of Mypy [START_REF] Lehtosalo | Mypy -optional static typing for python[END_REF], a static type checker for Python that uses the PEP 484 type hints. Given a Python code file as an input, we use Mypy's API to analyze the code, collecting the types of variables and method calls by searching through the imported library for type annotations. We then use these collected types to replace the variables and method calls during the deprecated API usage detection. One caveat of this approach is that it only works for a library that provides type annotations. To mitigate this problem, we further enhance our type inference functionality by utilizing deep learning-based type inference. Specifically, we use Type4Py [START_REF] Mir | Type4py: Deep similarity learning-based type inference for python[END_REF] that implements a deep similarity learning approach to infer the return type of a method invocation. Type4Py is trained on a dataset containing 4,910 Python projects with more than 1.1 million type annotations. From the source code of these projects, Type4Py extracts features from method invocations of known types. These features are extracted from the method names and the arguments appearing in the invocations, the body of the corresponding method definitions, as well as relevant import statements. These features are then used to train a deep learning model that can map a method invocation to its semantic vector representation. Next, given a method invocation with an unknown type, Type4Py infers its type by: (1) converting the method invocation to its semantic vector, (2) identifying k type-annotated data instances in the training set with similar semantic vectors (by default, k is set to 10), and (3) identifying the most common types of the k data instances. MLCatchUp uses Type4Py's topmost predicted type in the same way as the type inferred using Mypy.

IV. MLCATCHUP EVALUATION

A. Dataset Collection

Based on our empirical study, we use deprecated APIs from the Scikit-Learn, TensorFlow, and PyTorch libraries for our evaluation. We consider the 112 identified deprecated APIs from the three libraries. To further evaluate the performance and generalizability of MLCatchUp on additional ML libraries, we also investigate 8 deprecated APIs from Spacy and Numpy, which are Python libraries that are typically used for natural language processing and array processing. In order to provide a realistic evaluation, we use real API usages. With this in mind, we directed our search towards public GitHub repositories.

For the evaluation data collection, we created a search tool adapted from the work of Wang et al. [START_REF] Wang | Exploring how deprecated Python library APIs are (not) handled[END_REF]. Our search tool makes use of the GitHub search API, allowing up to 1,000 repositories to be retrieved for each search query. Each fully qualified name of API invocation is matched with the deprecated API signature to detect usages of deprecated APIs in the code. Using the deprecated API signatures as the input, we collected our evaluation data.

B. Evaluation Dataset

Using our search tool, we collected code containing deprecated API usages from GitHub public repositories for the 120 APIs (112 APIs from Scikit-Learn, PyTorch, and Tensorflow + 8 APIs from Numpy and Spacy). Out of the 120 APIs, we found public code usages for only 68 APIs. For each of these 68 APIs, we collected at most five files containing deprecated API usage for our evaluation dataset. For deprecated APIs used by more than five files, we randomly selected five files. Meanwhile, for deprecated APIs used by only five or fewer files, we used all of the files for our evaluation. In total, we collected 267 files containing 551 API usages from 68 different APIs. 44 files contain Scikit-Learn API usages, 82 files contain TensorFlow API usages, 110 files contain PyTorch API usages, 22 files contain Spacy API usages, and 9 files contain Numpy API usages.

C. Experiment Setting

We conducted an experiment to evaluate the ability of MLCatchUp to update the usages of deprecated APIs. We aim to measure whether MLCatchUp can detect deprecated API usages, and to check whether MLCatchUp is able to correctly update their usages. With this goal in mind, we calculated the detection rate of the deprecated API usages. We define the detection rate as the amount of correctly detected deprecated API usages divided by the number of deprecated API usages in the ground truth. We also calculated the accuracy of the update by measuring the number of correct updates produced compared to the number of deprecated API usages.

To check the update results, we make use of automated and manual analysis of the updated code. In the automated analysis, we automatically check whether the updated code produces any syntax error by compiling the updated code using the Python built-in py_compile module. 8 In the manual analysis, we employed the help of three Python programmers with at least four years of experience to label whether the updated code is correct. These programmers are non-authors, and were given instruction and training before the labelling process. Each instance of the deprecated API usages is labelled by two different programmers. If any labelling disagreement arises between the two programmers, we conducted a discussion until a consensus is achieved. Throughout the labelling process, only two disagreements occured, which resulted in 99.6% inter-rater reliability. We also measure the mean pairwise Cohen's kappa [START_REF] Cohen | A coefficient of agreement for nominal scales[END_REF] of the labelling result from the three programmers, and achieve a mean pairwise Cohen's kappa of 0.986, indicating a near perfect agreement.

D. Deprecated API Usage Detection Evaluation

For the deprecated API usage detection evaluation, we performed two different measurements: (1) detection rate without type inference, and (2) detection rate with type inference. The result of these measurements are provided in Table VII. From the result, we observe that without the type inference, MLCatchUp is unable to detect all of the deprecated API usages, achieving a detection rate of 93.7%. The integration of type inference in MLCatchUp, improves its detection rate, as shown by MLCatchUp achieving a 100.0% detection rate. We further check whether MLCatchUp detection rate holds for the Spacy and Numpy ML libraries. For this purpose, we conduct the same deprecated API usage evaluation only on these two additional libraries. The result of this evaluation is shown in Table VIII. From the result, we observe that without type inference, MLCatchUp has a low detection rate of 43.9%. With the addition of the type inference, it also manages to achieve 100.0% detection rate of the deprecated API usages.

E. Update Accuracy Evaluation

In the update accuracy measurement, we conducted two experiments, (1) experiment without user-added constraints, and (2) experiment with user-added constraints. The results of both experiments are shown in Table IX.

From the experiment without added constraints, ML-CatchUp achieved an accuracy of 80.6%. There are 19.4% instances of updated code that are labelled as false positives, indicating deprecated API usages that were updated incorrectly by MLCatchUp. One of the main reasons for the presence of false positives is due to the transformation constraint not being present for context-dependent updates because such a constraint cannot be automatically inferred by MLCatchUp.

To address the problem of context-dependent migration, we add user-added constraints for context-dependent deprecated API usage updates. Using this additional input, we conducted the follow-up experiment on MLCatchUp using the same test dataset. We manually define the user-added constraints for each context-dependent deprecated API usage migration and add them as an input to MLCatchUp. In total, we manually write 7 constraints. The result of this follow-up experiment is shown in the third row of Table IX.

Using the user-added constraints, MLCatchUp achieves 90.7% accuracy, which is an improvement of more than 10 percentage points compared to the previous experiment. While the addition of the user-added constraints improves the overall accuracy of MLCatchUp update result, there remain some incorrect updates. MLCatchUp failed to correctly update 9.3% of the deprecated API usages. To understand the reasons for Fig. 11: Migration for torch.addcdiv deprecated API usage from PyTorch version 1.6.0 these failures, we conducted a qualitative study, which we will discuss in the next subsection.

We also analyze whether MLCatchUp's update accuracy also applies to the additional ML libraries. We found that APIs from these libraries are context-independent, which mean that they do not require user-added constraints for the update. We conduct the update accuracy evaluation on the Numpy and Spacy deprecated API usages. The result of this evaluation is shown in Table X. We observe that MLCatchUp achieves 93.0% update accuracy on the additional ML libraries deprecated API usages. This indicates that MLCatchUp automatic update generalize well to other ML libraries.

F. MLCatchUp's Failed Migrations

Based on our evaluation of MLCatchUp, we see that 51 instances of deprecated API usage are updated incorrectly. We analyze these cases to find the reasons for these failed migrations. The reasons are: 1) API usage migration involving arithmetic operations. Deprecated API usage migration may involve an addition of arithmetic operations between the updated API and other values, such as the deprecated API parameter. This is currently not handled by MLCatchUp. This case is found in the torch.addcdiv deprecated API migration, shown in Figure 11. In this example, the deprecated API usage (line 1) needs to be replaced by an addition arithmetic operation between the input parameter of the deprecated API usage and a torch.floor_divide API invocation (line 2).

In the future, we can add support for arithmetic operation to handle this type of API migration. 2) API usage migration involving a 1:N API mapping.

Currently, MLCatchUp only handles API usage migrations with 1:1 and 1:0 API mappings, which are the most common API mapping migration categories identified in our empirical study (see Section II). An example of the 1:N case is found in the tensorflow.compat.v1.sparse_to_dense deprecated API migration, where the update requires adding an invocation of tensorflow.sparse.Sparse-Tensor and an API name change from tensorflow.compat.v1.sparse_to_dense to tensorflow.sparse_to_dense. This API migration is illustrated in Figure 12. In the future, it is possible to extend the operations provided by MLCatchUp to include operations adding new API invocations. 13. In the deprecated version, torch.masked_select allows for IntTensor as its second positional parameter. In the updated version, the second positional parameter must be of type BoolTensor, hence the conversion is done using the torch.gt API in line 3. In the future, it is possible to add more operations into MLCatchUp that would enable modifications of the values of API parameters.

V. THREATS TO VALIDITY

Threats to external validity relate to the generalizability of our findings. Our research investigated 112 APIs from three popular Python machine learning libraries, namely Scikit-Learn, TensorFlow, and PyTorch. We made this pragmatic choice to address the recent pain points that many developers face. We designed MLCatchUp based on the results of our empirical study, which may not hold true for other libraries. To mitigate this threat, we extend our evaluation dataset by including 8 additional deprecated APIs from Spacy and Numpy. In our evaluation, we find that MLCatchUp is capable of creating correct updates for Spacy's and Numpy's API migrations. Considering this result, we believe that there is minimal threat for this potential issue.

Threats to external validity also relate to our approach in collecting API deprecation data. We conduct our deprecated API collection by focusing on the change logs of the three libraries appearing in their official documentations and/or release notes. We understand that using this approach, we may miss some deprecated APIs that are not documented, as has been highlighted by Wang et al. [START_REF] Wang | Exploring how deprecated Python library APIs are (not) handled[END_REF]. Nevertheless, currently there is no standard in the documentation of Python library deprecated APIs and developers tend to use ad-hoc strategies to deprecate APIs. As such, we believe that the libraries' official documentations and/or release notes are still the most complete source of the API deprecation data.

Threats to internal validity relate to MLCatchUp's evaluation. We measure the update accuracy of MLCatchUp by checking the syntax of the produced code and through manual analysis by asking the help of three experienced Python programmers to determine the correctness of the updated code. It is possible that false positives (i.e., incorrectly updated code labelled as correct) or false negatives (i.e., correctly updated code labelled as incorrect) may occur due to human error. To mitigate this risk, we have shared a replication package of our evaluation. Using this replication package, others can check and improve the labels used in our accuracy evaluation.

VI. RELATED WORK

API deprecation: Zhou and Walker [START_REF] Zhou | API deprecation: a retrospective analysis and detection method for code examples on the web[END_REF] created a framework to detect deprecated API usages in source code examples for Android. Brito et al. [START_REF] Brito | On the use of replacement messages in API deprecation: An empirical study[END_REF] proposed a recommendation tool that helps to find deprecated API alternatives by mining solutions adopted by developers. Sawant et al. [START_REF] Sawant | Why are features deprecated? an investigation into the motivation behind deprecation[END_REF], [START_REF] Sawant | On the reaction to deprecation of 25,357 clients of 4+1 popular Java APIs[END_REF] found that most developers do not update their API usages due to the cost. Xavier et al. [START_REF] Xavier | Historical and impact analysis of API breaking changes: A large-scale study[END_REF] found that the frequency of API deprecations increases over time and more popular systems have a higher frequency of deprecations. Li et al. [START_REF] Li | Characterising deprecated Android APIs[END_REF] characterized deprecated Android APIs, finding that usage of deprecated APIs is mostly found in popular libraries. Our study is focused on the API deprecation of Python ML libraries, which has not been investigated before.

API migration: apiwave [START_REF] Hora | Apiwave: Keeping track of API popularity and migration[END_REF] keeps track of API popularity and migration of major frameworks and libraries from top 650 GitHub Java projects. Diff-CatchUp [START_REF] Xing | Api-evolution support with Diff-CatchUp[END_REF] is a classic work that automatically detects API changes in a Java library, infers possible replacements of the changed APIs, and identifies possible examples of how to migrate the changed APIs. Different from our approach, Diff-CatchUp does not produce a transformation script or comes with a transformation engine, which provides automatic update for the broken API usages in the client code base. Thus, developers utilizing Diff-CatchUp need to manually perform the transformation based on the change examples.

Program transformation: Sydit [START_REF] Meng | Systematic editing: Generating program transformations from an example[END_REF] generates a contextaware, abstract edit script using only one example. LASE [START_REF] Jacobellis | LASE: An example-based program transformation tool for locating and applying systematic edits[END_REF] automatically transforms code by creating context-aware edit scripts from two or more examples and use the scripts to automatically identify edit locations to be transformed. RE-FAZER [START_REF] Rolim | Learning syntactic program transformations from examples[END_REF] automatically learns program transformations from observation of code edits performed by developers. Using input-output examples, REFAZER synthesizes program transformations for Python code. SPINFER [START_REF] Serrano | SPINFER: Inferring semantic patches for the Linux kernel[END_REF] is capable of automatically inferring Coccinelle semantic patches from existing code change examples for the Linux kernel by lever-aging similar code fragments and control flows in the code changes to identify the patterns.

A4 [START_REF] Lamothe | A4: Automatically assisting Android API migrations using code examples[END_REF] assists Android API migration by learning API migration patterns from source code examples. AppEvolve [START_REF] Fazzini | Automated API-usage update for Android apps[END_REF] transforms the usage of deprecated Android APIs into backward-compatible updated code by learning from code examples. CocciEvolve [START_REF] Haryono | Automatic Android deprecated-API usage update by learning from single updated example[END_REF] provides improvement from App-Evolve by creating readable transformations using only a single update example. Thung et al. [START_REF] Thung | Towards generating transformation rules without examples for Android API replacement[END_REF] proposed NEAT, a tool to generate transformation rules that can assist developers in deprecated API replacement for Android APIs.

There are a number of differences between MLCatchUp and the aforementioned program transformation works. First, none of the previous works supports Python, with the majority supporting Java and C. Also, different from most of the prior works, MLCatchUp does not require any code example to infer transformations to migrate deprecated API usages. Moreover, MLCatchUp presents its transformation in the form of a DSL that is created based on the result of our empirical study of Python ML libraries. Furthermore, MLCatchUp performs type inference to address the problem associated with Python being a dynamically-typed language.

VII. CONCLUSION AND FUTURE WORK

We have conducted an empirical study using a collected list of 112 deprecated APIs to learn the characteristics of the API migrations required by Python deprecated APIs. Using manual thematic analysis, we found a number of categories of API considering three dimensions: update operation, API mapping, and context dependency. Based on findings in our empirical study, we created MLCatchUp, an automated tool to update the usage of deprecated ML APIs in Python. ML-CatchUp automatically infers the transformation operations required to update the usage of a deprecated API. MLCatchUp utilizes type inference to deal with the fact that Python is a dynamically-typed language. We have evaluated MLCatchUp using a dataset of 267 files containing 551 API usages from 68 different APIs, where it manages to detect 93.7% of the deprecated API usages without type inference. Utilization of type inference improves this detection rate to 100.00%. For the update accuracy measurement MLCatchUp achieves 80.58% accuracy. We have further improved MLCatchUp's accuracy by adding transformation constraint inputs, allowing it to handle context-dependent deprecated API usage updates. With this improvement, MLCatchUp achieves 90.74% accuracy.

For future work, we plan to extend our study to other popular Python libraries. By increasing the scope of the case study, we may encounter more variety of deprecated APIs and their migrations. We also plan to address the current shortcomings of MLCatchUp, which have been described in Section IV-F. A replication package of MLCatchUp can be accessed in the following link: https://zenodo.org/record/4736246

Fig. 1 :

 1 Fig. 1: Example of variable type change in Python

Fig. 5 :

 5 Fig. 5: Deprecated API migration involving a contextdependent change for sklearn.model_selection. KFold from Scikit-Learn version 0.22.0

Algorithm 1 : 5 if 8 D 9 foreach

 1589 MLCatchUp automatic inferenceInput : D ∈ deprecated API signature U ∈ updated API signature; Output: Update transformation DSL commands Cmds 1 Cmds ← null 2 if U ≡ null then 3 Cmds.add(remove AP I(Uname)) 4 else Dname = Uname then 6 Cmds.add(rename method(Dname, Uname)) 7 end , U ← eliminate identical param(D, U ) Parameter P ∈ Dparam do 10 foreach Parameter Q ∈ Uparam do 11 while ∃ (P position ≡ Q position ∧ Pname = Qname) do 12 Cmds.add(rename parameter(P, Q)) 13 D, U ← remove used param(P, Q) 14 end 15 while ∃ (Pname ≡ Qname ∧ P is a positional param ∧ Q is a keyword param) do 16 Cmds.add(pos to key parameter(P, Q)) 17 D, U ← remove used param(P, Q) 18 end 19 while ∃ (P ∈ Dparam ∧ P / ∈ Uparam) do 20 Cmds.add(remove parameter(P )) 21 end 22 while ∃ (Q ∈ Uparam) do 23 Cmds.add(add parameter(Q))

Fig. 8 :

 8 Fig. 7: DSL commands produced to convert tensorflow.compat.v1.to_float() usages to use tensorflow.cast(dtype=tensorflow.float32)

Fig. 9 :Fig. 10 :

 910 Fig. 9: DSL commands with input constraint for migrating sklearn.model_selection.KFold deprecated API usage from Scikit-Learn version 0.23.0 to add shuffle=True API parameter

  8 https://docs.python.org/3/library/py compile.html

  study of Python deprecated API migrations and its findings. Section III presents the structure and features of our Python API usage automated update tool, ML-CatchUp. Section IV describes our evaluation of MLCatchUp. Section VI discusses related work on API deprecation and program transformation. Section V discusses the threats to validity. Finally, Section VII concludes with future work.

• We evaluate MLCatchUp using a dataset of 551 deprecated API usages of popular ML libraries collected from public GitHub repositories, where MLCatchUp can achieve up to 90.7% accuracy.

The rest of this paper is organized as follows. Section II discusses our empirical

TABLE I :

 I Number of Deprecated APIs in ML Libraries

	Library	# Deprecated APIs
	Scikit-Learn	22
	TensorFlow	54
	PyTorch	36
	Total	112

  This operation removes the deprecated API

	1	from sklearn.model_selection import KFold
	2	def KFold_Selection(seed):
	3 +	if seed is not None:
	4	KFold(random_state = seed, shuffle=True)
	5 +	else:
	6 +	KFold(random_state = seed)
		1	import torch
		2	def normal(mean, std, output):
		3 -	torch.normal(mean, std, out=output)
		4 +	if mean.size()==output.size() and
		5 +

• Remove API: std.size()==output.size(): 6 + torch.normal(mean, std, out=output)

Fig. 4: Migration for a torch.normal deprecated API usage from PyTorch version 1.5.0

TABLE II :

 II Distribution of API migrations based on the required update operation to perform the migration

		Scikit-Learn	PyTorch	TensorFlow
	Remove Param	12	1	0
	Rename Param	0	1	25
	PosToKey Param	0	8	0
	Rename Method	4	18	17
	Add Parameter	2	1	9
	Change Param Type	2	3	0
	Add Constraint	1	4	0
	Remove API	1	0	3

TABLE III :

 III Distribution of API migrations based on its API mapping operations, such as the tensor flow.compat.v1.to_float deprecated API which requires both the rename method and add parameter operations.We also label each API based on its API mapping, as shown in TableIII. Almost all deprecated API migrations follow the 1:1 transformation, suggesting that API developers prefer a straightforward, less complex API update. Out of the 112 APIs, only 1 API follows the 1:N update category. The 1:0 category is found in 4 APIs.Then, we label each API based on its update context. The results of this labelling are shown in TableIV. The majority of the API updates are context-independent. Out of the 112 APIs, only 9 API updates are context-dependent.

		Scikit-Learn	PyTorch	TensorFlow
	1:1	21	36	50
	1:N	0	0	1
	1:0	1	0	3
	migrations have multiple

TABLE IV :

 IV Distribution of the API migrations based on the contextual dependency of the API update

		Scikit-Learn	PyTorch	TensorFlow
	Context-independent	19	30	54
	Context-dependent	3	6	0

TABLE V :

 V Mapping between each transformation operation and its DSL grammar

	Operation	DSL Grammar
	Rename Method	rename method
	Rename Parameter	rename parameter
	Remove Parameter	remove parameter
	Pos. to Key. Parameter	pos to key parameter
	Add Parameter	add parameter
	Change Parameter Type	type constraint
	Add Parameter Constraint	value constraint
	Remove API	remove api

TABLE VI :

 VI MLCatchUp's inferred type from the code example in Figure10

	Expression	Variable/Method Call	Inferred Type
	x1	Variable (line 2)	torch.Tensor
	x2	Variable (line 3)	torch.Tensor
	torch.empty	Method call	torch.Tensor
	torch.rand	Method call	torch.Tensor
	x1.add	Method call	torch.Tensor

TABLE VII :

 VII MLCatchUp detection rate evaluation results on all data

	Evaluation	Detected	Ground Truth	Detection Rate
	No Type Inference	516	551	93.7%
	Type Inference	551	551	100.0%

TABLE VIII :

 VIII MLCatchUp detection rate evaluation results on Numpy and Spacy deprecated API usages

	Evaluation	Detected	Ground Truth	Detection Rate
	No Type Inference	25	57	43.9%
	Type Inference	57	57	100.0%

TABLE IX :

 IX MLCatchUp update accuracy evaluation results on all data

	Experiment	Correct	Incorrect	Accuracy
	Without added constraints	444	107	80.6%
	With added constraints	500	51	90.7%

TABLE X :

 X MLCatchUp update accuracy evaluation results on Numpy and Spacy deprecated API usages

	Experiment	Correct	Incorrect	Accuracy
	Without added constraints	53	4	93%
	1 -torch.addcdiv(input, tensor, other)
	2 + input + torch.floor_divide(tensor, other)

  API usage migration involving value and/or type modifications of the parameter. MLCatchUp addresses the problem of parameter value or type change through the usage of transformation constraints. However, this approach can be insufficient as some deprecated APIs require the parameter values to be updated, which typically include constructing a new value through mathematical operations or other API invocations. An example of this case is found in the torch.masked_select deprecated API usage, which is shown in Figure

	1 -indices_scattered = tf.compat.v1.sparse_to_dense(
	2 -	sparse_indices, tf.cast(tf.shape(shape),
	3 -	tf.int64), indices_gathered)
	4 + sparse_tensor = tf.sparse.SparseTensor(sparse_indices,
	5 +	indices_gathered, tf.cast(tf.shape(shape),
	6 +	tf.int64))
	7 + indices_scattered = tf.sparse.to_dense(sparse_tensor)
	Fig. 12: Migration for tensorflow.compat.v1.sparse_
	to_dense deprecated API usage from TensorFlow version
	2.0.0
	1	import torch
	2	def MAPE_torch(pred, mask):
	3 +	mask = torch.gt(true, mask -0.01)
	4	pred = torch.masked_select(pred, mask)
	Fig. 13: Migration for torch.masked_select deprecated
	API usage from PyTorch version 1.2.0
	3)

https://docs.github.com/en/code-security/supply-chain-security/ about-the-dependency-graph

https://www.fast.ai/2017/01/03/keras/

https://scikit-learn.org/stable/whats new/v0.23.html

https://github.com/pytorch/pytorch/releases

https://github.com/TensorFlow/TensorFlow/releases

https://www.python.org/dev/peps/pep-0484/

Acknowledgement. This research is supported by the Singapore National Research Foundation (award number: NRF2016-NRF-ANR003) and the ANR ITrans project.