From abcbf91dc8894a5213d2005d8c1387996f4e579d Mon Sep 17 00:00:00 2001 From: Simon Bowly Date: Thu, 2 Nov 2023 15:43:54 +1100 Subject: [PATCH 1/3] Add numpydoc, intersphinx setup --- docs/requirements.txt | 2 ++ docs/source/conf.py | 23 ++++++++++++++++++----- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/docs/requirements.txt b/docs/requirements.txt index fd6aec7..cf03563 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,7 +1,9 @@ -r requirements-examples.txt + jinja2==3.0.3 myst-parser==0.19.2 nbsphinx==0.8.9 +numpydoc==1.6.0 sphinx-copybutton==0.5.2 sphinx-rtd-theme==1.3.0 # sphinx-tabs appears unmaintained and is holding up the show diff --git a/docs/source/conf.py b/docs/source/conf.py index 75916fc..575cff0 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -14,17 +14,18 @@ # -- General configuration --------------------------------------------------- extensions = [ - "sphinx.ext.duration", - "sphinx.ext.doctest", + "nbsphinx", + "numpydoc", "sphinx.ext.autodoc", "sphinx.ext.autosummary", + "sphinx.ext.doctest", + "sphinx.ext.duration", "sphinx.ext.extlinks", "sphinx.ext.intersphinx", + "sphinx_copybutton", "sphinx_tabs.tabs", - "sphinx_toolbox.collapse", "sphinx_toolbox.code", - "nbsphinx", - "sphinx_copybutton", + "sphinx_toolbox.collapse", ] pygments_style = "vs" @@ -40,6 +41,7 @@ intersphinx_mapping = { "python": ("https://docs.python.org/3/", None), "sphinx": ("https://www.sphinx-doc.org/en/master/", None), + "pandas": ("https://pandas.pydata.org/pandas-docs/stable/", None), } intersphinx_disabled_domains = ["std"] @@ -56,6 +58,17 @@ "ghsrc": ("https://github.com/Gurobi/gurobipy-pandas/tree/main/%s", "%s"), } +# -- numpydoc magic linking + +numpydoc_xref_param_type = True +numpydoc_xref_aliases = { + "DataFrame": "pandas.DataFrame", + "Series": "pandas.Series", + "Index": "pandas.Index", +} +numpydoc_xref_ignore = {"optional", "or", "of"} +numpydoc_class_members_toctree = False + # -- Options for EPUB output epub_show_urls = "footnote" From cf444808506df0f4004e3b8a34fce315f9b46692 Mon Sep 17 00:00:00 2001 From: Simon Bowly Date: Thu, 2 Nov 2023 15:53:05 +1100 Subject: [PATCH 2/3] Convert docstrings --- src/gurobipy_pandas/accessors.py | 90 ++++++++++++++++++-------------- src/gurobipy_pandas/api.py | 72 +++++++++++++++---------- 2 files changed, 94 insertions(+), 68 deletions(-) diff --git a/src/gurobipy_pandas/accessors.py b/src/gurobipy_pandas/accessors.py index 96ae630..048a1c1 100644 --- a/src/gurobipy_pandas/accessors.py +++ b/src/gurobipy_pandas/accessors.py @@ -25,9 +25,6 @@ class GRBDataFrameAccessor: The accessor does not expect particular types in the dataframe. This class should not be instantiated directly; it should be used via Pandas' accessor API - - :param pandas_obj: A pandas dataframe - :type pandas_obj: :class:`pd.DataFrame` """ def __init__(self, pandas_obj: pd.DataFrame): @@ -47,27 +44,32 @@ def add_vars( """Add a variable to the given model for each row in the dataframe referenced by this accessor. - :param model: A Gurobi model to which new variables will be added - :type model: :class:`gurobipy.Model` - :param name: Used as the appended column name, as well as the base + Parameters + ---------- + model : Model + A Gurobi model to which new variables will be added + name : str + Used as the appended column name, as well as the base name for added Gurobi variables - :type name: str - :param lb: Lower bound for created variables. May be a single value + lb : float or str, optional + Lower bound for created variables. May be a single value or the name of a column in the dataframe, defaults to 0.0 - :type lb: float or str, optional - :param ub: Upper bound for created variables. May be a single value + ub : float or str, optional + Upper bound for created variables. May be a single value or the name of a column in the dataframe, defaults to :code:`GRB.INFINITY` - :type ub: float or str, optional - :param obj: Objective function coefficient for created variables. + obj: float or str, optional + Objective function coefficient for created variables. May be a single value, or the name of a column in the dataframe, defaults to 0.0 - :type obj: float or str, optional - :param vtype: Gurobi variable type for created variables, defaults + vtype: str, optional + Gurobi variable type for created variables, defaults to :code:`GRB.CONTINUOUS` - :type vtype: str, optional - :return: A new DataFrame with new Vars appended as a column - :rtype: :class:`pd.DataFrame` + + Returns + ------- + DataFrame + A new DataFrame with new Vars appended as a column """ varseries = add_vars_from_dataframe( model, @@ -95,24 +97,29 @@ def add_constrs( """Add a constraint to the model for each row in the dataframe referenced by this accessor. - :param model: A Gurobi model to which new constraints will be added - :type model: :class:`gurobipy.Model` - :param lhs: A string representation of the entire constraint + Parameters + ---------- + model : Model + A Gurobi model to which new constraints will be added + lhs : str + A string representation of the entire constraint expression, or the name of a column - :type lhs: str - :param sense: Constraint sense. Required if lhs is not a complete + sense : str, optional + Constraint sense. Required if lhs is not a complete expression including a comparator - :type sense: str, optional - :param rhs: Constraint right hand side. Can be a column name or + rhs : str or float, optional + Constraint right hand side. Can be a column name or float value. Required if lhs is not a complete expression including a comparator - :type rhs: str or float, optional - :param name: Used as the appended column name, as well as the base + name : str + Used as the appended column name, as well as the base name for added Gurobi constraints. Constraint name suffixes come from the dataframe index. - :type name: str - :return: A new DataFrame with new Constrs appended as a column - :rtype: :class:`pd.DataFrame` + + Returns + ------- + DataFrame + A new DataFrame with new Constrs appended as a column Using some simple example data and variables to demo: @@ -195,9 +202,6 @@ class GRBSeriesAccessor: series by evaluating a target value across all objects in the series. This class should not be instantiated directly; it should be used via Pandas' accessor API - - :param pandas_obj: A pandas series - :type pandas_obj: :class:`pd.Series` """ def __init__(self, pandas_obj): @@ -272,8 +276,17 @@ def set_attr(self, attr, value): """Change the given Gurobi attribute for every object in the Series held by this accessor. Analogous to Var.setAttr, series-wise. - :return: The original series (allowing method chaining) - :rtype: :class:`pd.Series` + Parameters + ---------- + attr : str + The name of the Gurobi attribute to be modified + value : int, float, str, or Series + The value(s) to which the attributes should be set + + Returns + ------- + Series + The original series (allowing method chaining) For example, after creating a series of variables, their upper bounds can be set and retrieved. @@ -320,9 +333,6 @@ def __setattr__(self, attr, value): given Gurobi attribute for every object in the Series held by this accessor - :return: A new series with the evaluated attributes - :rtype: :class:`pd.Series` - For example, after creating a series of variables, their upper bounds can be set and retrieved. @@ -368,8 +378,10 @@ def get_value(self): by this accessor. Note that this assumes that the wrapped objects are gurobipy expressions (:class:`LinExpr` or :class:`QuadExpr`) - :return: A series with the evaluated expression values - :rtype: :class:`pd.Series` + Returns + ------- + Series + A series with the evaluated expression values """ return pd.Series( index=self._obj.index, diff --git a/src/gurobipy_pandas/api.py b/src/gurobipy_pandas/api.py index 44169a1..a6975db 100644 --- a/src/gurobipy_pandas/api.py +++ b/src/gurobipy_pandas/api.py @@ -55,9 +55,11 @@ def set_interactive(flag: bool = True): you call methods of gurobipy.Model directly, updates will not be run automatically. - :param flag: Pass True to enable interactive mode, False to disable. + Parameters + ---------- + flag : bool, optional + Pass True to enable interactive mode, False to disable. Defaults to True. - :type flag: bool, optional """ gppd_global_options["eager_updates"] = flag @@ -108,19 +110,25 @@ def add_vars( """Add a variable to the given model for each entry in the given pandas Index, Series, or DataFrame. - :param model: A Gurobi model to which new variables will be added - :type model: :class:`gurobipy.Model` - :param pandas_obj: A pandas Index, Series, or DataFrame - :param name: If provided, used as base name for new Gurobi variables - and the name of the returned series - :type name: str, optional - :param lb: Lower bound for created variables. Can be a single numeric - value. If :pandas_obj is an Index or Series, can be a Series aligned - with :pandas_obj. If :pandas_obj is a dataframe, can be a string - referring to a column of :pandas_obj. Defaults to 0.0 - :type lb: float, str, or pd.Series, optional - :return: A Series of vars with the the index of :pandas_obj - :rtype: :class:`pd.Series` + Parameters + ---------- + model : Model + A Gurobi model to which new variables will be added + pandas_obj : Index, Series, or DataFrame + A pandas Index, Series, or DataFrame + name : str, optional + If provided, used as base name for new Gurobi variables and the name + of the returned series + lb : float, str, or Series, optional + Lower bound for created variables. Can be a single numeric + value. If ``pandas_obj`` is an Index or Series, can be a Series + aligned with ``pandas_obj``. If ``pandas_obj`` is a dataframe, + can be a string referring to a column of ``pandas_obj``. Defaults to 0.0. + + Returns + ------- + Series + A Series of vars with the the index of `pandas_obj` """ if isinstance(pandas_obj, pd.Index): # Use the given index as the base object. All attribute arguments must @@ -177,20 +185,26 @@ def add_constrs( ) -> pd.Series: """Add a constraint to the model for each row in lhs & rhs. - :param model: A Gurobi model to which new constraints will be added - :type model: :class:`gurobipy.Model` - :param lhs: A series or numeric value - :type lhs: pd.Series - :param sense: Constraint sense - :type sense: str - :param rhs: A series or numeric value - :type rhs: pd.Series - :param name: Used as the returned series name, as well as the base - name for added Gurobi constraints. Constraint name suffixes - come from the lhs/rhs index. - :type name: str - :return: A Series of Constr objects - :rtype: :class:`pd.Series` + Parameters + ---------- + model : Model + A Gurobi model to which new constraints will be added + lhs : Series + A series of expressions forming the left hand side of constraints + sense : str + Constraint sense + rhs : Series or float + A series of expressions forming the right hand side of constraints, + or a common constant + name : str + Used as the returned series name, as well as the base name for added + Gurobi constraints. Constraint name suffixes come from the lhs/rhs + index. + + Returns + ------- + Series + A Series of Constr objects """ return add_constrs_from_series( model, lhs, sense, rhs, name=name, index_formatter=index_formatter From 01312ac6a89f18736d603f3cd4d0e7496bdf6ca8 Mon Sep 17 00:00:00 2001 From: Simon Bowly Date: Thu, 2 Nov 2023 16:11:17 +1100 Subject: [PATCH 3/3] Fix order --- src/gurobipy_pandas/accessors.py | 92 +++++++++++++++++--------------- 1 file changed, 48 insertions(+), 44 deletions(-) diff --git a/src/gurobipy_pandas/accessors.py b/src/gurobipy_pandas/accessors.py index 048a1c1..ee06ab2 100644 --- a/src/gurobipy_pandas/accessors.py +++ b/src/gurobipy_pandas/accessors.py @@ -97,32 +97,6 @@ def add_constrs( """Add a constraint to the model for each row in the dataframe referenced by this accessor. - Parameters - ---------- - model : Model - A Gurobi model to which new constraints will be added - lhs : str - A string representation of the entire constraint - expression, or the name of a column - sense : str, optional - Constraint sense. Required if lhs is not a complete - expression including a comparator - rhs : str or float, optional - Constraint right hand side. Can be a column name or - float value. Required if lhs is not a complete expression - including a comparator - name : str - Used as the appended column name, as well as the base - name for added Gurobi constraints. Constraint name suffixes - come from the dataframe index. - - Returns - ------- - DataFrame - A new DataFrame with new Constrs appended as a column - - Using some simple example data and variables to demo: - >>> import pandas as pd >>> import gurobipy as gp >>> from gurobipy import GRB @@ -182,6 +156,32 @@ def add_constrs( 0 x[0] + y[0] 1 x[1] + y[1] 2 x[2] + y[2] + + Parameters + ---------- + model : Model + A Gurobi model to which new constraints will be added + lhs : str + A string representation of the entire constraint + expression, or the name of a column + sense : str, optional + Constraint sense. Required if lhs is not a complete + expression including a comparator + rhs : str or float, optional + Constraint right hand side. Can be a column name or + float value. Required if lhs is not a complete expression + including a comparator + name : str + Used as the appended column name, as well as the base + name for added Gurobi constraints. Constraint name suffixes + come from the dataframe index. + + Returns + ------- + DataFrame + A new DataFrame with new Constrs appended as a column + + Using some simple example data and variables to demo: """ constrseries = add_constrs_from_dataframe( model, @@ -211,9 +211,6 @@ def get_attr(self, attr): """Retrieve the given Gurobi attribute for every object in the Series held by this accessor. Analogous to Var.getAttr, series-wise. - :return: A new series with the evaluated attributes - :rtype: :class:`pd.Series` - For example, after solving a model, the solution can be retrieved >>> import pandas as pd @@ -229,6 +226,16 @@ def get_attr(self, attr): 1 0.0 2 0.0 Name: x, dtype: float64 + + Parameters + ---------- + attr : str + The name of the Gurobi attribute to retrieve + + Returns + ------- + Series + A new series with the evaluated attributes """ return pd.Series( index=self._obj.index, @@ -240,9 +247,6 @@ def __getattr__(self, attr): """Retrieve the given Gurobi attribute for every object in the Series held by this accessor - :return: A series with the evaluated attributes - :rtype: :class:`pd.Series` - For example, after solving a model, solution values can be read using the :code:`X` attribute. @@ -276,18 +280,6 @@ def set_attr(self, attr, value): """Change the given Gurobi attribute for every object in the Series held by this accessor. Analogous to Var.setAttr, series-wise. - Parameters - ---------- - attr : str - The name of the Gurobi attribute to be modified - value : int, float, str, or Series - The value(s) to which the attributes should be set - - Returns - ------- - Series - The original series (allowing method chaining) - For example, after creating a series of variables, their upper bounds can be set and retrieved. @@ -314,6 +306,18 @@ def set_attr(self, attr, value): 1 5.0 2 5.0 Name: x, dtype: float64 + + Parameters + ---------- + attr : str + The name of the Gurobi attribute to be modified + value : int, float, str, or Series + The value(s) to which the attributes should be set + + Returns + ------- + Series + The original series (allowing method chaining) """ if isinstance(value, pd.Series): aligned = align_series(value, self._obj.index, attr)