Python Third Party Dependencies
-------------------------------

Adding Third Party Packages
~~~~~~~~~~~~~~~~~~~~~~~~~~~

In many cases, it is useful to add third-party Python packages that can be used in your plugin. 
This can be achieved by adding dependencies to the requirements.txt file in the tool workspace directory.

There are 2 options:

1. Manually add dependencies. If you use this approach, make sure to include all dependencies (including any sub-dependencies).
2. Use ``pip freeze > requirements.txt`` to generate a new requirements.txt file in the workspace.

Using Third Party Packages in Code
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

When you use third-party packages in Python, you typically import these packages 
at the top of a file. However, if the packages that you use are large (like numpy, pandas,
scikit-learn, etc.), then these imports can take a non-negligible amount of time.

Since the update-only mode of Alteryx Designer should be as fast as possible, these import statements
can be a bottleneck. Because of this, instead of putting import statements at the top of a file, you should include these 
inline so that they only occur just before they are needed. See the example below for an Input-type tool that
uses pandas to generate its data (note that pandas is imported in the ``on_complete`` method):

.. code:: python

    class ExampleInput(Plugin):
		"""Concrete implementation of an AyxPlugin."""

		def __init__(self, provider: ProviderBase) -> None:
			"""Construct a plugin."""
			self.provider = provider
			self.tool_config = provider.tool_config
			self.config_value = self.tool_config["Value"]
			self.output_anchor = self.provider.get_output_anchor("Output")

			self.output_metadata = Metadata()
			self.output_metadata.add_field("x", FieldType.float)
			self.output_metadata.add_field("y", FieldType.v_wstring, size=100)
			self.output_metadata.add_field("z", FieldType.float)

			self.output_anchor.open(self.output_metadata)

			if float(self.config_value) > 0.5:
				raise WorkflowRuntimeError("Values greater than 0.5 are not allowed.")

			self.provider.io.info("Plugin initialized.")

		def on_input_connection_opened(self, input_connection: InputConnectionBase) -> None:
			"""Initialize the Input Connections of this plugin."""
			raise NotImplementedError("Input tools don't have input connections.")

		def on_record_packet(self, input_connection: InputConnectionBase) -> None:
			"""Handle the record packet received through the input connection."""
			raise NotImplementedError("Input tools don't receive packets.")

		def on_complete(self) -> None:
			"""Create all records."""
			import pandas as pd

			df = pd.DataFrame(
				{
					"x": [1, 2, 3],
					"y": ["hello", "world", "from ayx_plugin_sdk!"],
					"z": [self.config_value, self.config_value, self.config_value],
				}
			)

			packet = RecordPacket.from_dataframe(self.output_metadata, df)

			self.output_anchor.write(packet)
			self.provider.io.info("Completed processing records.")