PyShp reads and writes the three ESRI shapefile files in one pure Python module
This library reads and writes ESRI Shapefiles in pure Python.
At a glance
- What is it?
- PyShp is a pure Python library for the Esri Shapefile format, where a dataset is really three files, the shp and shx geometry pair and a dbf attribute table. The library handles that whole trio with no dependencies, and its recent releases have been almost entirely about encoding correctness rather than new features.
- Who is it for?
- PyShp fits a script that needs to read or write a shapefile without installing a binary or a full GIS stack, and the dependency free package with Python 3.9 support is easy to drop into a data pipeline. It is the wrong tool for analysis, since it does not project coordinates and does not do spatial work beyond the filtering the README describes.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 1 day ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on November 7, 2026, and from our analysis. They are not legal advice.
Star history
- GeospatialPython/pyshp1,160 ★ · +3
| Repository | 2026-10-19 | 2026-11-07 |
|---|---|---|
| GeospatialPython/pyshp | 1.2k | 1.2k |
3 Stars in the last 19 days, measured from the daily GitHub snapshot. Compare with other projects
Editorial analysis
A shapefile is three files, and PyShp treats them as one dataset
The Overview section of the README explains the format before it explains the library, and that ordering is the right one to read it in.
A shapefile is not a single file. The Esri document describes the shp and shx file formats, but a third file format called dbf is also required, documented on the web as the XBase File Format Description, a simple file based database format created in the 1960s. The reason both the Esri and the XBase specifications are linked is that you need them to implement the format yourself.
The library's claim is that both formats are very simple in design and memory efficient, which the README offers as part of the reason the shapefile format remains popular despite the numerous ways to store and exchange GIS data available today. That is the technical context for what PyShp is for: a format that is still everywhere, whose geometry and attribute halves are separate files, and which most tools treat as a unit.
The project identity is also in the README. The author is Joel Lawhead, and the maintainers are James Parrott and Karim Bahgat. The author's blog is GeospatialPython.com, with more examples on that blog and on GIS StackExchange, and there is a wiki page on map projections that the README points to as required reading for anyone new to GIS.
That last point is the one to hold on to, because it tells you what the library does not do.
The Reader and the Writer, and four ways to open a file
The API is two classes, and the README's table of contents shows how much of the surface is about input and output plumbing rather than geometry.
The Reader class opens a shapefile, and the contents list shows four sources: local files, zip files, URLs and file like objects. Each of those has its own section, which means the same Reader handles a path, an archive, a download and an object you already have in memory. There is also a section on using the reader as a context manager, and one on reading shapefile metadata.
From the reader you get geometry, then records, and both at once by reading them together. Reading geometry and records together is the one that matters for large files.
The Writer class mirrors that structure, with sections for writing to local files, to file like objects, and through the context manager, then for setting the shape type, adding records and adding geometry. There is a section named Geometry and Record Balancing, which covers keeping the number of geometry records and attribute records in step.
The writer also has the field definitions and the shape type, and the shape type is not a detail you can ignore, because it is what tells a reader whether the file holds points, polylines, polygons or something else, and it has to match the geometry you actually write.
The last six releases are about encoding, not features
The Version Changes section is the most informative part of the README, because it shows where the maintenance effort has gone.
Version 3.1.6 added a feature: encodings can now be read from .cpg files, and optionally written to them. The .cpg file is a small sidecar that records the character encoding of the dbf table, and reading it removes a guess from the workflow.
Version 3.1.5 was a bug fix, another bug causing dates before the year 1000 to be encoded as less than 8 chars under the %Y%m%d format, found by Thomas Beierlein. Version 3.1.4 fixed a bug causing dates supplied as length 8 strings of digits to be encoded by the custom encoding rather than ascii, and its testing note says the CI now tests all available codecs, 92 of them, after adding tests for other codecs such as ascii, UTF-8, UTF-16 and UTF-32. Version 3.1.3 restored faster text writing paths for single byte Ascii encodings and UTF-8, which is a reminder that correctness work has a performance cost.
The bigger structural change came in 3.1.0 and 3.1.1, and it is about Unicode. Truncation of field names and text fields now respects Unicode code point boundaries, fixing two reported issues, and warnings are raised if truncation, or replacing a space with an underscore, would corrupt encoded field names, either because the result would be undecodable or because it would silently decode to incorrect data. When reading, only the minimum number of pad bytes is used to decode text successfully. When writing, PyShp warns, or raises in strict mode, if the text's encoding ends in pad bytes.
That last mechanism is the one to know about, because a silently mis-decoded attribute is the kind of bug that survives a long time in a pipeline. The new strict mode, Writer(strict=True), raises errors or refuses to create fields and text records with data that would be truncated or cannot be encoded.
Reading a big shapefile without loading it into memory
The Advanced Use section is organised around scale, and it is where the library earns its place in a data pipeline.
For reading large shapefiles, the README documents four techniques. The first is iterating through a shapefile, reading geometry and records simultaneously. The second is limiting which fields to read, so that a wide attribute table does not have to be decoded in full for a query that only needs two columns. The third is attribute filtering, and the fourth is spatial filtering.
Those last two are the interesting ones, because filtering is where a shapefile reader usually needs a spatial index, and the README presents them as built in features rather than as something you bolt on. A reader that can filter spatially without an external index is the difference between a script that scales and one that stops working when the dataset gets big.
For writing large shapefiles, the README documents two workflows: merging multiple shapefiles, and editing shapefiles. Editing in particular is the operation that a lot of tools do badly, because rewriting a file means re-encoding every record, and the encoding work described above is exactly what can go wrong in that path.
The last structural section covers 3D and other geometry types, with separate subsections for shapefiles with measurement (M) values, shapefiles with elevation (Z) values, and 3D MultiPatch shapefiles. Those are the format features that separate a simple polygon file from a full GIS dataset, and they are the ones most libraries skip.
One module, no dependencies, and a licence anyone can use
The packaging is deliberately plain. The build system is hatchling, the project name is pyshp, the licence is MIT with the text in LICENSE.TXT, and the version is dynamic, read by hatch from src/shapefile.py. The wheel target includes only src, with the sources mapping moving the files out of the src directory, and the sdist includes src and tests.
The interesting line is requires-python, which is >=3.9. The classifier list says Python 3 only, and the development status is recorded as 5, Production/Stable. The lint group pins mypy at 1.19.1 with a comment that it is the last version to support Python 3.9, and the test group is pytest plus hypothesis, which is a sensible pairing for a parser: property based testing is how you find the encoding edge cases that the 3.1.4 and 3.1.5 fixes describe.
There is also an optional extra for type stubs, stubs, which pulls in the separate pyshp-stubs package, so a typed codebase can use the library without mypy complaints, while the library itself stays dependency free.
The repository is small and conventional: src/, tests/, a changelog.txt, a SECURITY.md, a CONTRIBUTING.md, a pre-commit config and a uv.lock. The version in the README is 3.1.6, dated 25th July 2026, and the last push was on 2026-10-07.
Editorial conclusion
PyShp fits a script that needs to read or write a shapefile without installing a binary or a full GIS stack, and the dependency free package with Python 3.9 support is easy to drop into a data pipeline. It is the wrong tool for analysis, since it does not project coordinates and does not do spatial work beyond the filtering the README describes. Verify first which encoding your source files actually use, because that is where most of the recent bug fixes sit, and enable strict mode when writing so that a truncated field name fails loudly rather than silently corrupting data.
Frequently asked questions
How do I install PyShp?
The package is pyshp on PyPI, built with hatchling and requiring Python 3.9 or above, with no runtime dependencies. There is also an optional stubs extra, which installs the separate pyshp-stubs package for type checking.
What files does PyShp read for a shapefile?
A shapefile dataset is made of the shp and shx files described in the Esri Shapefile Technical Description, plus a dbf attribute table documented as the XBase File Format Description. PyShp handles the trio together through its Reader class.
How does PyShp handle encoding problems?
Since 3.1.6 encodings can be read from .cpg files and optionally written to them. Earlier releases made truncation respect Unicode code point boundaries, added warnings when a field name would be corrupted, and introduced a strict mode where Writer(strict=True) raises instead of writing data that would be truncated or cannot be encoded.
Can PyShp handle large shapefiles?
The README documents iterating through a shapefile, limiting which fields to read, attribute filtering and spatial filtering, and for writing it documents merging multiple shapefiles and editing shapefiles. The design of the underlying formats is described as memory efficient.
Does PyShp handle map projections?
The README does not describe projection handling as a feature, and it links to a map projections page in the project wiki with a note that anyone new to GIS should read about map projections before working with these files.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/geospatialpython-pyshp)Star history chart for your README
[](https://hysenlabs.com/projects/geospatialpython-pyshp)Was this useful?