Skip to main content

Sage Deps

Project description

Sage Deps - A Sage Dependency Analysis Tool

This is a SageMath dependency analysis tool used for understanding Sage's structure. It can be used to detect circular imports, upstream dependencies, and provide various dependency-graph metrics including PageRank.

Warning: This package is still in its testing phase, and may have unexpected behaviour.

Installation

Dependencies

The package requires numpy, scipy, networkx, and scikit-network.

Install from PyPi:

Run pip install sage-deps to install as a pypi package. Make sure the script sdeps.exe is added to PATH to run the sdeps command.

Manual Install

To install, simply download or clone the repository. Navigate to the root folder (where pyproject.toml lives) and run pip install ..

Additional Setup

The package requires access to the SageMath repository. By default, it assumes you have the repository cloned to the same parent directory as your sage-deps folder. You may modify this by modifying the configuration file, as shown below.

Getting started

To ensure the package is successfully installed, run sdeps. It should output a blank line by default.

The package comes with some pre-compiled resource files generated by SageMath version 10.6. To update these pre-generated files, run:

sdeps -gm -gg

To store and use local resource files, use the -m and -g flags or run:

sdeps -set-config modules_src <modules-path>
sdeps -set-config graph_src <graph-path>

Similarly, to specify a custom SageMath installation path, use the -s flag or run:

sdeps -set-config sage_path <sage-path>

Relative and absolute files are both supported.

Full options list

usage: sdeps [-h] [-s SOURCE_FILE] [-m SOURCE_FILE] [-g SOURCE_FILE] [-o OUTPUT_FILE] [-up SOURCE_CLASS DEPTH]
             [-cc SOURCE_CLASS TIMEOUT] [-cl SIZE] [-gm] [-gi] [-gd] [-gg] [-gdg SOURCE DISTANCE DIRECTION] [-f SOURCE_FILE] [-nf]
             [-view] [-set-config NAME VALUE] [--verbose]

A program top help manage SageMath dependencies.

options:
  -h, --help            show this help message and exit
  -s, --sage-source SOURCE_FILE
                        The source file of Sage.
  -m, --modules-source SOURCE_FILE
                        Specify the modules file.
  -g, --graph-source SOURCE_FILE
                        Specify the graph file.
  -o, --output-file OUTPUT_FILE
                        Specify the file to dump the output.
  -up SOURCE_CLASS DEPTH
                        Generates a breadth-first dependency tree rooted at SOURCE_CLASS, up to a given depth.
  -cc SOURCE_CLASS TIMEOUT
                        Finds cycles starting at SOURCE_CLASS with a timeout of TIMEOUT seconds.
  -cl SIZE              Finds cliques of size SIZE.
  -gm, --generate-modules
                        Generate a modules file. Will output to default location or `--modules-source`.
  -gi, --generate-imports
                        Generate an imports file.
  -gd, --generate-dependencies
                        Generate a dependencies file.
  -gg, --generate-graph
                        Generate an graph file. Will output to default location or `--graph-source`.
  -gdg, --generate-dependency-graph SOURCE DISTANCE DIRECTION
                        Generate a dependency graph rooted at a SOURCE node.
  -f, --ff SOURCE_FILE  Load a custom filter. If not, a default filter is used.
  -nf                   Disables the filter.
  -view, --view         Run a cytoscape.js instance. Specify graph source using `--graph-source`.
  -set-config NAME VALUE
                        Updates the configuration file.
  --verbose             Enable verbose output.

Note: Currently, verbose output doesn't do anything.

Example Usage

Command line examples

We can use the -up flag to compute all upwards dependencies of a particular class in SageMath.

% sdeps -up sage.rings.polynomial.polynomial\_element.Polynomial 1
{0: ['sage.rings.polynomial.polynomial_element.Polynomial'], 1: ['sage.rings.integer.Integer', 'sage.rings.rational_field.RationalField', 'sage.rings.integer_ring.IntegerRing_class', 'sage.rings.padics.padic_generic.pAdicGeneric', 'sage.rings.ideal.Ideal_generic', 'sage.rings.polynomial.polynomial_ring.PolynomialRing_generic', 'sage.rings.polynomial.multi_polynomial.MPolynomial', 'sage.rings.finite_rings.finite_field_base.FiniteField', 'sage.rings.number_field.number_field_base.NumberField', 'sage.rings.finite_rings.finite_field_constructor.FiniteFieldFactory', 'sage.rings.fraction_field.FractionField_generic']}

Similarly, we can do cycle detection. Notice that we need to set a time limit as finding cycles is, in general, NP-hard.

% sdeps -cc sage.rings.integer.Integer 120
[['sage.rings.integer.Integer', 'sage.rings.rational.Rational', 'sage.rings.integer_ring.IntegerRing_class', 'sage.rings.ring.CommutativeRing', 'sage.rings.polynomial.polynomial_element.Polynomial', 'sage.rings.rational_field.RationalField', 'sage.rings.number_field.number_field_base.NumberField', 'sage.rings.qqbar.AlgebraicRealField', 'sage.rings.qqbar.AlgebraicField_common', 'sage.rings.qqbar.AlgebraicNumberPowQQAction', 'sage.rings.real_mpfi.RealIntervalFieldElement', 'sage.rings.integer.Integer'], 
...
]

As a package

There is more freedom of use when treated as a package. An example workflow is shown below.

# Import relevant files
from sagedeps.main import *
from sagedeps.deps.loader import Loader
from sagedeps.deps.data import *
from sagedeps.deps.model.dependency import *
from sagedeps.deps.filter import *
from sagedeps.analysis import *

# Load from resources
Loader.initialize(scorer=DefaultScorer())

# Get classes and directories
filter = EmptyFilter()
classes = Data.get_classes_filtered(
    filter
)
dirs = Data.get_modules_filtered(
    filter
)
print(len(dirs))
print(len(classes))

# Count number of outdegrees over all classes to get an average
total_deg = 0
for sc in classes:
    total_deg += sc.out_degree(
        relations=[Relation.INHERITANCE, Relation.CLASS_ATTRIBUTE, Relation.DECLARED_SUB_IMPORT, Relation.DECLARED_TOP_IMPORT]
    )

print(total_deg/len(classes))

# Analyze for cliques of size 3
analyzer = CliquesAnalyzer(
    filter=EmptyFilter(),
    size=3,
    edge_types=[Relation.INHERITANCE, Relation.CLASS_ATTRIBUTE, Relation.DECLARED_SUB_IMPORT, Relation.DECLARED_TOP_IMPORT]
)

# Analyze PageRank
analyzer = PageRankAnalyzer(
    filter=EmptyFilter(),
    edge_types=[Relation.INHERITANCE, Relation.CLASS_ATTRIBUTE, Relation.DECLARED_SUB_IMPORT, Relation.DECLARED_TOP_IMPORT],
    weights=[1,1,1,1]
)
res = analyzer.run()
print(res[:15])
print(len(res))

The above snippet outputs

3202
5854
3.3659036556200888
[('sage.structure.sage_object.SageObject', np.float64(0.037002533039364974)), ('sage.rings.integer.Integer', np.float64(0.02290838092408753)), ('sage.rings.integer_ring.IntegerRing_class', np.float64(0.02273003398295342)), ('sage.structure.element.Element', np.float64(0.02090351208515615)), ('sage.structure.parent.Parent', np.float64(0.01437274473122256)), ('sage.categories.category.Category', np.float64(0.011457959949590773)), ('sage.categories.category_singleton.Category_singleton', np.float64(0.010601666149250333)), ('sage.typeset.character_art.CharacterArt', np.float64(0.010176442750443552)), ('sage.misc.lazy_attribute.lazy_attribute', np.float64(0.008751776770612866)), ('sage.categories.category_with_axiom.CategoryWithAxiom', np.float64(0.008289012215276066)), ('sage.structure.element.ModuleElement', np.float64(0.008201175230707807)), ('sage.rings.rational_field.RationalField', np.float64(0.008088172337409227)), ('sage.misc.lazy_attribute._lazy_attribute', np.float64(0.008085176090604891)), ('sage.categories.objects.Objects', np.float64(0.007503707995711554)), ('sage.structure.unique_representation.UniqueRepresentation', np.float64(0.007267035285008635))]
5854

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

sage_deps-0.1.2.tar.gz (27.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

sage_deps-0.1.2-py3-none-any.whl (38.8 kB view details)

Uploaded Python 3

File details

Details for the file sage_deps-0.1.2.tar.gz.

File metadata

  • Download URL: sage_deps-0.1.2.tar.gz
  • Upload date:
  • Size: 27.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for sage_deps-0.1.2.tar.gz
Algorithm Hash digest
SHA256 611150539ea8fb6b777a528721a5a38362db6feca550dd3bb205e1c97ddea547
MD5 3da365b92811f10c8b3c730a9ef997ab
BLAKE2b-256 d39463ab59374e6f1045ff316266d664787f4bb08c00d43380c6039bb518c5c1

See more details on using hashes here.

File details

Details for the file sage_deps-0.1.2-py3-none-any.whl.

File metadata

  • Download URL: sage_deps-0.1.2-py3-none-any.whl
  • Upload date:
  • Size: 38.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for sage_deps-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 1db20bba8cd5fb492e00b79cde1fe911bc7c3d9647874206a4f32a56e1d81a32
MD5 c917717b627a9f77c440a4a9f986a53b
BLAKE2b-256 0711565851efa37aaf26df38c1460b0c1ad10ff00c56052435111d23955b2107

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page