pydna


Namepydna JSON
Version 5.3.0 PyPI version JSON
download
home_pagehttps://github.com/BjornFJohansson/pydna#-pydna
SummaryRepresenting double stranded DNA and functions for simulating cloning and homologous recombination between DNA molecules.
upload_time2024-12-13 11:22:00
maintainerNone
docs_urlNone
authorBjornFJohansson
requires_python<4.0,>=3.8
licenseBSD
keywords
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage
            # ![icon](docs/_static/pydna.resized.png) pydna

| [![Tests & Coverage](https://github.com/BjornFJohansson/pydna/actions/workflows/pydna_test_and_coverage_workflow.yml/badge.svg?branch=dev_bjorn)](https://github.com/BjornFJohansson/pydna/actions/workflows/pydna_test_and_coverage_workflow.yml) | [![codecov](https://codecov.io/gh/BjornFJohansson/pydna/branch/master/graph/badge.svg)](https://codecov.io/gh/BjornFJohansson/pydna/branch/master) | [![PyPI version](https://badge.fury.io/py/pydna.svg)](https://badge.fury.io/py/pydna)                                                  | [![Google group : pydna](https://img.shields.io/badge/Google%20Group-pydna-blue.svg)](https://groups.google.com/g/pydna)              |
| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| [![Documentation Status](https://github.com/BjornFJohansson/pydna/actions/workflows/publish-docs.yml/badge.svg)](https://github.com/BjornFJohansson/pydna/actions/workflows/publish-docs.yml)                                                      | [![GitHub issues](https://img.shields.io/github/issues/BjornFJohansson/pydna.svg)](https://github.com/BjornFJohansson/pydna/issues)                | [![Anaconda-Server Badge2](https://anaconda.org/bjornfjohansson/pydna/badges/license.svg)](https://anaconda.org/bjornfjohansson/pydna) | [![GitHub stars](https://img.shields.io/github/stars/BjornFJohansson/pydna.svg)](https://github.com/BjornFJohansson/pydna/stargazers) |

<!-- docs/index.rst-start -->

Pydna is a python package that provides a human-readable formal descriptions of ๐Ÿงฌ cloning and genetic assembly strategies in Python ๐Ÿ for simulation and verification.
Pydna can be used as [executable documentation](https://en.wikipedia.org/wiki/Literate_programming) for cloning.

Designing genetic constructs with many components and steps, like recombinant metabolic pathways ๐Ÿงซ, often makes accurate documentation difficult, as seen in the poor state of scientific literature โ˜ข๏ธ

A cloning strategy expressed in pydna is **complete**, **unambiguous** and **stable**.

Pydna provides simulation of:

- Primer design
- PCR
- Restriction digestion
- Ligation
- Gel electrophoresis of DNA with generation of gel images
- Homologous recombination
- Gibson assembly
- Golden gate assembly (in progress)


Virtually any sub-cloning experiment can be described in pydna, and its execution yield the sequences of intermediate and final DNA molecules.

Pydna has been designed with the goal of being understandable for biologists with only some basic understanding of Python.

Pydna can formalize planning and sharing of cloning strategies and is especially useful for complex or combinatorial
DNA molecule constructions.

<!-- docs/index.rst-end -->

## Acknowledgement ๐Ÿค

If you use pydna in your research, please reference the paper:

Pereira, F., Azevedo, F., Carvalho, ร‚., Ribeiro, G. F., Budde, M. W., & Johansson, B. (2015). Pydna: a simulation and documentation tool for DNA assembly strategies using python. BMC Bioinformatics, 16(142), 142. [doi:10.1186/s12859-015-0544-x](https://doi.org/10.1186/s12859-015-0544-x)

## Documentation and usage ๐Ÿ“š

Full documentation of all modules and classes can be found at [https://bjornfjohansson.github.io/pydna](https://bjornfjohansson.github.io/pydna).

To get started, we recommend you to have a look at the [example notebooks](docs/notebooks). Start by having a look at [Dseq](docs/notebooks/Dseq.ipynb), [Dseq_Features](docs/notebooks/Dseq_Features.ipynb) and [Importing_Seqs](docs/notebooks/Importing_Seqs.ipynb), which cover the basics of working with sequences. The rest of the notebooks cover how to use pydna for different cloning strategies, such as Gibson assembly, Restriction-Ligation, etc.

Most pydna functionality is implemented as methods for the double stranded DNA sequence record
classes Dseq and Dseqrecord, which are subclasses of the [Biopython](http://biopython.org/wiki/Main_Page)
[Seq](http://biopython.org/wiki/Seq) and [SeqRecord](http://biopython.org/wiki/SeqRecord) classes.

These classes make PCR primer design, PCR simulation and cut-and-paste cloning very simple:

> **NOTE**: You can run this example in [this notebook](docs/notebooks/readme_example.ipynb)

```python
from pydna.dseqrecord import Dseqrecord
# Let's create a DNA sequence record, and add a feature to it
dsr = Dseqrecord("ATGCAAACAGTAATGATGGATGACATTCAAAGCACTGATTCTATTGCTGAAAAAGATAAT")
dsr.add_feature(x=0, y=60,type="gene", label="my_gene") # We add a feature to highlight the sequence as a gene
dsr.figure()
```

<pre>
Dseqrecord(-60)
<mark>ATGCAAACAGTAATGATGGATGACATTCAAAGCACTGATTCTATTGCTGAAAAAGATAAT</mark>
TACGTTTGTCATTACTACCTACTGTAAGTTTCGTGACTAAGATAACGACTTTTTCTATTA
</pre>


```python
# This is how it would look as a genbank file
print(dsr.format("genbank"))
```

    LOCUS       name                      60 bp    DNA     linear   UNK 01-JAN-1980
    DEFINITION  description.
    ACCESSION   id
    VERSION     id
    KEYWORDS    .
    SOURCE      .
      ORGANISM  .
                .
    FEATURES             Location/Qualifiers
         misc            1..60
                         /type="gene"
                         /label="my_gene"
    ORIGIN
            1 atgcaaacag taatgatgga tgacattcaa agcactgatt ctattgctga aaaagataat
    //



```python
# Now let's design primers to amplify it
from pydna.design import primer_design
# limit is the minimum length of the primer, target_tm is the desired melting temperature of the primer
amplicon = primer_design(dsr, limit=13, target_tm=55)
# Let's print the primers, and a figure that shows where they align with the template sequence
print("forward primer:", amplicon.forward_primer.seq)
print("reverse primer:", amplicon.reverse_primer.seq)
amplicon.figure()
```

```
forward primer: ATGCAAACAGTAATGATGGA
reverse primer: ATTATCTTTTTCAGCAATAGAATCA





5ATGCAAACAGTAATGATGGA...TGATTCTATTGCTGAAAAAGATAAT3
                        |||||||||||||||||||||||||
                        3ACTAAGATAACGACTTTTTCTATTA5
5ATGCAAACAGTAATGATGGA3
    ||||||||||||||||||||
3TACGTTTGTCATTACTACCT...ACTAAGATAACGACTTTTTCTATTA5
```



```python
# Let's say we don't want to just amplify it, but we want to add restriction sites to it!
from pydna.amplify import pcr
# We add the restriction sites to the primers
forward_primer = "ccccGGATCC" + amplicon.forward_primer
reverse_primer = "ttttGGATCC" + amplicon.reverse_primer

# We do the PCR
pcr_product = pcr(forward_primer, reverse_primer, dsr)
# The PCR product is of class `Amplicon`, a subclass of `Dseqrecord`.
# When doing a figure, it shows where primers anneal.
pcr_product.figure()
```

```
            5ATGCAAACAGTAATGATGGA...TGATTCTATTGCTGAAAAAGATAAT3
                                    |||||||||||||||||||||||||
                                    3ACTAAGATAACGACTTTTTCTATTACCTAGGtttt5
5ccccGGATCCATGCAAACAGTAATGATGGA3
            ||||||||||||||||||||
            3TACGTTTGTCATTACTACCT...ACTAAGATAACGACTTTTTCTATTA5
```

```python
# If we want to see the sequence more clearly, we can turn it into a `Dseqrecord`
pcr_product = Dseqrecord(pcr_product)
pcr_product.figure()
```

<pre>
Dseqrecord(-80)
ccccGGATCC<mark>ATGCAAACAGTAATGATGGATGACATTCAAAGCACTGATTCTATTGCTGAAAAAGATAAT</mark>GGATCCaaaa
ggggCCTAGGTACGTTTGTCATTACTACCTACTGTAAGTTTCGTGACTAAGATAACGACTTTTTCTATTACCTAGGtttt
</pre>


```python
from Bio.Restriction import BamHI # cuts GGATCC
# a, payload, c are the cut fragments
a, payload, c = pcr_product.cut (BamHI)
print(a.figure())
print()
print (payload.figure())
print()
print(c.figure())
```

<pre>
Dseqrecord(-9)
ccccG
ggggCCTAG

Dseqrecord(-70)
GATCC<mark>ATGCAAACAGTAATGATGGATGACATTCAAAGCACTGATTCTATTGCTGAAAAAGATAAT</mark>G
    GTACGTTTGTCATTACTACCTACTGTAAGTTTCGTGACTAAGATAACGACTTTTTCTATTACCTAG

Dseqrecord(-9)
GATCCaaaa
    Gtttt
</pre>

```python
# We create a circular vector to insert the amplicon into
vector = Dseqrecord("aatgtttttccctCCCGGGcaaaatAGATCTtgctatgcatcatcgatct", circular=True, name="vect")
vector.figure()
```


```
Dseqrecord(o50)
aatgtttttccctCCCGGGcaaaatAGATCTtgctatgcatcatcgatct
ttacaaaaagggaGGGCCCgttttaTCTAGAacgatacgtagtagctaga
```


```python
from Bio.Restriction import BglII # cuts AGATCT
linear_vector_bgl = vector.cut(BglII)[0] # Linearize the vector at BglII (produces only one fragment)

# Ligate the fragment of interest to the vector, and call looped() to circularize it
# synced is used to place the origin coordinate (0) in the same place for rec_vector and vector
rec_vector= (linear_vector_bgl + payload).looped().synced(vector)
rec_vector.figure()

```

<pre>
Dseqrecord(o116)
aatgtttttccctCCCGGGcaaaatAGATCC<mark>ATGCAAACAGTAATGATGGATGACATTCAAAGCACTGATTCTATTGCTGAAAAAGATAAT</mark>GGATCTtgctatgcatcatcgatct
ttacaaaaagggaGGGCCCgttttaTCTAGGTACGTTTGTCATTACTACCTACTGTAAGTTTCGTGACTAAGATAACGACTTTTTCTATTACCTAGAacgatacgtagtagctaga
</pre>



```python
# Let's simulate a Gibson assembly
from pydna.assembly import Assembly

fragments = [
    Dseqrecord('aatgtttttccctCACTACGtgctatgcatcat', name="fragment_A"),
    Dseqrecord('tgctatgcatcatCTATGGAcactctaataatg', name="fragment_B"),
    Dseqrecord('cactctaataatgTTACATAaatgtttttccct', name="fragment_C"),
]

# limit is the min. homology length between fragments in the assembly
asm = Assembly(fragments, limit=10)

# From the assembly object, which can generate all possible products, get a circular
product, *rest = asm.assemble_circular()

# We can print a figure that shows the overlaps between fragments
product.figure()

```
     -|fragment_A|13
    |             \/
    |             /\
    |             13|fragment_B|13
    |                           \/
    |                           /\
    |                           13|fragment_C|13
    |                                         \/
    |                                         /\
    |                                         13-
    |                                            |
     --------------------------------------------

```python
# Or show the final sequence:
Dseqrecord(product).figure()

```

```
Dseqrecord(o60)
aatgtttttccctCACTACGtgctatgcatcatCTATGGAcactctaataatgTTACATA
ttacaaaaagggaGTGATGCacgatacgtagtaGATACCTgtgagattattacAATGTAT
```


As the example above shows, pydna keeps track of sticky ends and features.

Pydna can be very compact. The eleven lines of Python below simulates the construction of a recombinant plasmid.
DNA sequences are downloaded from Genbank by accession numbers that are guaranteed to be stable over time.

```python
from pydna.genbank import Genbank
gb = Genbank("myself@email.com") # Tell Genbank who you are!
gene = gb.nucleotide("X06997") # Kluyveromyces lactis LAC12 gene for lactose permease.
from pydna.parsers import parse_primers
primer_f,primer_r = parse_primers(''' >760_KlLAC12_rv (20-mer)
                                        ttaaacagattctgcctctg

                                        >759_KlLAC12_fw (19-mer)
                                        aaatggcagatcattcgag ''')

from pydna.amplify import pcr
pcr_prod = pcr(primer_f,primer_r, gene)
vector = gb.nucleotide("AJ001614") # pCAPs cloning vector
from Bio.Restriction import EcoRV
lin_vector = vector.linearize(EcoRV)
rec_vec =  ( lin_vector + pcr_prod ).looped()
```

## Installation ๐Ÿ“ฆ

<!-- docs/installation.rst-start -->

By default, pydna is installed with minimal dependencies, but there are optional dependencies for additional functionality.


### Optional dependencies
<details>
<summary>Click here to see optional dependencies</summary>

<!-- I did not make these headers because they mess up the sphinx docs by being inside of a collapsible section-->

_________________

**clipboard**

Enables the `pydna.dseqrecord.Dseqrecord.copy_gb_to_clipboard()` and `pydna.dseqrecord.Dseqrecord.copy_fasta_to_clipboard()`

These methods will put a copy the sequence on the clipboard in either Genbank (gb) or fasta format.


| Dependency                                          | Function in pydna          |
| --------------------------------------------------- | -------------------------- |
| [pyperclip](https://pypi.python.org/pypi/pyperclip) | copy sequence to clipboard |

_________________

**download**

Pyparsing enables the `pydna.genbankfixer.gbtext_clean()` function that can automatically
correct malformed sequence files in Genbank format. These are often found online, so this
option also installs requests to enable the  `pydna.genbankfixer.download.download_text()` function which can be used to get cleaned up text from a URL.


| Dependency                                          | Function in pydna                                 |
| --------------------------------------------------- | ------------------------------------------------- |
| [pyparsing](https://pypi.python.org/pypi/pyparsing) | fix corrupt Genbank files with pydna.genbankfixer |
| [requests](https://pypi.org/project/requests)       | download sequences with pydna.download            |

_________________

**express**

This option enables the `pydna.utils.cai()` function and the `cai()` method
available from subclasses of `pydna.seqrecord.SeqRecord`, such as
`pydna.dseqrecord.Dseqrecord`.

| [cai2](https://pypi.python.org/pypi/cai2)           | codon adaptation index calculations in several modules |

_________________

**gel**

Scipy, matplotlib and pillow (PIL) enable the generation of gel images. Numpy is also
needed, but usually installed as a dependency of biopython.


| Dependency                                        | Function in pydna             |
| ------------------------------------------------- | ----------------------------- |
| [scipy](https://www.scipy.org)                    | gel simulation with pydna.gel |
| [matplotlib](http://matplotlib.org)               | โ€œ                             |
| [pillow](https://github.com/python-pillow/Pillow) | โ€œ                             |

_________________

</details>

### Installing with pip ๐Ÿ

```bash
# use the `--pre` flag to get the latest version of pydna.
pip install --pre --upgrade pydna

# to install the optional dependencies, you can use the following command:
pip install --pre --upgrade pydna[clipboard,download,express,gel]
```

Remove options inside the square brackets as required, but be sure not to leave spaces as pip will not recognize the options. See below under "Optional dependencies".

### Installing with poetry ๐Ÿง™โ€โ™‚๏ธ

If your project uses [poetry](https://python-poetry.org/) to manage dependencies, you can install pydna with the following commands:

```bash
# Basic installation
poetry add pydna
# With optional dependencies (ommit the options you don't want)
poetry add pydna --extras "clipboard download express gel"

# If you already have it installed and you want to add or remove optional
# dependencies, you have to uninstall and install again
poetry remove pydna
poetry add pydna --extras "express gel"
```

<!-- docs/installation.rst-end -->

## Contributing and feedback ๐Ÿ› ๏ธ

Feedback & suggestions are very welcome! Please create an issue with your question, comment or suggestion. Please include the version of pydna you are using and code to reproduce the issue if possible.

If you don't have a github account, you can get in touch through the [google group](https://groups.google.com/d/forum/pydna) for pydna.

Below are the instructions for developers who want to contribute to pydna. Please direct pull requests towards the `dev_bjorn` branch.

### Fork the repository and set up a dev branch ๐Ÿด

Fork the entire repository (not just the `master` branch by unticking the "Copy the `master` branch only" box)

<img src="docs/_static/create-fork.png" alt="Fork repository" width="400">

Create your branch starting from `dev_bjorn`, and if your changes are related to an issue, call the branch `issue_<number>`.

```bash
# Clone the repository
git clone https://github.com/<your-username>/pydna.git

# Change to the repository directory
cd pydna

# Go to the dev_bjorn branch
git checkout -b dev_bjorn

# Pull the current version of dev_bjorn
git pull origin dev_bjorn

# Create your own branch
git checkout -b issue_<number>
```

### Local development ๐Ÿ’ป

#### Preferred method (using `poetry`) ๐Ÿง™โ€โ™‚๏ธ

This is the preferred method to develop on pydna, so if you plan to contribute regularly, it's worth taking this route. If you
encounter any issues setting up the dev environment, create an issue on GitHub and we will be able to help.

Use [Poetry](https://python-poetry.org/docs/#installation) to install dependencies and activate virtual environment. This is necessary
if you want to edit the project dependencies. Install poetry using [pipx](https://github.com/pypa/pipx) following poetry's installation instructions, do not install it
in the system python or the project environment.

```bash
# If you want the virtual environment to be created in this folder
# (this is now the default, see `poetry.toml`)
poetry config virtualenvs.in-project true

# Install dependencies (extras are required for tests to pass)
poetry install --all-extras

# Activate virtual environment
poetry shell

# Install pre-commit hooks
poetry run pre-commit install
```

#### Alternative method (using `pip`) ๐Ÿ

Use this for a small contribution or if you don't manage to set up the dev environment.

```bash
# Create a new virtual environment
python -m venv .venv

# Activate the virtual environment
source .venv/bin/activate

# Install all dependencies (library deps + dev and test requirements)
pip install -r requirements.txt

# Install the project as editable dependency
pip install -e .

# Install the pre-commit hooks
pre-commit install
```

#### Contributing code ๐Ÿ’ป

1. Make your changes.
2. Add the necessary tests in `tests/`.
3. Run the tests from the root directory with `python run_test.py`.
   > **TIP:** You can run a particular test file with `pytest -vs test_file.py` (`-v` for verbose and `-s` to see print statements in the test). If you want to run just a single test, you can use `pytest -vs -k test_name`, where `test_name` is the name of the test function.
4. Before committing, install `pre-commit` hooks if you haven't by running `pre-commit install`. `pre-commit` should be available in the environment regardless of the method you use to set up the dev environment.
   > **TIP:** The hooks are a series of checks that will be run before you commit your code. If any of the checks fail, the commit will not be allowed. Some of them auto-fix the code (e.g., `black` formatting), so you can simply do `git add .` and commit again. Others like `flake8` will prevent the commit to happen until the code is compliant.  For instance, if you import a module in a file and not use it, `flake8` will complain. For a full list of checks, see `.pre-commit-config.yaml`.
5. Push the changes to your fork

### Creating a PR ๐Ÿ”—

 * From your fork, make a PR towards the branch `dev_bjorn` in the original repository.
 * Mention the issue number in the PR description (e.g., `Closes #123`).
 * Remember to click the "Allow edits from maintainers" checkbox so that we can make some changes to the PR if necessary.

### Continuous integration ๐Ÿค–

The test_and_coverage workflow is triggered on all pushed commits for all branches except the `master` branch. This workflow run tests, doctests and a series of Jupyter notebooks using pytest on Linux, Windows and macOS with all
supported python versions.

### Building the documentation locally ๐Ÿ“š

Documentation is built using [Sphinx](http://www.sphinx-doc.org/) from [docstrings](https://www.python.org/dev/peps/pep-0257/)
using a GitHub [action](https://github.com/BjornFJohansson/pydna/actions/workflows/publish-docs.yml).
The [numpy](https://www.numpy.org) [docstring format](https://numpy.org/doc/stable/dev/howto-docs.html#docstring-intro) is used.

Below the commands to run a local sphinx server that auto-updated when files are changed.

```bash
# Install docs dependency group
poetry install --with docs

# Start the sphinx server to see docs live by default at http://127.0.0.1:8000/
sphinx-autobuild --watch src/ docs docs/_build/html

```

More info about how to contribute to the documentation can be found [here](docs/README.md)

## Release process ๐Ÿš€

See the [releases](https://github.com/BjornFJohansson/pydna/releases) for changes and releases.

The build workflow builds a PyPI packages using poetry. This workflow is triggered by publishing a Github release manually from the Github web interface.

![----]( http://bit.ly/coloredline)

## History ๐Ÿ“œ

Pydna was made public in 2012 on [Google code](https://code.google.com/archive/p/pydna).

:microbe:

:portugal:

## Who is using pydna? ๐Ÿงช

Taylor, L. J., & Strebel, K. (2017).
Pyviko: an automated Python tool to design gene knockouts in complex viruses with overlapping genes.
BMC Microbiology, 17(1), 12.
[PubMed](https://www.ncbi.nlm.nih.gov/pubmed/28061810)

Wang, Y., Xue, H., Pourcel, C., Du, Y., & Gautheret, D. (2021).
2-kupl: mapping-free variant detection from DNA-seq data of matched samples.
In Cold Spring Harbor Laboratory (p. 2021.01.17.427048). [DOI](https://doi.org/10.1101/2021.01.17.427048)
[PubMed](https://www.ncbi.nlm.nih.gov/pmc/articles/PMC8180056)

[ShareYourCloning](https://shareyourcloning.org), a web application for designing and documenting DNA cloning strategies.

[An Automated Protein Synthesis Pipeline with Transcriptic and Snakemake](http://blog.booleanbiotech.com/transcriptic_protein_synthesis_pipeline.html)

and other projects on [github](https://github.com/BjornFJohansson/pydna/network/dependents?package_id=UGFja2FnZS01MjQ2MjYzNQ%3D%3D)

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/BjornFJohansson/pydna#-pydna",
    "name": "pydna",
    "maintainer": null,
    "docs_url": null,
    "requires_python": "<4.0,>=3.8",
    "maintainer_email": null,
    "keywords": null,
    "author": "BjornFJohansson",
    "author_email": "bjornjobb@gmail.com",
    "download_url": "https://files.pythonhosted.org/packages/28/ba/7e4afc1b4b5e09037043d23804a78eeff0f802adf32b9650ce627a6225a2/pydna-5.3.0.tar.gz",
    "platform": null,
    "description": "# ![icon](docs/_static/pydna.resized.png) pydna\n\n| [![Tests & Coverage](https://github.com/BjornFJohansson/pydna/actions/workflows/pydna_test_and_coverage_workflow.yml/badge.svg?branch=dev_bjorn)](https://github.com/BjornFJohansson/pydna/actions/workflows/pydna_test_and_coverage_workflow.yml) | [![codecov](https://codecov.io/gh/BjornFJohansson/pydna/branch/master/graph/badge.svg)](https://codecov.io/gh/BjornFJohansson/pydna/branch/master) | [![PyPI version](https://badge.fury.io/py/pydna.svg)](https://badge.fury.io/py/pydna)                                                  | [![Google group : pydna](https://img.shields.io/badge/Google%20Group-pydna-blue.svg)](https://groups.google.com/g/pydna)              |\n| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |\n| [![Documentation Status](https://github.com/BjornFJohansson/pydna/actions/workflows/publish-docs.yml/badge.svg)](https://github.com/BjornFJohansson/pydna/actions/workflows/publish-docs.yml)                                                      | [![GitHub issues](https://img.shields.io/github/issues/BjornFJohansson/pydna.svg)](https://github.com/BjornFJohansson/pydna/issues)                | [![Anaconda-Server Badge2](https://anaconda.org/bjornfjohansson/pydna/badges/license.svg)](https://anaconda.org/bjornfjohansson/pydna) | [![GitHub stars](https://img.shields.io/github/stars/BjornFJohansson/pydna.svg)](https://github.com/BjornFJohansson/pydna/stargazers) |\n\n<!-- docs/index.rst-start -->\n\nPydna is a python package that provides a human-readable formal descriptions of \ud83e\uddec cloning and genetic assembly strategies in Python \ud83d\udc0d for simulation and verification.\nPydna can be used as [executable documentation](https://en.wikipedia.org/wiki/Literate_programming) for cloning.\n\nDesigning genetic constructs with many components and steps, like recombinant metabolic pathways \ud83e\uddeb, often makes accurate documentation difficult, as seen in the poor state of scientific literature \u2622\ufe0f\n\nA cloning strategy expressed in pydna is **complete**, **unambiguous** and **stable**.\n\nPydna provides simulation of:\n\n- Primer design\n- PCR\n- Restriction digestion\n- Ligation\n- Gel electrophoresis of DNA with generation of gel images\n- Homologous recombination\n- Gibson assembly\n- Golden gate assembly (in progress)\n\n\nVirtually any sub-cloning experiment can be described in pydna, and its execution yield the sequences of intermediate and final DNA molecules.\n\nPydna has been designed with the goal of being understandable for biologists with only some basic understanding of Python.\n\nPydna can formalize planning and sharing of cloning strategies and is especially useful for complex or combinatorial\nDNA molecule constructions.\n\n<!-- docs/index.rst-end -->\n\n## Acknowledgement \ud83e\udd1d\n\nIf you use pydna in your research, please reference the paper:\n\nPereira, F., Azevedo, F., Carvalho, \u00c2., Ribeiro, G. F., Budde, M. W., & Johansson, B. (2015). Pydna: a simulation and documentation tool for DNA assembly strategies using python. BMC Bioinformatics, 16(142), 142. [doi:10.1186/s12859-015-0544-x](https://doi.org/10.1186/s12859-015-0544-x)\n\n## Documentation and usage \ud83d\udcda\n\nFull documentation of all modules and classes can be found at [https://bjornfjohansson.github.io/pydna](https://bjornfjohansson.github.io/pydna).\n\nTo get started, we recommend you to have a look at the [example notebooks](docs/notebooks). Start by having a look at [Dseq](docs/notebooks/Dseq.ipynb), [Dseq_Features](docs/notebooks/Dseq_Features.ipynb) and [Importing_Seqs](docs/notebooks/Importing_Seqs.ipynb), which cover the basics of working with sequences. The rest of the notebooks cover how to use pydna for different cloning strategies, such as Gibson assembly, Restriction-Ligation, etc.\n\nMost pydna functionality is implemented as methods for the double stranded DNA sequence record\nclasses Dseq and Dseqrecord, which are subclasses of the [Biopython](http://biopython.org/wiki/Main_Page)\n[Seq](http://biopython.org/wiki/Seq) and [SeqRecord](http://biopython.org/wiki/SeqRecord) classes.\n\nThese classes make PCR primer design, PCR simulation and cut-and-paste cloning very simple:\n\n> **NOTE**: You can run this example in [this notebook](docs/notebooks/readme_example.ipynb)\n\n```python\nfrom pydna.dseqrecord import Dseqrecord\n# Let's create a DNA sequence record, and add a feature to it\ndsr = Dseqrecord(\"ATGCAAACAGTAATGATGGATGACATTCAAAGCACTGATTCTATTGCTGAAAAAGATAAT\")\ndsr.add_feature(x=0, y=60,type=\"gene\", label=\"my_gene\") # We add a feature to highlight the sequence as a gene\ndsr.figure()\n```\n\n<pre>\nDseqrecord(-60)\n<mark>ATGCAAACAGTAATGATGGATGACATTCAAAGCACTGATTCTATTGCTGAAAAAGATAAT</mark>\nTACGTTTGTCATTACTACCTACTGTAAGTTTCGTGACTAAGATAACGACTTTTTCTATTA\n</pre>\n\n\n```python\n# This is how it would look as a genbank file\nprint(dsr.format(\"genbank\"))\n```\n\n    LOCUS       name                      60 bp    DNA     linear   UNK 01-JAN-1980\n    DEFINITION  description.\n    ACCESSION   id\n    VERSION     id\n    KEYWORDS    .\n    SOURCE      .\n      ORGANISM  .\n                .\n    FEATURES             Location/Qualifiers\n         misc            1..60\n                         /type=\"gene\"\n                         /label=\"my_gene\"\n    ORIGIN\n            1 atgcaaacag taatgatgga tgacattcaa agcactgatt ctattgctga aaaagataat\n    //\n\n\n\n```python\n# Now let's design primers to amplify it\nfrom pydna.design import primer_design\n# limit is the minimum length of the primer, target_tm is the desired melting temperature of the primer\namplicon = primer_design(dsr, limit=13, target_tm=55)\n# Let's print the primers, and a figure that shows where they align with the template sequence\nprint(\"forward primer:\", amplicon.forward_primer.seq)\nprint(\"reverse primer:\", amplicon.reverse_primer.seq)\namplicon.figure()\n```\n\n```\nforward primer: ATGCAAACAGTAATGATGGA\nreverse primer: ATTATCTTTTTCAGCAATAGAATCA\n\n\n\n\n\n5ATGCAAACAGTAATGATGGA...TGATTCTATTGCTGAAAAAGATAAT3\n                        |||||||||||||||||||||||||\n                        3ACTAAGATAACGACTTTTTCTATTA5\n5ATGCAAACAGTAATGATGGA3\n    ||||||||||||||||||||\n3TACGTTTGTCATTACTACCT...ACTAAGATAACGACTTTTTCTATTA5\n```\n\n\n\n```python\n# Let's say we don't want to just amplify it, but we want to add restriction sites to it!\nfrom pydna.amplify import pcr\n# We add the restriction sites to the primers\nforward_primer = \"ccccGGATCC\" + amplicon.forward_primer\nreverse_primer = \"ttttGGATCC\" + amplicon.reverse_primer\n\n# We do the PCR\npcr_product = pcr(forward_primer, reverse_primer, dsr)\n# The PCR product is of class `Amplicon`, a subclass of `Dseqrecord`.\n# When doing a figure, it shows where primers anneal.\npcr_product.figure()\n```\n\n```\n            5ATGCAAACAGTAATGATGGA...TGATTCTATTGCTGAAAAAGATAAT3\n                                    |||||||||||||||||||||||||\n                                    3ACTAAGATAACGACTTTTTCTATTACCTAGGtttt5\n5ccccGGATCCATGCAAACAGTAATGATGGA3\n            ||||||||||||||||||||\n            3TACGTTTGTCATTACTACCT...ACTAAGATAACGACTTTTTCTATTA5\n```\n\n```python\n# If we want to see the sequence more clearly, we can turn it into a `Dseqrecord`\npcr_product = Dseqrecord(pcr_product)\npcr_product.figure()\n```\n\n<pre>\nDseqrecord(-80)\nccccGGATCC<mark>ATGCAAACAGTAATGATGGATGACATTCAAAGCACTGATTCTATTGCTGAAAAAGATAAT</mark>GGATCCaaaa\nggggCCTAGGTACGTTTGTCATTACTACCTACTGTAAGTTTCGTGACTAAGATAACGACTTTTTCTATTACCTAGGtttt\n</pre>\n\n\n```python\nfrom Bio.Restriction import BamHI # cuts GGATCC\n# a, payload, c are the cut fragments\na, payload, c = pcr_product.cut (BamHI)\nprint(a.figure())\nprint()\nprint (payload.figure())\nprint()\nprint(c.figure())\n```\n\n<pre>\nDseqrecord(-9)\nccccG\nggggCCTAG\n\nDseqrecord(-70)\nGATCC<mark>ATGCAAACAGTAATGATGGATGACATTCAAAGCACTGATTCTATTGCTGAAAAAGATAAT</mark>G\n    GTACGTTTGTCATTACTACCTACTGTAAGTTTCGTGACTAAGATAACGACTTTTTCTATTACCTAG\n\nDseqrecord(-9)\nGATCCaaaa\n    Gtttt\n</pre>\n\n```python\n# We create a circular vector to insert the amplicon into\nvector = Dseqrecord(\"aatgtttttccctCCCGGGcaaaatAGATCTtgctatgcatcatcgatct\", circular=True, name=\"vect\")\nvector.figure()\n```\n\n\n```\nDseqrecord(o50)\naatgtttttccctCCCGGGcaaaatAGATCTtgctatgcatcatcgatct\nttacaaaaagggaGGGCCCgttttaTCTAGAacgatacgtagtagctaga\n```\n\n\n```python\nfrom Bio.Restriction import BglII # cuts AGATCT\nlinear_vector_bgl = vector.cut(BglII)[0] # Linearize the vector at BglII (produces only one fragment)\n\n# Ligate the fragment of interest to the vector, and call looped() to circularize it\n# synced is used to place the origin coordinate (0) in the same place for rec_vector and vector\nrec_vector= (linear_vector_bgl + payload).looped().synced(vector)\nrec_vector.figure()\n\n```\n\n<pre>\nDseqrecord(o116)\naatgtttttccctCCCGGGcaaaatAGATCC<mark>ATGCAAACAGTAATGATGGATGACATTCAAAGCACTGATTCTATTGCTGAAAAAGATAAT</mark>GGATCTtgctatgcatcatcgatct\nttacaaaaagggaGGGCCCgttttaTCTAGGTACGTTTGTCATTACTACCTACTGTAAGTTTCGTGACTAAGATAACGACTTTTTCTATTACCTAGAacgatacgtagtagctaga\n</pre>\n\n\n\n```python\n# Let's simulate a Gibson assembly\nfrom pydna.assembly import Assembly\n\nfragments = [\n    Dseqrecord('aatgtttttccctCACTACGtgctatgcatcat', name=\"fragment_A\"),\n    Dseqrecord('tgctatgcatcatCTATGGAcactctaataatg', name=\"fragment_B\"),\n    Dseqrecord('cactctaataatgTTACATAaatgtttttccct', name=\"fragment_C\"),\n]\n\n# limit is the min. homology length between fragments in the assembly\nasm = Assembly(fragments, limit=10)\n\n# From the assembly object, which can generate all possible products, get a circular\nproduct, *rest = asm.assemble_circular()\n\n# We can print a figure that shows the overlaps between fragments\nproduct.figure()\n\n```\n     -|fragment_A|13\n    |             \\/\n    |             /\\\n    |             13|fragment_B|13\n    |                           \\/\n    |                           /\\\n    |                           13|fragment_C|13\n    |                                         \\/\n    |                                         /\\\n    |                                         13-\n    |                                            |\n     --------------------------------------------\n\n```python\n# Or show the final sequence:\nDseqrecord(product).figure()\n\n```\n\n```\nDseqrecord(o60)\naatgtttttccctCACTACGtgctatgcatcatCTATGGAcactctaataatgTTACATA\nttacaaaaagggaGTGATGCacgatacgtagtaGATACCTgtgagattattacAATGTAT\n```\n\n\nAs the example above shows, pydna keeps track of sticky ends and features.\n\nPydna can be very compact. The eleven lines of Python below simulates the construction of a recombinant plasmid.\nDNA sequences are downloaded from Genbank by accession numbers that are guaranteed to be stable over time.\n\n```python\nfrom pydna.genbank import Genbank\ngb = Genbank(\"myself@email.com\") # Tell Genbank who you are!\ngene = gb.nucleotide(\"X06997\") # Kluyveromyces lactis LAC12 gene for lactose permease.\nfrom pydna.parsers import parse_primers\nprimer_f,primer_r = parse_primers(''' >760_KlLAC12_rv (20-mer)\n                                        ttaaacagattctgcctctg\n\n                                        >759_KlLAC12_fw (19-mer)\n                                        aaatggcagatcattcgag ''')\n\nfrom pydna.amplify import pcr\npcr_prod = pcr(primer_f,primer_r, gene)\nvector = gb.nucleotide(\"AJ001614\") # pCAPs cloning vector\nfrom Bio.Restriction import EcoRV\nlin_vector = vector.linearize(EcoRV)\nrec_vec =  ( lin_vector + pcr_prod ).looped()\n```\n\n## Installation \ud83d\udce6\n\n<!-- docs/installation.rst-start -->\n\nBy default, pydna is installed with minimal dependencies, but there are optional dependencies for additional functionality.\n\n\n### Optional dependencies\n<details>\n<summary>Click here to see optional dependencies</summary>\n\n<!-- I did not make these headers because they mess up the sphinx docs by being inside of a collapsible section-->\n\n_________________\n\n**clipboard**\n\nEnables the `pydna.dseqrecord.Dseqrecord.copy_gb_to_clipboard()` and `pydna.dseqrecord.Dseqrecord.copy_fasta_to_clipboard()`\n\nThese methods will put a copy the sequence on the clipboard in either Genbank (gb) or fasta format.\n\n\n| Dependency                                          | Function in pydna          |\n| --------------------------------------------------- | -------------------------- |\n| [pyperclip](https://pypi.python.org/pypi/pyperclip) | copy sequence to clipboard |\n\n_________________\n\n**download**\n\nPyparsing enables the `pydna.genbankfixer.gbtext_clean()` function that can automatically\ncorrect malformed sequence files in Genbank format. These are often found online, so this\noption also installs requests to enable the  `pydna.genbankfixer.download.download_text()` function which can be used to get cleaned up text from a URL.\n\n\n| Dependency                                          | Function in pydna                                 |\n| --------------------------------------------------- | ------------------------------------------------- |\n| [pyparsing](https://pypi.python.org/pypi/pyparsing) | fix corrupt Genbank files with pydna.genbankfixer |\n| [requests](https://pypi.org/project/requests)       | download sequences with pydna.download            |\n\n_________________\n\n**express**\n\nThis option enables the `pydna.utils.cai()` function and the `cai()` method\navailable from subclasses of `pydna.seqrecord.SeqRecord`, such as\n`pydna.dseqrecord.Dseqrecord`.\n\n| [cai2](https://pypi.python.org/pypi/cai2)           | codon adaptation index calculations in several modules |\n\n_________________\n\n**gel**\n\nScipy, matplotlib and pillow (PIL) enable the generation of gel images. Numpy is also\nneeded, but usually installed as a dependency of biopython.\n\n\n| Dependency                                        | Function in pydna             |\n| ------------------------------------------------- | ----------------------------- |\n| [scipy](https://www.scipy.org)                    | gel simulation with pydna.gel |\n| [matplotlib](http://matplotlib.org)               | \u201c                             |\n| [pillow](https://github.com/python-pillow/Pillow) | \u201c                             |\n\n_________________\n\n</details>\n\n### Installing with pip \ud83d\udc0d\n\n```bash\n# use the `--pre` flag to get the latest version of pydna.\npip install --pre --upgrade pydna\n\n# to install the optional dependencies, you can use the following command:\npip install --pre --upgrade pydna[clipboard,download,express,gel]\n```\n\nRemove options inside the square brackets as required, but be sure not to leave spaces as pip will not recognize the options. See below under \"Optional dependencies\".\n\n### Installing with poetry \ud83e\uddd9\u200d\u2642\ufe0f\n\nIf your project uses [poetry](https://python-poetry.org/) to manage dependencies, you can install pydna with the following commands:\n\n```bash\n# Basic installation\npoetry add pydna\n# With optional dependencies (ommit the options you don't want)\npoetry add pydna --extras \"clipboard download express gel\"\n\n# If you already have it installed and you want to add or remove optional\n# dependencies, you have to uninstall and install again\npoetry remove pydna\npoetry add pydna --extras \"express gel\"\n```\n\n<!-- docs/installation.rst-end -->\n\n## Contributing and feedback \ud83d\udee0\ufe0f\n\nFeedback & suggestions are very welcome! Please create an issue with your question, comment or suggestion. Please include the version of pydna you are using and code to reproduce the issue if possible.\n\nIf you don't have a github account, you can get in touch through the [google group](https://groups.google.com/d/forum/pydna) for pydna.\n\nBelow are the instructions for developers who want to contribute to pydna. Please direct pull requests towards the `dev_bjorn` branch.\n\n### Fork the repository and set up a dev branch \ud83c\udf74\n\nFork the entire repository (not just the `master` branch by unticking the \"Copy the `master` branch only\" box)\n\n<img src=\"docs/_static/create-fork.png\" alt=\"Fork repository\" width=\"400\">\n\nCreate your branch starting from `dev_bjorn`, and if your changes are related to an issue, call the branch `issue_<number>`.\n\n```bash\n# Clone the repository\ngit clone https://github.com/<your-username>/pydna.git\n\n# Change to the repository directory\ncd pydna\n\n# Go to the dev_bjorn branch\ngit checkout -b dev_bjorn\n\n# Pull the current version of dev_bjorn\ngit pull origin dev_bjorn\n\n# Create your own branch\ngit checkout -b issue_<number>\n```\n\n### Local development \ud83d\udcbb\n\n#### Preferred method (using `poetry`) \ud83e\uddd9\u200d\u2642\ufe0f\n\nThis is the preferred method to develop on pydna, so if you plan to contribute regularly, it's worth taking this route. If you\nencounter any issues setting up the dev environment, create an issue on GitHub and we will be able to help.\n\nUse [Poetry](https://python-poetry.org/docs/#installation) to install dependencies and activate virtual environment. This is necessary\nif you want to edit the project dependencies. Install poetry using [pipx](https://github.com/pypa/pipx) following poetry's installation instructions, do not install it\nin the system python or the project environment.\n\n```bash\n# If you want the virtual environment to be created in this folder\n# (this is now the default, see `poetry.toml`)\npoetry config virtualenvs.in-project true\n\n# Install dependencies (extras are required for tests to pass)\npoetry install --all-extras\n\n# Activate virtual environment\npoetry shell\n\n# Install pre-commit hooks\npoetry run pre-commit install\n```\n\n#### Alternative method (using `pip`) \ud83d\udc0d\n\nUse this for a small contribution or if you don't manage to set up the dev environment.\n\n```bash\n# Create a new virtual environment\npython -m venv .venv\n\n# Activate the virtual environment\nsource .venv/bin/activate\n\n# Install all dependencies (library deps + dev and test requirements)\npip install -r requirements.txt\n\n# Install the project as editable dependency\npip install -e .\n\n# Install the pre-commit hooks\npre-commit install\n```\n\n#### Contributing code \ud83d\udcbb\n\n1. Make your changes.\n2. Add the necessary tests in `tests/`.\n3. Run the tests from the root directory with `python run_test.py`.\n   > **TIP:** You can run a particular test file with `pytest -vs test_file.py` (`-v` for verbose and `-s` to see print statements in the test). If you want to run just a single test, you can use `pytest -vs -k test_name`, where `test_name` is the name of the test function.\n4. Before committing, install `pre-commit` hooks if you haven't by running `pre-commit install`. `pre-commit` should be available in the environment regardless of the method you use to set up the dev environment.\n   > **TIP:** The hooks are a series of checks that will be run before you commit your code. If any of the checks fail, the commit will not be allowed. Some of them auto-fix the code (e.g., `black` formatting), so you can simply do `git add .` and commit again. Others like `flake8` will prevent the commit to happen until the code is compliant.  For instance, if you import a module in a file and not use it, `flake8` will complain. For a full list of checks, see `.pre-commit-config.yaml`.\n5. Push the changes to your fork\n\n### Creating a PR \ud83d\udd17\n\n * From your fork, make a PR towards the branch `dev_bjorn` in the original repository.\n * Mention the issue number in the PR description (e.g., `Closes #123`).\n * Remember to click the \"Allow edits from maintainers\" checkbox so that we can make some changes to the PR if necessary.\n\n### Continuous integration \ud83e\udd16\n\nThe test_and_coverage workflow is triggered on all pushed commits for all branches except the `master` branch. This workflow run tests, doctests and a series of Jupyter notebooks using pytest on Linux, Windows and macOS with all\nsupported python versions.\n\n### Building the documentation locally \ud83d\udcda\n\nDocumentation is built using [Sphinx](http://www.sphinx-doc.org/) from [docstrings](https://www.python.org/dev/peps/pep-0257/)\nusing a GitHub [action](https://github.com/BjornFJohansson/pydna/actions/workflows/publish-docs.yml).\nThe [numpy](https://www.numpy.org) [docstring format](https://numpy.org/doc/stable/dev/howto-docs.html#docstring-intro) is used.\n\nBelow the commands to run a local sphinx server that auto-updated when files are changed.\n\n```bash\n# Install docs dependency group\npoetry install --with docs\n\n# Start the sphinx server to see docs live by default at http://127.0.0.1:8000/\nsphinx-autobuild --watch src/ docs docs/_build/html\n\n```\n\nMore info about how to contribute to the documentation can be found [here](docs/README.md)\n\n## Release process \ud83d\ude80\n\nSee the [releases](https://github.com/BjornFJohansson/pydna/releases) for changes and releases.\n\nThe build workflow builds a PyPI packages using poetry. This workflow is triggered by publishing a Github release manually from the Github web interface.\n\n![----]( http://bit.ly/coloredline)\n\n## History \ud83d\udcdc\n\nPydna was made public in 2012 on [Google code](https://code.google.com/archive/p/pydna).\n\n:microbe:\n\n:portugal:\n\n## Who is using pydna? \ud83e\uddea\n\nTaylor, L. J., & Strebel, K. (2017).\nPyviko: an automated Python tool to design gene knockouts in complex viruses with overlapping genes.\nBMC Microbiology, 17(1), 12.\n[PubMed](https://www.ncbi.nlm.nih.gov/pubmed/28061810)\n\nWang, Y., Xue, H., Pourcel, C., Du, Y., & Gautheret, D. (2021).\n2-kupl: mapping-free variant detection from DNA-seq data of matched samples.\nIn Cold Spring Harbor Laboratory (p. 2021.01.17.427048). [DOI](https://doi.org/10.1101/2021.01.17.427048)\n[PubMed](https://www.ncbi.nlm.nih.gov/pmc/articles/PMC8180056)\n\n[ShareYourCloning](https://shareyourcloning.org), a web application for designing and documenting DNA cloning strategies.\n\n[An Automated Protein Synthesis Pipeline with Transcriptic and Snakemake](http://blog.booleanbiotech.com/transcriptic_protein_synthesis_pipeline.html)\n\nand other projects on [github](https://github.com/BjornFJohansson/pydna/network/dependents?package_id=UGFja2FnZS01MjQ2MjYzNQ%3D%3D)\n",
    "bugtrack_url": null,
    "license": "BSD",
    "summary": "Representing double stranded DNA and functions for simulating cloning and homologous recombination between DNA molecules.",
    "version": "5.3.0",
    "project_urls": {
        "Changelog": "https://github.com/BjornFJohansson/pydna/blob/master/docs/CHANGELOG.md#changelog",
        "Documentation": "https://pydna.readthedocs.io/?badge=latest",
        "Homepage": "https://github.com/BjornFJohansson/pydna#-pydna",
        "Repository": "https://github.com/BjornFJohansson/pydna/tree/dev_bjorn"
    },
    "split_keywords": [],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "d6860753fb28e189fd769e95d1d18ba7cca1235aad8badda17723a1d423a51e3",
                "md5": "b014bb3c2535ca038ac62a8accb74c61",
                "sha256": "97572c15250c1a51e2facee5b85d85f80e519bd5368f46604ca0227a1000d060"
            },
            "downloads": -1,
            "filename": "pydna-5.3.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "b014bb3c2535ca038ac62a8accb74c61",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": "<4.0,>=3.8",
            "size": 128955,
            "upload_time": "2024-12-13T11:21:57",
            "upload_time_iso_8601": "2024-12-13T11:21:57.699238Z",
            "url": "https://files.pythonhosted.org/packages/d6/86/0753fb28e189fd769e95d1d18ba7cca1235aad8badda17723a1d423a51e3/pydna-5.3.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "28ba7e4afc1b4b5e09037043d23804a78eeff0f802adf32b9650ce627a6225a2",
                "md5": "bb4d64a613f447c382fb8ed436fe1197",
                "sha256": "84c4847753fd8d22e6cf5e6a6d973ea4a96cf99fee1007d12e53129418fc34dd"
            },
            "downloads": -1,
            "filename": "pydna-5.3.0.tar.gz",
            "has_sig": false,
            "md5_digest": "bb4d64a613f447c382fb8ed436fe1197",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": "<4.0,>=3.8",
            "size": 115137,
            "upload_time": "2024-12-13T11:22:00",
            "upload_time_iso_8601": "2024-12-13T11:22:00.364661Z",
            "url": "https://files.pythonhosted.org/packages/28/ba/7e4afc1b4b5e09037043d23804a78eeff0f802adf32b9650ce627a6225a2/pydna-5.3.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-12-13 11:22:00",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "BjornFJohansson",
    "github_project": "pydna#-pydna",
    "travis_ci": false,
    "coveralls": true,
    "github_actions": true,
    "requirements": [],
    "lcname": "pydna"
}
        
Elapsed time: 0.47270s